@tea-agent/loop-agent 0.39.0-next.9 → 0.39.1

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 (288) hide show
  1. package/AGENTS.md +4 -1
  2. package/CHANGELOG.md +269 -69
  3. package/README.md +11 -5
  4. package/bin/loop-agent.js +7 -3
  5. package/dist/application/dag/generate-task-dag.js +9 -0
  6. package/dist/application/task-lifecycle/advance.js +16 -0
  7. package/dist/build-stamp.json +3 -3
  8. package/dist/cli/command-definitions.js +16 -5
  9. package/dist/cli/program.js +16 -2
  10. package/dist/cli/update/notifier.js +2 -2
  11. package/dist/cli/update/runtime-activity.js +1 -29
  12. package/dist/cli.js +2 -1
  13. package/dist/commands/dag-rerun.js +55 -1
  14. package/dist/commands/init-model-catalog.js +464 -0
  15. package/dist/commands/init-upgrade.js +265 -97
  16. package/dist/commands/init.js +428 -27
  17. package/dist/commands/inspect-next.js +8 -0
  18. package/dist/commands/task-advance.js +31 -0
  19. package/dist/executors/dag-pi-executor.js +124 -18
  20. package/dist/executors/pi-event-serializer.js +42 -1
  21. package/dist/executors/pi-executor.js +51 -0
  22. package/dist/executors/pi-extension-resolver.js +233 -0
  23. package/dist/executors/pi-playwright-cli-tool.js +74 -28
  24. package/dist/executors/pi-sdk-executor.js +187 -59
  25. package/dist/executors/shell-executor.js +555 -34
  26. package/dist/executors/shell-write-guard.js +7 -0
  27. package/dist/shared/dag-failure-category.js +138 -0
  28. package/dist/shared/dag-prompt-override.js +27 -0
  29. package/dist/shared/operator/capabilities.js +181 -27
  30. package/dist/shared/playwright-cli-command-policy.js +15 -0
  31. package/dist/shared/update/console-notifier.js +100 -0
  32. package/dist/{cli → shared}/update/npm-client.js +70 -15
  33. package/dist/{cli → shared}/update/state.js +41 -13
  34. package/dist/task/config-types.js +28 -0
  35. package/dist/task/contract/apply.js +11 -1
  36. package/dist/task/contract/constants.js +3 -0
  37. package/dist/task/contract/diff.js +26 -0
  38. package/dist/task/contract/hash.js +3 -0
  39. package/dist/task/contract/observe.js +25 -4
  40. package/dist/task/contract/paths.js +2 -1
  41. package/dist/task/contract/project.js +20 -1
  42. package/dist/task/contract/schema.js +8 -1
  43. package/dist/task/contract/transaction.js +12 -0
  44. package/dist/task/source-prepare/build-draft.js +15 -0
  45. package/dist/task/source-prepare/completeness.js +188 -0
  46. package/dist/task/source-prepare/fragment-inventory.js +474 -0
  47. package/dist/task/source-prepare/index.js +3 -0
  48. package/dist/task/source-prepare/ledger-reconciliation.js +127 -0
  49. package/dist/task/source-prepare/ledger-review.js +214 -0
  50. package/dist/task/source-prepare/ledger.js +545 -0
  51. package/dist/task/source-prepare/parse-intent.js +24 -4
  52. package/dist/task/source-prepare/prepare.js +262 -1
  53. package/dist/task/source-prepare/semantic-intake.js +19 -3
  54. package/dist/task/source-prepare/source-fidelity-pi.js +384 -0
  55. package/dist/task/source-prepare/types.js +22 -0
  56. package/dist/worker/cli.js +18 -2
  57. package/dist/worker/console/chat/deferred-turn.js +91 -0
  58. package/dist/worker/console/chat/mcp-inventory.js +221 -0
  59. package/dist/worker/console/chat/operation-card.js +8 -1
  60. package/dist/worker/console/chat/pi-console-config.js +81 -10
  61. package/dist/worker/console/chat/pi-runtime.js +165 -83
  62. package/dist/worker/console/chat/repo-walk.js +10 -1
  63. package/dist/worker/console/chat/routes.js +480 -55
  64. package/dist/worker/console/chat/semantic-activity.js +20 -8
  65. package/dist/worker/console/chat/session-store.js +146 -2
  66. package/dist/worker/console/chat/turn-process.js +10 -10
  67. package/dist/worker/console/console-handoff.js +82 -0
  68. package/dist/worker/console/console-update-and-init.js +115 -0
  69. package/dist/worker/console/console-update-runtime.js +84 -0
  70. package/dist/worker/console/dag-execution-receipt.js +33 -0
  71. package/dist/worker/console/draft-store.js +49 -0
  72. package/dist/worker/console/inspect-split.js +18 -0
  73. package/dist/worker/console/operation-run-facts.js +19 -3
  74. package/dist/worker/console/operation-store.js +1 -1
  75. package/dist/worker/console/operator-actions.js +320 -4
  76. package/dist/worker/console/operator-surface-health.js +1 -0
  77. package/dist/worker/console/operator-user-error.js +2 -2
  78. package/dist/worker/console/pi-readiness.js +5 -4
  79. package/dist/worker/console/prd-intake-bridge.js +13 -0
  80. package/dist/worker/console/recovery-cta.js +4 -4
  81. package/dist/worker/console/recovery-error-copy.js +4 -4
  82. package/dist/worker/console/routes.js +46 -2
  83. package/dist/worker/console/security.js +63 -9
  84. package/dist/worker/console/server.js +111 -7
  85. package/dist/worker/console/static/assets/{abnfDiagram-N423BO3Z-BLXFe4qI.js → abnfDiagram-N423BO3Z-CTx1TrNa.js} +1 -1
  86. package/dist/worker/console/static/assets/{arc-7iOJeqho.js → arc-B4i9cVxX.js} +1 -1
  87. package/dist/worker/console/static/assets/{architectureDiagram-T3A2C74G-CYoyj5K7.js → architectureDiagram-T3A2C74G-BAXE8_Rl.js} +1 -1
  88. package/dist/worker/console/static/assets/{blockDiagram-VBNYF7ZC-fK01JNlR.js → blockDiagram-VBNYF7ZC-C5Xh59at.js} +1 -1
  89. package/dist/worker/console/static/assets/{c4Diagram-5PPSVZJV-bzbw5D_Z.js → c4Diagram-5PPSVZJV-B_asOzAu.js} +1 -1
  90. package/dist/worker/console/static/assets/channel-Dj_4Moei.js +1 -0
  91. package/dist/worker/console/static/assets/{chunk-2GRJ4B5K-Cf6hJFFG.js → chunk-2GRJ4B5K-wRO_iRNc.js} +1 -1
  92. package/dist/worker/console/static/assets/{chunk-2Q5K7J3B-DSFXR-et.js → chunk-2Q5K7J3B-ByOaSh_G.js} +1 -1
  93. package/dist/worker/console/static/assets/{chunk-5RXB4S5H-BagJechl.js → chunk-5RXB4S5H-DjLzudan.js} +1 -1
  94. package/dist/worker/console/static/assets/{chunk-5VM5RSS4-E7QNMFaW.js → chunk-5VM5RSS4-JCNGkXYT.js} +1 -1
  95. package/dist/worker/console/static/assets/{chunk-6Q2QTUOP-BG_eOBrC.js → chunk-6Q2QTUOP-BhrPXXMZ.js} +1 -1
  96. package/dist/worker/console/static/assets/{chunk-GF5L2VYU-Bo42dqol.js → chunk-GF5L2VYU-TJ5JuEBT.js} +1 -1
  97. package/dist/worker/console/static/assets/{chunk-JWPE2WC7-dibM-87v.js → chunk-JWPE2WC7-VVthn_mD.js} +1 -1
  98. package/dist/worker/console/static/assets/{chunk-KBJHAD2P-Bytrp3Oe.js → chunk-KBJHAD2P-D60-Mny4.js} +1 -1
  99. package/dist/worker/console/static/assets/{chunk-RYQCIY6F-DBABILrr.js → chunk-RYQCIY6F-zXv7aVye.js} +1 -1
  100. package/dist/worker/console/static/assets/{chunk-XXDRQBXY-DCUk5Pf9.js → chunk-XXDRQBXY-By9VQoi1.js} +1 -1
  101. package/dist/worker/console/static/assets/classDiagram-JCYQIIEL-C0YYAyCa.js +1 -0
  102. package/dist/worker/console/static/assets/classDiagram-v2-OCEON4UE-C0YYAyCa.js +1 -0
  103. package/dist/worker/console/static/assets/{cose-bilkent-JH36ORCC-BlGE9v6E.js → cose-bilkent-JH36ORCC-C4zQLe-M.js} +1 -1
  104. package/dist/worker/console/static/assets/{cynefin-VYW2F7L2-DGl5ewph.js → cynefin-VYW2F7L2-wh5N2ReN.js} +1 -1
  105. package/dist/worker/console/static/assets/{cynefinDiagram-MW4NZA55-DsJ_SVH_.js → cynefinDiagram-MW4NZA55-Dlu5wIqs.js} +1 -1
  106. package/dist/worker/console/static/assets/{dagre-VZM6K2ZE-BIhjFdzv.js → dagre-VZM6K2ZE-CrDgthc6.js} +1 -1
  107. package/dist/worker/console/static/assets/{diagram-7IWD3JNH-Dmy1ctTb.js → diagram-7IWD3JNH-zN1clg27.js} +1 -1
  108. package/dist/worker/console/static/assets/{diagram-B4RE2ZJO-DYCtWUF3.js → diagram-B4RE2ZJO-BN-o7J7-.js} +1 -1
  109. package/dist/worker/console/static/assets/{diagram-LBJQPF4R-BMZFHVd2.js → diagram-LBJQPF4R-C8SuPt0d.js} +1 -1
  110. package/dist/worker/console/static/assets/{diagram-Q27KOJAE-b_U8gfaO.js → diagram-Q27KOJAE-BoizuHbZ.js} +1 -1
  111. package/dist/worker/console/static/assets/{diagram-UB23O5K3-Dzy_bn-I.js → diagram-UB23O5K3-BzUzXixG.js} +1 -1
  112. package/dist/worker/console/static/assets/{ebnfDiagram-BXEA7PRR-DJCiMNEI.js → ebnfDiagram-BXEA7PRR-Ev3lA4Cf.js} +1 -1
  113. package/dist/worker/console/static/assets/{erDiagram-JOGREHBK-28lD016B.js → erDiagram-JOGREHBK-GALUzRbs.js} +1 -1
  114. package/dist/worker/console/static/assets/{flowDiagram-UKHOOZJN-DGyHJmIw.js → flowDiagram-UKHOOZJN-CZJN65Sb.js} +1 -1
  115. package/dist/worker/console/static/assets/{ganttDiagram-PKOTCBZU-CzdwUjrO.js → ganttDiagram-PKOTCBZU-JLB9OESl.js} +1 -1
  116. package/dist/worker/console/static/assets/{gitGraphDiagram-DS77QQ5N-D9bGwuo8.js → gitGraphDiagram-DS77QQ5N-CcvCr4GD.js} +1 -1
  117. package/dist/worker/console/static/assets/index-CW88Fjbw.js +406 -0
  118. package/dist/worker/console/static/assets/index-DP0ZJl39.css +1 -0
  119. package/dist/worker/console/static/assets/{infoDiagram-6WML65LV-LJgJUQFC.js → infoDiagram-6WML65LV-HG5z7aVg.js} +1 -1
  120. package/dist/worker/console/static/assets/{ishikawaDiagram-WSZJBQD7-98LaB8zb.js → ishikawaDiagram-WSZJBQD7-BHEu9chR.js} +1 -1
  121. package/dist/worker/console/static/assets/{journeyDiagram-NVQOT4AX-D-ISzwlQ.js → journeyDiagram-NVQOT4AX-Cp_Up8-a.js} +1 -1
  122. package/dist/worker/console/static/assets/{kanban-definition-27J2QSJJ-gfYOI-EL.js → kanban-definition-27J2QSJJ-DvVeY-em.js} +1 -1
  123. package/dist/worker/console/static/assets/{linear-CyntZgKV.js → linear-aGmcjgTn.js} +1 -1
  124. package/dist/worker/console/static/assets/{mermaid.core-BBOR7dg0.js → mermaid.core-Biyo-tqA.js} +5 -5
  125. package/dist/worker/console/static/assets/{mindmap-definition-FAOFIHXS-CQAgwPMk.js → mindmap-definition-FAOFIHXS-DyxY2pIb.js} +1 -1
  126. package/dist/worker/console/static/assets/{pegDiagram-VL7TDLO6-DkMiZFuV.js → pegDiagram-VL7TDLO6-CkdGuc50.js} +1 -1
  127. package/dist/worker/console/static/assets/{pieDiagram-7S7Q4E2Y-DLNXa_0J.js → pieDiagram-7S7Q4E2Y-NNQI9xVR.js} +1 -1
  128. package/dist/worker/console/static/assets/{quadrantDiagram-CIZ2JOQS-Dc7bdzjm.js → quadrantDiagram-CIZ2JOQS-PAJkuz_G.js} +1 -1
  129. package/dist/worker/console/static/assets/{railroadDiagram-AXF67PYL-BxMB0QqW.js → railroadDiagram-AXF67PYL-ZwrQod0O.js} +1 -1
  130. package/dist/worker/console/static/assets/{requirementDiagram-LRYGKXZP-FjumoKn4.js → requirementDiagram-LRYGKXZP-D3ZfrzM2.js} +1 -1
  131. package/dist/worker/console/static/assets/{sankeyDiagram-W5VNT64P-CkhKc_E3.js → sankeyDiagram-W5VNT64P-DDGFmWk5.js} +1 -1
  132. package/dist/worker/console/static/assets/{sequenceDiagram-SI44F4Z6-DoBWqTTH.js → sequenceDiagram-SI44F4Z6-DO6mmXTA.js} +1 -1
  133. package/dist/worker/console/static/assets/{sizeCapture-X5ZJPWSS-CQeh_YeE.js → sizeCapture-X5ZJPWSS-DMbCQiJt.js} +1 -1
  134. package/dist/worker/console/static/assets/{stateDiagram-OKZ733FA-LuHmFW-I.js → stateDiagram-OKZ733FA-Di_YUEfC.js} +1 -1
  135. package/dist/worker/console/static/assets/stateDiagram-v2-UEYNNEHI-DrdDvela.js +1 -0
  136. package/dist/worker/console/static/assets/{swimlanes-SLNWSIFB-CHwbDctY.js → swimlanes-SLNWSIFB-Bn2PphNJ.js} +2 -2
  137. package/dist/worker/console/static/assets/swimlanesDiagram-ULZ7WXOC-DPkEAULl.js +8 -0
  138. package/dist/worker/console/static/assets/{timeline-definition-Z64GVDOM-CoMngk0X.js → timeline-definition-Z64GVDOM-DPh8pRsp.js} +1 -1
  139. package/dist/worker/console/static/assets/{vennDiagram-T6HMQDX7-CURYbtbO.js → vennDiagram-T6HMQDX7-GMfl26pW.js} +1 -1
  140. package/dist/worker/console/static/assets/{wardleyDiagram-T6FBY63Y-BdqSECjU.js → wardleyDiagram-T6FBY63Y-DTlmVrmF.js} +1 -1
  141. package/dist/worker/console/static/assets/{xychartDiagram-ELKLHX3M-DbMUYuAg.js → xychartDiagram-ELKLHX3M-YGBjKAS5.js} +1 -1
  142. package/dist/worker/console/static/index.html +2 -2
  143. package/dist/worker/console/static-src/app/console-types.js +40 -1
  144. package/dist/worker/console/static-src/app/useOperatorActions.js +6 -1
  145. package/dist/worker/console/static-src/app/useRecoveryActions.js +2 -2
  146. package/dist/worker/console/static-src/app/useRecoveryConsole.js +38 -2
  147. package/dist/worker/console/static-src/app/useRunProgress.js +46 -0
  148. package/dist/worker/console/static-src/app/useTaskWizard.js +73 -1
  149. package/dist/worker/console/static-src/operator-chat/cards/failure-category-advice.js +25 -0
  150. package/dist/worker/console/static-src/operator-chat/chat-sse-events.js +74 -26
  151. package/dist/worker/console/static-src/operator-chat/input-history.js +76 -0
  152. package/dist/worker/console/static-src/operator-chat/mutation-gate.js +1 -1
  153. package/dist/worker/console/static-src/operator-chat/open-preview-in-browser.js +328 -0
  154. package/dist/worker/console/static-src/operator-chat/resource-diagnostics.js +204 -0
  155. package/dist/worker/console/static-src/operator-chat/turn-stream-controller.js +8 -1
  156. package/dist/worker/console/static-src/operator-chat/turn-submission.js +54 -0
  157. package/dist/worker/console/static-src/operator-chat/useChatSessions.js +3 -0
  158. package/dist/worker/console/static-src/operator-chat/useChatStream.js +237 -11
  159. package/dist/worker/console/static-src/operator-chat/useChatThread.js +50 -22
  160. package/dist/worker/console/static-src/operator-chat/useComposer.js +32 -0
  161. package/dist/worker/console/static-src/operator-chat/useRepoBrowser.js +26 -1
  162. package/dist/worker/console/static-src/pages/tasks/run-id-resolution.js +79 -0
  163. package/dist/worker/console/static-src/pages/tasks/run-ownership-verify.js +23 -0
  164. package/dist/worker/console/static-src/pages/tasks/run-panel-progress.js +110 -0
  165. package/dist/worker/loop-agent/loop-agent-client.js +7 -3
  166. package/dist/worker/materialize/harness-task-lineage.js +5 -2
  167. package/dist/worker/observability/init-runtime-activity.js +26 -0
  168. package/dist/worker/observability/read-model.js +22 -0
  169. package/dist/worker/observe/node-input.js +160 -3
  170. package/dist/worker/observe/node-process.js +377 -0
  171. package/dist/worker/observe/routes.js +224 -3
  172. package/dist/worker/observe/shell-handler-keys.js +34 -0
  173. package/dist/worker/observe/static/api.js +67 -1
  174. package/dist/worker/observe/static/constants.js +8 -1
  175. package/dist/worker/observe/static/dag-history-labels.js +4 -0
  176. package/dist/worker/observe/static/format.js +60 -0
  177. package/dist/worker/observe/static/index.html +5 -0
  178. package/dist/worker/observe/static/markdown-render.js +20 -1
  179. package/dist/worker/observe/static/operator-chrome.js +4 -0
  180. package/dist/worker/observe/static/prompt-restart-candidates.d.ts +18 -0
  181. package/dist/worker/observe/static/prompt-restart-candidates.js +36 -0
  182. package/dist/worker/observe/static/state.js +13 -2
  183. package/dist/worker/observe/static/styles.css +85 -0
  184. package/dist/worker/observe/static/views/dag-inspector.js +912 -8
  185. package/dist/worker/observe/static/views/dag.js +8 -1
  186. package/dist/worker/observe/static/views/failures.js +5 -2
  187. package/dist/worker/observe/static/views/session-timeline.js +78 -9
  188. package/dist/worker/observe/static/views/task.js +55 -0
  189. package/dist/workflows/dag/backend-test-case-coverage-analysis.js +856 -54
  190. package/dist/workflows/dag/backend-test-case-manifest.js +4 -0
  191. package/dist/workflows/dag/backend-test-execution-contract.js +18 -9
  192. package/dist/workflows/dag/backend-test-gap-fill.js +205 -0
  193. package/dist/workflows/dag/backend-test-intake-context.js +32 -0
  194. package/dist/workflows/dag/backend-test-layout.js +133 -0
  195. package/dist/workflows/dag/backend-test-markdown-workflow.js +343 -33
  196. package/dist/workflows/dag/backend-test-module-stem.js +5 -0
  197. package/dist/workflows/dag/backend-test-pytest-collection.js +454 -36
  198. package/dist/workflows/dag/backend-test-result-contract.js +1 -1
  199. package/dist/workflows/dag/backend-test-scenario-param.js +884 -140
  200. package/dist/workflows/dag/backend-test-scenario-partitions.js +321 -0
  201. package/dist/workflows/dag/backend-test-writer-completeness.js +110 -61
  202. package/dist/workflows/dag/contract-output-registry.js +15 -0
  203. package/dist/workflows/dag/contract-validator-registrations.js +3 -1
  204. package/dist/workflows/dag/convergence/controller.js +141 -0
  205. package/dist/workflows/dag/dynamic-runtime/loop-until.js +1 -1
  206. package/dist/workflows/dag/dynamic-runtime/map.js +25 -9
  207. package/dist/workflows/dag/dynamic-runtime/shared.js +1 -1
  208. package/dist/workflows/dag/failure-category.js +7 -116
  209. package/dist/workflows/dag/frontend-implementation-contract.js +465 -6
  210. package/dist/workflows/dag/frontend-plan-render.js +24 -0
  211. package/dist/workflows/dag/frontend-prewrite-gate.js +293 -84
  212. package/dist/workflows/dag/frontend-repair.js +14 -0
  213. package/dist/workflows/dag/frontend-review-context.js +92 -10
  214. package/dist/workflows/dag/frontend-risk.js +15 -2
  215. package/dist/workflows/dag/frontend-test-case-checklist.js +30 -4
  216. package/dist/workflows/dag/frontend-test-case-manifest.js +11 -4
  217. package/dist/workflows/dag/frontend-test-case-quality.js +11 -16
  218. package/dist/workflows/dag/frontend-test-environment-probe.js +230 -0
  219. package/dist/workflows/dag/frontend-test-html-report.js +3 -1
  220. package/dist/workflows/dag/frontend-test-l5-report.js +3 -1
  221. package/dist/workflows/dag/frontend-test-layout.js +159 -0
  222. package/dist/workflows/dag/frontend-test-markdown.js +61 -0
  223. package/dist/workflows/dag/frontend-test-result-contract.js +188 -42
  224. package/dist/workflows/dag/frontend-test-standard-scenarios.js +70 -0
  225. package/dist/workflows/dag/frontend-verification-trace.js +29 -4
  226. package/dist/workflows/dag/init-hybrid.js +1019 -209
  227. package/dist/workflows/dag/node-execution.js +228 -15
  228. package/dist/workflows/dag/prompt.js +60 -1
  229. package/dist/workflows/dag/rerun-feedback.js +212 -0
  230. package/dist/workflows/dag/rerun-plan.js +224 -27
  231. package/dist/workflows/dag/rerun-run.js +61 -6
  232. package/dist/workflows/dag/rerun-task.js +61 -2
  233. package/dist/workflows/dag/retry-policy.js +109 -0
  234. package/dist/workflows/dag/structured-output-repair.js +712 -0
  235. package/dist/workflows/dag/types.js +185 -12
  236. package/dist/workflows/dag/validate.js +64 -20
  237. package/docs/README.md +1 -0
  238. package/docs/architecture/evolution.md +45 -0
  239. package/docs/init-surface.manifest.json +6 -0
  240. package/docs/operations/README.md +1 -1
  241. package/docs/operations/local-development-environment.md +1 -5
  242. package/docs/skills/vetted-skill-registry.md +14 -0
  243. package/docs/templates/README.md +2 -2
  244. package/docs/templates/agent-dag.schema.json +44 -0
  245. package/docs/templates/backend-test-dag.json +60 -35
  246. package/docs/templates/frontend-implementation-contract.schema.json +681 -24
  247. package/docs/templates/frontend-test-case-checklist.md +2 -2
  248. package/docs/templates/frontend-test-dag.json +8 -10
  249. package/docs/templates/frontend-test-dag.retrieve-context.prompt.md +1 -1
  250. package/docs/templates/init-managed-agents.md +13 -3
  251. package/harness.json +6 -4
  252. package/package.json +12 -4
  253. package/scripts/next-info.mjs +356 -0
  254. package/scripts/next-publish-gate.mjs +238 -0
  255. package/scripts/release-source-binding.mjs +251 -0
  256. package/skills/analyze-product-requirements/SKILL.md +8 -5
  257. package/skills/analyze-product-requirements/references/acceptance-criteria.md +1 -1
  258. package/skills/analyze-product-requirements/references/clarification-and-knowledge.md +10 -6
  259. package/skills/analyze-product-requirements/references/example.md +50 -0
  260. package/skills/analyze-product-requirements/references/forward-test-cases.md +11 -7
  261. package/skills/analyze-product-requirements/references/kb-integration.md +5 -5
  262. package/skills/analyze-product-requirements/references/product-analysis-schema.md +8 -4
  263. package/skills/analyze-product-requirements/references/product-requirement-schema.md +2 -2
  264. package/skills/analyze-product-requirements/references/requirement-clarification-schema.md +1 -1
  265. package/skills/analyze-product-requirements/scripts/test-validators.mjs +11 -1
  266. package/skills/analyze-product-requirements/scripts/validate-product-analysis.mjs +20 -1
  267. package/skills/analyze-product-requirements/scripts/validate-requirement-clarification.mjs +9 -0
  268. package/skills/codebase-scout/SKILL.md +1 -1
  269. package/skills/fe-test-ui-scout/SKILL.md +65 -0
  270. package/skills/fe-test-ui-scout/references/ledger-schema.md +62 -0
  271. package/skills/fe-test-ui-scout/references/recon-protocol.md +54 -0
  272. package/skills/frontend-implementation/references/node-contracts.md +2 -2
  273. package/skills/improve-codebase-architecture/SKILL.md +81 -0
  274. package/skills/improve-codebase-architecture/deepening.md +37 -0
  275. package/skills/improve-codebase-architecture/html-report.md +123 -0
  276. package/skills/improve-codebase-architecture/interface-design.md +44 -0
  277. package/skills/improve-codebase-architecture/language.md +53 -0
  278. package/skills/loop-agent/references/command-reference.md +11 -4
  279. package/skills/loop-agent/references/hybrid-dag.md +7 -0
  280. package/skills/playwright-cli/SKILL.md +23 -1
  281. package/skills/playwright-cli-case-generator/SKILL.md +29 -8
  282. package/dist/worker/console/static/assets/channel-BBOTJHvD.js +0 -1
  283. package/dist/worker/console/static/assets/classDiagram-JCYQIIEL-Cm8Yf8tD.js +0 -1
  284. package/dist/worker/console/static/assets/classDiagram-v2-OCEON4UE-Cm8Yf8tD.js +0 -1
  285. package/dist/worker/console/static/assets/index-B-qWGThd.js +0 -325
  286. package/dist/worker/console/static/assets/index-C-xRgY_0.css +0 -1
  287. package/dist/worker/console/static/assets/stateDiagram-v2-UEYNNEHI-DZihfdKc.js +0 -1
  288. package/dist/worker/console/static/assets/swimlanesDiagram-ULZ7WXOC-CKnXCjHX.js +0 -8
