@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
@@ -15,7 +15,7 @@ LLM review (when `frontendTest.reviewMode=blocking`) must not invent blocking ru
15
15
  | `unknown-ac` | When task `sourceBinding.requirementIds` lists ACs, every `acIds` entry must be in that set |
16
16
  | `case-id-shape` | `caseId` matches `FE-<FEATURE>-<NNN>-...` (never `AC-FE-*`) |
17
17
  | `case-id-is-ac` | Do not use acceptance id as `caseId` / filename |
18
- | `case-path-mismatch` | `casePath === testcase/frontend/cases/{caseId}.md` |
18
+ | `case-path-mismatch` | `casePath === {casesDir}/{caseId}.md`(默认 `testcase/frontend/cases/{caseId}.md`) |
19
19
  | `case-file-missing` | `casePath` exists |
20
20
 
21
21
  ## Tool guidance (non-blocking)
@@ -40,5 +40,5 @@ LLM review (when `frontendTest.reviewMode=blocking`) must not invent blocking ru
40
40
 
41
41
  ## Pipeline vs quality
42
42
 
43
- - **Pipeline acceptance**: final `testcase/frontend/reports/frontend-test-retrospect-*.md` exists after result materialize
43
+ - **Pipeline acceptance**: final `{reportsDir}/frontend-test-retrospect-*.md` exists after result materialize (default `testcase/frontend/reports/`)
44
44
  - **Quality**: `frontend-test-result-v1.outcome=passed` with 0 blocked/failed (opt-in via `frontendTest.strictOutcomeGate`)
@@ -66,12 +66,11 @@
66
66
  ".harness/**",
67
67
  "artifacts/**"
68
68
  ],
69
- "outputContract": "Write testcase/frontend/rag/standard-scenarios.v1.json for generate-time standard scenario coverage.",
70
- "subtask_prompt": "Materialize frontend-test standard scenarios v1 into the RAG package.",
69
+ "outputContract": "Write testcase/frontend/rag/standard-scenarios.v1.json for generate-time standard scenario coverage. Copy docs/templates or harness.json governanceRoot templates (including ai_workspace/loop-agent/templates) when present; otherwise write the minimal STD-FE-SMOKE-ENTRY fallback.",
70
+ "subtask_prompt": "Prepare frontend-test package: materialize standard-scenarios.v1.json into the RAG package from docs/templates, governanceRoot/templates, or the init-projected ai_workspace/loop-agent/templates path.",
71
71
  "shell": {
72
- "commands": [
73
- "node -e \"const fs=require('fs'),path=require('path');const dest='testcase/frontend/rag/standard-scenarios.v1.json';const candidates=[path.join('docs','templates','frontend-test-standard-scenarios.v1.json')];let src=null;for(const c of candidates){if(fs.existsSync(c)){src=c;break;}}fs.mkdirSync(path.dirname(dest),{recursive:true});if(src){fs.copyFileSync(src,dest);process.stdout.write(JSON.stringify({status:'copied',from:src,to:dest}));}else{const minimal={schemaVersion:1,id:'frontend-test-standard-scenarios-v1',scenarios:[{id:'STD-FE-SMOKE-ENTRY',title:'入口可打开',category:'smoke',priority:'must',testPoints:['open'],minCases:1}]};fs.writeFileSync(dest,JSON.stringify(minimal,null,2)+'\\n');process.stdout.write(JSON.stringify({status:'fallback',to:dest}));}"
74
- ],
72
+ "commands": [],
73
+ "frontendTestStandardScenarios": {},
75
74
  "cwd": ".",
76
75
  "timeoutMs": 60000
77
76
  }
@@ -120,12 +119,11 @@
120
119
  ".harness/**",
121
120
  "artifacts/**"
122
121
  ],