@@ -0,0 +1,238 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * next-publish-gate: throttle main -> npm `next` publishing.
4
+ *
5
+ * Every main push used to publish a new next build. With this gate a
6
+ * push-triggered run only publishes when HEAD is at least COMMIT_THRESHOLD
7
+ * commits ahead of the commit that produced the current dist-tags.next
8
+ * build (read from the published tarball's dist/build-stamp.json).
9
+ *
10
+ * Bypasses (publish regardless of the count):
11
+ * - workflow_dispatch runs (manual trigger, e.g. right before cutting a
12
+ * release line); the workflow passes --force for those.
13
+ * - recovery: HEAD already IS the source of the current next build, so
14
+ * re-publishing would be the same version anyway.
15
+ * - unknown last-published SHA (no npm history / unreadable stamp /
16
+ * SHA not an ancestor of HEAD): fail open — a missed next build is
17
+ * cheap, permanently stuck publishing is not.
18
+ *
19
+ * Exit codes: 0 = publish, 2 = skip (gate), 1 = hard error. The workflow
20
+ * maps skip to a successful early exit so non-publishing runs are green.
21
+ */
22
+ import { execFileSync } from "node:child_process";
23
+ import { mkdtempSync, readdirSync, rmSync } from "node:fs";
24
+ import { tmpdir } from "node:os";
25
+ import { join } from "node:path";
26
+ import process from "node:process";
27
+ import { readTarballBuildStamp } from "./release-source-binding.mjs";
28
+
29
+ export const COMMIT_THRESHOLD_DEFAULT = 5;
30
+ const SKIP_EXIT_CODE = 2;
31
+
32
+ /** Run a command and return trimmed stdout; injected for tests. */
33
+ function normalizeWindowsTarArg(value) {
34
+ const match = /^([A-Za-z]):[\\/](.*)$/.exec(String(value));
35
+ if (!match) return value;
36
+ return `/${match[1].toLowerCase()}/${match[2].replaceAll("\\", "/")}`;
37
+ }
38
+
39
+ export function normalizeCommandArgs(cmd, args, platform = process.platform) {
40
+ if (platform !== "win32" || cmd !== "tar") return args;
41
+ return args.map(normalizeWindowsTarArg);
42
+ }
43
+
44
+ export function commandLaunch(cmd, args, platform = process.platform) {
45
+ if (platform === "win32" && cmd === "npm") {
46
+ return {
47
+ cmd: process.env.ComSpec || "cmd.exe",
48
+ args: ["/d", "/s", "/c", "npm", ...args],
49
+ };
50
+ }
51
+ return { cmd, args };
52
+ }
53
+
54
+ export function defaultRun(cmd, args) {
55
+ const launch = commandLaunch(cmd, normalizeCommandArgs(cmd, args));
56
+ return execFileSync(launch.cmd, launch.args, {
57
+ encoding: "utf8",
58
+ stdio: ["ignore", "pipe", "pipe"],
59
+ });
60
+ }
61
+
62
+ export function npmViewDistTags(run = defaultRun) {
63
+ const out = run("npm", [
64
+ "view",
65
+ "@tea-agent/loop-agent",
66
+ "dist-tags",
67
+ "--json",
68
+ ]);
69
+ const trimmed = String(out ?? "").trim();
70
+ if (!trimmed) return {};
71
+ let parsed;
72
+ try {
73
+ parsed = JSON.parse(trimmed);
74
+ } catch {
75
+ return {};
76
+ }
77
+ return parsed && typeof parsed === "object" ? parsed : {};
78
+ }
79
+
80
+ /** Download the exact published next version and read its build stamp. */
81
+ export function defaultStampProbe(version) {
82
+ const dir = mkdtempSync(join(tmpdir(), "loop-agent-next-gate-"));
83
+ try {
84
+ defaultRun("npm", [
85
+ "pack",
86
+ `@tea-agent/loop-agent@${version}`,
87
+ "--pack-destination",
88
+ dir,
89
+ ]);
90
+ const file = readdirSync(dir).find((entry) => entry.endsWith(".tgz"));
91
+ if (!file) return null;
92
+ try {
93
+ return readTarballBuildStamp(join(dir, file), defaultRun);
94
+ } catch {
95
+ return null;
96
+ }
97
+ } catch {
98
+ return null;
99
+ } finally {
100
+ rmSync(dir, { recursive: true, force: true });
101
+ }
102
+ }
103
+
104
+ export function isAncestor(sha, head, run = defaultRun) {
105
+ try {
106
+ run("git", ["merge-base", "--is-ancestor", sha, head]);
107
+ return true;
108
+ } catch {
109
+ return false;
110
+ }
111
+ }
112
+
113
+ /**
114
+ * Pure decision. Inputs:
115
+ * - threshold: minimum commits ahead of lastPublishedSha to publish
116
+ * - aheadBy: commits between lastPublishedSha and headSha (null = unknown)
117
+ * - lastPublishedSha / headSha: for the recovery equality check
118
+ * Returns { publish, reason, aheadBy }.
119
+ */
120
+ export function shouldPublishNext({
121
+ threshold = COMMIT_THRESHOLD_DEFAULT,
122
+ lastPublishedSha,
123
+ headSha,
124
+ aheadBy,
125
+ force = false,
126
+ }) {
127
+ if (force) {
128
+ return { publish: true, reason: "force-bypass", aheadBy };
129
+ }
130
+ if (!headSha) {
131
+ return { publish: true, reason: "head-unknown-fail-open", aheadBy };
132
+ }
133
+ if (!lastPublishedSha) {
134
+ return {
135
+ publish: true,
136
+ reason: "last-published-sha-unknown-fail-open",
137
+ aheadBy,
138
+ };
139
+ }
140
+ const last = String(lastPublishedSha).toLowerCase();
141
+ const head = String(headSha).toLowerCase();
142
+ if (last === head) {
143
+ return { publish: true, reason: "same-commit-recovery", aheadBy: 0 };
144
+ }
145
+ if (aheadBy === null || aheadBy === undefined || !Number.isFinite(aheadBy)) {
146
+ return { publish: true, reason: "ahead-unknown-fail-open", aheadBy: null };
147
+ }
148
+ const normalizedThreshold = Number(threshold);
149
+ if (!Number.isFinite(normalizedThreshold) || normalizedThreshold <= 0) {
150
+ return { publish: true, reason: "threshold-invalid-fail-open", aheadBy };
151
+ }
152
+ if (aheadBy >= normalizedThreshold) {
153
+ return { publish: true, reason: "ahead-threshold-met", aheadBy };
154
+ }
155
+ return { publish: false, reason: "below-threshold-skip", aheadBy };
156
+ }
157
+
158
+ function parseArgs(argv) {
159
+ return Object.fromEntries(
160
+ argv
161
+ .filter((arg) => arg.startsWith("--"))
162
+ .map((arg) => {
163
+ const [key, ...value] = arg.replace(/^--/, "").split("=");
164
+ return [key, value.join("=") || "true"];
165
+ }),
166
+ );
167
+ }
168
+
169
+ function main() {
170
+ const args = parseArgs(process.argv.slice(2));
171
+ const threshold = Number(args.threshold || COMMIT_THRESHOLD_DEFAULT);
172
+ const distTags = npmViewDistTags();
173
+ const currentNext = distTags.next ? String(distTags.next) : null;
174
+ let lastPublishedSha = null;
175
+ let currentNextNote = "no dist-tags.next";
176
+ if (currentNext) {
177
+ const stamp = defaultStampProbe(currentNext);
178
+ if (stamp && stamp.gitSha) {
179
+ lastPublishedSha = stamp.gitSha;
180
+ currentNextNote = `next=${currentNext} from ${stamp.gitSha.slice(0, 10)}`;
181
+ } else {
182
+ currentNextNote = `next=${currentNext} (stamp unreadable)`;
183
+ }
184
+ }
185
+ let headSha = null;
186
+ let aheadBy = null;
187
+ try {
188
+ headSha = defaultRun("git", ["rev-parse", "HEAD"]).trim();
189
+ } catch {
190
+ headSha = null;
191
+ }
192
+ if (headSha && lastPublishedSha) {
193
+ if (!isAncestor(lastPublishedSha, headSha)) {
194
+ aheadBy = null;
195
+ } else {
196
+ aheadBy = Number(
197
+ defaultRun("git", [
198
+ "rev-list",
199
+ "--count",
200
+ `${lastPublishedSha}..${headSha}`,
201
+ ]).trim(),
202
+ );
203
+ }
204
+ }
205
+ const decision = shouldPublishNext({
206
+ threshold,
207
+ lastPublishedSha,
208
+ headSha,
209
+ aheadBy,
210
+ force: args.force === "true",
211
+ });
212
+ process.stdout.write(
213
+ `next-publish-gate: ${currentNextNote}\n` +
214
+ `next-publish-gate: head=${headSha ? headSha.slice(0, 10) : "unknown"} ` +
215
+ `aheadBy=${aheadBy === null ? "unknown" : aheadBy} ` +
216
+ `threshold=${threshold}\n` +
217
+ `next-publish-gate: ${decision.publish ? "PUBLISH" : "SKIP"} ` +
218
+ `(${decision.reason})\n`,
219
+ );
220
+ process.exit(decision.publish ? 0 : SKIP_EXIT_CODE);
221
+ }
222
+
223
+ // CLI 入口安全判断(argv[1] 非合法 file: URL 时 new URL 会抛异常)
224
+ function scriptEntryHref(argv1) {
225
+ try {
226
+ return argv1 ? new URL(`file://${argv1}`).href : "";
227
+ } catch {
228
+ return "";
229
+ }
230
+ }
231
+
232
+ const invokedAsScript =
233
+ Boolean(process.argv[1]) &&
234
+ import.meta.url === scriptEntryHref(process.argv[1]);
235
+
236
+ if (invokedAsScript) {
237
+ main();
238
+ }
@@ -0,0 +1,251 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * release-source-binding: resolve the exact source SHA behind a selected next
4
+ * build, and validate cut-release-line preconditions.
5
+ *
6
+ * The next tarball carries dist/build-stamp.json { version, gitSha }. A release
7
+ * line must be cut from THAT commit — never from a floating main HEAD at
8
+ * workflow runtime. This module provides:
9
+ *
10
+ * - resolveSourceBinding: given a next version, return its gitSha (from the
11
+ * registry tarball build stamp) and validated facts.
12
+ * - validateCutPreconditions: line monotonicity, branch absence, no parallel
13
+ * un-promoted train, source sha on main.
14
+ */
15
+ import { execFileSync } from "node:child_process";
16
+ import process from "node:process";
17
+
18
+ export const NEXT_TARGET_ENV = "LOOP_AGENT_NEXT_TARGET";
19
+
20
+ const FORMAL_LINE_RE = /^\d+\.\d+$/;
21
+
22
+ /**
23
+ * Read build stamp fields from a packed tarball without installing it.
24
+ * @param {string} tarballPath
25
+ * @param {(cmd: string, args: string[]) => string} [run]
26
+ */
27
+ export function readTarballBuildStamp(tarballPath, run = runCommand) {
28
+ const listing = run("tar", ["-tzf", tarballPath]);
29
+ const stampEntry = listing
30
+ .split("\n")
31
+ .map((line) => line.trim())
32
+ .find((line) => /\/dist\/build-stamp\.json$/.test(line));
33
+ if (!stampEntry) {
34
+ throw new Error(`tarball ${tarballPath} does not contain dist/build-stamp.json`);
35
+ }
36
+ const stampJson = run("tar", ["-xzf", tarballPath, "-O", stampEntry]);
37
+ let parsed;
38
+ try {
39
+ parsed = JSON.parse(stampJson);
40
+ } catch (error) {
41
+ throw new Error(
42
+ `build stamp is not valid JSON: ${error instanceof Error ? error.message : String(error)}`,
43
+ );
44
+ }
45
+ if (typeof parsed.gitSha !== "string" || !/^[0-9a-f]{7,40}$/i.test(parsed.gitSha)) {
46
+ throw new Error("build stamp gitSha missing or malformed");
47
+ }
48
+ return { gitSha: parsed.gitSha, version: parsed.version ?? null };
49
+ }
50
+
51
+ function runCommand(cmd, args) {
52
+ return execFileSync(cmd, args, {
53
+ encoding: "utf8",
54
+ stdio: ["ignore", "pipe", "pipe"],
55
+ });
56
+ }
57
+
58
+ /**
59
+ * Download an exact next version tarball (without install scripts) into a
60
+ * directory and return its path.
61
+ */
62
+ export function downloadNpmTarball(version, destDir, run = runCommand) {
63
+ run("npm", [
64
+ "pack",
65
+ `@tea-agent/loop-agent@${version}`,
66
+ "--pack-destination",
67
+ destDir,
68
+ ]);
69
+ const listing = run("ls", [destDir]);
70
+ const file = listing
71
+ .split("\n")
72
+ .map((line) => line.trim())
73
+ .find((line) => line.endsWith(".tgz"));
74
+ if (!file) throw new Error(`npm pack did not produce a tarball in ${destDir}`);
75
+ return `${destDir}/${file}`;
76
+ }
77
+
78
+ /**
79
+ * Pure checks for cutting a release line.
80
+ *
81
+ * @param {object} input
82
+ * @param {string} input.selectedNextVersion e.g. "0.37.0-next.42"
83
+ * @param {string} input.releaseLine e.g. "0.37"
84
+ * @param {string} input.sourceSha commit the next tarball was built from
85
+ * @param {string[]} input.remoteBranches remote release branch names (e.g. ["release/0.36"])
86
+ * @param {string|null} [input.latestFormalVersion] current npm latest (for reference in results)
87
+ * @param {(sha: string) => boolean} [input.shaOnMain] whether sha is an ancestor of origin/main
88
+ * @returns {{ok: true} | {ok: false, reason: string, detail?: string}}
89
+ */
90
+ export function validateCutPreconditions(input) {
91
+ const nextMatch = /^(\d+)\.(\d+)\.(0|[1-9]\d*)-next\.([0-9]\d*)$/.exec(
92
+ String(input.selectedNextVersion ?? ""),
93
+ );
94
+ if (!nextMatch) {
95
+ return {
96
+ ok: false,
97
+ reason: "invalid-selected-next",
98
+ detail: `selectedNextVersion=${input.selectedNextVersion}`,
99
+ };
100
+ }
101
+ const nextLine = `${nextMatch[1]}.${nextMatch[2]}`;
102
+ const patch = nextMatch[3];
103
+ if (patch !== "0") {
104
+ return {
105
+ ok: false,
106
+ reason: "selected-next-not-minor-zero",
107
+ detail: `next target patch must be 0, got ${patch}`,
108
+ };
109
+ }
110
+ if (!FORMAL_LINE_RE.test(String(input.releaseLine ?? ""))) {
111
+ return {
112
+ ok: false,
113
+ reason: "invalid-release-line",
114
+ detail: `releaseLine=${input.releaseLine}`,
115
+ };
116
+ }
117
+ if (input.releaseLine !== nextLine) {
118
+ return {
119
+ ok: false,
120
+ reason: "line-mismatch",
121
+ detail: `selected next ${nextLine} vs release line ${input.releaseLine}`,
122
+ };
123
+ }
124
+ if (!/^[0-9a-f]{7,40}$/i.test(String(input.sourceSha ?? ""))) {
125
+ return {
126
+ ok: false,
127
+ reason: "invalid-source-sha",
128
+ detail: `sourceSha=${input.sourceSha}`,
129
+ };
130
+ }
131
+ const branches = Array.isArray(input.remoteBranches)
132
+ ? input.remoteBranches
133
+ : [];
134
+ const existing = branches.find((b) => b === `release/${input.releaseLine}`);
135
+ if (existing) {
136
+ return {
137
+ ok: false,
138
+ reason: "release-branch-exists",
139
+ detail: existing,
140
+ };
141
+ }
142
+ const existingLines = branches
143
+ .map((b) => /^release\/(\d+)\.(\d+)$/.exec(b))
144
+ .filter(Boolean)
145
+ .map((m) => ({ major: Number(m[1]), minor: Number(m[2]), name: m[0] }));
146
+ const [cutMajor, cutMinor] = input.releaseLine.split(".").map(Number);
147
+ const higher = existingLines.find(
148
+ (l) => l.major > cutMajor || (l.major === cutMajor && l.minor > cutMinor),
149
+ );
150
+ if (higher) {
151
+ return {
152
+ ok: false,
153
+ reason: "line-not-monotonic",
154
+ detail: `higher release branch exists: ${higher.name}`,
155
+ };
156
+ }
157
+ if (input.shaOnMain !== undefined && input.shaOnMain(input.sourceSha) === false) {
158
+ return {
159
+ ok: false,
160
+ reason: "source-sha-not-on-main",
161
+ detail: input.sourceSha,
162
+ };
163
+ }
164
+ return { ok: true };
165
+ }
166
+
167
+ /**
168
+ * Resolve the next target line from env override (LOOP_AGENT_NEXT_TARGET).
169
+ * Returns null when unset/invalid — callers decide the fallback derivation.
170
+ */
171
+ export function nextTargetFromEnv(env = process.env) {
172
+ const raw = env[NEXT_TARGET_ENV];
173
+ if (!raw) return null;
174
+ return /^\d+\.\d+\.0$/.test(raw) ? raw : null;
175
+ }
176
+
177
+ // CLI 入口安全判断(argv[1] 非合法 file: URL 时 new URL 会抛异常)
178
+ function scriptEntryHref(argv1) {
179
+ try {
180
+ return argv1 ? new URL(`file://${argv1}`).href : "";
181
+ } catch {
182
+ return "";
183
+ }
184
+ }
185
+
186
+ const invokedAsScript =
187
+ Boolean(process.argv[1]) && import.meta.url === scriptEntryHref(process.argv[1]);
188
+
189
+ if (invokedAsScript) {
190
+ const args = Object.fromEntries(
191
+ process.argv
192
+ .filter((arg) => arg.startsWith("--"))
193
+ .map((arg) => {
194
+ const [key, ...value] = arg.replace(/^--/, "").split("=");
195
+ return [key, value.join("=") || "true"];
196
+ }),
197
+ );
198
+ if (args["self-test"]) {
199
+ const scenario = String(args["self-test"]);
200
+ const scenarios = {
201
+ "cut-ok": () =>
202
+ validateCutPreconditions({
203
+ selectedNextVersion: "0.37.0-next.42",
204
+ releaseLine: "0.37",
205
+ sourceSha: "abc1234567890abcdef",
206
+ remoteBranches: ["release/0.36"],
207
+ }),
208
+ "cut-exists": () =>
209
+ validateCutPreconditions({
210
+ selectedNextVersion: "0.37.0-next.42",
211
+ releaseLine: "0.37",
212
+ sourceSha: "abc1234567890abcdef",
213
+ remoteBranches: ["release/0.36", "release/0.37"],
214
+ }),
215
+ "cut-not-monotonic": () =>
216
+ validateCutPreconditions({
217
+ selectedNextVersion: "0.37.0-next.42",
218
+ releaseLine: "0.37",
219
+ sourceSha: "abc1234567890abcdef",
220
+ remoteBranches: ["release/0.38"],
221
+ }),
222
+ "cut-line-mismatch": () =>
223
+ validateCutPreconditions({
224
+ selectedNextVersion: "0.37.0-next.42",
225
+ releaseLine: "0.38",
226
+ sourceSha: "abc1234567890abcdef",
227
+ remoteBranches: [],
228
+ }),
229
+ "cut-sha-not-on-main": () =>
230
+ validateCutPreconditions({
231
+ selectedNextVersion: "0.37.0-next.42",
232
+ releaseLine: "0.37",
233
+ sourceSha: "abc1234567890abcdef",
234
+ remoteBranches: [],
235
+ shaOnMain: () => false,
236
+ }),
237
+ };
238
+ const run = scenarios[scenario];
239
+ if (!run) {
240
+ process.stderr.write(`unknown self-test scenario: ${scenario}\n`);
241
+ process.exitCode = 2;
242
+ } else {
243
+ process.stdout.write(`${JSON.stringify(run())}\n`);
244
+ }
245
+ } else {
246
+ process.stderr.write(
247
+ "usage: node scripts/release-source-binding.mjs --self-test=<scenario>\n",
248
+ );
249
+ process.exitCode = 2;
250
+ }
251
+ }
@@ -48,8 +48,9 @@ IRON LAW:`product-analysis.md` 必须先写入正式路径,再对该正式
48
48
  - [ ] 知识库状态为 `executed-hit` 或 `executed-no-match`,或 `unavailable` 后用户明确确认跳过,才允许进入项目资料预扫描与常规代码探索;其余情况保持阻断。
49
49
  - [ ] 知识库门禁通过后,依次预扫描 `<project-root>/ai_workspace/project-how-to`、`code-specification`、`project-business`:先枚举文件,再读取入口文档及与当前需求直接相关的内容;缺失目录记录 `not-found` 并继续,不做无边界加载。
50
50
  - [ ] 然后读取并执行 `references/clarification-and-knowledge.md` 第 1 节,按需求问题和知识库结论定向探索代码库。当前宿主支持隔离的只读代码侦察 agent 时,优先委派限定范围的代码探索;不支持时由当前 agent 执行同等范围的定向搜索并只保留精简结果,不得阻断或扩大搜索范围。知识库结论不得替代代码落点证据。
51
+ - [ ] 执行「输入↔规范一致性核对」:将原始需求的每条明确声明与有效规范证据(`KB-FACT-*`、ai_workspace 项目资料、仓库规范文档)及代码现状事实(`CODE-FACT-*`)逐条比对,分类为 一致 / 规范补充 / 冲突 / 无规则。分类为"冲突"的条目必须逐条进入待确认问题,标注"输入声明 vs 规范/代码声明"与冲突来源,用户裁决前不选边。该核对是强制步骤,任何"输入明确"都不构成豁免;规范补充仅适用于规范类事实,代码现状在输入未说明时按 unknown 分流,不得静默填补。
51
52
  - [ ] 汇总原始需求、`KB-FACT-*`、项目资料与 `CODE-FACT-*`,识别可查明事实、冲突、unknown 和必须由用户选择的目标行为;完成以上顺序后才生成待确认问题并进入 Step 2。
52
- - [ ] 区分明确需求、推断需求和待确认问题。推断需求一律视为未确认产品内容;每一项推断需求以及任何含糊、缺失、冲突或存在多种合理解释的产品问题,都必须进入 Step 2 逐题向用户澄清,不得因模型认为推荐答案合理而跳过。
53
+ - [ ] 区分明确需求、推断需求和待确认问题。推断需求一律视为未确认产品内容;每一项推断需求以及任何含糊、缺失、冲突或存在多种合理解释的产品问题,都必须进入 Step 2 逐题向用户澄清,不得因模型认为推荐答案合理而跳过。与有效规范或代码现状冲突的行为不属于"明确需求",不得按 `source-requirement` 直接合并;冲突按 unknown 同款边界分流:影响范围、权限、业务规则、用户可感知输出/状态/边界或验收结果的冲突必须澄清,纯实现/技术细节冲突只记录事实、不生成问题。
53
54
  - [ ] scope 包含 backend 且需求涉及接口/API 时,必须确认实现范围为 Web、Remote 或 Web + Remote;只写笼统“接口/API”视为待确认问题。不得依据知识库或代码现状替用户选择。
54
55
  - [ ] 仅按 target 生成精简故事骨架和逐故事初步输出规范:`frontend` 只生成 `FE-US-*`,`backend` 只生成 `BE-US-*`,`both` 才生成两端。
55
56
  - [ ] Product Analysis 只记录验收关注点,不创建正式 `AC-*` 或完整 Given/When/Then。每个前端故事的同 ID 初步输出规范必须包含“页面路由”:独立页面写以 `/` 开头的目标 URL;组件、弹窗或抽屉无独立路由时写“`不适用;嵌入 /目标路径 页面`”(`/目标路径` 替换为真实路径)。
@@ -74,23 +75,23 @@ IRON LAW:`product-analysis.md` 必须先写入正式路径,再对该正式
74
75
  - [ ] 澄清进行中:每次合成后重写 `pending` Product Requirement,并保留“未决事项”;不得标为 `complete`。
75
76
  - [ ] pending Clarification 与 pending Product Requirement 写入后,使用 `--allow-pending` 运行二者校验器;两者状态必须一致。`--allow-pending` 仅用于内部中间产物校验,不得用于最终交付或下游消费。
76
77
  - [ ] 共同理解已确认后:生成 `complete` Product Requirement;Clarification 同步为 `complete`。
77
- - [ ] 优先级:用户确认决策 > 原始明确需求 > 当前有效的知识库项目规范 > 模型推断;知识库/代码事实只用于理解项目规范与现状、发现冲突和辅助澄清,不得发明产品意图。
78
+ - [ ] 优先级(仅用于「输入↔规范一致性核对」与冲突澄清完成、用户裁决后的合成默认,不构成跳过澄清的依据):用户确认决策 > 原始明确需求 > 当前有效的知识库项目规范 > 模型推断;知识库/代码事实只用于理解项目规范与现状、发现冲突和辅助澄清,不得发明产品意图。
78
79
  - [ ] 不得把 `KB-FACT-*`、`CODE-FACT-*`、知识库/仓库路径或代码符号原样写入 Product Requirement。
79
80
  - [ ] 用户故事只描述角色/使用方、目标/能力、价值、入口/触发方式和 AC 引用;详细产品行为只写在同 ID 输出规范中,正式 AC 嵌入该输出规范。
80
81
  - [ ] 逐个检查每个 `FE-US-*` 的同 ID 输出规范并写入“页面路由”,不得因多个故事共享页面而省略或合并该字段。独立页面写以 `/` 开头的目标 URL;组件、弹窗或抽屉无独立路由时写“`不适用;嵌入 /目标路径 页面`”(`/目标路径` 替换为真实路径)。
81
82
  - [ ] target 为 `backend` 或 `both` 时,后端故事只定义 API 的业务能力、输入输出语义、权限和规则;触发方式写 `API(Web)`、`API(Remote)` 或 `API(Web + Remote)`。Web + Remote 表示同一能力需要两个接口;具体 Method+Path 及 DTO 留给依赖 skill。
82
- - [ ] 后端分页:每页条数允许值按“原始需求/用户确认 > 有效知识库分页规范 > 默认集合 `10`、`20`、`50`、`100`”确定。参数名、必填性、默认值和其他契约不得从知识库 API 文档自动带入。
83
+ - [ ] 后端分页:每页条数允许值与其他规则同等参与「输入↔规范一致性核对」。输入与有效分页规范冲突(含允许值集合的差异、子集或超集)时必须进入待确认问题澄清,用户裁决后以确认值为准;无冲突时按”用户确认 > 原始需求 > 有效知识库分页规范 > 默认集合 `10`、`20`、`50`、`100`”确定。参数名、必填性、默认值和其他契约不得从知识库 API 文档自动带入。
83
84
  - [ ] Step 5:验证并交付 ⛔ BLOCKING
84
85
  - [ ] 再次以只读方式向已冻结 Product Analysis 和 Product Requirement 校验器传入归一化 target,只运行三个当前产物校验器;Product Analysis 在 Step 1 已通过正式文件校验,本步不得因任何原因修改它。交付路径不得使用 `--allow-pending`。
85
86
  - [ ] Requirement Clarification 校验器核对 Product Analysis/Clarification 的原始需求身份,以及三个产物的 requirement ID、analysis scope 和状态;冻结不做脚本校验。
86
87
  - [ ] 只有所有命令返回 0 才能声明完成。本步只交付 complete V4 Product Requirement;下游 `analyze-product-dependencies` 首选消费该产物,其 `--target` 可为本次 `analysis_scope` 的子集。
87
88
  - [ ] `test-validators.mjs` 仅在修改本 skill 的输出契约、schema、validator、artifact version、示例、forward-test contract,或发布/安装/回归验证时运行;普通需求分析不运行 validator matrix。
88
89
 
89
- 完整格式示例按需读取 `references/example.md`;维护或 forward-test 时读取 `references/forward-test-cases.md`。不要为了执行校验而阅读脚本,直接运行。
90
+ 完整格式示例按需读取 `references/example.md`(含无需澄清与输入↔规范冲突澄清两条路径);维护或 forward-test 时读取 `references/forward-test-cases.md`。不要为了执行校验而阅读脚本,直接运行。
90
91
 
91
92
  ## 完成规则
92
93
 
93
- - `no-clarification-required` 仍生成三个产物,但只适用于“推断需求”为 `- 无未确认的推断需求。` 且“待确认问题”为 `- 无待确认问题。` 的场景;Clarification 使用“澄清结论、来源、合并结果”三章精简结构,并记录 `- 内容补充:用户已确认无需补充`;不得仅凭模型判断需求足够明确就自动完成。
94
+ - `no-clarification-required` 仍生成三个产物,但只适用于”推断需求”为 `- 无未确认的推断需求。` 且”待确认问题”为 `- 无待确认问题。` 的场景,且必须完成「输入↔规范一致性核对」并在待确认问题记录 `- 一致性核对:…未发现冲突条目。`;Clarification 使用”澄清结论、来源、合并结果”三章精简结构,并记录 `- 内容补充:用户已确认无需补充`;不得仅凭模型判断需求足够明确就自动完成。
94
95
  - 需要澄清的 `complete` Clarification:全部分支 resolved,所有实际 `Q-*` 为 `confirmed/user`,决策索引含 `- 共同理解:已确认`,每个 `DEC-Q-*` 进入 Product Requirement 决策追溯。
95
96
  - Product Requirement 必须自包含;只描述目标产品行为,不得出现 `KB-FACT-*`、`CODE-FACT-*`、知识库/仓库文件路径、代码级类/函数/组件符号、模块调用关系、数据表名、证据位置或实现算法。
96
97
  - 不得生成独立用户角色、验收标准汇总、前后端契约、Open Questions、测试建议或独立边界 case 章节。
@@ -110,6 +111,8 @@ IRON LAW:`product-analysis.md` 必须先写入正式路径,再对该正式
110
111
  - 在 Product Analysis 写正式 `AC-*` 或 Given/When/Then。
111
112
  - 任何前端故事的同 ID Product Analysis 或 Product Requirement 输出规范缺少“页面路由”,或因共享页面而只在其中一个故事中填写。
112
113
  - 输入已给出分页允许值时,用知识库规范或默认 `10/20/50/100` 覆盖;或从知识库/API 文档自动带入路径、方法、参数名、必填性、默认值、响应、错误码或 DTO。
114
+ - 输入与有效规范(知识库、ai_workspace、仓库规范)或代码现状冲突时,按"原始需求优先"静默采用输入而不进入澄清;分页允许值冲突也不例外。
115
+ - 「输入↔规范一致性核对」漏掉任一证据通道,或把"规范补充"误判为"冲突"、把"冲突"静默当作"规范补充"处理,或用代码现状填补输入未说明的产品行为。
113
116
  - 生成独立用户角色、验收标准汇总、前后端契约、Open Questions、测试建议或边界 case 章节。
114
117
 
115
118
  ## 交付前自检
@@ -4,7 +4,7 @@
4
4
 
5
5
  每条验收标准必须独立可执行、结果可观察,并使用 Given/When/Then。一个用户故事存在多个关键流程时,拆成多个 AC,不要把互不相关的行为塞入一条 AC。
6
6
 
7
- 涉及状态变量、空数据、loading、error、disabled、错误提示或恢复入口时,Then 与异常场景必须使用已查明的项目枚举、共享组件、文案和交互规范;不得用通用占位状态替代项目规范。明确需求与项目规范冲突时先澄清目标行为。
7
+ 涉及状态变量、空数据、loading、error、disabled、错误提示或恢复入口时,Then 与异常场景必须使用已查明的项目枚举、共享组件、文案和交互规范;不得用通用占位状态替代项目规范。明确需求与项目规范或代码现状冲突时先澄清目标行为。
8
8
 
9
9
  每条 AC 必须说明:
10
10
 
@@ -6,21 +6,21 @@
6
6
 
7
7
  项目资料预扫描的时机与顺序按 `kb-integration.md` 执行;命中内容不得替代真实代码证据。
8
8
 
9
- 有效知识结果使用 `KB-FACT-*`,包含规范事实、来源文档及定位、版本/生效状态、适用范围、需求影响和置信度。知识库用于说明项目要求,代码库用于说明当前实现;知识库命中不能把代码文件、符号或调用关系标记为 confirmed。
9
+ 有效知识结果使用 `KB-FACT-*`,包含规范事实、来源文档及定位、版本/生效状态、适用范围、需求影响、置信度和与输入关系(一致 | 补充 | 冲突)。知识库用于说明项目要求,代码库用于说明当前实现;知识库命中不能把代码文件、符号或调用关系标记为 confirmed。
10
10
 
11
- 提供代码仓库且当前宿主支持隔离的只读代码侦察 agent 时,优先将定向事实搜索交给该 agent:认证、权限、状态枚举、相似能力、字段类型、统一错误结构、设计系统、空数据及 loading/error 展示。委派内容仅包含待查问题、允许搜索的范围和适用的知识库规范结论,当前会话只保留结论、证据位置、置信度和未定位项。当前宿主不支持该能力时,由当前 agent 先限定故事、问题、目录或关键词,再沿直接相关引用定向搜索,不做无边界扫描;不得因此阻断流程或扩大搜索范围。文件搜索优先使用 `rg --files` 和 `rg`,没有 `rg` 时使用宿主提供的等价只读搜索能力,不得降低证据标准。事实使用 `CODE-FACT-*`,包含事实、证据位置和需求影响。代码只能回答现状,不能替代用户决定目标需求。
11
+ 提供代码仓库且当前宿主支持隔离的只读代码侦察 agent 时,优先将定向事实搜索交给该 agent:认证、权限、状态枚举、相似能力、字段类型、统一错误结构、设计系统、空数据及 loading/error 展示。委派内容仅包含待查问题、允许搜索的范围和适用的知识库规范结论,当前会话只保留结论、证据位置、置信度和未定位项。当前宿主不支持该能力时,由当前 agent 先限定故事、问题、目录或关键词,再沿直接相关引用定向搜索,不做无边界扫描;不得因此阻断流程或扩大搜索范围。文件搜索优先使用 `rg --files` 和 `rg`,没有 `rg` 时使用宿主提供的等价只读搜索能力,不得降低证据标准。事实使用 `CODE-FACT-*`,包含事实、证据位置、需求影响、证据类别(项目规范 | 代码现状)和与输入关系(一致 | 补充 | 冲突)。ai_workspace 项目资料与仓库规范文档统一记录为 `CODE-FACT-*` 并标注证据类别:项目规范;代码现状标注证据类别:代码现状。代码只能回答现状,不能替代用户决定目标需求。
12
12
 
13
- scope 包含 backend 且涉及分页时:每页条数允许值以原始需求/用户确认为准;未说明时优先采用 `kb-design-assist` 返回的当前有效分页规范,仍未查明才使用默认集合 `10`、`20`、`50`、`100`。不得把知识库/API 文档的路径、方法、参数名、必填性、默认值、响应、错误码或 DTO 自动合并为产品需求。分析状态变量、空数据、loading、error、disabled 或兜底行为时,优先以当前有效知识库规范为项目规范来源,再核验仓库级指令、设计系统、共享组件和同类实现;未查明时写 unknown,不得用通用惯例冒充项目规范。
13
+ scope 包含 backend 且涉及分页时:每页条数允许值与其他明确声明一样参与「输入↔规范一致性核对」。输入与有效分页规范冲突(含允许值集合的差异、子集或超集)时必须进入澄清,用户裁决后以确认值为准;输入未说明时优先采用 `kb-design-assist` 返回的当前有效分页规范,仍未查明才使用默认集合 `10`、`20`、`50`、`100`。不得把知识库/API 文档的路径、方法、参数名、必填性、默认值、响应、错误码或 DTO 自动合并为产品需求。分析状态变量、空数据、loading、error、disabled 或兜底行为时,优先以当前有效知识库规范为项目规范来源,再核验仓库级指令、设计系统、共享组件和同类实现;未查明时写 unknown,不得用通用惯例冒充项目规范。
14
14
 
15
15
  unknown 按影响分流:会改变范围、权限、业务规则、用户可感知输出/状态/边界或验收结果时,提炼成目标行为的产品决策并进入澄清;只涉及代码位置、符号、实现方式、技术复用或证据缺失时,保留为 `CODE-FACT-*` unknown 并交给依赖分析,不向用户提问,也不进入 Product Requirement。不得询问用户“代码在哪里”;应询问用户希望产品表现为何。
16
16
 
17
17
  scope 包含 backend 且需求涉及接口/API 时,Web、Remote 或 Web + Remote 属于必须由用户确认的产品范围。只写笼统“接口/API”时生成一个澄清问题;确认结果写入现有“触发方式”,不得新增接口形态字段。Web + Remote 表示同一能力需要两个 HTTP 接口。
18
18
 
19
- 知识库、代码或需求之间冲突时:保留来源证据、生成澄清问题、用户裁决前不选边。过期、适用范围不明、互相冲突或无来源定位的知识结果按 unknown 处理。
19
+ 执行「输入↔规范一致性核对」:将原始需求的每条明确声明与有效规范证据(`KB-FACT-*`、ai_workspace 项目资料、仓库规范文档,统一以 `KB-FACT-*`/`CODE-FACT-*` 记录并标注与输入关系)及代码现状事实(`CODE-FACT-*`)逐条比对,分类为 一致 / 规范补充 / 冲突 / 无规则。分类为"冲突"的条目必须进入待确认问题,保留双方声明与来源证据,用户裁决前不选边;"输入明确"不构成豁免。规范补充仅适用于规范类事实(`KB-FACT-*` 及"证据类别:项目规范"的 `CODE-FACT-*`),输入未说明时直接并入、不生成问题;代码现状不得静默填补产品行为。冲突按 unknown 同款边界分流:影响范围、权限、业务规则、用户可感知输出/状态/边界或验收结果的冲突必须逐条澄清;纯实现/技术细节冲突只标"与输入关系:冲突"、不生成问题,留待依赖分析。过期、适用范围不明、互相冲突或无来源定位的知识结果按 unknown 处理。
20
20
 
21
21
  ## 2. 决策树式访谈
22
22
 
23
- 1. 从 Product Analysis 的全部推断需求、待确认问题和输出规范中的未确认产品内容提取顶层 `BR-*` 分支;每一项推断、含糊、缺失、冲突、多种合理解释或目标行为 unknown 都必须进入决策树,覆盖完整分支,不为满足数量制造分支。原始需求已明确且不存在歧义的行为直接作为 `source-requirement` 事实,不创建分支或问题。
23
+ 1. 从 Product Analysis 的全部推断需求、待确认问题和输出规范中的未确认产品内容提取顶层 `BR-*` 分支;每一项推断、含糊、缺失、冲突、多种合理解释或目标行为 unknown 都必须进入决策树,覆盖完整分支,不为满足数量制造分支。原始需求已明确、与有效规范及代码现状核对一致且不存在歧义的行为直接作为 `source-requirement` 事实,不创建分支或问题;与有效规范或代码现状冲突的行为视为存在歧义,必须进入决策树。
24
24
  2. 标注分支依赖,从范围、权限、核心流程、数据语义等基础决策开始。
25
25
  3. 每轮只处理一个决策问题:先给推荐答案和理由,再提问并等待回答。任何两个待决子项都不得合并为一次提问。
26
26
  4. 收到回答后重新识别剩余推断、模糊点、缺失项、冲突和新引入的未定义产品内容;只要仍存在未确认产品问题或需求,就开启下一轮。
@@ -32,7 +32,7 @@ scope 包含 backend 且需求涉及接口/API 时,Web、Remote 或 Web + Remo
32
32
 
33
33
  ### 回答复核
34
34
 
35
- 收到用户回答后,先判断它是否直接覆盖当前问题的关键决策点、是否只有一种合理的产品解释、是否足以写成明确的范围/规则/输出行为/验收结果、是否与原始明确需求或已有决策冲突,以及是否引入新的未定义概念、例外条件或依赖关系。全部满足时才形成最终决策并标记为 confirmed。
35
+ 收到用户回答后,先判断它是否直接覆盖当前问题的关键决策点、是否只有一种合理的产品解释、是否足以写成明确的范围/规则/输出行为/验收结果、是否与原始明确需求、已有决策、有效规范或代码现状冲突,以及是否引入新的未定义概念、例外条件或依赖关系。全部满足时才形成最终决策并标记为 confirmed。
36
36
 
37
37
  任一条件不满足时:
38
38
 
@@ -43,6 +43,10 @@ scope 包含 backend 且需求涉及接口/API 时,Web、Remote 或 Web + Remo
43
43
 
44
44
  当前问题明确后,再扫描全部推断需求、其他未解决问题和本次回答新引入的模糊点。只要内容属于产品需求或目标行为且尚未确认,就必须继续澄清;纯措辞、代码位置、符号、实现方式、技术复用和其他不构成产品需求的下游技术细节不消耗澄清轮次。
45
45
 
46
+ ### 澄清轮中的规范冲突
47
+
48
+ Product Analysis 冻结后,回答复核、用户回答或新证据暴露"用户回答或新增内容与有效规范/代码现状冲突"时:不得标记 confirmed;下一轮继续当前分支,把冲突双方声明与来源(`KB-FACT-*`/`CODE-FACT-*`)并列呈现,并在 Q-* 的"推荐理由"中成对写明,`最终决策` 记录用户裁决结果。已冻结的 Product Analysis 不回写。
49
+
46
50
  问题等级:
47
51
 
48
52
  - P0:改变范围、权限、关键流程、数据语义或验收结果;必须由用户明确确认。
@@ -24,6 +24,7 @@ analysis_status: no-clarification-required
24
24
  - 无未确认的推断需求。
25
25
  ### 4.3 待确认问题
26
26
  - 无待确认问题。
27
+ - 一致性核对:已逐条比对知识库、ai_workspace、仓库规范与代码现状,未发现冲突条目。
27
28
  - 理由:范围、权限、校验、失败恢复和非目标均已由原始需求明确。
28
29
  ### 4.4 初步非目标
29
30
  - 不修改头像。
@@ -102,3 +103,52 @@ Then:
102
103
  ```
103
104
 
104
105
  故事与输出规范使用同一 ID;故事只引用 AC,AC 正文只在对应输出规范中出现一次。
106
+
107
+ # 需要澄清路径示例(输入 ↔ 规范冲突)
108
+
109
+ 需求:查询订单列表支持分页,pageSize 允许值为 5、10、20。
110
+ 知识库命中分页规范:允许值为 20、50、100。
111
+
112
+ ## Product Analysis 外部事实与冲突条目
113
+
114
+ ```md
115
+ ## 5. 外部事实
116
+ ### 5.1 知识库事实
117
+ - 检索状态:executed-hit。
118
+ - KB-FACT-001:分页允许值为 20、50、100;来源:分页规范 v3 §2;版本:当前有效;与输入关系:冲突。
119
+ ### 5.2 代码库事实
120
+ - CODE-FACT-001:列表接口已存在,pageSize 为必填;证据位置:列表 controller;证据类别:代码现状;与输入关系:一致。
121
+
122
+ ## 4. 需求分析
123
+ ### 4.3 待确认问题
124
+ - P0:分页允许值集合冲突;冲突描述:输入声明「5、10、20」vs 规范声明「20、50、100」;冲突来源:KB-FACT-001;影响范围:backend。
125
+ ```
126
+
127
+ ## Clarification Q-* 冲突记录
128
+
129
+ 澄清轮中不新增字段,冲突双方声明成对写入推荐理由,最终决策记录裁决结果。
130
+
131
+ ```md
132
+ ### Q-001 分页允许值
133
+ - 澄清轮次:1
134
+ - 分支:BR-001
135
+ - 优先级:P0
136
+ - 影响范围:backend
137
+ - 推荐答案:采用项目分页规范 20、50、100
138
+ - 推荐理由:输入声明为 5、10、20,项目规范(KB-FACT-001:分页规范 v3 §2)为 20、50、100,两者冲突;代码现状(CODE-FACT-001)未约束允许值集合,需用户裁决。
139
+ - 用户回答:仍使用 5、10、20
140
+ - 最终决策:分页允许值为 5、10、20,覆盖项目分页规范默认值
141
+ - 决策来源:user
142
+ - 状态:confirmed
143
+ - 决策标记:DEC-Q-001
144
+ - 目标位置:后端输出规范分页约定
145
+ ```
146
+
147
+ ## Product Requirement 合成
148
+
149
+ ```md
150
+ ## 4. 业务规则
151
+ - 分页允许值集合为 5、10、20(用户裁决,覆盖项目分页规范默认值)。
152
+ ## 7. 决策追溯
153
+ - DEC-Q-001:分页允许值为 5、10、20,已合并到后端输出规范分页约定。
154
+ ```