123
- "outputContract": "Fail-closed environment preflight: absolute non-production baseUrl + curl HTTP reachability; writes environmentProbe facts; unreachable => blockedReason frontend-base-url-unreachable (node ERROR so generate/map do not run).",
124
- "subtask_prompt": "Parse the concrete baseUrl selected by retrieve-frontend-test-context-pi from testcase/frontend/rag/context.md. Reject production, non-http(s), credentials, query and fragment. Probe with curl (HEAD then GET fallback; connect/max-time; no auth/cookie). 2xx/3xx => reachable and continue. 4xx/5xx/DNS/timeout/connection refused/TLS => blockedReason frontend-base-url-unreachable. Missing curl => blockedReason curl-unavailable. Do not start the app. Runtime hybrid generator embeds the authoritative probe script.",
122
+ "outputContract": "Fail-closed environment preflight: absolute non-production baseUrl + curl HTTP reachability; writes environmentProbe facts; unreachable => blockedReason frontend-base-url-unreachable with errorClass (connection-refused / dns-unresolved / connect-timeout / http-N). Node ERROR so generate/map do not run. Does not start the app.",
123
+ "subtask_prompt": "Parse the concrete baseUrl selected by retrieve-frontend-test-context-pi from testcase/frontend/rag/context.md. Reject production, non-http(s), credentials, query and fragment. Probe with curl (HEAD then GET fallback; connect/max-time; no auth/cookie). 2xx/3xx => reachable and continue. Connection refused records errorClass=connection-refused and tells the operator to start the local app then rerun from this node. 4xx/5xx/DNS/timeout/TLS => blockedReason frontend-base-url-unreachable. Missing curl => blockedReason curl-unavailable. Do not start the app.",
125
124
  "shell": {
126
- "commands": [
127
- "node -e \"console.log('template placeholder: runtime hybrid DAG embeds curl preflight; do not use this static command as source of truth')\""
128
- ],
125
+ "commands": [],
126
+ "frontendTestEnvironmentProbe": {},
129
127
  "cwd": ".",
130
128
  "timeoutMs": 60000
131
129
  }
@@ -17,5 +17,5 @@ Do not claim the environment is reachable until preflight completes. Preflight d
17
17
 
18
18
  ## Standard scenario coverage
19
19
 
20
- - Copy or reference `docs/templates/frontend-test-standard-scenarios.v1.json` into `testcase/frontend/rag/standard-scenarios.v1.json` when available.
20
+ - Copy or reference `docs/templates/frontend-test-standard-scenarios.v1.json`, `harness.json` `governanceRoot`/templates, or the init-projected `ai_workspace/loop-agent/templates/frontend-test-standard-scenarios.v1.json` into `testcase/frontend/rag/standard-scenarios.v1.json` when available.
21
21
  - Add `## Standard scenario coverage` to coverage-map.md with planned/n/a for each must scenario.
@@ -80,9 +80,19 @@ loop-agent init update --repo-root . --apply-safe
80
80
  当用户要求初始化 loop-agent(“初始化 loop-agent”“loop agent 初始化”“loop agent初始化”“loop-agent 初始化”),或发现 `README.md` / `__LOOP_AGENT_GOVERNANCE_ROOT__/verification-matrix.md` 仍停留在通用初始化状态时,模型应在同一轮工作中完成初始化闭环,不要把补全文档和验证矩阵留给用户交互。
81
81
 
82
82
  1. 运行 `loop-agent init instructions --repo-root .`。
83
- 2. 运行 `loop-agent init --repo-root . --profile full --merge`。
84
- 3. 基于真实项目文件补全根 `README.md`、`__LOOP_AGENT_GOVERNANCE_ROOT__/verification-matrix.md`,必要时适配 `scripts/ci-tests.sh`。
85
- 4. 运行 `loop-agent init doctor --repo-root .`、`loop-agent inspect`、`loop-agent docs audit` 并完成 quick verification。
83
+ 2. 运行 `loop-agent init model-catalog --repo-root . --json`。loop-agent 不直接打开或解析认证文件原文,只让 Pi/OpenCode 自己的 runtime 加载其配置,并输出白名单模型元数据、Pi setup 状态、Pi 兼容性与 credential-ready 布尔值;token、headers、URL、原始命令输出和认证路径不会进入 catalog。
84
+ 3. 先处理 `piSetup`:如果没有模型定义,向用户索取无法推断的 provider/model id、API/base URL、上下文窗口、最大输出、输入/推理能力、成本约束和凭据方式,帮助按 Pi 原生 schema 合并 `~/.pi/agent/models.json`;不得让用户把凭据值写入对话、harness 或报告,优先 Pi 登录/auth storage 或环境变量引用。如果已有定义但凭据未就绪,只修复认证。随后重跑 catalog,未出现 credential-ready Pi model 前不得继续初始化。
85
+ 4. 对已有 `harness.json`,逐档保留仍存在于 Pi 的 LOW/MED/HIGH 原值;只为已移除或缺失的档位重新选择。结合目标项目实际技术栈、模型能力、成本与上下文窗口,从 `eligibleForHarness=true` 的候选中自主选择,并直接运行带完整三档参数的 init/update;代码会拒绝改动仍有效的档位。三档可以相同。只有凭据、成本、合规或可用性存在无法推断的实质歧义时才询问用户;OpenCode-only 候选不能证明 Pi executor 可用。
86
+ 5. 基于真实项目文件补全根 `README.md`、`__LOOP_AGENT_GOVERNANCE_ROOT__/verification-matrix.md`,必要时适配 `scripts/ci-tests.sh`。
87
+ 6. 运行 `loop-agent init doctor --repo-root .`、`loop-agent inspect`、`loop-agent docs audit` 并完成 quick verification;doctor 未确认 Pi model matrix 时不得开始 DAG。
88
+
89
+ ```bash
90
+ loop-agent init --repo-root . --profile full --merge \
91
+ --low-model <provider/model> --med-model <provider/model> --high-model <provider/model>
92
+ # 已初始化项目只替换失效档位;仍有效档位在完整参数中保持当前引用
93
+ loop-agent init update --repo-root . --apply-safe \
94
+ --low-model <current-or-selected> --med-model <current-or-selected> --high-model <current-or-selected>
95
+ ```
86
96
 
87
97
  信息不足时写明尚未识别到的事实;不要留下泛化占位符。
88
98
 
package/harness.json CHANGED
@@ -30,7 +30,9 @@
30
30
  "nightScheduler": {
31
31
  "enabled": true,
32
32
  "timezone": "Asia/Shanghai",
33
- "allowedHours": ["00:00-08:00"],
33
+ "allowedHours": [
34
+ "00:00-08:00"
35
+ ],
34
36
  "maxConcurrency": 1,
35
37
  "maxAutoAttempts": 1,
36
38
  "misfirePolicy": "wait-next-window",
@@ -80,9 +82,9 @@
80
82
  "executors": {
81
83
  "pi": {
82
84
  "description": "Pi 负责规划、评审、诊断;当 DAG toolProfile=write 时也可做有界写入。模型按复杂度三档配置,支持 provider/model 字符串或带 thinking 的对象;斜杠前为 Pi provider,后为 modelId,勿只写裸 modelId。",
83
- "LOW": "wizard-local/minimax-m3",
84
- "MED": "wizard-local/grok-4.6",
85
- "HIGH": "wizard-local/gpt-5.6-sol"
85
+ "LOW": "deepseek/deepseek-v4-flash",
86
+ "MED": "deepseek/deepseek-v4-flash",
87
+ "HIGH": "deepseek/deepseek-v4-flash"
86
88
  }
87
89
  }
88
90
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tea-agent/loop-agent",
3
- "version": "0.39.0-next.9",
3
+ "version": "0.39.1",
4
4
  "type": "module",
5
5
  "bin": {
6
6
  "loop-agent": "bin/loop-agent.js",
@@ -33,12 +33,18 @@
33
33
  "scripts/kb-graph-materialize.mjs",
34
34
  "scripts/kb-graph-promote.mjs",
35
35
  "scripts/kb-graph-incremental-prepare.mjs",
36
+ "scripts/next-info.mjs",
37
+ "scripts/next-publish-gate.mjs",
38
+ "scripts/release-source-binding.mjs",
36
39
  "README.md",
37
40
  "CHANGELOG.md"
38
41
  ],
39
42
  "publishConfig": {
40
43
  "access": "public"
41
44
  },
45
+ "engines": {
46
+ "node": ">=22.19.0"
47
+ },
42
48
  "scripts": {
43
49
  "dev": "node --import tsx/esm src/cli.ts",
44
50
  "cursor": "node --import tsx/esm src/cli.ts cursor-prompt",
@@ -55,6 +61,7 @@
55
61
  "test": "node scripts/run-tests.mjs",
56
62
  "test:host": "vitest run test/init-upgrade.test.ts --maxWorkers=1 -t \"records and reuses|controller-authorized semantic merge|authority-sensitive\"",
57
63
  "test:fast": "vitest run --config vitest.fast.config.ts",
64
+ "test:io-heavy": "vitest run --config vitest.io-heavy.config.ts",
58
65
  "test:integration": "vitest run --config vitest.integration.config.ts",
59
66
  "docs:dev": "npm --prefix website start",
60
67
  "docs:build": "npm --prefix website run build",
@@ -64,6 +71,8 @@
64
71
  "verify:tree": "node scripts/pre-push-verify.mjs --verify-current-tree"
65
72
  },
66
73
  "dependencies": {
74
+ "@earendil-works/pi-ai": "0.83.0",
75
+ "@earendil-works/pi-coding-agent": "0.83.0",
67
76
  "commander": "^12.1.0",
68
77
  "katex": "^0.16.47",
69
78
  "mermaid": "^11.16.1",
@@ -71,13 +80,12 @@
71
80
  "rehype-katex": "^7.0.1",
72
81
  "remark-math": "^6.0.0",
73
82
  "semver": "^7.8.5",
83
+ "typebox": "1.3.7",
74
84
  "yaml": "^2.9.0",
75
85
  "zod": "^3.25.76"
76
86
  },
77
87
  "optionalDependencies": {
78
- "@cursor/sdk": "^1.0.7",
79
- "@earendil-works/pi-ai": "0.80.10",
80
- "@earendil-works/pi-coding-agent": "0.80.10"
88
+ "@cursor/sdk": "^1.0.7"
81
89
  },
82
90
  "devDependencies": {
83
91
  "@remixicon/react": "^4.9.0",
@@ -0,0 +1,356 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * next-info: read-only report of the current npm `next` binding.
4
+ *
5
+ * Resolves the moving git ref `npm-next` (local, then origin) and the
6
+ * published tarball build stamp. Does not write the repo, move dist-tags,
7
+ * or call GitHub APIs.
8
+ */
9
+ import { execFileSync } from "node:child_process";
10
+ import { mkdtempSync, rmSync } from "node:fs";
11
+ import { tmpdir } from "node:os";
12
+ import { join } from "node:path";
13
+ import process from "node:process";
14
+ import {
15
+ commandLaunch,
16
+ defaultRun,
17
+ isAncestor,
18
+ normalizeCommandArgs,
19
+ npmViewDistTags,
20
+ } from "./next-publish-gate.mjs";
21
+ import {
22
+ downloadNpmTarball,
23
+ readTarballBuildStamp,
24
+ } from "./release-source-binding.mjs";
25
+
26
+ export const UNPUBLISHED_COMMIT_LIMIT_DEFAULT = 50;
27
+ const GIT_REF_CANDIDATES = ["refs/heads/npm-next", "origin/npm-next"];
28
+
29
+ /**
30
+ * @param {string} cmd
31
+ * @param {string[]} args
32
+ * @param {string} [cwd]
33
+ */
34
+ function runWithCwd(cmd, args, cwd) {
35
+ const launch = commandLaunch(cmd, normalizeCommandArgs(cmd, args));
36
+ return execFileSync(launch.cmd, launch.args, {
37
+ encoding: "utf8",
38
+ stdio: ["ignore", "pipe", "pipe"],
39
+ cwd,
40
+ });
41
+ }
42
+
43
+ function scriptEntryHref(argv1) {
44
+ try {
45
+ return argv1 ? new URL(`file://${argv1}`).href : "";
46
+ } catch {
47
+ return "";
48
+ }
49
+ }
50
+
51
+ function trimSha(value) {
52
+ if (typeof value !== "string") return null;
53
+ const sha = value.trim();
54
+ return sha ? sha : null;
55
+ }
56
+
57
+ function equalSha(left, right) {
58
+ if (!left || !right) return false;
59
+ return left.toLowerCase() === right.toLowerCase();
60
+ }
61
+
62
+ function tryRevParse(run, ref) {
63
+ try {
64
+ return trimSha(run("git", ["rev-parse", ref]));
65
+ } catch {
66
+ return null;
67
+ }
68
+ }
69
+
70
+ function resolveGitRefSha(run) {
71
+ for (const ref of GIT_REF_CANDIDATES) {
72
+ const sha = tryRevParse(run, ref);
73
+ if (sha) return { ref, sha };
74
+ }
75
+ return null;
76
+ }
77
+
78
+ function readStampBuiltAt(tarballPath, run) {
79
+ try {
80
+ const listing = run("tar", ["-tzf", tarballPath]);
81
+ const stampEntry = String(listing)
82
+ .split("\n")
83
+ .map((line) => line.trim())
84
+ .find((line) => /\/dist\/build-stamp\.json$/.test(line));
85
+ if (!stampEntry) return null;
86
+ const stampJson = run("tar", ["-xzf", tarballPath, "-O", stampEntry]);
87
+ const parsed = JSON.parse(String(stampJson));
88
+ return typeof parsed.builtAt === "string" ? parsed.builtAt : null;
89
+ } catch {
90
+ return null;
91
+ }
92
+ }
93
+
94
+ /** Download the published next tarball and read gitSha + builtAt. */
95
+ export function defaultNextStampProbe(version, run = defaultRun) {
96
+ const dir = mkdtempSync(join(tmpdir(), "loop-agent-next-info-"));
97
+ try {
98
+ const tarball = downloadNpmTarball(version, dir, run);
99
+ const stamp = readTarballBuildStamp(tarball, run);
100
+ return {
101
+ gitSha: stamp.gitSha,
102
+ version: stamp.version ?? null,
103
+ builtAt: readStampBuiltAt(tarball, run),
104
+ };
105
+ } catch {
106
+ return null;
107
+ } finally {
108
+ rmSync(dir, { recursive: true, force: true });
109
+ }
110
+ }
111
+
112
+ function emptyResult(overrides) {
113
+ return {
114
+ ok: false,
115
+ exitCode: 1,
116
+ npmNextVersion: null,
117
+ gitSha: null,
118
+ gitRef: null,
119
+ gitRefSha: null,
120
+ stampSha: null,
121
+ builtAt: null,
122
+ source: null,
123
+ aheadBy: null,
124
+ aheadByReason: null,
125
+ unpublishedCommits: [],
126
+ unpublishedTruncated: false,
127
+ unpublishedLimit: UNPUBLISHED_COMMIT_LIMIT_DEFAULT,
128
+ drift: false,
129
+ error: null,
130
+ ...overrides,
131
+ };
132
+ }
133
+
134
+ function collectAheadState(gitSha, run) {
135
+ if (!gitSha) {
136
+ return {
137
+ aheadBy: null,
138
+ aheadByReason: "no gitSha to compare against HEAD",
139
+ unpublishedCommits: [],
140
+ unpublishedTruncated: false,
141
+ };
142
+ }
143
+ const headSha = tryRevParse(run, "HEAD");
144
+ if (!headSha) {
145
+ return {
146
+ aheadBy: null,
147
+ aheadByReason: "HEAD is unavailable",
148
+ unpublishedCommits: [],
149
+ unpublishedTruncated: false,
150
+ };
151
+ }
152
+ let unpublishedCommits = [];
153
+ let unpublishedTruncated = false;
154
+ try {
155
+ const log = run("git", ["log", "--oneline", `${gitSha}..HEAD`]);
156
+ const lines = String(log ?? "")
157
+ .split("\n")
158
+ .map((line) => line.trim())
159
+ .filter(Boolean);
160
+ unpublishedTruncated = lines.length > UNPUBLISHED_COMMIT_LIMIT_DEFAULT;
161
+ unpublishedCommits = lines.slice(0, UNPUBLISHED_COMMIT_LIMIT_DEFAULT);
162
+ } catch {
163
+ unpublishedCommits = [];
164
+ }
165
+ if (!isAncestor(gitSha, headSha, run)) {
166
+ return {
167
+ aheadBy: null,
168
+ aheadByReason: "gitSha is not an ancestor of HEAD",
169
+ unpublishedCommits,
170
+ unpublishedTruncated,
171
+ };
172
+ }
173
+ try {
174
+ const count = Number(
175
+ String(run("git", ["rev-list", "--count", `${gitSha}..HEAD`])).trim(),
176
+ );
177
+ if (!Number.isFinite(count)) {
178
+ return {
179
+ aheadBy: null,
180
+ aheadByReason: "rev-list count is not a number",
181
+ unpublishedCommits,
182
+ unpublishedTruncated,
183
+ };
184
+ }
185
+ return {
186
+ aheadBy: count,
187
+ aheadByReason: null,
188
+ unpublishedCommits,
189
+ unpublishedTruncated,
190
+ };
191
+ } catch {
192
+ return {
193
+ aheadBy: null,
194
+ aheadByReason: "rev-list failed",
195
+ unpublishedCommits,
196
+ unpublishedTruncated,
197
+ };
198
+ }
199
+ }
200
+
201
+ /**
202
+ * Pure-ish collector. Tests inject `run` / `viewDistTags` / `stampProbe`
203
+ * so this never hits the real npm registry.
204
+ *
205
+ * @param {{
206
+ * cwd?: string,
207
+ * run?: (cmd: string, args: string[]) => string,
208
+ * viewDistTags?: () => Record<string, string>,
209
+ * stampProbe?: (version: string) =>
210
+ * | { gitSha?: string, builtAt?: string | null }
211
+ * | null,
212
+ * }} [deps]
213
+ */
214
+ export function collectNextInfo(deps = {}) {
215
+ const run =
216
+ deps.run ??
217
+ ((cmd, args) =>
218
+ deps.cwd ? runWithCwd(cmd, args, deps.cwd) : defaultRun(cmd, args));
219
+ const viewDistTags = deps.viewDistTags ?? (() => npmViewDistTags(run));
220
+ const stampProbe =
221
+ deps.stampProbe ?? ((version) => defaultNextStampProbe(version, run));
222
+
223
+ let distTags = {};
224
+ try {
225
+ distTags = viewDistTags() ?? {};
226
+ } catch {
227
+ distTags = {};
228
+ }
229
+ const npmNextVersion = distTags.next ? String(distTags.next) : null;
230
+ const gitRef = resolveGitRefSha(run);
231
+ const gitRefSha = gitRef?.sha ?? null;
232
+ let stamp = null;
233
+ if (npmNextVersion) {
234
+ try {
235
+ stamp = stampProbe(npmNextVersion);
236
+ } catch {
237
+ stamp = null;
238
+ }
239
+ }
240
+ const stampSha = trimSha(stamp?.gitSha);
241
+ const builtAt = typeof stamp?.builtAt === "string" ? stamp.builtAt : null;
242
+
243
+ if (!gitRefSha && !stampSha) {
244
+ const error = npmNextVersion
245
+ ? `no npm-next git ref and tarball stamp unreadable for next=${npmNextVersion}`
246
+ : "no npm-next git ref and no dist-tags.next";
247
+ return emptyResult({ error, npmNextVersion });
248
+ }
249
+
250
+ let source;
251
+ let gitSha;
252
+ let drift = false;
253
+ let error = null;
254
+ let ok = true;
255
+ let exitCode = 0;
256
+
257
+ if (gitRefSha && stampSha) {
258
+ source = "both";
259
+ if (!equalSha(gitRefSha, stampSha)) {
260
+ drift = true;
261
+ ok = false;
262
+ exitCode = 1;
263
+ error =
264
+ `npm-next git ref (${gitRefSha}) does not match tarball stamp gitSha (${stampSha})`;
265
+ }
266
+ gitSha = gitRefSha;
267
+ } else if (gitRefSha) {
268
+ source = "git-ref";
269
+ gitSha = gitRefSha;
270
+ } else {
271
+ source = "tarball-stamp";
272
+ gitSha = stampSha;
273
+ }
274
+
275
+ const ahead = collectAheadState(gitSha, run);
276
+ return {
277
+ ok,
278
+ exitCode,
279
+ npmNextVersion,
280
+ gitSha,
281
+ gitRef: gitRef?.ref ?? null,
282
+ gitRefSha,
283
+ stampSha,
284
+ builtAt,
285
+ source,
286
+ aheadBy: ahead.aheadBy,
287
+ aheadByReason: ahead.aheadByReason,
288
+ unpublishedCommits: ahead.unpublishedCommits,
289
+ unpublishedTruncated: ahead.unpublishedTruncated,
290
+ unpublishedLimit: UNPUBLISHED_COMMIT_LIMIT_DEFAULT,
291
+ drift,
292
+ error,
293
+ };
294
+ }
295
+
296
+ export function formatNextInfo(result, { json = false } = {}) {
297
+ if (json) {
298
+ return `${JSON.stringify(result, null, 2)}\n`;
299
+ }
300
+ const lines = [];
301
+ if (result.npmNextVersion) {
302
+ lines.push(`npm next: ${result.npmNextVersion}`);
303
+ } else {
304
+ lines.push("npm next: (no dist-tags.next)");
305
+ }
306
+ if (result.gitSha) {
307
+ lines.push(`gitSha: ${result.gitSha} (source: ${result.source})`);
308
+ } else {
309
+ lines.push("gitSha: (unavailable)");
310
+ }
311
+ if (result.gitRefSha && result.stampSha && result.drift) {
312
+ lines.push(`git-ref SHA: ${result.gitRefSha}`);
313
+ lines.push(`tarball stamp SHA: ${result.stampSha}`);
314
+ }
315
+ if (result.builtAt) {
316
+ lines.push(`builtAt: ${result.builtAt}`);
317
+ }
318
+ if (result.aheadBy === null) {
319
+ lines.push(
320
+ `aheadBy: null${result.aheadByReason ? ` (${result.aheadByReason})` : ""}`,
321
+ );
322
+ } else {
323
+ lines.push(`aheadBy: ${result.aheadBy}`);
324
+ }
325
+ const commits = result.unpublishedCommits ?? [];
326
+ if (commits.length === 0) {
327
+ lines.push("unpublishedCommits: (none)");
328
+ } else {
329
+ lines.push("unpublishedCommits:");
330
+ for (const commit of commits) lines.push(` ${commit}`);
331
+ if (result.unpublishedTruncated) {
332
+ lines.push(
333
+ ` … truncated to ${result.unpublishedLimit} commits`,
334
+ );
335
+ }
336
+ }
337
+ if (result.error) {
338
+ lines.push(`error: ${result.error}`);
339
+ }
340
+ return `${lines.join("\n")}\n`;
341
+ }
342
+
343
+ function main(argv = process.argv.slice(2)) {
344
+ const json = argv.includes("--json");
345
+ const result = collectNextInfo();
346
+ process.stdout.write(formatNextInfo(result, { json }));
347
+ process.exit(result.ok ? 0 : result.exitCode || 1);
348
+ }
349
+
350
+ const invokedAsScript =
351
+ Boolean(process.argv[1]) &&
352
+ import.meta.url === scriptEntryHref(process.argv[1]);
353
+
354
+ if (invokedAsScript) {
355
+ main();
356
+ }