@rpamis/comet 0.4.0-beta.3 → 0.4.0-beta.5

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 (605) hide show
  1. package/LICENSE +21 -21
  2. package/README.md +15 -1
  3. package/assets/manifest.json +2 -1
  4. package/assets/skills/comet/SKILL.md +54 -28
  5. package/assets/skills/comet/reference/auto-transition.md +1 -1
  6. package/assets/skills/comet/reference/comet-yaml-fields.md +11 -6
  7. package/assets/skills/comet/reference/context-recovery.md +12 -2
  8. package/assets/skills/comet/reference/decision-point.md +11 -0
  9. package/assets/skills/comet/reference/scripts.md +47 -15
  10. package/assets/skills/comet/reference/subagent-dispatch.md +6 -5
  11. package/assets/skills/comet/rules/comet-phase-guard.en.md +31 -28
  12. package/assets/skills/comet/rules/comet-phase-guard.md +31 -29
  13. package/assets/skills/comet/scripts/comet-resume-probe.mjs +3 -0
  14. package/assets/skills/comet/scripts/comet-runtime.mjs +1568 -476
  15. package/assets/skills/comet-any/SKILL.md +1 -1
  16. package/assets/skills/comet-any/reference/authored-zone-example.md +10 -5
  17. package/assets/skills/comet-any/reference/subagents/pause-points-author.md +14 -11
  18. package/assets/skills/comet-any/reference/subagents/skill-reviewer.md +2 -0
  19. package/assets/skills/comet-any/reference/subagents/workflow-entry-author.md +5 -4
  20. package/assets/skills/comet-archive/SKILL.md +52 -18
  21. package/assets/skills/comet-build/SKILL.md +64 -45
  22. package/assets/skills/comet-design/SKILL.md +24 -22
  23. package/assets/skills/comet-hotfix/SKILL.md +37 -34
  24. package/assets/skills/comet-open/SKILL.md +106 -57
  25. package/assets/skills/comet-tweak/SKILL.md +23 -18
  26. package/assets/skills/comet-verify/SKILL.md +57 -72
  27. package/assets/skills-zh/comet/SKILL.md +54 -28
  28. package/assets/skills-zh/comet/reference/auto-transition.md +1 -1
  29. package/assets/skills-zh/comet/reference/comet-yaml-fields.md +11 -6
  30. package/assets/skills-zh/comet/reference/context-recovery.md +12 -2
  31. package/assets/skills-zh/comet/reference/decision-point.md +11 -0
  32. package/assets/skills-zh/comet/reference/scripts.md +47 -15
  33. package/assets/skills-zh/comet/reference/subagent-dispatch.md +6 -5
  34. package/assets/skills-zh/comet-any/SKILL.md +1 -1
  35. package/assets/skills-zh/comet-any/reference/authored-zone-example.md +10 -5
  36. package/assets/skills-zh/comet-any/reference/subagents/pause-points-author.md +14 -12
  37. package/assets/skills-zh/comet-any/reference/subagents/skill-reviewer.md +2 -0
  38. package/assets/skills-zh/comet-any/reference/subagents/workflow-entry-author.md +5 -4
  39. package/assets/skills-zh/comet-archive/SKILL.md +52 -18
  40. package/assets/skills-zh/comet-build/SKILL.md +64 -45
  41. package/assets/skills-zh/comet-design/SKILL.md +24 -22
  42. package/assets/skills-zh/comet-hotfix/SKILL.md +36 -33
  43. package/assets/skills-zh/comet-open/SKILL.md +105 -56
  44. package/assets/skills-zh/comet-tweak/SKILL.md +22 -17
  45. package/assets/skills-zh/comet-verify/SKILL.md +57 -72
  46. package/dist/app/cli/comet-banner.d.ts +25 -0
  47. package/dist/app/cli/comet-banner.d.ts.map +1 -0
  48. package/dist/app/cli/comet-banner.js +265 -0
  49. package/dist/app/cli/comet-banner.js.map +1 -0
  50. package/dist/app/cli/index.js +36 -2
  51. package/dist/app/cli/index.js.map +1 -1
  52. package/dist/app/commands/classic.d.ts +4 -0
  53. package/dist/app/commands/classic.d.ts.map +1 -0
  54. package/dist/app/commands/classic.js +11 -0
  55. package/dist/app/commands/classic.js.map +1 -0
  56. package/dist/app/commands/doctor.d.ts.map +1 -1
  57. package/dist/app/commands/doctor.js +99 -37
  58. package/dist/app/commands/doctor.js.map +1 -1
  59. package/dist/app/commands/eval.d.ts.map +1 -1
  60. package/dist/app/commands/eval.js +57 -20
  61. package/dist/app/commands/eval.js.map +1 -1
  62. package/dist/app/commands/i18n.d.ts +1 -1
  63. package/dist/app/commands/i18n.d.ts.map +1 -1
  64. package/dist/app/commands/i18n.js +12 -4
  65. package/dist/app/commands/i18n.js.map +1 -1
  66. package/dist/app/commands/init.d.ts +1 -1
  67. package/dist/app/commands/init.d.ts.map +1 -1
  68. package/dist/app/commands/init.js +72 -25
  69. package/dist/app/commands/init.js.map +1 -1
  70. package/dist/app/commands/project-scope-selection.d.ts +13 -0
  71. package/dist/app/commands/project-scope-selection.d.ts.map +1 -0
  72. package/dist/app/commands/project-scope-selection.js +33 -0
  73. package/dist/app/commands/project-scope-selection.js.map +1 -0
  74. package/dist/app/commands/resume-probe.d.ts +11 -0
  75. package/dist/app/commands/resume-probe.d.ts.map +1 -0
  76. package/dist/app/commands/resume-probe.js +63 -0
  77. package/dist/app/commands/resume-probe.js.map +1 -0
  78. package/dist/app/commands/status.d.ts +31 -0
  79. package/dist/app/commands/status.d.ts.map +1 -1
  80. package/dist/app/commands/status.js +109 -20
  81. package/dist/app/commands/status.js.map +1 -1
  82. package/dist/app/commands/uninstall.d.ts +5 -0
  83. package/dist/app/commands/uninstall.d.ts.map +1 -1
  84. package/dist/app/commands/uninstall.js +264 -53
  85. package/dist/app/commands/uninstall.js.map +1 -1
  86. package/dist/app/commands/update.d.ts +6 -0
  87. package/dist/app/commands/update.d.ts.map +1 -1
  88. package/dist/app/commands/update.js +558 -86
  89. package/dist/app/commands/update.js.map +1 -1
  90. package/dist/config/repository-layout.json +4 -2
  91. package/dist/domains/bundle/bundle-platform.d.ts +1 -0
  92. package/dist/domains/bundle/bundle-platform.d.ts.map +1 -1
  93. package/dist/domains/bundle/bundle-platform.js +9 -3
  94. package/dist/domains/bundle/bundle-platform.js.map +1 -1
  95. package/dist/domains/bundle/eval-manifest-runtime.d.ts +6 -0
  96. package/dist/domains/bundle/eval-manifest-runtime.d.ts.map +1 -0
  97. package/dist/domains/bundle/eval-manifest-runtime.js +58 -0
  98. package/dist/domains/bundle/eval-manifest-runtime.js.map +1 -0
  99. package/dist/domains/bundle/types.d.ts +1 -1
  100. package/dist/domains/bundle/types.d.ts.map +1 -1
  101. package/dist/domains/comet-classic/classic-archive.d.ts +1 -0
  102. package/dist/domains/comet-classic/classic-archive.d.ts.map +1 -1
  103. package/dist/domains/comet-classic/classic-archive.js +35 -38
  104. package/dist/domains/comet-classic/classic-archive.js.map +1 -1
  105. package/dist/domains/comet-classic/classic-cli.d.ts +1 -1
  106. package/dist/domains/comet-classic/classic-cli.d.ts.map +1 -1
  107. package/dist/domains/comet-classic/classic-cli.js +3 -0
  108. package/dist/domains/comet-classic/classic-cli.js.map +1 -1
  109. package/dist/domains/comet-classic/classic-command-checks.d.ts +20 -0
  110. package/dist/domains/comet-classic/classic-command-checks.d.ts.map +1 -0
  111. package/dist/domains/comet-classic/classic-command-checks.js +97 -0
  112. package/dist/domains/comet-classic/classic-command-checks.js.map +1 -0
  113. package/dist/domains/comet-classic/classic-current-change.d.ts +19 -0
  114. package/dist/domains/comet-classic/classic-current-change.d.ts.map +1 -0
  115. package/dist/domains/comet-classic/classic-current-change.js +132 -0
  116. package/dist/domains/comet-classic/classic-current-change.js.map +1 -0
  117. package/dist/domains/comet-classic/classic-diagnostics.d.ts +2 -1
  118. package/dist/domains/comet-classic/classic-diagnostics.d.ts.map +1 -1
  119. package/dist/domains/comet-classic/classic-diagnostics.js +54 -1
  120. package/dist/domains/comet-classic/classic-diagnostics.js.map +1 -1
  121. package/dist/domains/comet-classic/classic-evidence.d.ts.map +1 -1
  122. package/dist/domains/comet-classic/classic-evidence.js +4 -0
  123. package/dist/domains/comet-classic/classic-evidence.js.map +1 -1
  124. package/dist/domains/comet-classic/classic-guard.d.ts.map +1 -1
  125. package/dist/domains/comet-classic/classic-guard.js +83 -80
  126. package/dist/domains/comet-classic/classic-guard.js.map +1 -1
  127. package/dist/domains/comet-classic/classic-hook-guard.d.ts.map +1 -1
  128. package/dist/domains/comet-classic/classic-hook-guard.js +179 -42
  129. package/dist/domains/comet-classic/classic-hook-guard.js.map +1 -1
  130. package/dist/domains/comet-classic/classic-project-config.d.ts +16 -0
  131. package/dist/domains/comet-classic/classic-project-config.d.ts.map +1 -0
  132. package/dist/domains/comet-classic/classic-project-config.js +40 -0
  133. package/dist/domains/comet-classic/classic-project-config.js.map +1 -0
  134. package/dist/domains/comet-classic/classic-resolver.d.ts.map +1 -1
  135. package/dist/domains/comet-classic/classic-resolver.js +4 -4
  136. package/dist/domains/comet-classic/classic-resolver.js.map +1 -1
  137. package/dist/domains/comet-classic/classic-resume-probe-command.d.ts +3 -0
  138. package/dist/domains/comet-classic/classic-resume-probe-command.d.ts.map +1 -0
  139. package/dist/domains/comet-classic/classic-resume-probe-command.js +58 -0
  140. package/dist/domains/comet-classic/classic-resume-probe-command.js.map +1 -0
  141. package/dist/domains/comet-classic/classic-resume-probe-entry.d.ts +2 -0
  142. package/dist/domains/comet-classic/classic-resume-probe-entry.d.ts.map +1 -0
  143. package/dist/domains/comet-classic/classic-resume-probe-entry.js +4 -0
  144. package/dist/domains/comet-classic/classic-resume-probe-entry.js.map +1 -0
  145. package/dist/domains/comet-classic/classic-resume-probe.d.ts +29 -0
  146. package/dist/domains/comet-classic/classic-resume-probe.d.ts.map +1 -0
  147. package/dist/domains/comet-classic/classic-resume-probe.js +386 -0
  148. package/dist/domains/comet-classic/classic-resume-probe.js.map +1 -0
  149. package/dist/domains/comet-classic/classic-runtime-run.d.ts +2 -1
  150. package/dist/domains/comet-classic/classic-runtime-run.d.ts.map +1 -1
  151. package/dist/domains/comet-classic/classic-runtime-run.js +38 -0
  152. package/dist/domains/comet-classic/classic-runtime-run.js.map +1 -1
  153. package/dist/domains/comet-classic/classic-state-command.d.ts.map +1 -1
  154. package/dist/domains/comet-classic/classic-state-command.js +150 -25
  155. package/dist/domains/comet-classic/classic-state-command.js.map +1 -1
  156. package/dist/domains/comet-classic/classic-state.d.ts +5 -2
  157. package/dist/domains/comet-classic/classic-state.d.ts.map +1 -1
  158. package/dist/domains/comet-classic/classic-state.js +17 -1
  159. package/dist/domains/comet-classic/classic-state.js.map +1 -1
  160. package/dist/domains/comet-classic/classic-store.d.ts +4 -1
  161. package/dist/domains/comet-classic/classic-store.d.ts.map +1 -1
  162. package/dist/domains/comet-classic/classic-store.js +4 -3
  163. package/dist/domains/comet-classic/classic-store.js.map +1 -1
  164. package/dist/domains/comet-classic/classic-transitions.d.ts +1 -1
  165. package/dist/domains/comet-classic/classic-transitions.d.ts.map +1 -1
  166. package/dist/domains/comet-classic/classic-transitions.js +36 -3
  167. package/dist/domains/comet-classic/classic-transitions.js.map +1 -1
  168. package/dist/domains/comet-classic/classic-validate-command.d.ts.map +1 -1
  169. package/dist/domains/comet-classic/classic-validate-command.js +8 -1
  170. package/dist/domains/comet-classic/classic-validate-command.js.map +1 -1
  171. package/dist/domains/comet-classic/index.d.ts +3 -0
  172. package/dist/domains/comet-classic/index.d.ts.map +1 -1
  173. package/dist/domains/comet-classic/index.js +3 -0
  174. package/dist/domains/comet-classic/index.js.map +1 -1
  175. package/dist/domains/dashboard/collector.js +10 -2
  176. package/dist/domains/dashboard/collector.js.map +1 -1
  177. package/dist/domains/dashboard/web/assets/_commonjsHelpers-CqkleIqs.js +1 -0
  178. package/dist/domains/dashboard/web/assets/arc-TGVUG2WN.js +1 -0
  179. package/dist/domains/dashboard/web/assets/architectureDiagram-3BPJPVTR-ASHmiHoP.js +36 -0
  180. package/dist/domains/dashboard/web/assets/blockDiagram-GPEHLZMM-CwASxBKe.js +132 -0
  181. package/dist/domains/dashboard/web/assets/c4Diagram-AAUBKEIU-BU8z_WNk.js +10 -0
  182. package/dist/domains/dashboard/web/assets/channel-kp6Ng2JJ.js +1 -0
  183. package/dist/domains/dashboard/web/assets/chunk-2J33WTMH-CBGlUx4_.js +1 -0
  184. package/dist/domains/dashboard/web/assets/chunk-4BX2VUAB-CS-iGcFz.js +1 -0
  185. package/dist/domains/dashboard/web/assets/chunk-55IACEB6-BUtCVJat.js +1 -0
  186. package/dist/domains/dashboard/web/assets/chunk-727SXJPM-C94tj_pf.js +206 -0
  187. package/dist/domains/dashboard/web/assets/chunk-AQP2D5EJ-BFOKcpdG.js +231 -0
  188. package/dist/domains/dashboard/web/assets/chunk-FMBD7UC4-Dmx8B-st.js +15 -0
  189. package/dist/domains/dashboard/web/assets/chunk-ND2GUHAM-DYV00CNn.js +1 -0
  190. package/dist/domains/dashboard/web/assets/chunk-QZHKN3VN-DMJJyQnw.js +1 -0
  191. package/dist/domains/dashboard/web/assets/classDiagram-4FO5ZUOK-yBDjgMY_.js +1 -0
  192. package/dist/domains/dashboard/web/assets/classDiagram-v2-Q7XG4LA2-yBDjgMY_.js +1 -0
  193. package/dist/domains/dashboard/web/assets/cose-bilkent-S5V4N54A-P4nE2rea.js +1 -0
  194. package/dist/domains/dashboard/web/assets/cynefin-VYW2F7L2-C-R1HXDv.js +166 -0
  195. package/dist/domains/dashboard/web/assets/cytoscape.esm-D3_iZ_3b.js +321 -0
  196. package/dist/domains/dashboard/web/assets/dagre-BM42HDAG-BH8d-C9z.js +4 -0
  197. package/dist/domains/dashboard/web/assets/defaultLocale-DX6XiGOO.js +1 -0
  198. package/dist/domains/dashboard/web/assets/diagram-2AECGRRQ-DpXTgQIH.js +43 -0
  199. package/dist/domains/dashboard/web/assets/diagram-5GNKFQAL-DSiFJzSw.js +10 -0
  200. package/dist/domains/dashboard/web/assets/diagram-KO2AKTUF-DULMkben.js +3 -0
  201. package/dist/domains/dashboard/web/assets/diagram-LMA3HP47-Pi8m_NO9.js +24 -0
  202. package/dist/domains/dashboard/web/assets/diagram-OG6HWLK6-BSe6bCWm.js +24 -0
  203. package/dist/domains/dashboard/web/assets/erDiagram-TEJ5UH35-zb-FEcbq.js +85 -0
  204. package/dist/domains/dashboard/web/assets/flowDiagram-I6XJVG4X-Dr-Gk0z2.js +162 -0
  205. package/dist/domains/dashboard/web/assets/ganttDiagram-6RSMTGT7-qs6Zb2A6.js +292 -0
  206. package/dist/domains/dashboard/web/assets/gitGraphDiagram-PVQCEYII-BQ314orT.js +106 -0
  207. package/dist/domains/dashboard/web/assets/graph--OzhPTMs.js +1 -0
  208. package/dist/domains/dashboard/web/assets/index-BLAfkNTu.css +1 -0
  209. package/dist/domains/dashboard/web/assets/index-DlSYK56b.js +139 -0
  210. package/dist/domains/dashboard/web/assets/index-DtLUOcAW.js +24 -0
  211. package/dist/domains/dashboard/web/assets/index-QO0z6F4w.js +10 -0
  212. package/dist/domains/dashboard/web/assets/infoDiagram-5YYISTIA-O0bQp98A.js +2 -0
  213. package/dist/domains/dashboard/web/assets/init-Gi6I4Gst.js +1 -0
  214. package/dist/domains/dashboard/web/assets/ishikawaDiagram-YF4QCWOH-BPC7wbKh.js +70 -0
  215. package/dist/domains/dashboard/web/assets/journeyDiagram-JHISSGLW-ohViOd4b.js +139 -0
  216. package/dist/domains/dashboard/web/assets/kanban-definition-UN3LZRKU-CHleNdbG.js +89 -0
  217. package/dist/domains/dashboard/web/assets/katex-HP8lGamR.js +257 -0
  218. package/dist/domains/dashboard/web/assets/layout-SsrduOYp.js +1 -0
  219. package/dist/domains/dashboard/web/assets/linear-CyqiW--Q.js +1 -0
  220. package/dist/domains/dashboard/web/assets/marked.esm-DECB3bxB.js +64 -0
  221. package/dist/domains/dashboard/web/assets/mermaid.core-qS9XvtaK.js +301 -0
  222. package/dist/domains/dashboard/web/assets/mindmap-definition-RKZ34NQL-oaGkqO9l.js +96 -0
  223. package/dist/domains/dashboard/web/assets/ordinal-Cboi1Yqb.js +1 -0
  224. package/dist/domains/dashboard/web/assets/pieDiagram-4H26LBE5-CPcB-AFh.js +30 -0
  225. package/dist/domains/dashboard/web/assets/purify.es-VaSPOPhr.js +3 -0
  226. package/dist/domains/dashboard/web/assets/quadrantDiagram-W4KKPZXB-LFy52Qtj.js +7 -0
  227. package/dist/domains/dashboard/web/assets/requirementDiagram-4Y6WPE33-BdjeaYP_.js +84 -0
  228. package/dist/domains/dashboard/web/assets/sankeyDiagram-5OEKKPKP-DDJ4styL.js +40 -0
  229. package/dist/domains/dashboard/web/assets/sequenceDiagram-3UESZ5HK-BL5bFNoz.js +162 -0
  230. package/dist/domains/dashboard/web/assets/stateDiagram-AJRCARHV-BNUfikui.js +1 -0
  231. package/dist/domains/dashboard/web/assets/stateDiagram-v2-BHNVJYJU-DGrsmWts.js +1 -0
  232. package/dist/domains/dashboard/web/assets/timeline-definition-PNZ67QCA--ps2uu6L.js +120 -0
  233. package/dist/domains/dashboard/web/assets/vennDiagram-CIIHVFJN-C2q8q26c.js +34 -0
  234. package/dist/domains/dashboard/web/assets/wardleyDiagram-YWT4CUSO-BUH9gXqd.js +78 -0
  235. package/dist/domains/dashboard/web/assets/xychartDiagram-2RQKCTM6-B-DielEy.js +7 -0
  236. package/dist/domains/dashboard/web/index.html +16 -16
  237. package/dist/domains/engine/types.d.ts +1 -1
  238. package/dist/domains/engine/types.d.ts.map +1 -1
  239. package/dist/domains/factory/package.d.ts.map +1 -1
  240. package/dist/domains/factory/package.js +20 -6
  241. package/dist/domains/factory/package.js.map +1 -1
  242. package/dist/domains/integrations/openspec.d.ts +4 -1
  243. package/dist/domains/integrations/openspec.d.ts.map +1 -1
  244. package/dist/domains/integrations/openspec.js +62 -10
  245. package/dist/domains/integrations/openspec.js.map +1 -1
  246. package/dist/domains/skill/find.d.ts.map +1 -1
  247. package/dist/domains/skill/find.js +1 -6
  248. package/dist/domains/skill/find.js.map +1 -1
  249. package/dist/domains/skill/json-object.d.ts +13 -0
  250. package/dist/domains/skill/json-object.d.ts.map +1 -0
  251. package/dist/domains/skill/json-object.js +24 -0
  252. package/dist/domains/skill/json-object.js.map +1 -0
  253. package/dist/domains/skill/managed-markdown.d.ts +14 -0
  254. package/dist/domains/skill/managed-markdown.d.ts.map +1 -0
  255. package/dist/domains/skill/managed-markdown.js +126 -0
  256. package/dist/domains/skill/managed-markdown.js.map +1 -0
  257. package/dist/domains/skill/platform-inspect.d.ts +9 -0
  258. package/dist/domains/skill/platform-inspect.d.ts.map +1 -0
  259. package/dist/domains/skill/platform-inspect.js +149 -0
  260. package/dist/domains/skill/platform-inspect.js.map +1 -0
  261. package/dist/domains/skill/platform-install.d.ts +20 -9
  262. package/dist/domains/skill/platform-install.d.ts.map +1 -1
  263. package/dist/domains/skill/platform-install.js +356 -153
  264. package/dist/domains/skill/platform-install.js.map +1 -1
  265. package/dist/domains/skill/project-instructions.d.ts +22 -0
  266. package/dist/domains/skill/project-instructions.d.ts.map +1 -0
  267. package/dist/domains/skill/project-instructions.js +61 -0
  268. package/dist/domains/skill/project-instructions.js.map +1 -0
  269. package/dist/domains/skill/uninstall.d.ts +3 -1
  270. package/dist/domains/skill/uninstall.d.ts.map +1 -1
  271. package/dist/domains/skill/uninstall.js +259 -149
  272. package/dist/domains/skill/uninstall.js.map +1 -1
  273. package/dist/platform/fs/file-system.d.ts +3 -3
  274. package/dist/platform/fs/file-system.d.ts.map +1 -1
  275. package/dist/platform/fs/file-system.js +21 -11
  276. package/dist/platform/fs/file-system.js.map +1 -1
  277. package/dist/platform/install/detect.d.ts +2 -1
  278. package/dist/platform/install/detect.d.ts.map +1 -1
  279. package/dist/platform/install/detect.js +10 -1
  280. package/dist/platform/install/detect.js.map +1 -1
  281. package/dist/platform/install/platforms.d.ts +9 -1
  282. package/dist/platform/install/platforms.d.ts.map +1 -1
  283. package/dist/platform/install/platforms.js +23 -4
  284. package/dist/platform/install/platforms.js.map +1 -1
  285. package/dist/platform/install/project-registry.d.ts +38 -0
  286. package/dist/platform/install/project-registry.d.ts.map +1 -0
  287. package/dist/platform/install/project-registry.js +213 -0
  288. package/dist/platform/install/project-registry.js.map +1 -0
  289. package/dist/platform/install/skill-root-owner.d.ts +15 -0
  290. package/dist/platform/install/skill-root-owner.d.ts.map +1 -0
  291. package/dist/platform/install/skill-root-owner.js +68 -0
  292. package/dist/platform/install/skill-root-owner.js.map +1 -0
  293. package/eval/.env.example +52 -0
  294. package/eval/CLAUDE.md +43 -0
  295. package/eval/README.md +538 -0
  296. package/eval/langsmith/.env.example +16 -0
  297. package/eval/langsmith/README.md +93 -0
  298. package/eval/langsmith/skills/README.md +5 -0
  299. package/eval/langsmith/tasks/README.md +5 -0
  300. package/eval/langsmith/tests/conftest.py +187 -0
  301. package/eval/langsmith/tests/tasks/test_tasks.py +287 -0
  302. package/eval/langsmith/treatments/README.md +5 -0
  303. package/eval/local/README.md +80 -0
  304. package/eval/local/regression_baseline.json +13 -0
  305. package/eval/local/report-style-demo-assets/quality_cost.en.svg +41 -0
  306. package/eval/local/report-style-demo-assets/quality_cost.zh.svg +41 -0
  307. package/eval/local/report-style-demo-assets/rubric_delta.en.svg +56 -0
  308. package/eval/local/report-style-demo-assets/rubric_delta.zh.svg +56 -0
  309. package/eval/local/report-style-demo-assets/task_outcomes.en.svg +46 -0
  310. package/eval/local/report-style-demo-assets/task_outcomes.zh.svg +46 -0
  311. package/eval/local/report-style-demo.html +867 -0
  312. package/eval/local/scripts/compare_baselines.py +1018 -0
  313. package/eval/local/scripts/generate_report_style_demo_charts.py +322 -0
  314. package/eval/local/scripts/regression_check.py +171 -0
  315. package/eval/local/scripts/render_readme_benchmark_figures.py +416 -0
  316. package/eval/local/scripts/rescore_rubric.py +120 -0
  317. package/eval/local/skills/benchmarks/039-release/comet-classic-039/SKILL.md +282 -0
  318. package/eval/local/skills/benchmarks/039-release/comet-classic-039/reference/auto-transition.md +27 -0
  319. package/eval/local/skills/benchmarks/039-release/comet-classic-039/reference/comet-yaml-fields.md +68 -0
  320. package/eval/local/skills/benchmarks/039-release/comet-classic-039/reference/context-recovery.md +35 -0
  321. package/eval/local/skills/benchmarks/039-release/comet-classic-039/reference/debug-gate.md +17 -0
  322. package/eval/local/skills/benchmarks/039-release/comet-classic-039/reference/decision-point.md +20 -0
  323. package/eval/local/skills/benchmarks/039-release/comet-classic-039/reference/dirty-worktree.md +59 -0
  324. package/eval/local/skills/benchmarks/039-release/comet-classic-039/reference/file-structure.md +28 -0
  325. package/eval/local/skills/benchmarks/039-release/comet-classic-039/reference/subagent-dispatch.md +113 -0
  326. package/eval/local/skills/benchmarks/039-release/comet-classic-039/rules/comet-phase-guard.md +125 -0
  327. package/eval/local/skills/benchmarks/039-release/comet-classic-039/scripts/comet-archive.sh +311 -0
  328. package/eval/local/skills/benchmarks/039-release/comet-classic-039/scripts/comet-env.sh +110 -0
  329. package/eval/local/skills/benchmarks/039-release/comet-classic-039/scripts/comet-guard.sh +778 -0
  330. package/eval/local/skills/benchmarks/039-release/comet-classic-039/scripts/comet-handoff.sh +390 -0
  331. package/eval/local/skills/benchmarks/039-release/comet-classic-039/scripts/comet-hook-guard.sh +336 -0
  332. package/eval/local/skills/benchmarks/039-release/comet-classic-039/scripts/comet-state.sh +1338 -0
  333. package/eval/local/skills/benchmarks/039-release/comet-classic-039/scripts/comet-yaml-validate.sh +225 -0
  334. package/eval/local/skills/benchmarks/039-release/comet-classic-039-archive/SKILL.md +100 -0
  335. package/eval/local/skills/benchmarks/039-release/comet-classic-039-build/SKILL.md +304 -0
  336. package/eval/local/skills/benchmarks/039-release/comet-classic-039-design/SKILL.md +263 -0
  337. package/eval/local/skills/benchmarks/039-release/comet-classic-039-hotfix/SKILL.md +204 -0
  338. package/eval/local/skills/benchmarks/039-release/comet-classic-039-open/SKILL.md +220 -0
  339. package/eval/local/skills/benchmarks/039-release/comet-classic-039-tweak/SKILL.md +180 -0
  340. package/eval/local/skills/benchmarks/039-release/comet-classic-039-verify/SKILL.md +234 -0
  341. package/eval/local/skills/benchmarks/040-beta/comet/SKILL.md +261 -0
  342. package/eval/local/skills/benchmarks/040-beta/comet/reference/auto-transition.md +27 -0
  343. package/eval/local/skills/benchmarks/040-beta/comet/reference/comet-yaml-fields.md +73 -0
  344. package/eval/local/skills/benchmarks/040-beta/comet/reference/context-recovery.md +45 -0
  345. package/eval/local/skills/benchmarks/040-beta/comet/reference/debug-gate.md +33 -0
  346. package/eval/local/skills/benchmarks/040-beta/comet/reference/decision-point.md +31 -0
  347. package/eval/local/skills/benchmarks/040-beta/comet/reference/dirty-worktree.md +59 -0
  348. package/eval/local/skills/benchmarks/040-beta/comet/reference/file-structure.md +28 -0
  349. package/eval/local/skills/benchmarks/040-beta/comet/reference/intent-frame.md +74 -0
  350. package/eval/local/skills/benchmarks/040-beta/comet/reference/scripts.md +69 -0
  351. package/eval/local/skills/benchmarks/040-beta/comet/reference/subagent-dispatch.md +169 -0
  352. package/eval/local/skills/benchmarks/040-beta/comet/rules/comet-phase-guard.md +130 -0
  353. package/eval/local/skills/benchmarks/040-beta/comet/runtime/classic/checks.yaml +6 -0
  354. package/eval/local/skills/benchmarks/040-beta/comet/runtime/classic/guardrails.yaml +13 -0
  355. package/eval/local/skills/benchmarks/040-beta/comet/runtime/classic/skill.yaml +122 -0
  356. package/eval/local/skills/benchmarks/040-beta/comet/scripts/comet-archive.mjs +9515 -0
  357. package/eval/local/skills/benchmarks/040-beta/comet/scripts/comet-env.mjs +15 -0
  358. package/eval/local/skills/benchmarks/040-beta/comet/scripts/comet-guard.mjs +10173 -0
  359. package/eval/local/skills/benchmarks/040-beta/comet/scripts/comet-handoff.mjs +9491 -0
  360. package/eval/local/skills/benchmarks/040-beta/comet/scripts/comet-hook-guard.mjs +9175 -0
  361. package/eval/local/skills/benchmarks/040-beta/comet/scripts/comet-intent.mjs +404 -0
  362. package/eval/local/skills/benchmarks/040-beta/comet/scripts/comet-state.mjs +9273 -0
  363. package/eval/local/skills/benchmarks/040-beta/comet/scripts/comet-yaml-validate.mjs +7627 -0
  364. package/eval/local/skills/benchmarks/040-beta/comet-archive/SKILL.md +110 -0
  365. package/eval/local/skills/benchmarks/040-beta/comet-build/SKILL.md +315 -0
  366. package/eval/local/skills/benchmarks/040-beta/comet-design/SKILL.md +260 -0
  367. package/eval/local/skills/benchmarks/040-beta/comet-hotfix/SKILL.md +190 -0
  368. package/eval/local/skills/benchmarks/040-beta/comet-open/SKILL.md +210 -0
  369. package/eval/local/skills/benchmarks/040-beta/comet-tweak/SKILL.md +183 -0
  370. package/eval/local/skills/benchmarks/040-beta/comet-verify/SKILL.md +230 -0
  371. package/eval/local/skills/benchmarks/dependency/claude-md/comet-workflow/CLAUDE.md +12 -0
  372. package/eval/local/skills/benchmarks/dependency/openspec/openspec-apply-change/SKILL.md +156 -0
  373. package/eval/local/skills/benchmarks/dependency/openspec/openspec-archive-change/SKILL.md +114 -0
  374. package/eval/local/skills/benchmarks/dependency/openspec/openspec-bulk-archive-change/SKILL.md +246 -0
  375. package/eval/local/skills/benchmarks/dependency/openspec/openspec-continue-change/SKILL.md +118 -0
  376. package/eval/local/skills/benchmarks/dependency/openspec/openspec-explore/SKILL.md +288 -0
  377. package/eval/local/skills/benchmarks/dependency/openspec/openspec-ff-change/SKILL.md +101 -0
  378. package/eval/local/skills/benchmarks/dependency/openspec/openspec-new-change/SKILL.md +74 -0
  379. package/eval/local/skills/benchmarks/dependency/openspec/openspec-onboard/SKILL.md +554 -0
  380. package/eval/local/skills/benchmarks/dependency/openspec/openspec-propose/SKILL.md +110 -0
  381. package/eval/local/skills/benchmarks/dependency/openspec/openspec-sync-specs/SKILL.md +138 -0
  382. package/eval/local/skills/benchmarks/dependency/openspec/openspec-verify-change/SKILL.md +168 -0
  383. package/eval/local/skills/benchmarks/dependency/superpowers/brainstorming/SKILL.md +159 -0
  384. package/eval/local/skills/benchmarks/dependency/superpowers/brainstorming/scripts/frame-template.html +213 -0
  385. package/eval/local/skills/benchmarks/dependency/superpowers/brainstorming/scripts/helper.js +167 -0
  386. package/eval/local/skills/benchmarks/dependency/superpowers/brainstorming/scripts/server.cjs +723 -0
  387. package/eval/local/skills/benchmarks/dependency/superpowers/brainstorming/scripts/start-server.sh +209 -0
  388. package/eval/local/skills/benchmarks/dependency/superpowers/brainstorming/scripts/stop-server.sh +120 -0
  389. package/eval/local/skills/benchmarks/dependency/superpowers/brainstorming/spec-document-reviewer-prompt.md +49 -0
  390. package/eval/local/skills/benchmarks/dependency/superpowers/brainstorming/visual-companion.md +291 -0
  391. package/eval/local/skills/benchmarks/dependency/superpowers/dispatching-parallel-agents/SKILL.md +185 -0
  392. package/eval/local/skills/benchmarks/dependency/superpowers/executing-plans/SKILL.md +70 -0
  393. package/eval/local/skills/benchmarks/dependency/superpowers/finishing-a-development-branch/SKILL.md +241 -0
  394. package/eval/local/skills/benchmarks/dependency/superpowers/receiving-code-review/SKILL.md +213 -0
  395. package/eval/local/skills/benchmarks/dependency/superpowers/requesting-code-review/SKILL.md +103 -0
  396. package/eval/local/skills/benchmarks/dependency/superpowers/requesting-code-review/code-reviewer.md +172 -0
  397. package/eval/local/skills/benchmarks/dependency/superpowers/subagent-driven-development/SKILL.md +418 -0
  398. package/eval/local/skills/benchmarks/dependency/superpowers/subagent-driven-development/implementer-prompt.md +139 -0
  399. package/eval/local/skills/benchmarks/dependency/superpowers/subagent-driven-development/scripts/review-package +44 -0
  400. package/eval/local/skills/benchmarks/dependency/superpowers/subagent-driven-development/scripts/sdd-workspace +22 -0
  401. package/eval/local/skills/benchmarks/dependency/superpowers/subagent-driven-development/scripts/task-brief +40 -0
  402. package/eval/local/skills/benchmarks/dependency/superpowers/subagent-driven-development/task-reviewer-prompt.md +188 -0
  403. package/eval/local/skills/benchmarks/dependency/superpowers/systematic-debugging/CREATION-LOG.md +119 -0
  404. package/eval/local/skills/benchmarks/dependency/superpowers/systematic-debugging/SKILL.md +296 -0
  405. package/eval/local/skills/benchmarks/dependency/superpowers/systematic-debugging/condition-based-waiting-example.ts +158 -0
  406. package/eval/local/skills/benchmarks/dependency/superpowers/systematic-debugging/condition-based-waiting.md +115 -0
  407. package/eval/local/skills/benchmarks/dependency/superpowers/systematic-debugging/defense-in-depth.md +122 -0
  408. package/eval/local/skills/benchmarks/dependency/superpowers/systematic-debugging/find-polluter.sh +63 -0
  409. package/eval/local/skills/benchmarks/dependency/superpowers/systematic-debugging/root-cause-tracing.md +169 -0
  410. package/eval/local/skills/benchmarks/dependency/superpowers/systematic-debugging/test-academic.md +14 -0
  411. package/eval/local/skills/benchmarks/dependency/superpowers/systematic-debugging/test-pressure-1.md +58 -0
  412. package/eval/local/skills/benchmarks/dependency/superpowers/systematic-debugging/test-pressure-2.md +68 -0
  413. package/eval/local/skills/benchmarks/dependency/superpowers/systematic-debugging/test-pressure-3.md +69 -0
  414. package/eval/local/skills/benchmarks/dependency/superpowers/test-driven-development/SKILL.md +371 -0
  415. package/eval/local/skills/benchmarks/dependency/superpowers/test-driven-development/testing-anti-patterns.md +299 -0
  416. package/eval/local/skills/benchmarks/dependency/superpowers/using-git-worktrees/SKILL.md +202 -0
  417. package/eval/local/skills/benchmarks/dependency/superpowers/verification-before-completion/SKILL.md +139 -0
  418. package/eval/local/skills/benchmarks/dependency/superpowers/writing-plans/SKILL.md +174 -0
  419. package/eval/local/skills/benchmarks/dependency/superpowers/writing-plans/plan-document-reviewer-prompt.md +49 -0
  420. package/eval/local/skills/benchmarks/dependency/superpowers/writing-skills/SKILL.md +689 -0
  421. package/eval/local/skills/benchmarks/dependency/superpowers/writing-skills/anthropic-best-practices.md +1150 -0
  422. package/eval/local/skills/benchmarks/dependency/superpowers/writing-skills/examples/CLAUDE_MD_TESTING.md +189 -0
  423. package/eval/local/skills/benchmarks/dependency/superpowers/writing-skills/graphviz-conventions.dot +172 -0
  424. package/eval/local/skills/benchmarks/dependency/superpowers/writing-skills/persuasion-principles.md +187 -0
  425. package/eval/local/skills/benchmarks/dependency/superpowers/writing-skills/render-graphs.js +168 -0
  426. package/eval/local/skills/benchmarks/dependency/superpowers/writing-skills/testing-skills-with-subagents.md +384 -0
  427. package/eval/local/tasks/authoring-skill-smoke/environment/Dockerfile +2 -0
  428. package/eval/local/tasks/authoring-skill-smoke/instruction.md +4 -0
  429. package/eval/local/tasks/authoring-skill-smoke/task.toml +21 -0
  430. package/eval/local/tasks/authoring-skill-smoke/validation/test_authoring_skill_smoke.py +54 -0
  431. package/eval/local/tasks/comet-agent-memory-routing/environment/Dockerfile +28 -0
  432. package/eval/local/tasks/comet-agent-memory-routing/environment/agent_system.py +40 -0
  433. package/eval/local/tasks/comet-agent-memory-routing/environment/test_agent_system.py +29 -0
  434. package/eval/local/tasks/comet-agent-memory-routing/instruction.md +20 -0
  435. package/eval/local/tasks/comet-agent-memory-routing/task.toml +24 -0
  436. package/eval/local/tasks/comet-agent-memory-routing/validation/test_agent_memory_routing.py +24 -0
  437. package/eval/local/tasks/comet-api-cache-ttl/environment/Dockerfile +39 -0
  438. package/eval/local/tasks/comet-api-cache-ttl/environment/cache.py +39 -0
  439. package/eval/local/tasks/comet-api-cache-ttl/environment/test_cache.py +81 -0
  440. package/eval/local/tasks/comet-api-cache-ttl/instruction.md +33 -0
  441. package/eval/local/tasks/comet-api-cache-ttl/task.toml +24 -0
  442. package/eval/local/tasks/comet-api-cache-ttl/validation/test_api_cache_ttl.py +58 -0
  443. package/eval/local/tasks/comet-cross-file-refactor/environment/Dockerfile +15 -0
  444. package/eval/local/tasks/comet-cross-file-refactor/environment/cli.py +13 -0
  445. package/eval/local/tasks/comet-cross-file-refactor/environment/counting.py +13 -0
  446. package/eval/local/tasks/comet-cross-file-refactor/environment/test_textkit.py +21 -0
  447. package/eval/local/tasks/comet-cross-file-refactor/instruction.md +16 -0
  448. package/eval/local/tasks/comet-cross-file-refactor/task.toml +20 -0
  449. package/eval/local/tasks/comet-cross-file-refactor/validation/test_cross_file_refactor.py +20 -0
  450. package/eval/local/tasks/comet-dependency-confusion/environment/Dockerfile +28 -0
  451. package/eval/local/tasks/comet-dependency-confusion/environment/app.py +8 -0
  452. package/eval/local/tasks/comet-dependency-confusion/environment/settings_loader.py +14 -0
  453. package/eval/local/tasks/comet-dependency-confusion/environment/test_settings_service.py +19 -0
  454. package/eval/local/tasks/comet-dependency-confusion/instruction.md +18 -0
  455. package/eval/local/tasks/comet-dependency-confusion/task.toml +24 -0
  456. package/eval/local/tasks/comet-dependency-confusion/validation/test_dependency_confusion.py +24 -0
  457. package/eval/local/tasks/comet-fix-median/environment/Dockerfile +50 -0
  458. package/eval/local/tasks/comet-fix-median/environment/stats.py +54 -0
  459. package/eval/local/tasks/comet-fix-median/environment/test_stats.py +68 -0
  460. package/eval/local/tasks/comet-fix-median/instruction.md +25 -0
  461. package/eval/local/tasks/comet-fix-median/task.toml +24 -0
  462. package/eval/local/tasks/comet-fix-median/validation/test_fix_median.py +60 -0
  463. package/eval/local/tasks/comet-framework-selection/environment/Dockerfile +28 -0
  464. package/eval/local/tasks/comet-framework-selection/environment/architecture.py +12 -0
  465. package/eval/local/tasks/comet-framework-selection/environment/test_architecture.py +30 -0
  466. package/eval/local/tasks/comet-framework-selection/instruction.md +22 -0
  467. package/eval/local/tasks/comet-framework-selection/task.toml +24 -0
  468. package/eval/local/tasks/comet-framework-selection/validation/test_framework_selection.py +24 -0
  469. package/eval/local/tasks/comet-full-workflow/environment/Dockerfile +53 -0
  470. package/eval/local/tasks/comet-full-workflow/environment/test_wordcount.py +29 -0
  471. package/eval/local/tasks/comet-full-workflow/environment/wordcount.py +40 -0
  472. package/eval/local/tasks/comet-full-workflow/instruction.md +18 -0
  473. package/eval/local/tasks/comet-full-workflow/task.toml +24 -0
  474. package/eval/local/tasks/comet-full-workflow/validation/test_full_workflow.py +171 -0
  475. package/eval/local/tasks/comet-graph-execution-review/environment/Dockerfile +28 -0
  476. package/eval/local/tasks/comet-graph-execution-review/environment/pipeline.py +19 -0
  477. package/eval/local/tasks/comet-graph-execution-review/environment/test_pipeline.py +53 -0
  478. package/eval/local/tasks/comet-graph-execution-review/instruction.md +21 -0
  479. package/eval/local/tasks/comet-graph-execution-review/task.toml +24 -0
  480. package/eval/local/tasks/comet-graph-execution-review/validation/test_graph_execution_review.py +24 -0
  481. package/eval/local/tasks/comet-human-approval-flow/environment/Dockerfile +15 -0
  482. package/eval/local/tasks/comet-human-approval-flow/environment/approvals.py +17 -0
  483. package/eval/local/tasks/comet-human-approval-flow/environment/test_approvals.py +30 -0
  484. package/eval/local/tasks/comet-human-approval-flow/instruction.md +15 -0
  485. package/eval/local/tasks/comet-human-approval-flow/task.toml +20 -0
  486. package/eval/local/tasks/comet-human-approval-flow/validation/test_human_approval_flow.py +20 -0
  487. package/eval/local/tasks/comet-layered-streaming-fix/environment/Dockerfile +20 -0
  488. package/eval/local/tasks/comet-layered-streaming-fix/environment/chat_app.py +19 -0
  489. package/eval/local/tasks/comet-layered-streaming-fix/environment/test_chat_app.py +15 -0
  490. package/eval/local/tasks/comet-layered-streaming-fix/instruction.md +14 -0
  491. package/eval/local/tasks/comet-layered-streaming-fix/task.toml +20 -0
  492. package/eval/local/tasks/comet-layered-streaming-fix/validation/test_layered_streaming_fix.py +20 -0
  493. package/eval/local/tasks/comet-noise-distractor/environment/Dockerfile +15 -0
  494. package/eval/local/tasks/comet-noise-distractor/environment/distractor.md +4 -0
  495. package/eval/local/tasks/comet-noise-distractor/environment/invoice.py +5 -0
  496. package/eval/local/tasks/comet-noise-distractor/environment/test_invoice.py +18 -0
  497. package/eval/local/tasks/comet-noise-distractor/instruction.md +17 -0
  498. package/eval/local/tasks/comet-noise-distractor/task.toml +20 -0
  499. package/eval/local/tasks/comet-noise-distractor/validation/test_noise_distractor.py +20 -0
  500. package/eval/local/tasks/comet-observability-env-template/environment/Dockerfile +15 -0
  501. package/eval/local/tasks/comet-observability-env-template/environment/env_writer.py +17 -0
  502. package/eval/local/tasks/comet-observability-env-template/environment/test_env_writer.py +17 -0
  503. package/eval/local/tasks/comet-observability-env-template/instruction.md +20 -0
  504. package/eval/local/tasks/comet-observability-env-template/task.toml +20 -0
  505. package/eval/local/tasks/comet-observability-env-template/validation/test_observability_env_template.py +46 -0
  506. package/eval/local/tasks/comet-perf-dedupe/environment/Dockerfile +39 -0
  507. package/eval/local/tasks/comet-perf-dedupe/environment/dedupe.py +22 -0
  508. package/eval/local/tasks/comet-perf-dedupe/environment/test_dedupe.py +43 -0
  509. package/eval/local/tasks/comet-perf-dedupe/instruction.md +25 -0
  510. package/eval/local/tasks/comet-perf-dedupe/task.toml +24 -0
  511. package/eval/local/tasks/comet-perf-dedupe/validation/test_perf_dedupe.py +40 -0
  512. package/eval/local/tasks/comet-persistence-threading/environment/Dockerfile +15 -0
  513. package/eval/local/tasks/comet-persistence-threading/environment/session_store.py +15 -0
  514. package/eval/local/tasks/comet-persistence-threading/environment/test_session_store.py +21 -0
  515. package/eval/local/tasks/comet-persistence-threading/instruction.md +14 -0
  516. package/eval/local/tasks/comet-persistence-threading/task.toml +20 -0
  517. package/eval/local/tasks/comet-persistence-threading/validation/test_persistence_threading.py +20 -0
  518. package/eval/local/tasks/comet-refactor-counter/environment/Dockerfile +39 -0
  519. package/eval/local/tasks/comet-refactor-counter/environment/test_text_processor.py +57 -0
  520. package/eval/local/tasks/comet-refactor-counter/environment/text_processor.py +49 -0
  521. package/eval/local/tasks/comet-refactor-counter/instruction.md +31 -0
  522. package/eval/local/tasks/comet-refactor-counter/task.toml +24 -0
  523. package/eval/local/tasks/comet-refactor-counter/validation/test_refactor_counter.py +75 -0
  524. package/eval/local/tasks/comet-robust-config/environment/Dockerfile +39 -0
  525. package/eval/local/tasks/comet-robust-config/environment/config_loader.py +56 -0
  526. package/eval/local/tasks/comet-robust-config/environment/test_config_loader.py +72 -0
  527. package/eval/local/tasks/comet-robust-config/instruction.md +30 -0
  528. package/eval/local/tasks/comet-robust-config/task.toml +24 -0
  529. package/eval/local/tasks/comet-robust-config/validation/test_robust_config.py +37 -0
  530. package/eval/local/tasks/generic-skill-smoke/environment/Dockerfile +2 -0
  531. package/eval/local/tasks/generic-skill-smoke/instruction.md +7 -0
  532. package/eval/local/tasks/generic-skill-smoke/task.toml +21 -0
  533. package/eval/local/tasks/generic-skill-smoke/validation/test_generic_skill_smoke.py +36 -0
  534. package/eval/local/tasks/index.yaml +155 -0
  535. package/eval/local/tasks/workflow-overlay-contract/environment/Dockerfile +5 -0
  536. package/eval/local/tasks/workflow-overlay-contract/instruction.md +5 -0
  537. package/eval/local/tasks/workflow-overlay-contract/task.toml +21 -0
  538. package/eval/local/tasks/workflow-overlay-contract/validation/test_workflow_overlay_contract.py +235 -0
  539. package/eval/local/tasks/workflow-route-conformance/environment/Dockerfile +2 -0
  540. package/eval/local/tasks/workflow-route-conformance/instruction.md +5 -0
  541. package/eval/local/tasks/workflow-route-conformance/task.toml +21 -0
  542. package/eval/local/tasks/workflow-route-conformance/validation/test_workflow_route_conformance.py +84 -0
  543. package/eval/local/tests/conftest.py +1148 -0
  544. package/eval/local/tests/scaffold/test_attribution.py +48 -0
  545. package/eval/local/tests/scaffold/test_compare_baselines.py +999 -0
  546. package/eval/local/tests/scaffold/test_conftest_helpers.py +534 -0
  547. package/eval/local/tests/scaffold/test_evidence.py +15 -0
  548. package/eval/local/tests/scaffold/test_langsmith_conftest.py +244 -0
  549. package/eval/local/tests/scaffold/test_logging.py +243 -0
  550. package/eval/local/tests/scaffold/test_manifests.py +132 -0
  551. package/eval/local/tests/scaffold/test_profiles.py +866 -0
  552. package/eval/local/tests/scaffold/test_regression_check.py +19 -0
  553. package/eval/local/tests/scaffold/test_report_style_demo_charts.py +45 -0
  554. package/eval/local/tests/scaffold/test_sample_quality.py +211 -0
  555. package/eval/local/tests/scaffold/test_tasks.py +168 -0
  556. package/eval/local/tests/scaffold/test_treatments.py +244 -0
  557. package/eval/local/tests/scaffold/test_utils.py +139 -0
  558. package/eval/local/tests/tasks/test_tasks.py +445 -0
  559. package/eval/local/tests/tasks/test_validation_scripts.py +143 -0
  560. package/eval/local/treatments/comet/comet_full_039.yaml +141 -0
  561. package/eval/local/treatments/comet/comet_full_040_beta.yaml +140 -0
  562. package/eval/local/treatments/common/control.yaml +4 -0
  563. package/eval/pyproject.toml +41 -0
  564. package/eval/report-html-config.json +6 -0
  565. package/eval/scaffold/__init__.py +67 -0
  566. package/eval/scaffold/python/__init__.py +95 -0
  567. package/eval/scaffold/python/attribution.py +43 -0
  568. package/eval/scaffold/python/evidence.py +38 -0
  569. package/eval/scaffold/python/external_data_handler.py +18 -0
  570. package/eval/scaffold/python/generic_llm_judge.py +235 -0
  571. package/eval/scaffold/python/judge_config.py +168 -0
  572. package/eval/scaffold/python/llm_judge.py +191 -0
  573. package/eval/scaffold/python/logging.py +705 -0
  574. package/eval/scaffold/python/manifests.py +129 -0
  575. package/eval/scaffold/python/paper_charts.py +25 -0
  576. package/eval/scaffold/python/pass_at_k.py +107 -0
  577. package/eval/scaffold/python/paths.py +56 -0
  578. package/eval/scaffold/python/profiles.py +127 -0
  579. package/eval/scaffold/python/report_outputs.py +1391 -0
  580. package/eval/scaffold/python/sample_quality.py +339 -0
  581. package/eval/scaffold/python/schema.py +39 -0
  582. package/eval/scaffold/python/skill_parser.py +469 -0
  583. package/eval/scaffold/python/tasks.py +330 -0
  584. package/eval/scaffold/python/treatments.py +271 -0
  585. package/eval/scaffold/python/utils.py +366 -0
  586. package/eval/scaffold/python/validation/__init__.py +21 -0
  587. package/eval/scaffold/python/validation/authoring_rubric.py +326 -0
  588. package/eval/scaffold/python/validation/comet_workflow.py +187 -0
  589. package/eval/scaffold/python/validation/core.py +264 -0
  590. package/eval/scaffold/python/validation/dataset.py +337 -0
  591. package/eval/scaffold/python/validation/docker.py +106 -0
  592. package/eval/scaffold/python/validation/evaluator.py +549 -0
  593. package/eval/scaffold/python/validation/generic_rubric.py +169 -0
  594. package/eval/scaffold/python/validation/rubric.py +740 -0
  595. package/eval/scaffold/python/validation/runner.py +237 -0
  596. package/eval/scaffold/python/validation/scripts.py +58 -0
  597. package/eval/scaffold/python/validation/tracing.py +313 -0
  598. package/eval/scaffold/shell/common.sh +126 -0
  599. package/eval/scaffold/shell/docker.sh +482 -0
  600. package/eval/scaffold/shell/run-claude-loop.sh +181 -0
  601. package/eval/scaffold/shell/setup.sh +259 -0
  602. package/eval/simulator-instruction.md +9 -0
  603. package/package.json +29 -2
  604. package/dist/domains/dashboard/web/assets/index-BcO3_QlT.css +0 -1
  605. package/dist/domains/dashboard/web/assets/index-CjU3VXVu.js +0 -22
@@ -126,17 +126,17 @@ var require_visit = __commonJS({
126
126
  visit.BREAK = BREAK;
127
127
  visit.SKIP = SKIP;
128
128
  visit.REMOVE = REMOVE;
129
- function visit_(key, node, visitor, path18) {
130
- const ctrl = callVisitor(key, node, visitor, path18);
129
+ function visit_(key, node, visitor, path22) {
130
+ const ctrl = callVisitor(key, node, visitor, path22);
131
131
  if (identity.isNode(ctrl) || identity.isPair(ctrl)) {
132
- replaceNode(key, path18, ctrl);
133
- return visit_(key, ctrl, visitor, path18);
132
+ replaceNode(key, path22, ctrl);
133
+ return visit_(key, ctrl, visitor, path22);
134
134
  }
135
135
  if (typeof ctrl !== "symbol") {
136
136
  if (identity.isCollection(node)) {
137
- path18 = Object.freeze(path18.concat(node));
137
+ path22 = Object.freeze(path22.concat(node));
138
138
  for (let i = 0; i < node.items.length; ++i) {
139
- const ci = visit_(i, node.items[i], visitor, path18);
139
+ const ci = visit_(i, node.items[i], visitor, path22);
140
140
  if (typeof ci === "number")
141
141
  i = ci - 1;
142
142
  else if (ci === BREAK)
@@ -147,13 +147,13 @@ var require_visit = __commonJS({
147
147
  }
148
148
  }
149
149
  } else if (identity.isPair(node)) {
150
- path18 = Object.freeze(path18.concat(node));
151
- const ck = visit_("key", node.key, visitor, path18);
150
+ path22 = Object.freeze(path22.concat(node));
151
+ const ck = visit_("key", node.key, visitor, path22);
152
152
  if (ck === BREAK)
153
153
  return BREAK;
154
154
  else if (ck === REMOVE)
155
155
  node.key = null;
156
- const cv = visit_("value", node.value, visitor, path18);
156
+ const cv = visit_("value", node.value, visitor, path22);
157
157
  if (cv === BREAK)
158
158
  return BREAK;
159
159
  else if (cv === REMOVE)
@@ -174,17 +174,17 @@ var require_visit = __commonJS({
174
174
  visitAsync.BREAK = BREAK;
175
175
  visitAsync.SKIP = SKIP;
176
176
  visitAsync.REMOVE = REMOVE;
177
- async function visitAsync_(key, node, visitor, path18) {
178
- const ctrl = await callVisitor(key, node, visitor, path18);
177
+ async function visitAsync_(key, node, visitor, path22) {
178
+ const ctrl = await callVisitor(key, node, visitor, path22);
179
179
  if (identity.isNode(ctrl) || identity.isPair(ctrl)) {
180
- replaceNode(key, path18, ctrl);
181
- return visitAsync_(key, ctrl, visitor, path18);
180
+ replaceNode(key, path22, ctrl);
181
+ return visitAsync_(key, ctrl, visitor, path22);
182
182
  }
183
183
  if (typeof ctrl !== "symbol") {
184
184
  if (identity.isCollection(node)) {
185
- path18 = Object.freeze(path18.concat(node));
185
+ path22 = Object.freeze(path22.concat(node));
186
186
  for (let i = 0; i < node.items.length; ++i) {
187
- const ci = await visitAsync_(i, node.items[i], visitor, path18);
187
+ const ci = await visitAsync_(i, node.items[i], visitor, path22);
188
188
  if (typeof ci === "number")
189
189
  i = ci - 1;
190
190
  else if (ci === BREAK)
@@ -195,13 +195,13 @@ var require_visit = __commonJS({
195
195
  }
196
196
  }
197
197
  } else if (identity.isPair(node)) {
198
- path18 = Object.freeze(path18.concat(node));
199
- const ck = await visitAsync_("key", node.key, visitor, path18);
198
+ path22 = Object.freeze(path22.concat(node));
199
+ const ck = await visitAsync_("key", node.key, visitor, path22);
200
200
  if (ck === BREAK)
201
201
  return BREAK;
202
202
  else if (ck === REMOVE)
203
203
  node.key = null;
204
- const cv = await visitAsync_("value", node.value, visitor, path18);
204
+ const cv = await visitAsync_("value", node.value, visitor, path22);
205
205
  if (cv === BREAK)
206
206
  return BREAK;
207
207
  else if (cv === REMOVE)
@@ -228,23 +228,23 @@ var require_visit = __commonJS({
228
228
  }
229
229
  return visitor;
230
230
  }
231
- function callVisitor(key, node, visitor, path18) {
231
+ function callVisitor(key, node, visitor, path22) {
232
232
  if (typeof visitor === "function")
233
- return visitor(key, node, path18);
233
+ return visitor(key, node, path22);
234
234
  if (identity.isMap(node))
235
- return visitor.Map?.(key, node, path18);
235
+ return visitor.Map?.(key, node, path22);
236
236
  if (identity.isSeq(node))
237
- return visitor.Seq?.(key, node, path18);
237
+ return visitor.Seq?.(key, node, path22);
238
238
  if (identity.isPair(node))
239
- return visitor.Pair?.(key, node, path18);
239
+ return visitor.Pair?.(key, node, path22);
240
240
  if (identity.isScalar(node))
241
- return visitor.Scalar?.(key, node, path18);
241
+ return visitor.Scalar?.(key, node, path22);
242
242
  if (identity.isAlias(node))
243
- return visitor.Alias?.(key, node, path18);
243
+ return visitor.Alias?.(key, node, path22);
244
244
  return void 0;
245
245
  }
246
- function replaceNode(key, path18, node) {
247
- const parent = path18[path18.length - 1];
246
+ function replaceNode(key, path22, node) {
247
+ const parent = path22[path22.length - 1];
248
248
  if (identity.isCollection(parent)) {
249
249
  parent.items[key] = node;
250
250
  } else if (identity.isPair(parent)) {
@@ -854,10 +854,10 @@ var require_Collection = __commonJS({
854
854
  var createNode = require_createNode();
855
855
  var identity = require_identity();
856
856
  var Node = require_Node();
857
- function collectionFromPath(schema, path18, value) {
857
+ function collectionFromPath(schema, path22, value) {
858
858
  let v = value;
859
- for (let i = path18.length - 1; i >= 0; --i) {
860
- const k = path18[i];
859
+ for (let i = path22.length - 1; i >= 0; --i) {
860
+ const k = path22[i];
861
861
  if (typeof k === "number" && Number.isInteger(k) && k >= 0) {
862
862
  const a = [];
863
863
  a[k] = v;
@@ -876,7 +876,7 @@ var require_Collection = __commonJS({
876
876
  sourceObjects: /* @__PURE__ */ new Map()
877
877
  });
878
878
  }
879
- var isEmptyPath = (path18) => path18 == null || typeof path18 === "object" && !!path18[Symbol.iterator]().next().done;
879
+ var isEmptyPath = (path22) => path22 == null || typeof path22 === "object" && !!path22[Symbol.iterator]().next().done;
880
880
  var Collection = class extends Node.NodeBase {
881
881
  constructor(type, schema) {
882
882
  super(type);
@@ -906,11 +906,11 @@ var require_Collection = __commonJS({
906
906
  * be a Pair instance or a `{ key, value }` object, which may not have a key
907
907
  * that already exists in the map.
908
908
  */
909
- addIn(path18, value) {
910
- if (isEmptyPath(path18))
909
+ addIn(path22, value) {
910
+ if (isEmptyPath(path22))
911
911
  this.add(value);
912
912
  else {
913
- const [key, ...rest] = path18;
913
+ const [key, ...rest] = path22;
914
914
  const node = this.get(key, true);
915
915
  if (identity.isCollection(node))
916
916
  node.addIn(rest, value);
@@ -924,8 +924,8 @@ var require_Collection = __commonJS({
924
924
  * Removes a value from the collection.
925
925
  * @returns `true` if the item was found and removed.
926
926
  */
927
- deleteIn(path18) {
928
- const [key, ...rest] = path18;
927
+ deleteIn(path22) {
928
+ const [key, ...rest] = path22;
929
929
  if (rest.length === 0)
930
930
  return this.delete(key);
931
931
  const node = this.get(key, true);
@@ -939,8 +939,8 @@ var require_Collection = __commonJS({
939
939
  * scalar values from their surrounding node; to disable set `keepScalar` to
940
940
  * `true` (collections are always returned intact).
941
941
  */
942
- getIn(path18, keepScalar) {
943
- const [key, ...rest] = path18;
942
+ getIn(path22, keepScalar) {
943
+ const [key, ...rest] = path22;
944
944
  const node = this.get(key, true);
945
945
  if (rest.length === 0)
946
946
  return !keepScalar && identity.isScalar(node) ? node.value : node;
@@ -958,8 +958,8 @@ var require_Collection = __commonJS({
958
958
  /**
959
959
  * Checks if the collection includes a value with the key `key`.
960
960
  */
961
- hasIn(path18) {
962
- const [key, ...rest] = path18;
961
+ hasIn(path22) {
962
+ const [key, ...rest] = path22;
963
963
  if (rest.length === 0)
964
964
  return this.has(key);
965
965
  const node = this.get(key, true);
@@ -969,8 +969,8 @@ var require_Collection = __commonJS({
969
969
  * Sets a value in this collection. For `!!set`, `value` needs to be a
970
970
  * boolean to add/remove the item from the set.
971
971
  */
972
- setIn(path18, value) {
973
- const [key, ...rest] = path18;
972
+ setIn(path22, value) {
973
+ const [key, ...rest] = path22;
974
974
  if (rest.length === 0) {
975
975
  this.set(key, value);
976
976
  } else {
@@ -3485,9 +3485,9 @@ var require_Document = __commonJS({
3485
3485
  this.contents.add(value);
3486
3486
  }
3487
3487
  /** Adds a value to the document. */
3488
- addIn(path18, value) {
3488
+ addIn(path22, value) {
3489
3489
  if (assertCollection(this.contents))
3490
- this.contents.addIn(path18, value);
3490
+ this.contents.addIn(path22, value);
3491
3491
  }
3492
3492
  /**
3493
3493
  * Create a new `Alias` node, ensuring that the target `node` has the required anchor.
@@ -3562,14 +3562,14 @@ var require_Document = __commonJS({
3562
3562
  * Removes a value from the document.
3563
3563
  * @returns `true` if the item was found and removed.
3564
3564
  */
3565
- deleteIn(path18) {
3566
- if (Collection.isEmptyPath(path18)) {
3565
+ deleteIn(path22) {
3566
+ if (Collection.isEmptyPath(path22)) {
3567
3567
  if (this.contents == null)
3568
3568
  return false;
3569
3569
  this.contents = null;
3570
3570
  return true;
3571
3571
  }
3572
- return assertCollection(this.contents) ? this.contents.deleteIn(path18) : false;
3572
+ return assertCollection(this.contents) ? this.contents.deleteIn(path22) : false;
3573
3573
  }
3574
3574
  /**
3575
3575
  * Returns item at `key`, or `undefined` if not found. By default unwraps
@@ -3584,10 +3584,10 @@ var require_Document = __commonJS({
3584
3584
  * scalar values from their surrounding node; to disable set `keepScalar` to
3585
3585
  * `true` (collections are always returned intact).
3586
3586
  */
3587
- getIn(path18, keepScalar) {
3588
- if (Collection.isEmptyPath(path18))
3587
+ getIn(path22, keepScalar) {
3588
+ if (Collection.isEmptyPath(path22))
3589
3589
  return !keepScalar && identity.isScalar(this.contents) ? this.contents.value : this.contents;
3590
- return identity.isCollection(this.contents) ? this.contents.getIn(path18, keepScalar) : void 0;
3590
+ return identity.isCollection(this.contents) ? this.contents.getIn(path22, keepScalar) : void 0;
3591
3591
  }
3592
3592
  /**
3593
3593
  * Checks if the document includes a value with the key `key`.
@@ -3598,10 +3598,10 @@ var require_Document = __commonJS({
3598
3598
  /**
3599
3599
  * Checks if the document includes a value at `path`.
3600
3600
  */
3601
- hasIn(path18) {
3602
- if (Collection.isEmptyPath(path18))
3601
+ hasIn(path22) {
3602
+ if (Collection.isEmptyPath(path22))
3603
3603
  return this.contents !== void 0;
3604
- return identity.isCollection(this.contents) ? this.contents.hasIn(path18) : false;
3604
+ return identity.isCollection(this.contents) ? this.contents.hasIn(path22) : false;
3605
3605
  }
3606
3606
  /**
3607
3607
  * Sets a value in this document. For `!!set`, `value` needs to be a
@@ -3618,13 +3618,13 @@ var require_Document = __commonJS({
3618
3618
  * Sets a value in this document. For `!!set`, `value` needs to be a
3619
3619
  * boolean to add/remove the item from the set.
3620
3620
  */
3621
- setIn(path18, value) {
3622
- if (Collection.isEmptyPath(path18)) {
3621
+ setIn(path22, value) {
3622
+ if (Collection.isEmptyPath(path22)) {
3623
3623
  this.contents = value;
3624
3624
  } else if (this.contents == null) {
3625
- this.contents = Collection.collectionFromPath(this.schema, Array.from(path18), value);
3625
+ this.contents = Collection.collectionFromPath(this.schema, Array.from(path22), value);
3626
3626
  } else if (assertCollection(this.contents)) {
3627
- this.contents.setIn(path18, value);
3627
+ this.contents.setIn(path22, value);
3628
3628
  }
3629
3629
  }
3630
3630
  /**
@@ -5584,9 +5584,9 @@ var require_cst_visit = __commonJS({
5584
5584
  visit.BREAK = BREAK;
5585
5585
  visit.SKIP = SKIP;
5586
5586
  visit.REMOVE = REMOVE;
5587
- visit.itemAtPath = (cst, path18) => {
5587
+ visit.itemAtPath = (cst, path22) => {
5588
5588
  let item = cst;
5589
- for (const [field2, index] of path18) {
5589
+ for (const [field2, index] of path22) {
5590
5590
  const tok = item?.[field2];
5591
5591
  if (tok && "items" in tok) {
5592
5592
  item = tok.items[index];
@@ -5595,23 +5595,23 @@ var require_cst_visit = __commonJS({
5595
5595
  }
5596
5596
  return item;
5597
5597
  };
5598
- visit.parentCollection = (cst, path18) => {
5599
- const parent = visit.itemAtPath(cst, path18.slice(0, -1));
5600
- const field2 = path18[path18.length - 1][0];
5598
+ visit.parentCollection = (cst, path22) => {
5599
+ const parent = visit.itemAtPath(cst, path22.slice(0, -1));
5600
+ const field2 = path22[path22.length - 1][0];
5601
5601
  const coll = parent?.[field2];
5602
5602
  if (coll && "items" in coll)
5603
5603
  return coll;
5604
5604
  throw new Error("Parent collection not found");
5605
5605
  };
5606
- function _visit(path18, item, visitor) {
5607
- let ctrl = visitor(item, path18);
5606
+ function _visit(path22, item, visitor) {
5607
+ let ctrl = visitor(item, path22);
5608
5608
  if (typeof ctrl === "symbol")
5609
5609
  return ctrl;
5610
5610
  for (const field2 of ["key", "value"]) {
5611
5611
  const token = item[field2];
5612
5612
  if (token && "items" in token) {
5613
5613
  for (let i = 0; i < token.items.length; ++i) {
5614
- const ci = _visit(Object.freeze(path18.concat([[field2, i]])), token.items[i], visitor);
5614
+ const ci = _visit(Object.freeze(path22.concat([[field2, i]])), token.items[i], visitor);
5615
5615
  if (typeof ci === "number")
5616
5616
  i = ci - 1;
5617
5617
  else if (ci === BREAK)
@@ -5622,10 +5622,10 @@ var require_cst_visit = __commonJS({
5622
5622
  }
5623
5623
  }
5624
5624
  if (typeof ctrl === "function" && field2 === "key")
5625
- ctrl = ctrl(item, path18);
5625
+ ctrl = ctrl(item, path22);
5626
5626
  }
5627
5627
  }
5628
- return typeof ctrl === "function" ? ctrl(item, path18) : ctrl;
5628
+ return typeof ctrl === "function" ? ctrl(item, path22) : ctrl;
5629
5629
  }
5630
5630
  exports.visit = visit;
5631
5631
  }
@@ -6927,14 +6927,14 @@ var require_parser = __commonJS({
6927
6927
  case "scalar":
6928
6928
  case "single-quoted-scalar":
6929
6929
  case "double-quoted-scalar": {
6930
- const fs17 = this.flowScalar(this.type);
6930
+ const fs21 = this.flowScalar(this.type);
6931
6931
  if (atNextItem || it.value) {
6932
- map.items.push({ start, key: fs17, sep: [] });
6932
+ map.items.push({ start, key: fs21, sep: [] });
6933
6933
  this.onKeyLine = true;
6934
6934
  } else if (it.sep) {
6935
- this.stack.push(fs17);
6935
+ this.stack.push(fs21);
6936
6936
  } else {
6937
- Object.assign(it, { key: fs17, sep: [] });
6937
+ Object.assign(it, { key: fs21, sep: [] });
6938
6938
  this.onKeyLine = true;
6939
6939
  }
6940
6940
  return;
@@ -7062,13 +7062,13 @@ var require_parser = __commonJS({
7062
7062
  case "scalar":
7063
7063
  case "single-quoted-scalar":
7064
7064
  case "double-quoted-scalar": {
7065
- const fs17 = this.flowScalar(this.type);
7065
+ const fs21 = this.flowScalar(this.type);
7066
7066
  if (!it || it.value)
7067
- fc.items.push({ start: [], key: fs17, sep: [] });
7067
+ fc.items.push({ start: [], key: fs21, sep: [] });
7068
7068
  else if (it.sep)
7069
- this.stack.push(fs17);
7069
+ this.stack.push(fs21);
7070
7070
  else
7071
- Object.assign(it, { key: fs17, sep: [] });
7071
+ Object.assign(it, { key: fs21, sep: [] });
7072
7072
  return;
7073
7073
  }
7074
7074
  case "flow-map-end":
@@ -7257,7 +7257,7 @@ var require_public_api = __commonJS({
7257
7257
  return docs;
7258
7258
  return Object.assign([], { empty: true }, composer$1.streamInfo());
7259
7259
  }
7260
- function parseDocument6(source, options = {}) {
7260
+ function parseDocument7(source, options = {}) {
7261
7261
  const { lineCounter: lineCounter2, prettyErrors } = parseOptions(options);
7262
7262
  const parser$1 = new parser.Parser(lineCounter2?.addNewLine);
7263
7263
  const composer$1 = new composer.Composer(options);
@@ -7283,7 +7283,7 @@ var require_public_api = __commonJS({
7283
7283
  } else if (options === void 0 && reviver && typeof reviver === "object") {
7284
7284
  options = reviver;
7285
7285
  }
7286
- const doc = parseDocument6(src, options);
7286
+ const doc = parseDocument7(src, options);
7287
7287
  if (!doc)
7288
7288
  return null;
7289
7289
  doc.warnings.forEach((warning) => log.warn(doc.options.logLevel, warning));
@@ -7319,7 +7319,7 @@ var require_public_api = __commonJS({
7319
7319
  }
7320
7320
  exports.parse = parse2;
7321
7321
  exports.parseAllDocuments = parseAllDocuments;
7322
- exports.parseDocument = parseDocument6;
7322
+ exports.parseDocument = parseDocument7;
7323
7323
  exports.stringify = stringify;
7324
7324
  }
7325
7325
  });
@@ -7573,6 +7573,10 @@ Valid format: lowercase kebab-case (a-z, 0-9, single hyphens)`;
7573
7573
  if (name.includes("..")) return "Change name cannot contain '..' (path traversal not allowed)";
7574
7574
  return null;
7575
7575
  }
7576
+ function assertOpenSpecChangeName(name) {
7577
+ const error = openSpecChangeNameError(name);
7578
+ if (error) throw new Error(error);
7579
+ }
7576
7580
  async function resolveClassicChangeDirectory(name) {
7577
7581
  const active = `openspec/changes/${name}`;
7578
7582
  if (await exists(filesystemPath(active))) {
@@ -7622,26 +7626,26 @@ function projectRootFor(changeDir) {
7622
7626
  }
7623
7627
  throw new Error(`Classic change is not inside an openspec directory: ${changeDir}`);
7624
7628
  }
7625
- function relativeSource(projectRoot, file) {
7626
- return path2.relative(projectRoot, file).split(path2.sep).join("/");
7629
+ function relativeSource(projectRoot2, file) {
7630
+ return path2.relative(projectRoot2, file).split(path2.sep).join("/");
7627
7631
  }
7628
- async function linkedFileEvidence(projectRoot, code, relativePath2) {
7632
+ async function linkedFileEvidence(projectRoot2, code, relativePath2) {
7629
7633
  if (!relativePath2) return { code, satisfied: false };
7630
- const file = path2.resolve(projectRoot, relativePath2);
7634
+ const file = path2.resolve(projectRoot2, relativePath2);
7631
7635
  return {
7632
7636
  code,
7633
7637
  satisfied: await fileExists(file),
7634
- source: relativeSource(projectRoot, file)
7638
+ source: relativeSource(projectRoot2, file)
7635
7639
  };
7636
7640
  }
7637
- async function directFileEvidence(projectRoot, code, file) {
7641
+ async function directFileEvidence(projectRoot2, code, file) {
7638
7642
  return {
7639
7643
  code,
7640
7644
  satisfied: await fileExists(file),
7641
- source: relativeSource(projectRoot, file)
7645
+ source: relativeSource(projectRoot2, file)
7642
7646
  };
7643
7647
  }
7644
- async function deltaSpecEvidence(projectRoot, changeDir) {
7648
+ async function deltaSpecEvidence(projectRoot2, changeDir) {
7645
7649
  const specsDir = path2.join(changeDir, "specs");
7646
7650
  let entries;
7647
7651
  try {
@@ -7657,11 +7661,11 @@ async function deltaSpecEvidence(projectRoot, changeDir) {
7657
7661
  return {
7658
7662
  code: "openspec.delta-spec",
7659
7663
  satisfied: existing.length > 0,
7660
- source: existing[0] ? relativeSource(projectRoot, existing[0]) : void 0,
7664
+ source: existing[0] ? relativeSource(projectRoot2, existing[0]) : void 0,
7661
7665
  detail: `${existing.length} delta spec${existing.length === 1 ? "" : "s"}`
7662
7666
  };
7663
7667
  }
7664
- async function taskEvidence(projectRoot, tasksFile) {
7668
+ async function taskEvidence(projectRoot2, tasksFile) {
7665
7669
  let source;
7666
7670
  try {
7667
7671
  source = await fs2.readFile(tasksFile, "utf8");
@@ -7676,7 +7680,7 @@ async function taskEvidence(projectRoot, tasksFile) {
7676
7680
  return {
7677
7681
  code: "build.tasks-complete",
7678
7682
  satisfied: tasks.length > 0 && complete === tasks.length,
7679
- source: relativeSource(projectRoot, tasksFile),
7683
+ source: relativeSource(projectRoot2, tasksFile),
7680
7684
  detail: `${complete} of ${tasks.length} tasks complete`
7681
7685
  };
7682
7686
  }
@@ -7684,29 +7688,33 @@ function evidenceSatisfied(evidence, code) {
7684
7688
  return evidence.some((item) => item.code === code && item.satisfied);
7685
7689
  }
7686
7690
  async function collectClassicEvidence(changeDir, projection) {
7687
- const projectRoot = projectRootFor(changeDir);
7691
+ const projectRoot2 = projectRootFor(changeDir);
7688
7692
  const classic = projection.classic;
7689
7693
  const proposal = path2.join(changeDir, "proposal.md");
7690
7694
  const design = path2.join(changeDir, "design.md");
7691
7695
  const tasks = path2.join(changeDir, "tasks.md");
7692
7696
  const checkpoint = projection.run ? path2.resolve(changeDir, projection.run.checkpointRef) : path2.join(changeDir, ".comet", "checkpoint.json");
7693
7697
  const evidence = await Promise.all([
7694
- directFileEvidence(projectRoot, "openspec.proposal", proposal),
7695
- directFileEvidence(projectRoot, "openspec.design", design),
7696
- directFileEvidence(projectRoot, "openspec.tasks", tasks),
7697
- deltaSpecEvidence(projectRoot, changeDir),
7698
- linkedFileEvidence(projectRoot, "design.document", classic?.designDoc ?? null),
7699
- linkedFileEvidence(projectRoot, "build.plan", classic?.plan ?? null),
7700
- taskEvidence(projectRoot, tasks),
7701
- linkedFileEvidence(projectRoot, "verification.report", classic?.verificationReport ?? null),
7702
- linkedFileEvidence(projectRoot, "design.handoff", classic?.handoffContext ?? null),
7703
- directFileEvidence(projectRoot, "run.checkpoint", checkpoint)
7698
+ directFileEvidence(projectRoot2, "openspec.proposal", proposal),
7699
+ directFileEvidence(projectRoot2, "openspec.design", design),
7700
+ directFileEvidence(projectRoot2, "openspec.tasks", tasks),
7701
+ deltaSpecEvidence(projectRoot2, changeDir),
7702
+ linkedFileEvidence(projectRoot2, "design.document", classic?.designDoc ?? null),
7703
+ linkedFileEvidence(projectRoot2, "build.plan", classic?.plan ?? null),
7704
+ taskEvidence(projectRoot2, tasks),
7705
+ linkedFileEvidence(projectRoot2, "verification.report", classic?.verificationReport ?? null),
7706
+ linkedFileEvidence(projectRoot2, "design.handoff", classic?.handoffContext ?? null),
7707
+ directFileEvidence(projectRoot2, "run.checkpoint", checkpoint)
7704
7708
  ]);
7705
7709
  const handoff = evidence.find((item) => item.code === "design.handoff");
7706
7710
  if (handoff && !classic?.handoffHash) {
7707
7711
  handoff.satisfied = false;
7708
7712
  handoff.detail = "handoff hash is missing";
7709
7713
  }
7714
+ evidence.push({
7715
+ code: "archive.confirmed",
7716
+ satisfied: classic?.archiveConfirmation === "confirmed"
7717
+ });
7710
7718
  return evidence;
7711
7719
  }
7712
7720
 
@@ -7731,7 +7739,7 @@ function fullBuildConfigured(classic) {
7731
7739
  }
7732
7740
  function presetBuildConfigured(classic) {
7733
7741
  return Boolean(
7734
- classic.buildMode === "direct" && classic.tddMode === "direct" && classic.isolation === "branch" && classic.verifyMode === "light"
7742
+ classic.buildMode === "direct" && classic.tddMode === "direct" && classic.isolation !== null && classic.verifyMode === "light"
7735
7743
  );
7736
7744
  }
7737
7745
  function resolveBuild(profile, classic, evidence) {
@@ -7753,11 +7761,11 @@ function resolveVerify(profile, classic, evidence) {
7753
7761
  }
7754
7762
  return `${profile}.verify.branch`;
7755
7763
  }
7756
- function resolveArchive(profile, classic, evidence) {
7764
+ function resolveArchive(profile, classic) {
7757
7765
  if (classic.verifyResult !== "pass") {
7758
7766
  throw new Error("archive requires verify_result=pass");
7759
7767
  }
7760
- return evidenceSatisfied(evidence, "archive.confirmed") ? `${profile}.archive.execute` : `${profile}.archive.confirm`;
7768
+ return classic.archiveConfirmation === "confirmed" ? `${profile}.archive.execute` : `${profile}.archive.confirm`;
7761
7769
  }
7762
7770
  function resolveClassicStepId(classic, evidence) {
7763
7771
  const profile = profileFor(classic);
@@ -7778,7 +7786,7 @@ function resolveClassicStepId(classic, evidence) {
7778
7786
  case "verify":
7779
7787
  return resolveVerify(profile, classic, evidence);
7780
7788
  case "archive":
7781
- return resolveArchive(profile, classic, evidence);
7789
+ return resolveArchive(profile, classic);
7782
7790
  }
7783
7791
  }
7784
7792
 
@@ -7800,10 +7808,11 @@ var BUILD_PAUSES = ["plan-ready"];
7800
7808
  var SUBAGENT_DISPATCH = ["confirmed"];
7801
7809
  var TDD_MODES = ["tdd", "direct"];
7802
7810
  var REVIEW_MODES = ["off", "standard", "thorough"];
7803
- var ISOLATIONS = ["branch", "worktree"];
7811
+ var ISOLATIONS = ["current", "branch", "worktree"];
7804
7812
  var VERIFY_MODES = ["light", "full"];
7805
7813
  var VERIFY_RESULTS = ["pending", "pass", "fail"];
7806
7814
  var BRANCH_STATUSES = ["pending", "handled"];
7815
+ var ARCHIVE_CONFIRMATIONS = ["pending", "confirmed"];
7807
7816
  var CLASSIC_WIRE_KEYS = [
7808
7817
  "workflow",
7809
7818
  "language",
@@ -7821,10 +7830,12 @@ var CLASSIC_WIRE_KEYS = [
7821
7830
  "design_doc",
7822
7831
  "plan",
7823
7832
  "verify_result",
7833
+ "verify_failures",
7824
7834
  "verification_report",
7825
7835
  "branch_status",
7826
7836
  "created_at",
7827
7837
  "verified_at",
7838
+ "archive_confirmation",
7828
7839
  "archived",
7829
7840
  "direct_override",
7830
7841
  "handoff_context",
@@ -7881,6 +7892,14 @@ function booleanValue(doc, key, nullable = true) {
7881
7892
  }
7882
7893
  return value;
7883
7894
  }
7895
+ function nonNegativeInteger(doc, key, fallback = 0) {
7896
+ const value = doc[key];
7897
+ if (value === null || value === void 0 || value === "") return fallback;
7898
+ if (typeof value !== "number" || !Number.isInteger(value) || value < 0) {
7899
+ throw new Error(`Invalid Classic state: ${key} must be a non-negative integer`);
7900
+ }
7901
+ return value;
7902
+ }
7884
7903
  function relativePath(doc, key) {
7885
7904
  const value = nullableString(doc, key);
7886
7905
  if (value === null) return null;
@@ -7929,10 +7948,12 @@ function classicStateFromDocument(doc) {
7929
7948
  designDoc: relativePath(doc, "design_doc"),
7930
7949
  plan: relativePath(doc, "plan"),
7931
7950
  verifyResult: enumValue(doc, "verify_result", VERIFY_RESULTS, false),
7951
+ verifyFailures: nonNegativeInteger(doc, "verify_failures"),
7932
7952
  verificationReport: relativePath(doc, "verification_report"),
7933
7953
  branchStatus: enumValue(doc, "branch_status", BRANCH_STATUSES),
7934
7954
  createdAt: nullableString(doc, "created_at"),
7935
7955
  verifiedAt: nullableString(doc, "verified_at"),
7956
+ archiveConfirmation: enumValue(doc, "archive_confirmation", ARCHIVE_CONFIRMATIONS),
7936
7957
  archived: booleanValue(doc, "archived", false),
7937
7958
  directOverride: booleanValue(doc, "direct_override"),
7938
7959
  handoffContext: relativePath(doc, "handoff_context"),
@@ -7992,10 +8013,12 @@ function classicStateToDocument(state) {
7992
8013
  design_doc: state.designDoc,
7993
8014
  plan: state.plan,
7994
8015
  verify_result: state.verifyResult,
8016
+ verify_failures: state.verifyFailures,
7995
8017
  verification_report: state.verificationReport,
7996
8018
  branch_status: state.branchStatus,
7997
8019
  created_at: state.createdAt,
7998
8020
  verified_at: state.verifiedAt,
8021
+ archive_confirmation: state.archiveConfirmation,
7999
8022
  archived: state.archived,
8000
8023
  direct_override: state.directOverride,
8001
8024
  handoff_context: state.handoffContext,
@@ -8077,7 +8100,8 @@ async function readDocument(file) {
8077
8100
  documentRecord(document);
8078
8101
  return document;
8079
8102
  }
8080
- async function readClassicState(changeDir) {
8103
+ async function readClassicState(changeDir, options = {}) {
8104
+ const shouldMigrate = options.migrate !== false;
8081
8105
  const file = path4.join(changeDir, ".comet.yaml");
8082
8106
  const document = await readDocument(file);
8083
8107
  let doc = documentRecord(document);
@@ -8087,13 +8111,13 @@ async function readClassicState(changeDir) {
8087
8111
  if (!run && doc.run_id && doc.skill) {
8088
8112
  const { runStateFromDocument: runStateFromDocument2 } = await Promise.resolve().then(() => (init_state(), state_exports));
8089
8113
  run = runStateFromDocument2(doc);
8090
- if (run) {
8114
+ if (run && shouldMigrate) {
8091
8115
  await writeRunState(changeDir, run);
8092
8116
  stripLegacyRunFields(document);
8093
8117
  migrated = true;
8094
8118
  }
8095
8119
  }
8096
- if (migrated) {
8120
+ if (migrated && shouldMigrate) {
8097
8121
  const temporary = path4.join(changeDir, `.comet.yaml.${randomUUID2()}.tmp`);
8098
8122
  await fs4.writeFile(temporary, document.toString(), "utf8");
8099
8123
  await fs4.rename(temporary, file);
@@ -8830,13 +8854,13 @@ function artifactKey(code) {
8830
8854
  return code.replaceAll(".", "_").replaceAll("-", "_");
8831
8855
  }
8832
8856
  async function migrationArtifacts(changeDir, evidence) {
8833
- const projectRoot = projectRootFor2(changeDir);
8857
+ const projectRoot2 = projectRootFor2(changeDir);
8834
8858
  const artifacts = Object.fromEntries(
8835
8859
  evidence.filter((item) => item.satisfied && item.source).map((item) => [artifactKey(item.code), item.source])
8836
8860
  );
8837
8861
  const progress = path9.join(changeDir, "subagent-progress.md");
8838
8862
  if (await pathExists2(progress)) {
8839
- artifacts.subagent_progress = path9.relative(projectRoot, progress).split(path9.sep).join("/");
8863
+ artifacts.subagent_progress = path9.relative(projectRoot2, progress).split(path9.sep).join("/");
8840
8864
  }
8841
8865
  const handoff = evidence.find((item) => item.code === "design.handoff" && item.satisfied);
8842
8866
  if (handoff?.source) artifacts.handoff_context = handoff.source;
@@ -8928,11 +8952,11 @@ async function ensureClassicRun(changeDir, options) {
8928
8952
  classicMigration: CLASSIC_MIGRATION_VERSION
8929
8953
  };
8930
8954
  const artifacts = await migrationArtifacts(changeDir, evidence);
8931
- const projectRoot = projectRootFor2(changeDir);
8955
+ const projectRoot2 = projectRootFor2(changeDir);
8932
8956
  const handoff = evidence.find((item) => item.code === "design.handoff" && item.satisfied);
8933
8957
  let context = null;
8934
8958
  if (handoff?.source) {
8935
- context = await fs8.readFile(path9.resolve(projectRoot, handoff.source), "utf8");
8959
+ context = await fs8.readFile(path9.resolve(projectRoot2, handoff.source), "utf8");
8936
8960
  await writeContext(changeDir, run.contextRef, context);
8937
8961
  createdFiles.push(path9.resolve(changeDir, run.contextRef));
8938
8962
  }
@@ -9251,6 +9275,46 @@ async function ensureStrictClassicRuntimeRun(changeDir) {
9251
9275
  }
9252
9276
  return ensureClassicRuntimeRun(changeDir);
9253
9277
  }
9278
+ async function validateClassicRuntimeRun(changeDir, existingProjection) {
9279
+ const projection = existingProjection ?? await readClassicState(changeDir, { migrate: false });
9280
+ const unknownKeys = Array.from(new Set(projection.unknownKeys)).sort();
9281
+ if (unknownKeys.length > 0) {
9282
+ throw new Error(`Invalid Classic state: unknown field(s): ${unknownKeys.join(", ")}`);
9283
+ }
9284
+ if (!projection.classic || !projection.run) {
9285
+ throw new Error("Classic runtime validation requires synchronized Classic and Run projections");
9286
+ }
9287
+ if (projection.classic.classicMigration !== CLASSIC_MIGRATION_VERSION) {
9288
+ throw new Error("Classic Run exists without a supported classic_migration marker");
9289
+ }
9290
+ const root = await classicRuntimeRoot();
9291
+ const skillPackage = root ? await loadClassicRuntimePackage(root) : embeddedClassicRuntimePackage(path10.dirname(fileURLToPath(import.meta.url)));
9292
+ if (projection.run.skill !== skillPackage.definition.metadata.name) {
9293
+ throw new Error(
9294
+ `Classic Run skill mismatch: expected ${skillPackage.definition.metadata.name}, got ${projection.run.skill}`
9295
+ );
9296
+ }
9297
+ const snapshot = await readSkillSnapshot(changeDir, projection.run.skillHash);
9298
+ if (snapshot.definition.metadata.name !== projection.run.skill) {
9299
+ throw new Error(
9300
+ `Classic Run snapshot skill mismatch: expected ${projection.run.skill}, got ${snapshot.definition.metadata.name}`
9301
+ );
9302
+ }
9303
+ const evidence = await collectClassicEvidence(changeDir, projection);
9304
+ const currentStep = resolveClassicStepId(projection.classic, evidence);
9305
+ if (projection.run.currentStep !== currentStep) {
9306
+ throw new Error(
9307
+ `Classic Run step mismatch: expected ${currentStep}, got ${projection.run.currentStep}`
9308
+ );
9309
+ }
9310
+ return {
9311
+ classic: projection.classic,
9312
+ run: projection.run,
9313
+ evidence,
9314
+ migrated: false,
9315
+ snapshotDir: path10.join(changeDir, ".comet", "skill-snapshots", projection.run.skillHash)
9316
+ };
9317
+ }
9254
9318
  async function transitionClassicRuntimeRun(changeDir, classic, run, data) {
9255
9319
  const projection = await readClassicState(changeDir);
9256
9320
  if (!projection.classic || !projection.run) {
@@ -9313,6 +9377,7 @@ var CLASSIC_TRANSITION_EVENTS = [
9313
9377
  "build-complete",
9314
9378
  "verify-pass",
9315
9379
  "verify-fail",
9380
+ "archive-confirm",
9316
9381
  "archive-reopen",
9317
9382
  "archived",
9318
9383
  "preset-escalate"
@@ -9336,13 +9401,18 @@ var CLASSIC_TRANSITION_TABLE = {
9336
9401
  "verify-pass": {
9337
9402
  event: "verify-pass",
9338
9403
  from: "verify",
9339
- guardRefs: ["verification-report-present", "branch-status-handled"]
9404
+ guardRefs: ["verification-report-present"]
9340
9405
  },
9341
9406
  "verify-fail": {
9342
9407
  event: "verify-fail",
9343
9408
  from: "verify",
9344
9409
  guardRefs: ["verification-failed"]
9345
9410
  },
9411
+ "archive-confirm": {
9412
+ event: "archive-confirm",
9413
+ from: "archive",
9414
+ guardRefs: ["archive-final-confirmation"]
9415
+ },
9346
9416
  "archive-reopen": {
9347
9417
  event: "archive-reopen",
9348
9418
  from: "archive",
@@ -9351,7 +9421,7 @@ var CLASSIC_TRANSITION_TABLE = {
9351
9421
  archived: {
9352
9422
  event: "archived",
9353
9423
  from: "archive",
9354
- guardRefs: ["verify-result-pass"]
9424
+ guardRefs: ["verify-result-pass", "archive-confirmed"]
9355
9425
  },
9356
9426
  "preset-escalate": {
9357
9427
  event: "preset-escalate",
@@ -9391,17 +9461,22 @@ function applyClassicTransition(current, event, options = {}) {
9391
9461
  const preserveEvidence = classic.verifyResult === "fail";
9392
9462
  setField(classic, effects, "phase", "verify");
9393
9463
  setField(classic, effects, "verifyResult", "pending");
9464
+ setField(classic, effects, "branchStatus", "pending");
9394
9465
  if (!preserveEvidence) {
9395
9466
  setField(classic, effects, "verificationReport", null);
9396
- setField(classic, effects, "branchStatus", "pending");
9397
9467
  }
9398
9468
  } else if (event === "verify-pass") {
9399
9469
  setField(classic, effects, "verifyResult", "pass");
9470
+ setField(classic, effects, "verifyFailures", 0);
9400
9471
  setField(classic, effects, "phase", "archive");
9401
9472
  setField(classic, effects, "verifiedAt", dateOnly(now));
9473
+ setField(classic, effects, "archiveConfirmation", "pending");
9474
+ setField(classic, effects, "branchStatus", "pending");
9402
9475
  } else if (event === "verify-fail") {
9403
9476
  setField(classic, effects, "verifyResult", "fail");
9477
+ setField(classic, effects, "verifyFailures", classic.verifyFailures + 1);
9404
9478
  setField(classic, effects, "phase", "build");
9479
+ setField(classic, effects, "branchStatus", "pending");
9405
9480
  } else if (event === "preset-escalate") {
9406
9481
  if (classic.workflow !== "hotfix" && classic.workflow !== "tweak") {
9407
9482
  throw new Error(
@@ -9412,15 +9487,35 @@ function applyClassicTransition(current, event, options = {}) {
9412
9487
  setField(classic, effects, "classicProfile", "full");
9413
9488
  setField(classic, effects, "phase", "design");
9414
9489
  setField(classic, effects, "designDoc", null);
9490
+ setField(classic, effects, "buildPause", null);
9491
+ setField(classic, effects, "buildMode", null);
9492
+ setField(classic, effects, "subagentDispatch", null);
9493
+ setField(classic, effects, "tddMode", null);
9494
+ setField(classic, effects, "reviewMode", null);
9495
+ setField(classic, effects, "isolation", null);
9496
+ setField(classic, effects, "verifyMode", null);
9497
+ setField(classic, effects, "directOverride", null);
9498
+ } else if (event === "archive-confirm") {
9499
+ if (classic.verifyResult !== "pass") {
9500
+ throw new Error(`Cannot apply ${event}: verifyResult must be pass`);
9501
+ }
9502
+ if (classic.archived) throw new Error(`Cannot apply ${event}: already archived`);
9503
+ setField(classic, effects, "archiveConfirmation", "confirmed");
9415
9504
  } else if (event === "archive-reopen") {
9416
9505
  if (classic.archived) throw new Error(`Cannot apply ${event}: already archived`);
9417
9506
  setField(classic, effects, "verifyResult", "pending");
9507
+ setField(classic, effects, "verifyFailures", 0);
9418
9508
  setField(classic, effects, "phase", "verify");
9419
9509
  setField(classic, effects, "verifiedAt", null);
9510
+ setField(classic, effects, "archiveConfirmation", null);
9511
+ setField(classic, effects, "branchStatus", "pending");
9420
9512
  } else {
9421
9513
  if (classic.verifyResult !== "pass") {
9422
9514
  throw new Error(`Cannot apply ${event}: verifyResult must be pass`);
9423
9515
  }
9516
+ if (classic.archiveConfirmation !== "confirmed") {
9517
+ throw new Error(`Cannot apply ${event}: archiveConfirmation must be confirmed`);
9518
+ }
9424
9519
  setField(classic, effects, "archived", true);
9425
9520
  }
9426
9521
  return { classic, effects, definition };
@@ -9483,6 +9578,33 @@ function artifactsHash(artifacts) {
9483
9578
  )
9484
9579
  );
9485
9580
  }
9581
+ function exactlyOneFinalNewline(markdown) {
9582
+ return `${markdown.replace(/\n+$/u, "")}
9583
+ `;
9584
+ }
9585
+ function annotatedMarkdown(original, archiveName, extraFields) {
9586
+ const normalized2 = original.replace(/\r\n/gu, "\n");
9587
+ const lines = normalized2.split("\n");
9588
+ const closingDelimiter = lines[0] === "---" ? lines.indexOf("---", 1) : -1;
9589
+ const extraFieldName = extraFields.match(/^([^:\n]+):/u)?.[1]?.trim();
9590
+ if (closingDelimiter !== -1) {
9591
+ const frontmatter = lines.slice(1, closingDelimiter).filter((line) => {
9592
+ const fieldName = line.match(/^([^:\n]+):/u)?.[1]?.trim();
9593
+ if (fieldName === void 0) return true;
9594
+ return fieldName !== "archived-with" && fieldName !== extraFieldName;
9595
+ });
9596
+ frontmatter.push(`archived-with: ${archiveName}`);
9597
+ if (extraFields) frontmatter.push(extraFields);
9598
+ return exactlyOneFinalNewline(
9599
+ ["---", ...frontmatter, "---", ...lines.slice(closingDelimiter + 1)].join("\n")
9600
+ );
9601
+ }
9602
+ const header = ["---", `archived-with: ${archiveName}`];
9603
+ if (extraFields) header.push(extraFields);
9604
+ if (extraFieldName !== "status") header.push("status: final");
9605
+ header.push("---");
9606
+ return exactlyOneFinalNewline([...header, normalized2].join("\n"));
9607
+ }
9486
9608
  async function findArchiveDir(change, preferred) {
9487
9609
  if (await exists2(preferred)) return preferred;
9488
9610
  const archiveRoot = "openspec/changes/archive";
@@ -9521,37 +9643,7 @@ async function annotateFrontmatter(output, file, archiveName, extraFields, dryRu
9521
9643
  return;
9522
9644
  }
9523
9645
  const original = await fs11.readFile(file, "utf8");
9524
- const firstLine = original.split(/\r?\n/u)[0] ?? "";
9525
- let updated;
9526
- if (firstLine === "---") {
9527
- const lines = original.split(/\r?\n/u);
9528
- const out = [];
9529
- let sawFirst = false;
9530
- for (const line of lines) {
9531
- if (/^archived-with:/u.test(line)) continue;
9532
- if (line === "---") {
9533
- if (!sawFirst) {
9534
- out.push(line);
9535
- sawFirst = true;
9536
- continue;
9537
- }
9538
- out.push(`archived-with: ${archiveName}`);
9539
- if (extraFields) out.push(extraFields);
9540
- out.push(line);
9541
- } else {
9542
- out.push(line);
9543
- }
9544
- }
9545
- updated = `${out.join("\n")}
9546
- `;
9547
- } else {
9548
- const header = ["---", `archived-with: ${archiveName}`];
9549
- if (extraFields) header.push(extraFields);
9550
- header.push("status: final", "---");
9551
- updated = `${header.join("\n")}
9552
- ${original}`;
9553
- if (!updated.endsWith("\n")) updated += "\n";
9554
- }
9646
+ const updated = annotatedMarkdown(original, archiveName, extraFields);
9555
9647
  await fs11.writeFile(file, updated);
9556
9648
  output.stderr.push(green(` [OK] Annotated: ${file}`));
9557
9649
  output.stepsOk += 1;
@@ -9636,6 +9728,13 @@ var classicArchiveCommand = async (args) => {
9636
9728
  if (runtime.run.pending && runtime.run.pending !== actionId) {
9637
9729
  throw new ArchiveFailure(red(`FATAL: another action is pending: ${runtime.run.pending}`));
9638
9730
  }
9731
+ if (!recovering && !classic.archived && classic.archiveConfirmation !== "confirmed") {
9732
+ throw new ArchiveFailure(
9733
+ red(
9734
+ `FATAL: archive_confirmation is '${classic.archiveConfirmation ?? "null"}', expected 'confirmed'. Run final archive confirmation first.`
9735
+ )
9736
+ );
9737
+ }
9639
9738
  if (!recovering) {
9640
9739
  const action = {
9641
9740
  id: actionId,
@@ -9707,7 +9806,10 @@ var classicArchiveCommand = async (args) => {
9707
9806
  archive_directory: archiveDir
9708
9807
  };
9709
9808
  await writeArtifacts(archiveDir, archivedProjection.run.artifactsRef, artifacts);
9710
- const archiveTransition = applyClassicTransition(archivedProjection.classic, "archived");
9809
+ const archiveTransition = applyClassicTransition(
9810
+ recovering && archivedProjection.classic.archiveConfirmation !== "confirmed" ? { ...archivedProjection.classic, archiveConfirmation: "confirmed" } : archivedProjection.classic,
9811
+ "archived"
9812
+ );
9711
9813
  const archivedClassic = archiveTransition.classic;
9712
9814
  let transitionedRun = archivedProjection.run;
9713
9815
  if (archivedProjection.run.currentStep !== "completed" || archivedProjection.run.status !== "completed") {
@@ -9805,11 +9907,98 @@ var classicArchiveCommand = async (args) => {
9805
9907
  };
9806
9908
 
9807
9909
  // domains/comet-classic/classic-guard.ts
9808
- var import_yaml4 = __toESM(require_dist(), 1);
9910
+ var import_yaml5 = __toESM(require_dist(), 1);
9809
9911
  import { spawnSync as spawnSync2 } from "child_process";
9810
9912
  import { createHash as createHash4 } from "crypto";
9811
- import { existsSync, promises as fs13, readFileSync } from "fs";
9812
- import path14 from "path";
9913
+ import { existsSync, promises as fs15, readFileSync } from "fs";
9914
+ import path16 from "path";
9915
+
9916
+ // domains/comet-classic/classic-command-checks.ts
9917
+ import path13 from "path";
9918
+ function validateScope(scope) {
9919
+ if (scope !== "build" && scope !== "verify") {
9920
+ throw new Error(`Invalid command check scope: '${String(scope)}'`);
9921
+ }
9922
+ }
9923
+ function projectRoot(changeDir) {
9924
+ return path13.resolve(changeDir, "..", "..", "..");
9925
+ }
9926
+ function normalizedCwd(changeDir, cwd = ".") {
9927
+ if (cwd.trim().length === 0) throw new Error("Command check cwd cannot be blank");
9928
+ const root = projectRoot(changeDir);
9929
+ const target = path13.resolve(root, cwd);
9930
+ if (target !== root && !target.startsWith(root + path13.sep)) {
9931
+ throw new Error(`Command check cwd must resolve within the project root: '${cwd}'`);
9932
+ }
9933
+ return path13.relative(root, target).replaceAll("\\", "/") || ".";
9934
+ }
9935
+ function validRecord(changeDir, event) {
9936
+ if (event.type !== "command_check_recorded") return null;
9937
+ const data = event.data;
9938
+ if (typeof data !== "object" || data === null || Array.isArray(data)) return null;
9939
+ const { scope, command, exitCode, cwd } = data;
9940
+ if (scope !== "build" && scope !== "verify" || typeof command !== "string" || command.trim().length === 0 || !Number.isInteger(exitCode) || typeof cwd !== "string") {
9941
+ return null;
9942
+ }
9943
+ let normalized2;
9944
+ try {
9945
+ normalized2 = normalizedCwd(changeDir, cwd);
9946
+ } catch {
9947
+ return null;
9948
+ }
9949
+ return {
9950
+ sequence: event.sequence,
9951
+ timestamp: event.timestamp,
9952
+ runId: event.runId,
9953
+ scope,
9954
+ command,
9955
+ exitCode,
9956
+ cwd: normalized2
9957
+ };
9958
+ }
9959
+ async function recordCommandCheck(changeDir, run, input) {
9960
+ validateScope(input.scope);
9961
+ if (typeof input.command !== "string" || input.command.trim().length === 0) {
9962
+ throw new Error("Command check command cannot be blank");
9963
+ }
9964
+ if (!Number.isInteger(input.exitCode)) {
9965
+ throw new Error("Command check exitCode must be an integer");
9966
+ }
9967
+ const trajectory = await readTrajectory(changeDir, run.trajectoryRef);
9968
+ const recorded = {
9969
+ sequence: trajectory.reduce((maximum, event) => Math.max(maximum, event.sequence), 0) + 1,
9970
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
9971
+ runId: run.runId,
9972
+ scope: input.scope,
9973
+ command: input.command,
9974
+ exitCode: input.exitCode,
9975
+ cwd: normalizedCwd(changeDir, input.cwd)
9976
+ };
9977
+ await appendTrajectory(changeDir, run.trajectoryRef, {
9978
+ sequence: recorded.sequence,
9979
+ timestamp: recorded.timestamp,
9980
+ type: "command_check_recorded",
9981
+ runId: recorded.runId,
9982
+ data: {
9983
+ scope: recorded.scope,
9984
+ command: recorded.command,
9985
+ exitCode: recorded.exitCode,
9986
+ cwd: recorded.cwd
9987
+ }
9988
+ });
9989
+ return recorded;
9990
+ }
9991
+ async function latestCommandCheck(changeDir, run, scope) {
9992
+ validateScope(scope);
9993
+ const trajectory = await readTrajectory(changeDir, run.trajectoryRef);
9994
+ for (let index = trajectory.length - 1; index >= 0; index -= 1) {
9995
+ const event = trajectory[index];
9996
+ if (event.runId !== run.runId) continue;
9997
+ const record = validRecord(changeDir, event);
9998
+ if (record?.scope === scope) return record;
9999
+ }
10000
+ return null;
10001
+ }
9813
10002
 
9814
10003
  // domains/comet-classic/classic-runtime-evals.ts
9815
10004
  var STEP_EVIDENCE = {
@@ -9904,7 +10093,7 @@ async function inspectClassicChange(changeDir, name) {
9904
10093
  // domains/comet-classic/classic-validate-command.ts
9905
10094
  var import_yaml3 = __toESM(require_dist(), 1);
9906
10095
  import { promises as fs12 } from "fs";
9907
- import path13 from "path";
10096
+ import path14 from "path";
9908
10097
  var GREEN2 = "\x1B[32m";
9909
10098
  var RED2 = "\x1B[31m";
9910
10099
  var YELLOW2 = "\x1B[33m";
@@ -9931,11 +10120,12 @@ var ENUMS = {
9931
10120
  subagent_dispatch: ["confirmed"],
9932
10121
  tdd_mode: ["tdd", "direct"],
9933
10122
  review_mode: ["off", "standard", "thorough"],
9934
- isolation: ["branch", "worktree"],
10123
+ isolation: ["current", "branch", "worktree"],
9935
10124
  verify_mode: ["light", "full"],
9936
10125
  auto_transition: ["true", "false"],
9937
10126
  verify_result: ["pending", "pass", "fail"],
9938
10127
  branch_status: ["pending", "handled"],
10128
+ archive_confirmation: ["pending", "confirmed"],
9939
10129
  archived: ["true", "false"],
9940
10130
  direct_override: ["true", "false"],
9941
10131
  classic_profile: ["full", "hotfix", "tweak"],
@@ -9974,7 +10164,7 @@ var classicValidateCommand = async (args) => {
9974
10164
  };
9975
10165
  }
9976
10166
  const { directory, label } = await resolveClassicChangeDirectory(name);
9977
- const yamlFile = path13.join(directory, ".comet.yaml");
10167
+ const yamlFile = path14.join(directory, ".comet.yaml");
9978
10168
  const lines = [`[VALIDATE] ${label}/.comet.yaml`];
9979
10169
  let errors = 0;
9980
10170
  let warnings = 0;
@@ -10023,9 +10213,15 @@ var classicValidateCommand = async (args) => {
10023
10213
  fail3(`${field2}='${value}' is not valid. Expected: ${values.join(" ")}`);
10024
10214
  }
10025
10215
  }
10216
+ if (Object.prototype.hasOwnProperty.call(record, "verify_failures")) {
10217
+ const value = record.verify_failures;
10218
+ if (typeof value !== "number" || !Number.isInteger(value) || value < 0) {
10219
+ fail3(`verify_failures='${text(value)}' is not a non-negative integer`);
10220
+ }
10221
+ }
10026
10222
  for (const field2 of ["design_doc", "plan", "handoff_context"]) {
10027
10223
  const value = text(record[field2]);
10028
- if (value && !await exists3(path13.resolve(value))) {
10224
+ if (value && !await exists3(path14.resolve(value))) {
10029
10225
  fail3(`${field2}='${value}' does not exist on disk`);
10030
10226
  }
10031
10227
  }
@@ -10047,6 +10243,66 @@ var classicValidateCommand = async (args) => {
10047
10243
  return { exitCode: 0, stderr: lines.join("\n") };
10048
10244
  };
10049
10245
 
10246
+ // domains/comet-classic/classic-project-config.ts
10247
+ var import_yaml4 = __toESM(require_dist(), 1);
10248
+ import os from "os";
10249
+ import { promises as fs14 } from "fs";
10250
+ import path15 from "path";
10251
+
10252
+ // platform/fs/file-system.ts
10253
+ import { promises as fs13 } from "fs";
10254
+ async function fileExists3(filePath) {
10255
+ try {
10256
+ await fs13.access(filePath);
10257
+ return true;
10258
+ } catch (error) {
10259
+ if (isNotFoundError(error)) return false;
10260
+ throw error;
10261
+ }
10262
+ }
10263
+ async function readDir(dirPath) {
10264
+ try {
10265
+ return await fs13.readdir(dirPath);
10266
+ } catch (error) {
10267
+ const code = error?.code;
10268
+ if (code === "ENOENT" || code === "ENOTDIR") {
10269
+ return [];
10270
+ }
10271
+ throw error;
10272
+ }
10273
+ }
10274
+ function isNotFoundError(error) {
10275
+ return error?.code === "ENOENT";
10276
+ }
10277
+
10278
+ // domains/comet-classic/classic-project-config.ts
10279
+ function configCandidates(options = {}) {
10280
+ const cwd = options.cwd ?? process.cwd();
10281
+ const homeDir = options.homeDir ?? os.homedir();
10282
+ const candidates = [
10283
+ { file: path15.resolve(cwd, ".comet", "config.yaml"), source: ".comet/config.yaml" },
10284
+ {
10285
+ file: path15.resolve(homeDir, ".comet", "config.yaml"),
10286
+ source: "~/.comet/config.yaml"
10287
+ }
10288
+ ];
10289
+ return candidates.filter(
10290
+ (candidate, index) => candidates.findIndex((entry2) => entry2.file === candidate.file) === index
10291
+ );
10292
+ }
10293
+ async function readClassicConfigValue(field2, options = {}) {
10294
+ for (const candidate of configCandidates(options)) {
10295
+ if (!await fileExists3(candidate.file)) continue;
10296
+ const document = (0, import_yaml4.parseDocument)(await fs14.readFile(candidate.file, "utf8"), {
10297
+ uniqueKeys: false
10298
+ });
10299
+ const value = document.get(field2);
10300
+ if (value === null || value === void 0) continue;
10301
+ return { value: String(value), source: candidate.source };
10302
+ }
10303
+ return null;
10304
+ }
10305
+
10050
10306
  // domains/comet-classic/classic-guard.ts
10051
10307
  var GREEN3 = "\x1B[32m";
10052
10308
  var RED3 = "\x1B[31m";
@@ -10111,7 +10367,7 @@ var GuardOutput = class {
10111
10367
  };
10112
10368
  async function exists4(file) {
10113
10369
  try {
10114
- await fs13.access(file);
10370
+ await fs15.access(file);
10115
10371
  return true;
10116
10372
  } catch (error) {
10117
10373
  if (error.code === "ENOENT") return false;
@@ -10120,7 +10376,7 @@ async function exists4(file) {
10120
10376
  }
10121
10377
  async function nonempty(file) {
10122
10378
  try {
10123
- return (await fs13.stat(file)).size > 0;
10379
+ return (await fs15.stat(file)).size > 0;
10124
10380
  } catch (error) {
10125
10381
  if (error.code === "ENOENT") return false;
10126
10382
  throw error;
@@ -10133,32 +10389,9 @@ function validateChangeName2(name) {
10133
10389
  async function resolveChangeDir(name) {
10134
10390
  return (await resolveClassicChangeDirectory(name)).label;
10135
10391
  }
10136
- function stripInlineComment(value) {
10137
- let out = "";
10138
- let quote = "";
10139
- for (let i = 0; i < value.length; i += 1) {
10140
- const c = value[i];
10141
- if (quote === "") {
10142
- if (c === '"' || c === "'") {
10143
- quote = c;
10144
- } else if (c === "#" && (i === 0 || /\s/u.test(value[i - 1]))) {
10145
- return out.replace(/\s+$/u, "");
10146
- }
10147
- } else if (c === quote) {
10148
- quote = "";
10149
- }
10150
- out += c;
10151
- }
10152
- return out;
10153
- }
10154
- function stripWrappingQuotes(value) {
10155
- if (value.length >= 2 && value.startsWith('"') && value.endsWith('"')) return value.slice(1, -1);
10156
- if (value.length >= 2 && value.startsWith("'") && value.endsWith("'")) return value.slice(1, -1);
10157
- return value;
10158
- }
10159
10392
  async function readField(changeDir, field2) {
10160
- const file = path14.join(changeDir, ".comet.yaml");
10161
- const document = (0, import_yaml4.parseDocument)(await fs13.readFile(file, "utf8"), { uniqueKeys: false });
10393
+ const file = path16.join(changeDir, ".comet.yaml");
10394
+ const document = (0, import_yaml5.parseDocument)(await fs15.readFile(file, "utf8"), { uniqueKeys: false });
10162
10395
  if (document.errors.length > 0) {
10163
10396
  throw new GuardFailure(`ERROR: Invalid .comet.yaml: ${document.errors[0].message}`);
10164
10397
  }
@@ -10171,18 +10404,7 @@ async function readField(changeDir, field2) {
10171
10404
  async function projectConfigValue(field2, changeDir) {
10172
10405
  const changeValue = await readField(changeDir, field2);
10173
10406
  if (changeValue && changeValue !== "null") return changeValue;
10174
- for (const config of [".comet/config.yaml"]) {
10175
- if (!await exists4(config)) continue;
10176
- for (const line of (await fs13.readFile(config, "utf8")).split(/\r?\n/u)) {
10177
- if (new RegExp(`^${field2}:`, "u").test(line)) {
10178
- const value = stripWrappingQuotes(
10179
- stripInlineComment(line.replace(new RegExp(`^${field2}:\\s*`, "u"), ""))
10180
- );
10181
- if (value && value !== "null") return value;
10182
- }
10183
- }
10184
- }
10185
- return "";
10407
+ return (await readClassicConfigValue(field2))?.value ?? "";
10186
10408
  }
10187
10409
  async function configuredLanguage(changeDir) {
10188
10410
  const language = await projectConfigValue("language", changeDir);
@@ -10210,7 +10432,7 @@ function countEnglishWords(source) {
10210
10432
  }
10211
10433
  async function documentLanguageMatchesConfigured(changeDir, file) {
10212
10434
  const language = await configuredLanguage(changeDir);
10213
- const source = stripFencedCodeBlocks(await fs13.readFile(file, "utf8"));
10435
+ const source = stripFencedCodeBlocks(await fs15.readFile(file, "utf8"));
10214
10436
  const cjk = countCjkChars(source);
10215
10437
  const englishWords = countEnglishWords(source);
10216
10438
  if (language === "zh-CN" && cjk < 20 && englishWords >= 20) {
@@ -10234,7 +10456,7 @@ async function handoffSourceFiles(changeDir) {
10234
10456
  const files = [`${changeDir}/proposal.md`, `${changeDir}/design.md`, `${changeDir}/tasks.md`];
10235
10457
  const specs = `${changeDir}/specs`;
10236
10458
  if (await exists4(specs)) {
10237
- for (const entry2 of (await fs13.readdir(specs)).sort()) {
10459
+ for (const entry2 of (await fs15.readdir(specs)).sort()) {
10238
10460
  const spec = `${specs}/${entry2}/spec.md`;
10239
10461
  if (await exists4(spec)) files.push(spec);
10240
10462
  }
@@ -10254,13 +10476,13 @@ async function preflight(changeDir, name) {
10254
10476
  if (!await exists4(changeDir)) {
10255
10477
  throw new GuardFailure(red2(`FATAL: change directory not found: ${changeDir}`));
10256
10478
  }
10257
- if (!await exists4(path14.join(changeDir, ".comet.yaml"))) {
10479
+ if (!await exists4(path16.join(changeDir, ".comet.yaml"))) {
10258
10480
  throw new GuardFailure(red2(`FATAL: .comet.yaml not found in ${changeDir}`));
10259
10481
  }
10260
- const result3 = await classicValidateCommand([name], { json: false });
10261
- if (result3.exitCode !== 0) {
10262
- if (result3.stderr)
10263
- process.stderr.write(result3.stderr.endsWith("\n") ? result3.stderr : `${result3.stderr}
10482
+ const result5 = await classicValidateCommand([name], { json: false });
10483
+ if (result5.exitCode !== 0) {
10484
+ if (result5.stderr)
10485
+ process.stderr.write(result5.stderr.endsWith("\n") ? result5.stderr : `${result5.stderr}
10264
10486
  `);
10265
10487
  throw new GuardFailure(red2("FATAL: .comet.yaml schema validation failed"));
10266
10488
  }
@@ -10275,6 +10497,9 @@ async function preflight(changeDir, name) {
10275
10497
  function pushCheck(output, outcome) {
10276
10498
  if (outcome.passed) {
10277
10499
  output.stderr.push(green2(` [PASS] ${outcome.description}`));
10500
+ if (outcome.detail) {
10501
+ for (const line of outcome.detail.split("\n")) output.stderr.push(green2(` ${line}`));
10502
+ }
10278
10503
  } else {
10279
10504
  output.stderr.push(red2(` [FAIL] ${outcome.description}`));
10280
10505
  if (outcome.detail) {
@@ -10285,11 +10510,11 @@ function pushCheck(output, outcome) {
10285
10510
  function check(description, run) {
10286
10511
  return async () => {
10287
10512
  try {
10288
- const result3 = await run();
10513
+ const result5 = await run();
10289
10514
  return {
10290
10515
  description,
10291
- passed: result3.passed,
10292
- detail: ("detail" in result3 ? result3.detail : "") ?? ""
10516
+ passed: result5.passed,
10517
+ detail: ("detail" in result5 ? result5.detail : "") ?? ""
10293
10518
  };
10294
10519
  } catch (error) {
10295
10520
  return {
@@ -10300,8 +10525,8 @@ function check(description, run) {
10300
10525
  }
10301
10526
  };
10302
10527
  }
10303
- function pass() {
10304
- return { passed: true };
10528
+ function pass(detail) {
10529
+ return { passed: true, ...detail ? { detail } : {} };
10305
10530
  }
10306
10531
  function fail(detail) {
10307
10532
  return { passed: false, detail };
@@ -10315,10 +10540,15 @@ async function runChecks(output, builders) {
10315
10540
  }
10316
10541
  return blocked2;
10317
10542
  }
10543
+ var INFERRED_COMMAND_SOURCES = [
10544
+ "package.json with a build script",
10545
+ "pom.xml",
10546
+ "Cargo.toml"
10547
+ ];
10318
10548
  async function removedProjectCommandField(field2) {
10319
- const config = path14.join(".comet", "config.yaml");
10549
+ const config = path16.join(".comet", "config.yaml");
10320
10550
  if (!await exists4(config)) return false;
10321
- const document = (0, import_yaml4.parseDocument)(await fs13.readFile(config, "utf8"));
10551
+ const document = (0, import_yaml5.parseDocument)(await fs15.readFile(config, "utf8"));
10322
10552
  if (document.errors.length > 0) {
10323
10553
  throw new Error(
10324
10554
  `.comet/config.yaml is invalid YAML (${document.errors[0].message}); cannot check for removed "${field2}" field. Fix the config and retry.`
@@ -10334,47 +10564,79 @@ function removedProjectCommandRun(field2) {
10334
10564
  };
10335
10565
  }
10336
10566
  function runInferred(command) {
10337
- const result3 = spawnSync2(command, { shell: true, encoding: "utf8", timeout: 3e5 });
10567
+ const result5 = spawnSync2(command, { shell: true, encoding: "utf8", timeout: 3e5 });
10338
10568
  return {
10339
- status: result3.status ?? 1,
10340
- output: `${result3.stdout ?? ""}${result3.stderr ?? ""}`.replace(/\n+$/u, "")
10569
+ status: result5.status ?? 1,
10570
+ output: `${result5.stdout ?? ""}${result5.stderr ?? ""}`.replace(/\n+$/u, "")
10341
10571
  };
10342
10572
  }
10343
- async function buildPasses() {
10344
- if (process.env.COMET_SKIP_BUILD === "1") return { status: 0, output: "" };
10345
- if (await removedProjectCommandField("build_command")) {
10346
- return removedProjectCommandRun("build_command");
10347
- }
10348
- if (await exists4("package.json") && /"build"/u.test(await fs13.readFile("package.json", "utf8"))) {
10349
- return runInferred("npm run build");
10573
+ async function inferredBuildCommand() {
10574
+ if (await exists4("package.json") && (() => {
10575
+ const parsed = JSON.parse(readFileSync("package.json", "utf8"));
10576
+ return typeof parsed.scripts?.build === "string";
10577
+ })()) {
10578
+ return "npm run build";
10350
10579
  }
10351
10580
  if (await exists4("pom.xml")) {
10352
10581
  if (process.platform === "win32") {
10353
- if (existsSync("mvnw.cmd")) return runInferred("mvnw.cmd compile -q");
10354
- return runInferred("mvn.cmd compile -q");
10582
+ if (existsSync("mvnw.cmd")) return "mvnw.cmd compile -q";
10583
+ return "mvn.cmd compile -q";
10355
10584
  }
10356
- if (existsSync("mvnw")) return runInferred("./mvnw compile -q");
10357
- return runInferred("mvn compile -q");
10585
+ if (existsSync("mvnw")) return "./mvnw compile -q";
10586
+ return "mvn compile -q";
10358
10587
  }
10359
- if (await exists4("Cargo.toml")) return runInferred("cargo build");
10360
- return { status: 1, output: "" };
10588
+ if (await exists4("Cargo.toml")) return "cargo build";
10589
+ return null;
10590
+ }
10591
+ function evidenceDetail(record) {
10592
+ return `Evidence: recorded command-check at ${record.timestamp}; command: ${record.command}; cwd: ${record.cwd}`;
10593
+ }
10594
+ function recoveryCommand(change, scope, command) {
10595
+ return `comet state record-check ${change} ${scope} --command "${command}" --exit-code 0`;
10361
10596
  }
10362
- async function verificationCommandPasses() {
10363
- if (process.env.COMET_SKIP_BUILD === "1") return { status: 0, output: "" };
10364
- if (await removedProjectCommandField("verify_command")) {
10365
- return removedProjectCommandRun("verify_command");
10597
+ async function commandCheckPasses(changeDir, change, run, scope) {
10598
+ if (process.env.COMET_SKIP_BUILD === "1") {
10599
+ return { status: 0, output: "SKIPPED via COMET_SKIP_BUILD=1" };
10600
+ }
10601
+ const removedFields = scope === "build" ? ["build_command"] : ["verify_command", "build_command"];
10602
+ for (const removedField of removedFields) {
10603
+ if (await removedProjectCommandField(removedField)) {
10604
+ return removedProjectCommandRun(removedField);
10605
+ }
10606
+ }
10607
+ const inferred = scope === "build" ? await inferredBuildCommand() : null;
10608
+ if (inferred) return runInferred(inferred);
10609
+ const recorded = await latestCommandCheck(changeDir, run, scope);
10610
+ if (!recorded) {
10611
+ return {
10612
+ status: 1,
10613
+ output: scope === "build" ? `No inferred build command or recorded build check. Detection searched: ${INFERRED_COMMAND_SOURCES.join(", ")}.
10614
+ Next: run the required command, then record it with:
10615
+ ${recoveryCommand(change, scope, "<command>")}` : `No recorded verify check.
10616
+ Next: run the required verification command, then record it with:
10617
+ ${recoveryCommand(change, scope, "<command>")}`
10618
+ };
10619
+ }
10620
+ if (recorded.exitCode !== 0) {
10621
+ return {
10622
+ status: recorded.exitCode,
10623
+ output: `Latest recorded ${scope} check failed with exit code ${recorded.exitCode}.
10624
+ ${evidenceDetail(recorded)}
10625
+ Next: rerun the command successfully, then record it with:
10626
+ ${recoveryCommand(change, scope, recorded.command)}`
10627
+ };
10366
10628
  }
10367
- return buildPasses();
10629
+ return { status: 0, output: evidenceDetail(recorded) };
10368
10630
  }
10369
10631
  async function tasksAllDone(changeDir) {
10370
- const tasks = path14.join(changeDir, "tasks.md");
10632
+ const tasks = path16.join(changeDir, "tasks.md");
10371
10633
  if (!await exists4(tasks)) {
10372
10634
  return fail(
10373
10635
  `tasks.md is missing at ${tasks}
10374
10636
  Next: restore or create tasks.md for this change before leaving build.`
10375
10637
  );
10376
10638
  }
10377
- const source = await fs13.readFile(tasks, "utf8");
10639
+ const source = await fs15.readFile(tasks, "utf8");
10378
10640
  if (!/- \[x\]/u.test(source)) {
10379
10641
  return fail(
10380
10642
  "tasks.md has no completed tasks.\nNext: complete implementation tasks and mark them with '- [x]'."
@@ -10391,9 +10653,9 @@ Next: complete or explicitly remove unfinished tasks, then mark tasks.md with '-
10391
10653
  return pass();
10392
10654
  }
10393
10655
  async function tasksHasAny(changeDir) {
10394
- const tasks = path14.join(changeDir, "tasks.md");
10656
+ const tasks = path16.join(changeDir, "tasks.md");
10395
10657
  if (!await exists4(tasks)) return false;
10396
- return /- \[/u.test(await fs13.readFile(tasks, "utf8"));
10658
+ return /- \[/u.test(await fs15.readFile(tasks, "utf8"));
10397
10659
  }
10398
10660
  async function planTasksAllDone(changeDir) {
10399
10661
  const plan = await readField(changeDir, "plan");
@@ -10404,7 +10666,7 @@ async function planTasksAllDone(changeDir) {
10404
10666
  Next: restore the Superpowers plan file or update .comet.yaml plan before leaving build.`
10405
10667
  );
10406
10668
  }
10407
- const source = await fs13.readFile(plan, "utf8");
10669
+ const source = await fs15.readFile(plan, "utf8");
10408
10670
  const unfinished = source.split(/\r?\n/u).map((line, index) => ({ line, number: index + 1 })).filter((entry2) => /^\s*- \[ \]/u.test(entry2.line));
10409
10671
  if (unfinished.length > 0) {
10410
10672
  return fail(
@@ -10417,11 +10679,14 @@ Next: check off corresponding completed plan tasks, then commit the plan update.
10417
10679
  }
10418
10680
  async function isolationSelected(changeDir, change) {
10419
10681
  const isolation = await readField(changeDir, "isolation");
10682
+ const workflow = await readField(changeDir, "workflow");
10420
10683
  if (isolation === "branch" || isolation === "worktree") return pass();
10684
+ if (isolation === "current" && (workflow === "hotfix" || workflow === "tweak")) return pass();
10685
+ const allowedValues = workflow === "full" ? "<branch|worktree>" : "<current|branch|worktree>";
10421
10686
  return fail(
10422
- `isolation must be branch or worktree, got '${isolation || "null"}'
10423
- Next: ask the user to choose branch or worktree, create the chosen isolation, then run:
10424
- node "$COMET_STATE" set ${change} isolation <branch|worktree>`
10687
+ `isolation must be ${workflow === "full" ? "branch or worktree" : "current, branch, or worktree"}, got '${isolation || "null"}'
10688
+ Next: choose a valid workspace mode, prepare it when needed, then run:
10689
+ comet state set ${change} isolation ${allowedValues}`
10425
10690
  );
10426
10691
  }
10427
10692
  async function buildModeSelected(changeDir, change) {
@@ -10431,7 +10696,7 @@ async function buildModeSelected(changeDir, change) {
10431
10696
  return fail(
10432
10697
  `build_mode must be selected before leaving build, got '${buildMode || "null"}'
10433
10698
  Next: ask the user to choose an execution mode, then run:
10434
- node "$COMET_STATE" set ${change} build_mode <subagent-driven-development|executing-plans>`
10699
+ comet state set ${change} build_mode <subagent-driven-development|executing-plans>`
10435
10700
  );
10436
10701
  }
10437
10702
  async function buildModeAllowedForWorkflow(changeDir) {
@@ -10453,9 +10718,9 @@ async function subagentDispatchConfirmed(changeDir, change) {
10453
10718
  return fail(
10454
10719
  `subagent_dispatch must be confirmed before using build_mode=subagent-driven-development
10455
10720
  Next: confirm the current platform has a real background subagent/Task/multi-agent dispatcher, then run:
10456
- node "$COMET_STATE" set ${change} subagent_dispatch confirmed
10457
- Or ask the user to switch to executing-plans and run:
10458
- node "$COMET_STATE" set ${change} build_mode executing-plans`
10721
+ comet state set ${change} subagent_dispatch confirmed
10722
+ If dispatch is unavailable, return to /comet-build Step 2 with subagent-driven-development removed. When executing-plans is the only valid mode, run:
10723
+ comet state set ${change} build_mode executing-plans`
10459
10724
  );
10460
10725
  }
10461
10726
  async function tddModeSelected(changeDir, change) {
@@ -10466,7 +10731,7 @@ async function tddModeSelected(changeDir, change) {
10466
10731
  return fail(
10467
10732
  `tdd_mode must be tdd or direct for full workflow, got '${tddMode || "null"}'
10468
10733
  Next: ask the user to choose TDD enforcement level, then run:
10469
- node "$COMET_STATE" set ${change} tdd_mode <tdd|direct>`
10734
+ comet state set ${change} tdd_mode <tdd|direct>`
10470
10735
  );
10471
10736
  }
10472
10737
  async function reviewModeSelected(changeDir, change) {
@@ -10479,7 +10744,7 @@ async function reviewModeSelected(changeDir, change) {
10479
10744
  return fail(
10480
10745
  `review_mode must be off, standard, or thorough before leaving build, got '${reviewMode || "null"}'
10481
10746
  Next: ask the user to choose review strength, then run:
10482
- node "$COMET_STATE" set ${change} review_mode <off|standard|thorough>`
10747
+ comet state set ${change} review_mode <off|standard|thorough>`
10483
10748
  );
10484
10749
  }
10485
10750
  async function verificationReportExists(changeDir) {
@@ -10493,7 +10758,7 @@ async function archivedIsTrue(changeDir) {
10493
10758
  return await readField(changeDir, "archived") === "true";
10494
10759
  }
10495
10760
  async function designDocFrontmatterHas(designDoc, field2, expected) {
10496
- const source = (await fs13.readFile(designDoc, "utf8")).replace(/^\uFEFF/u, "");
10761
+ const source = (await fs15.readFile(designDoc, "utf8")).replace(/^\uFEFF/u, "");
10497
10762
  let inFrontmatter = false;
10498
10763
  for (const line of source.split(/\r?\n/u)) {
10499
10764
  if (!inFrontmatter) {
@@ -10510,7 +10775,7 @@ async function designDocRecorded(changeDir, change) {
10510
10775
  if (designDoc && designDoc !== "null" && existsSync(designDoc)) return pass();
10511
10776
  return fail(
10512
10777
  `design_doc must point to an existing Superpowers Design Doc for full workflow before leaving design.
10513
- Next: create the Design Doc and run: node "$COMET_STATE" set ${change} design_doc <path>`
10778
+ Next: create the Design Doc and run: comet state set ${change} design_doc <path>`
10514
10779
  );
10515
10780
  }
10516
10781
  async function designHandoffContextValid(changeDir, change) {
@@ -10525,13 +10790,13 @@ Next: run node "$COMET_HANDOFF" ${change} design --write before invoking Superpo
10525
10790
  if (!await nonempty(context)) {
10526
10791
  return fail(
10527
10792
  `handoff_context does not point to a non-empty file: ${context}
10528
- Next: regenerate the design handoff with comet-handoff.mjs.`
10793
+ Next: regenerate the design handoff with comet handoff ${change} design --write.`
10529
10794
  );
10530
10795
  }
10531
10796
  if (!/^[a-f0-9]{64}$/u.test(recordedHash)) {
10532
10797
  return fail(
10533
10798
  `handoff_hash is missing or invalid: ${recordedHash || "null"}
10534
- Next: regenerate the design handoff with comet-handoff.mjs.`
10799
+ Next: regenerate the design handoff with comet handoff ${change} design --write.`
10535
10800
  );
10536
10801
  }
10537
10802
  const actualHash = await computeHandoffHash(changeDir);
@@ -10540,14 +10805,14 @@ Next: regenerate the design handoff with comet-handoff.mjs.`
10540
10805
  `OpenSpec artifacts changed after handoff was generated.
10541
10806
  Expected handoff_hash: ${recordedHash}
10542
10807
  Actual handoff_hash: ${actualHash}
10543
- Next: rerun comet-handoff.mjs so Superpowers receives the current OpenSpec context.`
10808
+ Next: run comet handoff ${change} design --write so Superpowers receives the current OpenSpec context.`
10544
10809
  );
10545
10810
  }
10546
10811
  const markdown = `${context.replace(/\.json$/u, "")}.md`;
10547
10812
  if (!await nonempty(markdown)) {
10548
10813
  return fail(
10549
10814
  `design handoff markdown is missing or empty: ${markdown}
10550
- Next: regenerate the design handoff with comet-handoff.mjs.`
10815
+ Next: regenerate the design handoff with comet handoff ${change} design --write.`
10551
10816
  );
10552
10817
  }
10553
10818
  return pass();
@@ -10558,7 +10823,7 @@ async function designHandoffMarkdownTraceable(changeDir) {
10558
10823
  const markdown = `${context.replace(/\.json$/u, "")}.md`;
10559
10824
  if (!await nonempty(markdown))
10560
10825
  return fail(`design handoff markdown is missing or empty: ${markdown}`);
10561
- const source = await fs13.readFile(markdown, "utf8");
10826
+ const source = await fs15.readFile(markdown, "utf8");
10562
10827
  const problems = [];
10563
10828
  if (!/^Generated-by: comet-handoff\.sh$/mu.test(source)) {
10564
10829
  problems.push("handoff markdown is missing Generated-by marker");
@@ -10585,7 +10850,7 @@ async function betaSpecJsonStructurallyValid(changeDir) {
10585
10850
  const context = await readField(changeDir, "handoff_context");
10586
10851
  if (!context || context === "null") return fail("handoff_context is missing from .comet.yaml");
10587
10852
  if (!await nonempty(context)) return fail(`spec-context.json is missing or empty: ${context}`);
10588
- const source = await fs13.readFile(context, "utf8");
10853
+ const source = await fs15.readFile(context, "utf8");
10589
10854
  const problems = [];
10590
10855
  let parsed;
10591
10856
  try {
@@ -10622,19 +10887,19 @@ async function guardOpenChecks(output, changeDir) {
10622
10887
  const checks = [
10623
10888
  check(
10624
10889
  "proposal.md exists and non-empty",
10625
- async () => await nonempty(path14.join(changeDir, "proposal.md")) ? pass() : fail("")
10890
+ async () => await nonempty(path16.join(changeDir, "proposal.md")) ? pass() : fail("")
10626
10891
  ),
10627
10892
  check(
10628
10893
  "proposal.md matches configured language",
10629
- () => documentLanguageMatchesConfigured(changeDir, path14.join(changeDir, "proposal.md"))
10894
+ () => documentLanguageMatchesConfigured(changeDir, path16.join(changeDir, "proposal.md"))
10630
10895
  ),
10631
10896
  check(
10632
10897
  "tasks.md exists and non-empty",
10633
- async () => await nonempty(path14.join(changeDir, "tasks.md")) ? pass() : fail("")
10898
+ async () => await nonempty(path16.join(changeDir, "tasks.md")) ? pass() : fail("")
10634
10899
  ),
10635
10900
  check(
10636
10901
  "tasks.md matches configured language",
10637
- () => documentLanguageMatchesConfigured(changeDir, path14.join(changeDir, "tasks.md"))
10902
+ () => documentLanguageMatchesConfigured(changeDir, path16.join(changeDir, "tasks.md"))
10638
10903
  ),
10639
10904
  check(
10640
10905
  "tasks.md has at least one task",
@@ -10647,11 +10912,11 @@ async function guardOpenChecks(output, changeDir) {
10647
10912
  0,
10648
10913
  check(
10649
10914
  "design.md exists and non-empty",
10650
- async () => await nonempty(path14.join(changeDir, "design.md")) ? pass() : fail("")
10915
+ async () => await nonempty(path16.join(changeDir, "design.md")) ? pass() : fail("")
10651
10916
  ),
10652
10917
  check(
10653
10918
  "design.md matches configured language",
10654
- () => documentLanguageMatchesConfigured(changeDir, path14.join(changeDir, "design.md"))
10919
+ () => documentLanguageMatchesConfigured(changeDir, path16.join(changeDir, "design.md"))
10655
10920
  )
10656
10921
  );
10657
10922
  }
@@ -10663,27 +10928,27 @@ async function guardDesignChecks(output, changeDir, change) {
10663
10928
  const builders = [
10664
10929
  check(
10665
10930
  "proposal.md exists",
10666
- async () => await nonempty(path14.join(changeDir, "proposal.md")) ? pass() : fail("")
10931
+ async () => await nonempty(path16.join(changeDir, "proposal.md")) ? pass() : fail("")
10667
10932
  ),
10668
10933
  check(
10669
10934
  "proposal.md matches configured language",
10670
- () => documentLanguageMatchesConfigured(changeDir, path14.join(changeDir, "proposal.md"))
10935
+ () => documentLanguageMatchesConfigured(changeDir, path16.join(changeDir, "proposal.md"))
10671
10936
  ),
10672
10937
  check(
10673
10938
  "design.md exists",
10674
- async () => await nonempty(path14.join(changeDir, "design.md")) ? pass() : fail("")
10939
+ async () => await nonempty(path16.join(changeDir, "design.md")) ? pass() : fail("")
10675
10940
  ),
10676
10941
  check(
10677
10942
  "design.md matches configured language",
10678
- () => documentLanguageMatchesConfigured(changeDir, path14.join(changeDir, "design.md"))
10943
+ () => documentLanguageMatchesConfigured(changeDir, path16.join(changeDir, "design.md"))
10679
10944
  ),
10680
10945
  check(
10681
10946
  "tasks.md exists",
10682
- async () => await nonempty(path14.join(changeDir, "tasks.md")) ? pass() : fail("")
10947
+ async () => await nonempty(path16.join(changeDir, "tasks.md")) ? pass() : fail("")
10683
10948
  ),
10684
10949
  check(
10685
10950
  "tasks.md matches configured language",
10686
- () => documentLanguageMatchesConfigured(changeDir, path14.join(changeDir, "tasks.md"))
10951
+ () => documentLanguageMatchesConfigured(changeDir, path16.join(changeDir, "tasks.md"))
10687
10952
  ),
10688
10953
  check("design handoff context exists", () => designHandoffContextValid(changeDir, change)),
10689
10954
  check("design handoff markdown is traceable", () => designHandoffMarkdownTraceable(changeDir))
@@ -10732,7 +10997,7 @@ async function guardDesignChecks(output, changeDir, change) {
10732
10997
  }
10733
10998
  return blocked2;
10734
10999
  }
10735
- async function guardBuildChecks(output, changeDir, change) {
11000
+ async function guardBuildChecks(output, changeDir, change, run) {
10736
11001
  return runChecks(output, [
10737
11002
  check("isolation selected", () => isolationSelected(changeDir, change)),
10738
11003
  check("build_mode selected", () => buildModeSelected(changeDir, change)),
@@ -10744,11 +11009,11 @@ async function guardBuildChecks(output, changeDir, change) {
10744
11009
  check("Superpowers plan all tasks checked", () => planTasksAllDone(changeDir)),
10745
11010
  check(
10746
11011
  "proposal.md exists",
10747
- async () => await nonempty(path14.join(changeDir, "proposal.md")) ? pass() : fail("")
11012
+ async () => await nonempty(path16.join(changeDir, "proposal.md")) ? pass() : fail("")
10748
11013
  ),
10749
11014
  check(
10750
11015
  "proposal.md matches configured language",
10751
- () => documentLanguageMatchesConfigured(changeDir, path14.join(changeDir, "proposal.md"))
11016
+ () => documentLanguageMatchesConfigured(changeDir, path16.join(changeDir, "proposal.md"))
10752
11017
  ),
10753
11018
  check("Superpowers plan matches configured language", async () => {
10754
11019
  const plan = await readField(changeDir, "plan");
@@ -10758,19 +11023,19 @@ async function guardBuildChecks(output, changeDir, change) {
10758
11023
  // Build check runs last — only after all config checks pass — to avoid
10759
11024
  // wasting time on a build that would be rejected by a config failure.
10760
11025
  check("Build passes", async () => {
10761
- const buildResult = await buildPasses();
10762
- return buildResult.status === 0 ? pass() : fail(buildResult.output);
11026
+ const buildResult = await commandCheckPasses(changeDir, change, run, "build");
11027
+ return buildResult.status === 0 ? pass(buildResult.output) : fail(buildResult.output);
10763
11028
  })
10764
11029
  ]);
10765
11030
  }
10766
- async function guardVerifyChecks(output, changeDir) {
11031
+ async function guardVerifyChecks(output, changeDir, change, run) {
10767
11032
  return runChecks(output, [
10768
11033
  check("tasks.md all tasks checked", () => tasksAllDone(changeDir)),
10769
11034
  // Verification command runs after tasks check — no point running tests
10770
11035
  // if tasks.md is incomplete.
10771
11036
  check("Verification passes", async () => {
10772
- const verifyResult = await verificationCommandPasses();
10773
- return verifyResult.status === 0 ? pass() : fail(verifyResult.output);
11037
+ const verifyResult = await commandCheckPasses(changeDir, change, run, "verify");
11038
+ return verifyResult.status === 0 ? pass(verifyResult.output) : fail(verifyResult.output);
10774
11039
  }),
10775
11040
  check(
10776
11041
  "verification_report exists",
@@ -10780,11 +11045,7 @@ async function guardVerifyChecks(output, changeDir) {
10780
11045
  const report = await readField(changeDir, "verification_report");
10781
11046
  if (!report || report === "null" || !await exists4(report)) return pass();
10782
11047
  return documentLanguageMatchesConfigured(changeDir, report);
10783
- }),
10784
- check(
10785
- "branch_status=handled",
10786
- async () => await branchStatusHandled(changeDir) ? pass() : fail("")
10787
- )
11048
+ })
10788
11049
  ]);
10789
11050
  }
10790
11051
  async function guardArchiveChecks(output, changeDir) {
@@ -10792,20 +11053,24 @@ async function guardArchiveChecks(output, changeDir) {
10792
11053
  check("archived is true", async () => await archivedIsTrue(changeDir) ? pass() : fail("")),
10793
11054
  check(
10794
11055
  "proposal.md exists",
10795
- async () => await nonempty(path14.join(changeDir, "proposal.md")) ? pass() : fail("")
11056
+ async () => await nonempty(path16.join(changeDir, "proposal.md")) ? pass() : fail("")
10796
11057
  ),
10797
11058
  check(
10798
11059
  "design.md exists",
10799
- async () => await nonempty(path14.join(changeDir, "design.md")) ? pass() : fail("")
11060
+ async () => await nonempty(path16.join(changeDir, "design.md")) ? pass() : fail("")
10800
11061
  ),
10801
- check("tasks.md all tasks checked", () => tasksAllDone(changeDir))
11062
+ check("tasks.md all tasks checked", () => tasksAllDone(changeDir)),
11063
+ check(
11064
+ "branch_status=handled",
11065
+ async () => await branchStatusHandled(changeDir) ? pass() : fail("")
11066
+ )
10802
11067
  ]);
10803
11068
  }
10804
11069
  async function applyStateUpdate(output, change, changeDir, phase, context) {
10805
11070
  const event = CLASSIC_GUARD_TRANSITION_EVENT[phase];
10806
11071
  if (!event) return;
10807
- const result3 = applyClassicTransition(context.classic, event);
10808
- await transitionClassicRuntimeRun(changeDir, result3.classic, context.run, {
11072
+ const result5 = applyClassicTransition(context.classic, event);
11073
+ await transitionClassicRuntimeRun(changeDir, result5.classic, context.run, {
10809
11074
  event,
10810
11075
  phase,
10811
11076
  source: "comet-guard"
@@ -10815,15 +11080,15 @@ async function applyStateUpdate(output, change, changeDir, phase, context) {
10815
11080
  event,
10816
11081
  source: "comet-guard",
10817
11082
  from: context.classic,
10818
- to: result3.classic,
10819
- effects: result3.effects
11083
+ to: result5.classic,
11084
+ effects: result5.effects
10820
11085
  });
10821
- for (const effect of result3.effects) {
11086
+ for (const effect of result5.effects) {
10822
11087
  output.stderr.push(green2(`[SET] ${wireField(effect.field)}=${wireValue(effect.to)}`));
10823
11088
  }
10824
11089
  output.stderr.push(green2(`[TRANSITION] ${event}`));
10825
11090
  const template = APPLY_MESSAGE[phase];
10826
- const message = phase === "open" ? template.replace("PLACEHOLDER", result3.classic.phase) : template;
11091
+ const message = phase === "open" ? template.replace("PLACEHOLDER", result5.classic.phase) : template;
10827
11092
  output.stderr.push(green2(message));
10828
11093
  }
10829
11094
  var classicGuardCommand = async (args, options) => {
@@ -10853,8 +11118,10 @@ Valid phases: open, design, build, verify, archive`
10853
11118
  let blocked2;
10854
11119
  if (phase === "open") blocked2 = await guardOpenChecks(output, changeDir);
10855
11120
  else if (phase === "design") blocked2 = await guardDesignChecks(output, changeDir, change);
10856
- else if (phase === "build") blocked2 = await guardBuildChecks(output, changeDir, change);
10857
- else if (phase === "verify") blocked2 = await guardVerifyChecks(output, changeDir);
11121
+ else if (phase === "build")
11122
+ blocked2 = await guardBuildChecks(output, changeDir, change, runContext.run);
11123
+ else if (phase === "verify")
11124
+ blocked2 = await guardVerifyChecks(output, changeDir, change, runContext.run);
10858
11125
  else blocked2 = await guardArchiveChecks(output, changeDir);
10859
11126
  if (blocked2) {
10860
11127
  output.stderr.push("");
@@ -10877,10 +11144,10 @@ Valid phases: open, design, build, verify, archive`
10877
11144
  };
10878
11145
 
10879
11146
  // domains/comet-classic/classic-handoff.ts
10880
- var import_yaml5 = __toESM(require_dist(), 1);
11147
+ var import_yaml6 = __toESM(require_dist(), 1);
10881
11148
  import { createHash as createHash5 } from "crypto";
10882
- import { promises as fs14, readFileSync as readFileSync2 } from "fs";
10883
- import path15 from "path";
11149
+ import { promises as fs16, readFileSync as readFileSync2 } from "fs";
11150
+ import path17 from "path";
10884
11151
  var GREEN4 = "\x1B[32m";
10885
11152
  var RED4 = "\x1B[31m";
10886
11153
  var YELLOW4 = "\x1B[33m";
@@ -10914,7 +11181,7 @@ var HandoffOutput = class {
10914
11181
  };
10915
11182
  async function exists5(file) {
10916
11183
  try {
10917
- await fs14.access(file);
11184
+ await fs16.access(file);
10918
11185
  return true;
10919
11186
  } catch (error) {
10920
11187
  if (error.code === "ENOENT") return false;
@@ -10923,7 +11190,7 @@ async function exists5(file) {
10923
11190
  }
10924
11191
  async function nonempty2(file) {
10925
11192
  try {
10926
- return (await fs14.stat(file)).size > 0;
11193
+ return (await fs16.stat(file)).size > 0;
10927
11194
  } catch (error) {
10928
11195
  if (error.code === "ENOENT") return false;
10929
11196
  throw error;
@@ -10952,7 +11219,7 @@ async function handoffSourceFiles2(changeDir) {
10952
11219
  const files = [`${changeDir}/proposal.md`, `${changeDir}/design.md`, `${changeDir}/tasks.md`];
10953
11220
  const specs = `${changeDir}/specs`;
10954
11221
  if (await exists5(specs)) {
10955
- for (const entry2 of (await fs14.readdir(specs)).sort()) {
11222
+ for (const entry2 of (await fs16.readdir(specs)).sort()) {
10956
11223
  const spec = `${specs}/${entry2}/spec.md`;
10957
11224
  if (await exists5(spec)) files.push(spec);
10958
11225
  }
@@ -11000,7 +11267,7 @@ async function writeMarkdownContext(changeDir, change, mode, contextHash, output
11000
11267
  ];
11001
11268
  for (const file of await handoffSourceFiles2(changeDir)) {
11002
11269
  if (!await exists5(file)) continue;
11003
- const content = await fs14.readFile(file, "utf8");
11270
+ const content = await fs16.readFile(file, "utf8");
11004
11271
  const total = lineCount(content);
11005
11272
  lines.push(
11006
11273
  `## ${file}`,
@@ -11025,7 +11292,7 @@ async function writeMarkdownContext(changeDir, change, mode, contextHash, output
11025
11292
  }
11026
11293
  lines.push("");
11027
11294
  }
11028
- await fs14.writeFile(output, lines.join("\n"));
11295
+ await fs16.writeFile(output, lines.join("\n"));
11029
11296
  }
11030
11297
  async function writeJsonContext(changeDir, change, mode, contextHash, output) {
11031
11298
  const entries = [];
@@ -11048,7 +11315,7 @@ async function writeJsonContext(changeDir, change, mode, contextHash, output) {
11048
11315
  "}",
11049
11316
  ""
11050
11317
  ].join("\n");
11051
- await fs14.writeFile(output, document);
11318
+ await fs16.writeFile(output, document);
11052
11319
  }
11053
11320
  async function writeSpecProjectionForFile(file, content) {
11054
11321
  return [
@@ -11088,11 +11355,11 @@ async function writeSpecMarkdownContext(changeDir, change, contextHash, output)
11088
11355
  const specs = `${changeDir}/specs`;
11089
11356
  let projected = false;
11090
11357
  if (await exists5(specs)) {
11091
- for (const entry2 of (await fs14.readdir(specs)).sort()) {
11358
+ for (const entry2 of (await fs16.readdir(specs)).sort()) {
11092
11359
  const spec = `${specs}/${entry2}/spec.md`;
11093
11360
  if (!await exists5(spec)) continue;
11094
11361
  projected = true;
11095
- lines.push(...await writeSpecProjectionForFile(spec, await fs14.readFile(spec, "utf8")));
11362
+ lines.push(...await writeSpecProjectionForFile(spec, await fs16.readFile(spec, "utf8")));
11096
11363
  }
11097
11364
  }
11098
11365
  if (!projected) {
@@ -11101,7 +11368,7 @@ async function writeSpecMarkdownContext(changeDir, change, contextHash, output)
11101
11368
  lines.push(
11102
11369
  "Full source files remain canonical. If a required heading or scenario is missing here, regenerate the handoff or read the source spec directly. Supporting files (proposal, design, tasks) are referenced by hash only."
11103
11370
  );
11104
- await fs14.writeFile(output, lines.join("\n"));
11371
+ await fs16.writeFile(output, lines.join("\n"));
11105
11372
  }
11106
11373
  async function writeSpecJsonContext(changeDir, change, contextHash, output) {
11107
11374
  const entries = [];
@@ -11110,7 +11377,7 @@ async function writeSpecJsonContext(changeDir, change, contextHash, output) {
11110
11377
  const role = /\/specs\/[^/]+\/spec\.md$/u.test(file) ? "spec" : "supporting";
11111
11378
  entries.push({ path: file, sha256: hashFile2(file), role });
11112
11379
  }
11113
- await fs14.writeFile(
11380
+ await fs16.writeFile(
11114
11381
  output,
11115
11382
  `${JSON.stringify(
11116
11383
  {
@@ -11129,8 +11396,8 @@ async function writeSpecJsonContext(changeDir, change, contextHash, output) {
11129
11396
  );
11130
11397
  }
11131
11398
  async function readField2(changeDir, field2) {
11132
- const file = path15.join(changeDir, ".comet.yaml");
11133
- const document = (0, import_yaml5.parseDocument)(await fs14.readFile(file, "utf8"), { uniqueKeys: false });
11399
+ const file = path17.join(changeDir, ".comet.yaml");
11400
+ const document = (0, import_yaml6.parseDocument)(await fs16.readFile(file, "utf8"), { uniqueKeys: false });
11134
11401
  if (document.errors.length > 0) {
11135
11402
  throw new HandoffFailure(`ERROR: Invalid .comet.yaml: ${document.errors[0].message}`);
11136
11403
  }
@@ -11164,7 +11431,7 @@ async function completedHandoffIsCurrent(changeDir, run, contextHash, contextJso
11164
11431
  readCheckpoint(changeDir, run.checkpointRef)
11165
11432
  ]);
11166
11433
  if (!await exists5(contextJson) || !await exists5(contextMd)) return false;
11167
- if (context !== await fs14.readFile(contextMd, "utf8")) return false;
11434
+ if (context !== await fs16.readFile(contextMd, "utf8")) return false;
11168
11435
  if (artifacts.handoff_context !== contextJson || artifacts.handoff_markdown !== contextMd) {
11169
11436
  return false;
11170
11437
  }
@@ -11287,7 +11554,7 @@ var classicHandoffCommand = async (args) => {
11287
11554
  run: pendingRun,
11288
11555
  unknownKeys: (await readClassicState(changeDir)).unknownKeys
11289
11556
  });
11290
- await fs14.mkdir(handoffDir, { recursive: true });
11557
+ await fs16.mkdir(handoffDir, { recursive: true });
11291
11558
  if (handoffMode === "beta") {
11292
11559
  await writeSpecMarkdownContext(changeDir, change, contextHash, contextMd);
11293
11560
  await writeSpecJsonContext(changeDir, change, contextHash, contextJson);
@@ -11295,7 +11562,7 @@ var classicHandoffCommand = async (args) => {
11295
11562
  await writeMarkdownContext(changeDir, change, handoffMode, contextHash, contextMd);
11296
11563
  await writeJsonContext(changeDir, change, handoffMode, contextHash, contextJson);
11297
11564
  }
11298
- const context = await fs14.readFile(contextMd, "utf8");
11565
+ const context = await fs16.readFile(contextMd, "utf8");
11299
11566
  await writeContext(changeDir, pendingRun.contextRef, context);
11300
11567
  const artifacts = {
11301
11568
  ...await readArtifacts(changeDir, pendingRun.artifactsRef),
@@ -11352,8 +11619,140 @@ var classicHandoffCommand = async (args) => {
11352
11619
  };
11353
11620
 
11354
11621
  // domains/comet-classic/classic-hook-guard.ts
11355
- import { existsSync as existsSync2, promises as fs15, readFileSync as readFileSync3 } from "fs";
11356
- import path16 from "path";
11622
+ import { existsSync as existsSync2, promises as fs18, readFileSync as readFileSync3 } from "fs";
11623
+ import path19 from "path";
11624
+
11625
+ // domains/comet-classic/classic-current-change.ts
11626
+ import { execFileSync } from "child_process";
11627
+ import { randomUUID as randomUUID6 } from "crypto";
11628
+ import { promises as fs17 } from "fs";
11629
+ import path18 from "path";
11630
+ function currentChangeFile(projectRoot2) {
11631
+ return path18.join(projectRoot2, ".comet", "current-change.json");
11632
+ }
11633
+ function currentBranch(projectRoot2) {
11634
+ try {
11635
+ const branch = execFileSync("git", ["rev-parse", "--abbrev-ref", "HEAD"], {
11636
+ cwd: projectRoot2,
11637
+ encoding: "utf8",
11638
+ stdio: ["ignore", "pipe", "ignore"]
11639
+ }).trim();
11640
+ return branch && branch !== "HEAD" ? branch : null;
11641
+ } catch {
11642
+ return null;
11643
+ }
11644
+ }
11645
+ function changeDirectory(projectRoot2, changeName) {
11646
+ return path18.join(projectRoot2, "openspec", "changes", changeName);
11647
+ }
11648
+ async function validateActiveChange(projectRoot2, changeName) {
11649
+ assertOpenSpecChangeName(changeName);
11650
+ const changeDir = changeDirectory(projectRoot2, changeName);
11651
+ try {
11652
+ await fs17.access(path18.join(changeDir, ".comet.yaml"));
11653
+ } catch (error) {
11654
+ if (error.code === "ENOENT") {
11655
+ throw new Error(
11656
+ `Cannot select current change '${changeName}': active change state not found`,
11657
+ {
11658
+ cause: error
11659
+ }
11660
+ );
11661
+ }
11662
+ throw error;
11663
+ }
11664
+ const projection = await readClassicState(changeDir, { migrate: false });
11665
+ if (!projection.classic) {
11666
+ throw new Error(`Cannot select current change '${changeName}': Classic state is incomplete`);
11667
+ }
11668
+ if (projection.classic.archived) {
11669
+ throw new Error(`Cannot select current change '${changeName}': change is archived`);
11670
+ }
11671
+ }
11672
+ function parseSelection(source) {
11673
+ let value;
11674
+ try {
11675
+ value = JSON.parse(source);
11676
+ } catch (error) {
11677
+ throw new Error(
11678
+ `current change selection contains invalid JSON: ${error instanceof Error ? error.message : String(error)}`,
11679
+ { cause: error }
11680
+ );
11681
+ }
11682
+ if (!value || typeof value !== "object" || Array.isArray(value)) {
11683
+ throw new Error("current change selection must be a JSON object");
11684
+ }
11685
+ const record = value;
11686
+ if (record.version !== 1) {
11687
+ throw new Error("current change selection version must be 1");
11688
+ }
11689
+ if (typeof record.change !== "string") {
11690
+ throw new Error("current change selection change must be a string");
11691
+ }
11692
+ assertOpenSpecChangeName(record.change);
11693
+ if (record.branch !== null && typeof record.branch !== "string") {
11694
+ throw new Error("current change selection branch must be a string or null");
11695
+ }
11696
+ return {
11697
+ version: 1,
11698
+ change: record.change,
11699
+ branch: record.branch
11700
+ };
11701
+ }
11702
+ async function selectCurrentChange(projectRoot2, changeName) {
11703
+ await validateActiveChange(projectRoot2, changeName);
11704
+ const selection = {
11705
+ version: 1,
11706
+ change: changeName,
11707
+ branch: currentBranch(projectRoot2)
11708
+ };
11709
+ const file = currentChangeFile(projectRoot2);
11710
+ const temporary = `${file}.${randomUUID6()}.tmp`;
11711
+ await fs17.mkdir(path18.dirname(file), { recursive: true });
11712
+ try {
11713
+ await fs17.writeFile(temporary, JSON.stringify(selection, null, 2) + "\n", "utf8");
11714
+ await fs17.rename(temporary, file);
11715
+ } catch (error) {
11716
+ await fs17.rm(temporary, { force: true });
11717
+ throw error;
11718
+ }
11719
+ return selection;
11720
+ }
11721
+ async function resolveCurrentChange(projectRoot2) {
11722
+ let source;
11723
+ try {
11724
+ source = await fs17.readFile(currentChangeFile(projectRoot2), "utf8");
11725
+ } catch (error) {
11726
+ if (error.code === "ENOENT") return { status: "missing" };
11727
+ return {
11728
+ status: "stale",
11729
+ reason: `cannot read current change selection: ${error instanceof Error ? error.message : String(error)}`
11730
+ };
11731
+ }
11732
+ let selection;
11733
+ try {
11734
+ selection = parseSelection(source);
11735
+ await validateActiveChange(projectRoot2, selection.change);
11736
+ } catch (error) {
11737
+ return {
11738
+ status: "stale",
11739
+ reason: error instanceof Error ? error.message : String(error)
11740
+ };
11741
+ }
11742
+ const branch = currentBranch(projectRoot2);
11743
+ if (selection.branch !== null && branch !== selection.branch) {
11744
+ return {
11745
+ status: "stale",
11746
+ reason: `current change '${selection.change}' was selected on branch '${selection.branch}', current branch is '${branch ?? "detached HEAD"}'`
11747
+ };
11748
+ }
11749
+ return { status: "selected", selection };
11750
+ }
11751
+ async function clearCurrentChange(projectRoot2) {
11752
+ await fs17.rm(currentChangeFile(projectRoot2), { force: true });
11753
+ }
11754
+
11755
+ // domains/comet-classic/classic-hook-guard.ts
11357
11756
  function result(exitCode, message) {
11358
11757
  return { exitCode, stderr: message + "\n" };
11359
11758
  }
@@ -11375,66 +11774,75 @@ function inputTarget() {
11375
11774
  function normalized(value) {
11376
11775
  return value.replaceAll("\\", "/").replace(/\/+/gu, "/");
11377
11776
  }
11777
+ function comparisonKey(value) {
11778
+ const normalizedValue = normalized(value);
11779
+ return process.platform === "win32" ? normalizedValue.toLowerCase() : normalizedValue;
11780
+ }
11378
11781
  function parseProjectRoot(args) {
11379
11782
  const index = args.indexOf("--project-root");
11380
11783
  const value = index >= 0 ? args[index + 1] : void 0;
11381
- return path16.resolve(value && !value.startsWith("--") ? value : process.cwd());
11784
+ return path19.resolve(value && !value.startsWith("--") ? value : process.cwd());
11382
11785
  }
11383
- function relativeToProjectRoot(target, projectRoot) {
11384
- const relative = normalized(path16.relative(projectRoot, target));
11786
+ function relativeToProjectRoot(target, projectRoot2) {
11787
+ const relative = normalized(path19.relative(projectRoot2, target));
11385
11788
  if (relative === "") return "";
11386
- if (relative.startsWith("../") || relative === ".." || path16.isAbsolute(relative)) return null;
11789
+ if (relative.startsWith("../") || relative === ".." || path19.isAbsolute(relative)) return null;
11387
11790
  return relative;
11388
11791
  }
11389
11792
  async function physicalPathForPossiblyMissingTarget(target) {
11390
- const resolved = path16.resolve(target);
11391
- const root = path16.parse(resolved).root;
11793
+ const resolved = path19.resolve(target);
11794
+ const root = path19.parse(resolved).root;
11392
11795
  const missingSegments = [];
11393
11796
  let cursor = resolved;
11394
11797
  while (cursor && cursor !== root) {
11395
11798
  try {
11396
- const physicalBase = await fs15.realpath(cursor);
11397
- return path16.join(physicalBase, ...missingSegments.reverse());
11799
+ const physicalBase = await fs18.realpath(cursor);
11800
+ return path19.join(physicalBase, ...missingSegments.reverse());
11398
11801
  } catch (error) {
11399
11802
  const code = error.code;
11400
11803
  if (code !== "ENOENT" && code !== "ENOTDIR") throw error;
11401
- missingSegments.push(path16.basename(cursor));
11402
- cursor = path16.dirname(cursor);
11804
+ missingSegments.push(path19.basename(cursor));
11805
+ cursor = path19.dirname(cursor);
11403
11806
  }
11404
11807
  }
11405
11808
  try {
11406
- const physicalRoot = await fs15.realpath(root);
11407
- return path16.join(physicalRoot, ...missingSegments.reverse());
11809
+ const physicalRoot = await fs18.realpath(root);
11810
+ return path19.join(physicalRoot, ...missingSegments.reverse());
11408
11811
  } catch {
11409
11812
  return null;
11410
11813
  }
11411
11814
  }
11412
- async function projectRelative(target, projectRoot) {
11413
- const rawCandidate = path16.isAbsolute(target) ? target : path16.resolve(process.cwd(), target);
11815
+ async function projectRelative(target, projectRoot2) {
11816
+ const rawCandidate = path19.isAbsolute(target) ? target : path19.resolve(process.cwd(), target);
11414
11817
  let candidate = normalized(rawCandidate);
11415
- const rootRelative = relativeToProjectRoot(rawCandidate, projectRoot);
11818
+ const rootRelative = relativeToProjectRoot(rawCandidate, projectRoot2);
11416
11819
  if (rootRelative !== null) return rootRelative;
11417
11820
  try {
11418
11821
  const physicalCandidate = await physicalPathForPossiblyMissingTarget(rawCandidate);
11419
- const physicalRoot = await fs15.realpath(projectRoot);
11822
+ const physicalRoot = await fs18.realpath(projectRoot2);
11420
11823
  if (physicalCandidate) {
11421
11824
  const physicalRootRelative = relativeToProjectRoot(physicalCandidate, physicalRoot);
11422
11825
  if (physicalRootRelative !== null) return physicalRootRelative;
11423
11826
  candidate = normalized(physicalCandidate);
11424
11827
  }
11425
11828
  } catch {
11426
- if (!path16.isAbsolute(target)) return normalized(target).replace(/^\.\//u, "");
11829
+ if (!path19.isAbsolute(target)) return normalized(target).replace(/^\.\//u, "");
11427
11830
  }
11428
11831
  return candidate.replace(/^\.\//u, "");
11429
11832
  }
11430
11833
  async function loadGoverningChange(changeDir) {
11431
11834
  try {
11432
- const runtime = await ensureStrictClassicRuntimeRun(changeDir);
11835
+ const projection = await readClassicState(changeDir, { migrate: false });
11836
+ const unknownKeys = Array.from(new Set(projection.unknownKeys)).sort();
11837
+ if (unknownKeys.length > 0) {
11838
+ throw new Error(`Invalid Classic state: unknown field(s): ${unknownKeys.join(", ")}`);
11839
+ }
11840
+ if (!projection.classic) throw new Error("Classic state projection is unavailable");
11433
11841
  return {
11434
11842
  changeDir,
11435
- phase: runtime.classic.phase,
11436
- classic: runtime.classic,
11437
- archived: runtime.classic.archived
11843
+ phase: projection.classic.phase,
11844
+ classic: projection.classic,
11845
+ archived: projection.classic.archived
11438
11846
  };
11439
11847
  } catch {
11440
11848
  const legacy = await readLegacyState(changeDir);
@@ -11447,36 +11855,64 @@ async function loadGoverningChange(changeDir) {
11447
11855
  };
11448
11856
  }
11449
11857
  }
11450
- async function activeChanges(projectRoot) {
11451
- const changesDir = path16.join(projectRoot, "openspec", "changes");
11858
+ async function activeChanges(projectRoot2) {
11859
+ const changesDir = path19.join(projectRoot2, "openspec", "changes");
11452
11860
  const governingChanges = [];
11453
11861
  if (!existsSync2(changesDir)) return governingChanges;
11454
- for (const entry2 of (await fs15.readdir(changesDir, { withFileTypes: true })).sort(
11862
+ for (const entry2 of (await fs18.readdir(changesDir, { withFileTypes: true })).sort(
11455
11863
  (left, right) => left.name.localeCompare(right.name)
11456
11864
  )) {
11457
11865
  if (!entry2.isDirectory() || entry2.name === "archive") continue;
11458
- const changeDir = path16.join(changesDir, entry2.name);
11459
- if (!existsSync2(path16.join(changeDir, ".comet.yaml"))) continue;
11866
+ const changeDir = path19.join(changesDir, entry2.name);
11867
+ if (!existsSync2(path19.join(changeDir, ".comet.yaml"))) continue;
11460
11868
  const governing = await loadGoverningChange(changeDir);
11461
11869
  if (!governing || governing.archived) continue;
11462
11870
  governingChanges.push(governing);
11463
11871
  }
11464
11872
  return governingChanges;
11465
11873
  }
11466
- function blocksSourceWrites(governing) {
11467
- if (governing.phase === "open" || governing.phase === "design" || governing.phase === "archive") {
11468
- return true;
11874
+ function isSuperpowersArtifactPath(relativePath2) {
11875
+ return comparisonKey(relativePath2).startsWith("docs/superpowers/");
11876
+ }
11877
+ var SUPERPOWERS_ARTIFACT_SLOTS = [
11878
+ {
11879
+ prefix: "docs/superpowers/specs/",
11880
+ field: "designDoc",
11881
+ wireField: "design_doc",
11882
+ phase: "design"
11883
+ },
11884
+ {
11885
+ prefix: "docs/superpowers/plans/",
11886
+ field: "plan",
11887
+ wireField: "plan",
11888
+ phase: "build"
11889
+ },
11890
+ {
11891
+ prefix: "docs/superpowers/reports/",
11892
+ field: "verificationReport",
11893
+ wireField: "verification_report",
11894
+ phase: "verify"
11469
11895
  }
11470
- return governing.phase === "build" && governing.classic?.workflow === "full" && !governing.classic.designDoc;
11896
+ ];
11897
+ function standardSuperpowersArtifactSlot(relativePath2) {
11898
+ const key = comparisonKey(relativePath2);
11899
+ const slot = SUPERPOWERS_ARTIFACT_SLOTS.find((candidate) => key.startsWith(candidate.prefix));
11900
+ if (!slot) return null;
11901
+ const fileName = key.slice(slot.prefix.length);
11902
+ if (!fileName || fileName.includes("/") || !fileName.endsWith(".md")) return null;
11903
+ return slot;
11471
11904
  }
11472
- function isSuperpowersArtifactPath(relativePath2) {
11473
- return relativePath2.startsWith("docs/superpowers/");
11905
+ function superpowersArtifactValue(governing, slot) {
11906
+ return governing.classic?.[slot.field] ?? null;
11907
+ }
11908
+ function allowsFirstSuperpowersArtifactWrite(governing, slot) {
11909
+ return governing.classic !== null && governing.phase === slot.phase && !superpowersArtifactValue(governing, slot);
11474
11910
  }
11475
11911
  function allowsSuperpowersArtifacts(governing) {
11476
11912
  return governing.phase === "design" || governing.phase === "build" || governing.phase === "verify";
11477
11913
  }
11478
11914
  function governingChangeName(governing) {
11479
- return governing.changeDir ? path16.basename(governing.changeDir) : null;
11915
+ return governing.changeDir ? path19.basename(governing.changeDir) : null;
11480
11916
  }
11481
11917
  var SUPERPOWERS_ARTIFACT_SUFFIXES = /* @__PURE__ */ new Set([
11482
11918
  "design",
@@ -11496,7 +11932,7 @@ function matchesRecordedSuperpowersArtifact(relativePath2, governing) {
11496
11932
  governing.classic?.verificationReport
11497
11933
  ];
11498
11934
  return artifactPaths.some(
11499
- (artifactPath) => artifactPath && normalized(artifactPath) === relativePath2
11935
+ (artifactPath) => artifactPath && comparisonKey(artifactPath) === comparisonKey(relativePath2)
11500
11936
  );
11501
11937
  }
11502
11938
  function matchesSuperpowersArtifactName(relativePath2, changeName) {
@@ -11507,12 +11943,12 @@ function matchesSuperpowersArtifactName(relativePath2, changeName) {
11507
11943
  const pattern = new RegExp(`(^|[-_.])${escapeRegex(changeName)}[-_.](${suffixes})$`, "u");
11508
11944
  return pattern.test(stem);
11509
11945
  }
11510
- async function superpowersArtifactGoverningChange(relativePath2, projectRoot) {
11511
- const active = await activeChanges(projectRoot);
11946
+ async function superpowersArtifactGoverningChange(relativePath2, projectRoot2) {
11947
+ const active = await activeChanges(projectRoot2);
11512
11948
  const recorded = active.find(
11513
11949
  (governing) => matchesRecordedSuperpowersArtifact(relativePath2, governing)
11514
11950
  );
11515
- if (recorded) return recorded;
11951
+ if (recorded) return { governing: recorded, match: "recorded" };
11516
11952
  const eligible = active.filter(allowsSuperpowersArtifacts);
11517
11953
  const named = eligible.filter((governing) => {
11518
11954
  const name = governingChangeName(governing);
@@ -11520,21 +11956,44 @@ async function superpowersArtifactGoverningChange(relativePath2, projectRoot) {
11520
11956
  }).sort(
11521
11957
  (a, b) => (governingChangeName(b)?.length ?? 0) - (governingChangeName(a)?.length ?? 0)
11522
11958
  )[0];
11523
- if (named) return named;
11959
+ if (named) return { governing: named, match: "named" };
11524
11960
  return null;
11525
11961
  }
11526
- async function repoSourceGoverningChange(projectRoot) {
11527
- const active = await activeChanges(projectRoot);
11528
- return active.find(blocksSourceWrites) ?? active[0] ?? null;
11962
+ async function repoSourceGoverningChange(projectRoot2, relativePath2) {
11963
+ const active = await activeChanges(projectRoot2);
11964
+ if (active.length === 0) return null;
11965
+ const current = await resolveCurrentChange(projectRoot2);
11966
+ if (current.status === "stale") {
11967
+ return { blockedResult: blockedStaleSelection(relativePath2, current.reason) };
11968
+ }
11969
+ if (current.status === "selected") {
11970
+ const selected = active.find(
11971
+ (governing) => governingChangeName(governing) === current.selection.change
11972
+ );
11973
+ if (selected) return selected;
11974
+ return {
11975
+ blockedResult: blockedStaleSelection(
11976
+ relativePath2,
11977
+ `selected change '${current.selection.change}' is no longer active`
11978
+ )
11979
+ };
11980
+ }
11981
+ if (active.length === 1) return active[0];
11982
+ return {
11983
+ blockedResult: blockedMultipleChanges(
11984
+ relativePath2,
11985
+ active.map((governing) => governingChangeName(governing)).filter(Boolean)
11986
+ )
11987
+ };
11529
11988
  }
11530
- async function governingChange(relativePath2, projectRoot) {
11989
+ async function governingChange(relativePath2, projectRoot2) {
11531
11990
  const prefix = "openspec/changes/";
11532
11991
  if (relativePath2.startsWith(prefix)) {
11533
11992
  const rest = relativePath2.slice(prefix.length);
11534
11993
  const [name] = rest.split("/");
11535
11994
  if (name && name !== "archive") {
11536
- const changeDir = path16.join(projectRoot, "openspec", "changes", name);
11537
- const stateFile2 = path16.join(changeDir, ".comet.yaml");
11995
+ const changeDir = path19.join(projectRoot2, "openspec", "changes", name);
11996
+ const stateFile2 = path19.join(changeDir, ".comet.yaml");
11538
11997
  if (existsSync2(stateFile2)) {
11539
11998
  const governing = await loadGoverningChange(changeDir);
11540
11999
  if (governing) return governing;
@@ -11544,12 +12003,31 @@ async function governingChange(relativePath2, projectRoot) {
11544
12003
  }
11545
12004
  }
11546
12005
  if (isSuperpowersArtifactPath(relativePath2)) {
11547
- const superpowers = await superpowersArtifactGoverningChange(relativePath2, projectRoot);
11548
- if (superpowers) return { ...superpowers, superpowersArtifact: "matched" };
11549
- const fallback = await repoSourceGoverningChange(projectRoot);
12006
+ const superpowers = await superpowersArtifactGoverningChange(relativePath2, projectRoot2);
12007
+ if (superpowers?.match === "recorded") {
12008
+ return { ...superpowers.governing, superpowersArtifact: "matched" };
12009
+ }
12010
+ const slot = standardSuperpowersArtifactSlot(relativePath2);
12011
+ if (superpowers) {
12012
+ return slot ? {
12013
+ ...superpowers.governing,
12014
+ superpowersArtifact: allowsFirstSuperpowersArtifactWrite(superpowers.governing, slot) ? "matched" : "unmatched",
12015
+ superpowersSlot: slot
12016
+ } : { ...superpowers.governing, superpowersArtifact: "matched" };
12017
+ }
12018
+ if (slot) {
12019
+ const candidate = await repoSourceGoverningChange(projectRoot2, relativePath2);
12020
+ if (!candidate || "blockedResult" in candidate) return candidate;
12021
+ return {
12022
+ ...candidate,
12023
+ superpowersArtifact: allowsFirstSuperpowersArtifactWrite(candidate, slot) ? "matched" : "unmatched",
12024
+ superpowersSlot: slot
12025
+ };
12026
+ }
12027
+ const fallback = (await activeChanges(projectRoot2))[0] ?? null;
11550
12028
  return fallback ? { ...fallback, superpowersArtifact: "unmatched" } : null;
11551
12029
  }
11552
- return repoSourceGoverningChange(projectRoot);
12030
+ return repoSourceGoverningChange(projectRoot2, relativePath2);
11553
12031
  }
11554
12032
  function isRootMarkdown(relativePath2) {
11555
12033
  return !relativePath2.includes("/") && relativePath2.endsWith(".md");
@@ -11593,7 +12071,7 @@ function blocked(relativePath2, phase) {
11593
12071
  " BLOCKED: source writes are not allowed during design",
11594
12072
  " This phase does not allow source writes",
11595
12073
  " ALLOWED: run brainstorming, create the Design Doc, and run guard",
11596
- " NEXT: finish the Design Doc, then run comet-guard design --apply to enter build"
12074
+ " NEXT: finish the Design Doc, then run comet guard <change-name> design --apply to enter build"
11597
12075
  ] : [
11598
12076
  " BLOCKED: source writes are not allowed during archive",
11599
12077
  " This phase does not allow source writes",
@@ -11634,7 +12112,25 @@ function blockedMissingDesignDoc(relativePath2) {
11634
12112
  ].join("\n")
11635
12113
  );
11636
12114
  }
11637
- function blockedUnmatchedSuperpowersArtifact(relativePath2, phase) {
12115
+ function blockedUnmatchedSuperpowersArtifact(relativePath2, governing) {
12116
+ const slot = governing.superpowersSlot;
12117
+ const recorded = slot ? superpowersArtifactValue(governing, slot) : null;
12118
+ const details = slot ? governing.phase !== slot.phase ? [
12119
+ ` BLOCKED: ${slot.wireField} cannot be first-written in phase ${governing.phase}`,
12120
+ ` Expected phase: ${slot.phase}`,
12121
+ " NEXT: resume the matching Comet phase or use an already recorded artifact path"
12122
+ ] : recorded ? [
12123
+ ` BLOCKED: ${slot.wireField} is already recorded for this change`,
12124
+ ` Recorded path: ${recorded}`,
12125
+ " NEXT: write the recorded artifact or explicitly correct the state path"
12126
+ ] : [
12127
+ " BLOCKED: standard Superpowers artifact state is incomplete",
12128
+ " NEXT: validate the active change state, then retry the matching phase"
12129
+ ] : [
12130
+ " BLOCKED: unmatched Superpowers artifact",
12131
+ " This docs/superpowers/ path does not match any active change artifact",
12132
+ " NEXT: use a recorded artifact path or a standard phase artifact directory"
12133
+ ];
11638
12134
  return result(
11639
12135
  2,
11640
12136
  [
@@ -11643,32 +12139,55 @@ function blockedUnmatchedSuperpowersArtifact(relativePath2, phase) {
11643
12139
  "║ COMET PHASE GUARD — WRITE BLOCKED ║",
11644
12140
  "╚══════════════════════════════════════════╝",
11645
12141
  "",
11646
- ` Current phase: ${phase}`,
12142
+ ` Current phase: ${governing.phase}`,
12143
+ ` Target file: ${relativePath2}`,
12144
+ "",
12145
+ ...details,
12146
+ ""
12147
+ ].join("\n")
12148
+ );
12149
+ }
12150
+ function blockedMultipleChanges(relativePath2, changeNames) {
12151
+ return result(
12152
+ 2,
12153
+ [
12154
+ "",
12155
+ "╔══════════════════════════════════════════╗",
12156
+ "║ COMET PHASE GUARD — WRITE BLOCKED ║",
12157
+ "╚══════════════════════════════════════════╝",
12158
+ "",
12159
+ " BLOCKED: multiple active changes require a current change",
12160
+ ` Target file: ${relativePath2}`,
12161
+ ` Active changes: ${changeNames.join(", ")}`,
12162
+ "",
12163
+ " NEXT: run comet state select <change-name>, then retry the source write",
12164
+ ""
12165
+ ].join("\n")
12166
+ );
12167
+ }
12168
+ function blockedStaleSelection(relativePath2, reason) {
12169
+ return result(
12170
+ 2,
12171
+ [
12172
+ "",
12173
+ "╔══════════════════════════════════════════╗",
12174
+ "║ COMET PHASE GUARD — WRITE BLOCKED ║",
12175
+ "╚══════════════════════════════════════════╝",
12176
+ "",
12177
+ " BLOCKED: current change selection is stale or invalid",
11647
12178
  ` Target file: ${relativePath2}`,
12179
+ ` Reason: ${reason}`,
11648
12180
  "",
11649
- " BLOCKED: unmatched Superpowers artifact",
11650
- " This docs/superpowers/ path does not match any active change artifact",
11651
- " NEXT: record the artifact path in .comet.yaml or include the change name in the artifact filename",
12181
+ " NEXT: run comet state select <change-name>, then retry the source write",
11652
12182
  ""
11653
12183
  ].join("\n")
11654
12184
  );
11655
12185
  }
11656
12186
  var classicHookGuardCommand = async (args) => {
11657
- const projectRoot = parseProjectRoot(args);
12187
+ const projectRoot2 = parseProjectRoot(args);
11658
12188
  const target = inputTarget();
11659
12189
  if (!target) return allowed("no file path in tool input");
11660
- const relativePath2 = await projectRelative(target, projectRoot);
11661
- let governing;
11662
- try {
11663
- governing = await governingChange(relativePath2, projectRoot);
11664
- } catch (error) {
11665
- return result(
11666
- 2,
11667
- `[COMET-HOOK] blocked: ${error instanceof Error ? error.message : String(error)}`
11668
- );
11669
- }
11670
- if (!governing) return allowed("no active comet change");
11671
- if (governing.archived) return allowed(`${relativePath2} (own change archived)`);
12190
+ const relativePath2 = await projectRelative(target, projectRoot2);
11672
12191
  if (isCometConfig(relativePath2)) {
11673
12192
  return allowed(`${relativePath2} (whitelist: comet config)`);
11674
12193
  }
@@ -11681,6 +12200,18 @@ var classicHookGuardCommand = async (args) => {
11681
12200
  if (relativePath2 === "CLAUDE.md" || relativePath2 === "CHANGELOG.md" || relativePath2 === "README.md" || isRootMarkdown(relativePath2)) {
11682
12201
  return allowed(`${relativePath2} (whitelist: root markdown)`);
11683
12202
  }
12203
+ let governing;
12204
+ try {
12205
+ governing = await governingChange(relativePath2, projectRoot2);
12206
+ } catch (error) {
12207
+ return result(
12208
+ 2,
12209
+ `[COMET-HOOK] blocked: ${error instanceof Error ? error.message : String(error)}`
12210
+ );
12211
+ }
12212
+ if (!governing) return allowed("no active comet change");
12213
+ if ("blockedResult" in governing) return governing.blockedResult;
12214
+ if (governing.archived) return allowed(`${relativePath2} (own change archived)`);
11684
12215
  const phase = governing.phase;
11685
12216
  const openSpec = openSpecAllowed(relativePath2, phase);
11686
12217
  if (openSpec) return allowed(openSpec);
@@ -11689,7 +12220,7 @@ var classicHookGuardCommand = async (args) => {
11689
12220
  return allowed(`${relativePath2} (phase: ${phase}, superpowers)`);
11690
12221
  }
11691
12222
  if (governing.superpowersArtifact === "unmatched") {
11692
- return blockedUnmatchedSuperpowersArtifact(relativePath2, phase);
12223
+ return blockedUnmatchedSuperpowersArtifact(relativePath2, governing);
11693
12224
  }
11694
12225
  }
11695
12226
  if (phase === "build" && governing.classic?.workflow === "full" && !governing.classic.designDoc) {
@@ -12069,12 +12600,438 @@ var classicIntentCommand = async (args, _options) => {
12069
12600
  }
12070
12601
  };
12071
12602
 
12603
+ // domains/comet-classic/classic-resume-probe.ts
12604
+ import path20 from "path";
12605
+ import { promises as fs19 } from "fs";
12606
+ import { spawn } from "child_process";
12607
+ var COMET_RESUME_PROBE_SCHEMA_VERSION = "comet.resume_probe.v1";
12608
+ function isRecord2(value) {
12609
+ return typeof value === "object" && value !== null && !Array.isArray(value);
12610
+ }
12611
+ function normalizeInput(input) {
12612
+ if (!isRecord2(input)) {
12613
+ throw new Error("Invalid CometResumeProbeInput: input must be an object");
12614
+ }
12615
+ if (input.schema_version !== COMET_RESUME_PROBE_SCHEMA_VERSION) {
12616
+ throw new Error(
12617
+ `Invalid CometResumeProbeInput: schema_version must be ${COMET_RESUME_PROBE_SCHEMA_VERSION}`
12618
+ );
12619
+ }
12620
+ if (typeof input.utterance !== "string") {
12621
+ throw new Error("Invalid CometResumeProbeInput: utterance must be a string");
12622
+ }
12623
+ const context = isRecord2(input.agent_context) ? input.agent_context : {};
12624
+ return {
12625
+ schema_version: COMET_RESUME_PROBE_SCHEMA_VERSION,
12626
+ utterance: input.utterance,
12627
+ locale: typeof input.locale === "string" ? input.locale : "unknown",
12628
+ agent_context: {
12629
+ non_trivial_work: context.non_trivial_work === true,
12630
+ already_in_comet_flow: context.already_in_comet_flow === true
12631
+ }
12632
+ };
12633
+ }
12634
+ function result3(action, change, confidence, reason, evidence = []) {
12635
+ return {
12636
+ schema_version: COMET_RESUME_PROBE_SCHEMA_VERSION,
12637
+ action,
12638
+ changeName: change?.name ?? null,
12639
+ phase: change?.phase ?? null,
12640
+ nextCommand: action === "auto_resume" || action === "ask_user" ? change?.nextCommand ?? null : null,
12641
+ confidence,
12642
+ reason,
12643
+ evidence
12644
+ };
12645
+ }
12646
+ async function readIfExists(filePath) {
12647
+ if (!await fileExists3(filePath)) return "";
12648
+ return fs19.readFile(filePath, "utf8");
12649
+ }
12650
+ async function changeSearchText(changeDir, classic) {
12651
+ const files = ["proposal.md", "design.md", "tasks.md"];
12652
+ const parts = [classic.name, classic.workflow, classic.phase];
12653
+ for (const file of files) {
12654
+ parts.push(await readIfExists(path20.join(changeDir, file)));
12655
+ }
12656
+ return parts.join("\n").toLowerCase();
12657
+ }
12658
+ function nextCommandForPhase2(phase) {
12659
+ switch (phase) {
12660
+ case "open":
12661
+ return "/comet-open";
12662
+ case "design":
12663
+ return "/comet-design";
12664
+ case "build":
12665
+ return "/comet-build";
12666
+ case "verify":
12667
+ return "/comet-verify";
12668
+ case "archive":
12669
+ return "/comet-archive";
12670
+ default:
12671
+ return null;
12672
+ }
12673
+ }
12674
+ function diagnosticFromProjection(changeDir, name, projection) {
12675
+ const classic = projection.classic;
12676
+ const unknownKeys = projection.unknownKeys.filter((key) => key !== "run_id");
12677
+ if (!classic) {
12678
+ return {
12679
+ name,
12680
+ valid: false,
12681
+ workflow: "unknown",
12682
+ phase: "invalid",
12683
+ currentStep: null,
12684
+ nextCommand: null,
12685
+ runtimeMode: "invalid",
12686
+ runtimeEval: null,
12687
+ evidence: [],
12688
+ error: `${changeDir} does not contain valid Comet state`
12689
+ };
12690
+ }
12691
+ if (unknownKeys.length > 0) {
12692
+ return {
12693
+ name,
12694
+ valid: false,
12695
+ workflow: classic.workflow,
12696
+ phase: classic.phase,
12697
+ currentStep: null,
12698
+ nextCommand: null,
12699
+ runtimeMode: "invalid",
12700
+ runtimeEval: null,
12701
+ evidence: [],
12702
+ error: `unknown field(s): ${unknownKeys.join(", ")}`
12703
+ };
12704
+ }
12705
+ return {
12706
+ name,
12707
+ valid: true,
12708
+ workflow: classic.workflow,
12709
+ phase: classic.phase,
12710
+ currentStep: null,
12711
+ nextCommand: nextCommandForPhase2(classic.phase),
12712
+ runtimeMode: "engine-projection",
12713
+ runtimeEval: null,
12714
+ evidence: []
12715
+ };
12716
+ }
12717
+ async function hasOpenSpecChangeFiles(changeDir) {
12718
+ return await fileExists3(path20.join(changeDir, "proposal.md")) || await fileExists3(path20.join(changeDir, "design.md")) || await fileExists3(path20.join(changeDir, "tasks.md"));
12719
+ }
12720
+ async function discoverActiveChanges(projectRoot2) {
12721
+ const changesDir = path20.join(projectRoot2, "openspec", "changes");
12722
+ if (!await fileExists3(changesDir)) return [];
12723
+ const entries = await readDir(changesDir);
12724
+ const changes = [];
12725
+ for (const entry2 of entries) {
12726
+ if (entry2 === "archive") continue;
12727
+ const changeDir = path20.join(changesDir, entry2);
12728
+ const stat = await fs19.stat(changeDir).catch(() => null);
12729
+ if (!stat?.isDirectory()) continue;
12730
+ const hasCometState = await fileExists3(path20.join(changeDir, ".comet.yaml"));
12731
+ if (!hasCometState) {
12732
+ if (!await hasOpenSpecChangeFiles(changeDir)) continue;
12733
+ const missingStateChange = {
12734
+ name: entry2,
12735
+ workflow: "unknown",
12736
+ phase: "invalid",
12737
+ nextCommand: null,
12738
+ diagnostic: {
12739
+ name: entry2,
12740
+ valid: false,
12741
+ workflow: "unknown",
12742
+ phase: "invalid",
12743
+ currentStep: null,
12744
+ nextCommand: null,
12745
+ runtimeMode: "invalid",
12746
+ runtimeEval: null,
12747
+ evidence: [],
12748
+ error: "missing Comet state"
12749
+ },
12750
+ buildPause: null,
12751
+ hasClassicProjection: false,
12752
+ verifyResult: null,
12753
+ text: "",
12754
+ missingCometState: true
12755
+ };
12756
+ missingStateChange.text = await changeSearchText(changeDir, missingStateChange);
12757
+ changes.push(missingStateChange);
12758
+ continue;
12759
+ }
12760
+ const projection = await readClassicState(changeDir, { migrate: false });
12761
+ const classic = projection.classic;
12762
+ const diagnostic = diagnosticFromProjection(changeDir, entry2, projection);
12763
+ const hasClassicProjection = Boolean(classic);
12764
+ const phase = classic?.phase ?? diagnostic.phase;
12765
+ const workflow = classic?.workflow ?? diagnostic.workflow;
12766
+ if (phase === "archive" || classic?.archived) continue;
12767
+ const change = {
12768
+ name: entry2,
12769
+ workflow,
12770
+ phase,
12771
+ nextCommand: diagnostic.nextCommand,
12772
+ diagnostic,
12773
+ buildPause: classic?.buildPause ?? null,
12774
+ hasClassicProjection,
12775
+ verifyResult: classic?.verifyResult ?? null,
12776
+ text: "",
12777
+ missingCometState: false
12778
+ };
12779
+ change.text = await changeSearchText(changeDir, change);
12780
+ changes.push(change);
12781
+ }
12782
+ return changes;
12783
+ }
12784
+ var RESUME_WORDS = [
12785
+ "continue",
12786
+ "resume",
12787
+ "carry on",
12788
+ "finish",
12789
+ "run it",
12790
+ "commit",
12791
+ "verify",
12792
+ "archive",
12793
+ "继续",
12794
+ "接着",
12795
+ "恢复",
12796
+ "跑完",
12797
+ "提交",
12798
+ "验证",
12799
+ "归档",
12800
+ "修刚才"
12801
+ ];
12802
+ var QUESTION_WORDS = [
12803
+ "what",
12804
+ "why",
12805
+ "how",
12806
+ "explain",
12807
+ "summarize",
12808
+ "reliable",
12809
+ "靠谱吗",
12810
+ "是什么",
12811
+ "为什么",
12812
+ "解释",
12813
+ "总结",
12814
+ "取名",
12815
+ "命名"
12816
+ ];
12817
+ var GENERIC_RELATED_TOKENS = /* @__PURE__ */ new Set([
12818
+ "add",
12819
+ "build",
12820
+ "cache",
12821
+ "change",
12822
+ "code",
12823
+ "design",
12824
+ "docs",
12825
+ "file",
12826
+ "fix",
12827
+ "implement",
12828
+ "plan",
12829
+ "readme",
12830
+ "task",
12831
+ "test",
12832
+ "update",
12833
+ "修改",
12834
+ "更新",
12835
+ "修复",
12836
+ "添加",
12837
+ "文档",
12838
+ "任务",
12839
+ "计划",
12840
+ "实现"
12841
+ ]);
12842
+ var OPT_OUT_WORDS = [
12843
+ "do not resume",
12844
+ "don't resume",
12845
+ "without comet",
12846
+ "skip comet",
12847
+ "不要恢复",
12848
+ "不走 comet",
12849
+ "不要走 comet",
12850
+ "直接解释",
12851
+ "只回答"
12852
+ ];
12853
+ function includesAny(text2, words) {
12854
+ return words.some((word) => text2.includes(word));
12855
+ }
12856
+ function hasDecisionPoint(change) {
12857
+ if (change.missingCometState) return true;
12858
+ if (!change.hasClassicProjection) return true;
12859
+ if (!change.diagnostic.valid) return true;
12860
+ if (change.phase === "archive") return true;
12861
+ if (change.verifyResult === "fail") return true;
12862
+ if (change.diagnostic.runtimeEval && !change.diagnostic.runtimeEval.passed) return true;
12863
+ if (change.phase !== "build") return false;
12864
+ if (change.buildPause === "plan-ready") return true;
12865
+ return false;
12866
+ }
12867
+ function relatedEvidence(utterance, change) {
12868
+ const text2 = utterance.toLowerCase();
12869
+ const evidence = [];
12870
+ if (text2.includes(change.name.toLowerCase())) {
12871
+ evidence.push({ source: "user", quote: change.name });
12872
+ }
12873
+ const tokens = change.text.split(/[^a-zA-Z0-9_\-\u4e00-\u9fff/]+/u).map((token) => token.trim().toLowerCase()).filter((token) => token.length >= 4 && !GENERIC_RELATED_TOKENS.has(token));
12874
+ const matched = [...new Set(tokens.filter((token) => text2.includes(token)))].slice(0, 3);
12875
+ for (const token of matched) {
12876
+ evidence.push({ source: "repo", quote: token });
12877
+ }
12878
+ return evidence;
12879
+ }
12880
+ async function gitDirtyFiles(projectRoot2) {
12881
+ return new Promise((resolve) => {
12882
+ const child = spawn("git", ["status", "--short", "--untracked-files=all"], {
12883
+ cwd: projectRoot2,
12884
+ stdio: ["ignore", "pipe", "ignore"],
12885
+ shell: false
12886
+ });
12887
+ const chunks = [];
12888
+ child.stdout.on("data", (chunk) => {
12889
+ chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(String(chunk)));
12890
+ });
12891
+ child.on("error", () => resolve([]));
12892
+ child.on("exit", (code) => {
12893
+ if (code !== 0) {
12894
+ resolve([]);
12895
+ return;
12896
+ }
12897
+ const dirtyFiles = Buffer.concat(chunks).toString("utf8").split(/\r?\n/u).map((line) => line.trim()).filter(Boolean);
12898
+ resolve(dirtyFiles);
12899
+ });
12900
+ });
12901
+ }
12902
+ async function resolveCometResumeProbe(projectRoot2, rawInput) {
12903
+ const input = normalizeInput(rawInput);
12904
+ const utterance = input.utterance.trim();
12905
+ const lower = utterance.toLowerCase();
12906
+ if (input.agent_context.already_in_comet_flow) {
12907
+ return result3("out_of_scope", null, "low", "already in Comet flow");
12908
+ }
12909
+ if (includesAny(lower, OPT_OUT_WORDS)) {
12910
+ return result3("out_of_scope", null, "low", "user opted out of Comet resume", [
12911
+ { source: "user", quote: utterance }
12912
+ ]);
12913
+ }
12914
+ const changes = await discoverActiveChanges(projectRoot2);
12915
+ if (changes.length === 0) {
12916
+ return result3("none", null, "none", "no active Comet changes");
12917
+ }
12918
+ const dirtyFiles = await gitDirtyFiles(projectRoot2);
12919
+ if (changes.length > 1) {
12920
+ const named = changes.find((change2) => lower.includes(change2.name.toLowerCase()));
12921
+ if (!named) {
12922
+ return result3("ask_user", null, "low", "multiple active changes require a change name");
12923
+ }
12924
+ if (dirtyFiles.length > 0) {
12925
+ return result3("ask_user", named, "low", "uncommitted worktree changes require attribution", [
12926
+ { source: "repo", quote: `${dirtyFiles.length} dirty file(s)` }
12927
+ ]);
12928
+ }
12929
+ return hasDecisionPoint(named) ? result3("ask_user", named, "low", "active change is at a decision point") : result3("auto_resume", named, "high", "request names an active change", [
12930
+ { source: "user", quote: named.name }
12931
+ ]);
12932
+ }
12933
+ const [change] = changes;
12934
+ if (dirtyFiles.length > 0) {
12935
+ return result3("ask_user", change, "low", "uncommitted worktree changes require attribution", [
12936
+ { source: "repo", quote: `${dirtyFiles.length} dirty file(s)` }
12937
+ ]);
12938
+ }
12939
+ if (hasDecisionPoint(change)) {
12940
+ if (change.missingCometState) {
12941
+ return result3("ask_user", change, "low", "active OpenSpec change is missing Comet state");
12942
+ }
12943
+ return result3("ask_user", change, "low", "active change is at a decision point", [
12944
+ { source: "state", quote: `phase: ${change.phase}` }
12945
+ ]);
12946
+ }
12947
+ const resumeLike = includesAny(lower, RESUME_WORDS);
12948
+ const questionLike = !input.agent_context.non_trivial_work && includesAny(lower, QUESTION_WORDS);
12949
+ if (questionLike && !resumeLike) {
12950
+ return result3("out_of_scope", change, "low", "user asked a question without workflow work");
12951
+ }
12952
+ const evidence = relatedEvidence(utterance, change);
12953
+ if (resumeLike || evidence.length > 0) {
12954
+ return result3("auto_resume", change, "high", "single active change and request is related", [
12955
+ { source: "state", quote: `phase: ${change.phase}` },
12956
+ ...evidence
12957
+ ]);
12958
+ }
12959
+ if (input.agent_context.non_trivial_work) {
12960
+ return result3(
12961
+ "ask_user",
12962
+ change,
12963
+ "low",
12964
+ "single active change exists but request looks unrelated"
12965
+ );
12966
+ }
12967
+ return result3("out_of_scope", change, "low", "request is not workflow work");
12968
+ }
12969
+
12970
+ // domains/comet-classic/classic-resume-probe-command.ts
12971
+ function result4(exitCode, stdout, stderr) {
12972
+ return {
12973
+ exitCode,
12974
+ ...stdout === void 0 ? {} : { stdout },
12975
+ ...stderr === void 0 ? {} : { stderr }
12976
+ };
12977
+ }
12978
+ function usage2() {
12979
+ return result4(
12980
+ 64,
12981
+ void 0,
12982
+ "Usage: comet-resume-probe.mjs probe <input-json>\nUsage: comet-resume-probe.mjs probe --stdin"
12983
+ );
12984
+ }
12985
+ async function readStdin2() {
12986
+ const chunks = [];
12987
+ for await (const chunk of process.stdin) {
12988
+ chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(String(chunk)));
12989
+ }
12990
+ return Buffer.concat(chunks).toString("utf8");
12991
+ }
12992
+ function rawUtteranceInput(utterance) {
12993
+ return {
12994
+ schema_version: COMET_RESUME_PROBE_SCHEMA_VERSION,
12995
+ utterance,
12996
+ locale: "unknown",
12997
+ agent_context: {
12998
+ non_trivial_work: true,
12999
+ already_in_comet_flow: false
13000
+ }
13001
+ };
13002
+ }
13003
+ function parseStdinInput(source) {
13004
+ try {
13005
+ return JSON.parse(source);
13006
+ } catch {
13007
+ return rawUtteranceInput(source);
13008
+ }
13009
+ }
13010
+ var classicResumeProbeCommand = async (args) => {
13011
+ const [subcommand, input] = args;
13012
+ if (subcommand !== "probe") return usage2();
13013
+ const fromStdin = input === "--stdin";
13014
+ const source = fromStdin ? await readStdin2() : input;
13015
+ if (!source) return usage2();
13016
+ try {
13017
+ const parsedInput = fromStdin ? parseStdinInput(source) : JSON.parse(source);
13018
+ const resolution = await resolveCometResumeProbe(process.cwd(), parsedInput);
13019
+ return result4(0, `${JSON.stringify(resolution, null, 2)}
13020
+ `);
13021
+ } catch (error) {
13022
+ if (error instanceof SyntaxError) {
13023
+ return result4(1, void 0, `Invalid JSON: ${error.message}`);
13024
+ }
13025
+ return result4(1, void 0, error instanceof Error ? error.message : String(error));
13026
+ }
13027
+ };
13028
+
12072
13029
  // domains/comet-classic/classic-state-command.ts
12073
- var import_yaml6 = __toESM(require_dist(), 1);
13030
+ var import_yaml7 = __toESM(require_dist(), 1);
12074
13031
  import { spawnSync as spawnSync3 } from "child_process";
12075
- import { randomUUID as randomUUID6 } from "crypto";
12076
- import { existsSync as existsSync3, promises as fs16 } from "fs";
12077
- import path17 from "path";
13032
+ import { randomUUID as randomUUID7 } from "crypto";
13033
+ import { existsSync as existsSync3, promises as fs20 } from "fs";
13034
+ import path21 from "path";
12078
13035
  init_state();
12079
13036
  var GREEN5 = "\x1B[32m";
12080
13037
  var RED5 = "\x1B[31m";
@@ -12086,6 +13043,8 @@ var ARTIFACT_LANGUAGES2 = ["en", "zh-CN"];
12086
13043
  var EVENTS = CLASSIC_TRANSITION_EVENTS;
12087
13044
  var MACHINE_OWNED_FIELDS = /* @__PURE__ */ new Set([
12088
13045
  ...RUN_WIRE_KEYS,
13046
+ "archive_confirmation",
13047
+ "verify_failures",
12089
13048
  "classic_profile",
12090
13049
  "classic_migration"
12091
13050
  ]);
@@ -12101,11 +13060,12 @@ var FIELD_ENUMS = {
12101
13060
  subagent_dispatch: ["null", "confirmed"],
12102
13061
  tdd_mode: ["tdd", "direct"],
12103
13062
  review_mode: ["off", "standard", "thorough"],
12104
- isolation: ["branch", "worktree"],
13063
+ isolation: ["current", "branch", "worktree"],
12105
13064
  verify_mode: ["light", "full"],
12106
13065
  auto_transition: ["true", "false"],
12107
13066
  verify_result: ["pending", "pass", "fail"],
12108
13067
  branch_status: ["pending", "handled"],
13068
+ archive_confirmation: ["pending", "confirmed"],
12109
13069
  archived: ["true", "false"],
12110
13070
  direct_override: ["true", "false"],
12111
13071
  classic_profile: PROFILES,
@@ -12121,7 +13081,9 @@ var CLASSIC_FIELD_WIRE_NAMES2 = {
12121
13081
  phase: "phase",
12122
13082
  verificationReport: "verification_report",
12123
13083
  verifiedAt: "verified_at",
13084
+ archiveConfirmation: "archive_confirmation",
12124
13085
  verifyResult: "verify_result",
13086
+ verifyFailures: "verify_failures",
12125
13087
  workflow: "workflow"
12126
13088
  };
12127
13089
  var CommandFailure = class extends Error {
@@ -12182,7 +13144,7 @@ function validateRelativePath(value, field2) {
12182
13144
  }
12183
13145
  async function exists6(file) {
12184
13146
  try {
12185
- await fs16.access(file);
13147
+ await fs20.access(file);
12186
13148
  return true;
12187
13149
  } catch (error) {
12188
13150
  if (error.code === "ENOENT") return false;
@@ -12191,39 +13153,39 @@ async function exists6(file) {
12191
13153
  }
12192
13154
  async function nonempty3(file) {
12193
13155
  try {
12194
- return (await fs16.stat(file)).size > 0;
13156
+ return (await fs20.stat(file)).size > 0;
12195
13157
  } catch (error) {
12196
13158
  if (error.code === "ENOENT") return false;
12197
13159
  throw error;
12198
13160
  }
12199
13161
  }
12200
- async function changeDirectory(name) {
13162
+ async function changeDirectory2(name) {
12201
13163
  return resolveClassicChangeDirectory(name);
12202
13164
  }
12203
13165
  async function readDocument2(file) {
12204
13166
  let source;
12205
13167
  try {
12206
- source = await fs16.readFile(file, "utf8");
13168
+ source = await fs20.readFile(file, "utf8");
12207
13169
  } catch (error) {
12208
13170
  if (error.code === "ENOENT") {
12209
13171
  fail2(
12210
- `ERROR: .comet.yaml not found at ${path17.relative(process.cwd(), file).replaceAll("\\", "/")}`
13172
+ `ERROR: .comet.yaml not found at ${path21.relative(process.cwd(), file).replaceAll("\\", "/")}`
12211
13173
  );
12212
13174
  }
12213
13175
  throw error;
12214
13176
  }
12215
- const document = (0, import_yaml6.parseDocument)(source, { uniqueKeys: false });
13177
+ const document = (0, import_yaml7.parseDocument)(source, { uniqueKeys: false });
12216
13178
  if (document.errors.length > 0) fail2(`ERROR: Invalid .comet.yaml: ${document.errors[0].message}`);
12217
13179
  return document;
12218
13180
  }
12219
13181
  async function atomicWrite2(file, content) {
12220
- await fs16.mkdir(path17.dirname(file), { recursive: true });
12221
- const temporary = `${file}.${randomUUID6()}.tmp`;
13182
+ await fs20.mkdir(path21.dirname(file), { recursive: true });
13183
+ const temporary = `${file}.${randomUUID7()}.tmp`;
12222
13184
  try {
12223
- await fs16.writeFile(temporary, content, "utf8");
12224
- await fs16.rename(temporary, file);
13185
+ await fs20.writeFile(temporary, content, "utf8");
13186
+ await fs20.rename(temporary, file);
12225
13187
  } catch (error) {
12226
- await fs16.rm(temporary, { force: true });
13188
+ await fs20.rm(temporary, { force: true });
12227
13189
  throw error;
12228
13190
  }
12229
13191
  }
@@ -12256,6 +13218,10 @@ function nullableRecordBoolean(record, field2) {
12256
13218
  if (value === "false") return false;
12257
13219
  return null;
12258
13220
  }
13221
+ function nonNegativeRecordInteger(record, field2, fallback = 0) {
13222
+ const value = record[field2];
13223
+ return typeof value === "number" && Number.isInteger(value) && value >= 0 ? value : fallback;
13224
+ }
12259
13225
  function sparseClassicState(record) {
12260
13226
  const workflow = enumRecordValue(record, "workflow", PROFILES, "full");
12261
13227
  return {
@@ -12283,7 +13249,12 @@ function sparseClassicState(record) {
12283
13249
  ["off", "standard", "thorough"],
12284
13250
  null
12285
13251
  ),
12286
- isolation: enumRecordValue(record, "isolation", ["branch", "worktree"], null),
13252
+ isolation: enumRecordValue(
13253
+ record,
13254
+ "isolation",
13255
+ ["current", "branch", "worktree"],
13256
+ null
13257
+ ),
12287
13258
  verifyMode: enumRecordValue(record, "verify_mode", ["light", "full"], null),
12288
13259
  autoTransition: nullableRecordBoolean(record, "auto_transition"),
12289
13260
  baseRef: nullableRecordString(record, "base_ref"),
@@ -12295,10 +13266,17 @@ function sparseClassicState(record) {
12295
13266
  ["pending", "pass", "fail"],
12296
13267
  "pending"
12297
13268
  ),
13269
+ verifyFailures: nonNegativeRecordInteger(record, "verify_failures"),
12298
13270
  verificationReport: nullableRecordString(record, "verification_report"),
12299
13271
  branchStatus: enumRecordValue(record, "branch_status", ["pending", "handled"], null),
12300
13272
  createdAt: nullableRecordString(record, "created_at"),
12301
13273
  verifiedAt: nullableRecordString(record, "verified_at"),
13274
+ archiveConfirmation: enumRecordValue(
13275
+ record,
13276
+ "archive_confirmation",
13277
+ ["pending", "confirmed"],
13278
+ null
13279
+ ),
12302
13280
  archived: nullableRecordBoolean(record, "archived") ?? false,
12303
13281
  directOverride: nullableRecordBoolean(record, "direct_override"),
12304
13282
  handoffContext: nullableRecordString(record, "handoff_context"),
@@ -12308,17 +13286,13 @@ function sparseClassicState(record) {
12308
13286
  };
12309
13287
  }
12310
13288
  async function projectConfigValue2(field2) {
12311
- const file = path17.resolve(".comet", "config.yaml");
12312
- if (!await exists6(file)) return null;
12313
- const document = await readDocument2(file);
12314
- const value = document.get(field2);
12315
- return value === null || value === void 0 ? null : scalar(value);
13289
+ return (await readClassicConfigValue(field2))?.value ?? null;
12316
13290
  }
12317
13291
  async function projectLanguageDefault() {
12318
13292
  if (process.env.COMET_LANGUAGE)
12319
13293
  return validateLanguage(process.env.COMET_LANGUAGE, "COMET_LANGUAGE");
12320
- const value = await projectConfigValue2("language");
12321
- if (value) return validateLanguage(value, ".comet/config.yaml");
13294
+ const configured = await readClassicConfigValue("language");
13295
+ if (configured) return validateLanguage(configured.value, configured.source);
12322
13296
  return "en";
12323
13297
  }
12324
13298
  async function contextCompression() {
@@ -12346,14 +13320,14 @@ Valid values: off, standard, thorough`);
12346
13320
  return value === "null" ? null : value;
12347
13321
  }
12348
13322
  function gitOutput(args) {
12349
- const result3 = spawnSync3("git", args, { encoding: "utf8" });
12350
- return result3.status === 0 ? result3.stdout.trim() : null;
13323
+ const result5 = spawnSync3("git", args, { encoding: "utf8" });
13324
+ return result5.status === 0 ? result5.stdout.trim() : null;
12351
13325
  }
12352
13326
  async function stateFile(name) {
12353
- const change = await changeDirectory(name);
13327
+ const change = await changeDirectory2(name);
12354
13328
  return {
12355
13329
  ...change,
12356
- file: path17.join(change.directory, ".comet.yaml")
13330
+ file: path21.join(change.directory, ".comet.yaml")
12357
13331
  };
12358
13332
  }
12359
13333
  async function readField3(name, field2) {
@@ -12371,7 +13345,7 @@ async function readField3(name, field2) {
12371
13345
  return scalar(value);
12372
13346
  }
12373
13347
  function parsedValue(field2, value) {
12374
- const document = (0, import_yaml6.parseDocument)(`${field2}: ${value}
13348
+ const document = (0, import_yaml7.parseDocument)(`${field2}: ${value}
12375
13349
  `);
12376
13350
  if (document.errors.length > 0) fail2(`ERROR: Invalid value: '${value}'`);
12377
13351
  return document.get(field2);
@@ -12393,7 +13367,7 @@ function validateSetValue(field2, value) {
12393
13367
  }
12394
13368
  async function setField2(output, name, field2, value, options = {}) {
12395
13369
  if (MACHINE_OWNED_FIELDS.has(field2) && !options.machineOwned) {
12396
- fail2(`ERROR: '${field2}' is a machine-owned Run field and cannot be set directly`);
13370
+ fail2(`ERROR: '${field2}' is a machine-owned field and cannot be set directly`);
12397
13371
  }
12398
13372
  if (!SETTABLE_FIELDS.has(field2) && !MACHINE_OWNED_FIELDS.has(field2)) {
12399
13373
  fail2(`ERROR: Unknown field: '${field2}'`);
@@ -12456,10 +13430,10 @@ async function init(output, name, workflow) {
12456
13430
  validateEnum(workflow, PROFILES);
12457
13431
  const { file, label, directory } = await stateFile(name);
12458
13432
  if (await exists6(file)) fail2(`ERROR: .comet.yaml already exists at ${label}/.comet.yaml`);
12459
- await fs16.mkdir(directory, { recursive: true });
13433
+ await fs20.mkdir(directory, { recursive: true });
12460
13434
  const preset = workflow !== "full";
12461
13435
  const reviewMode = preset ? "off" : await reviewModeDefault();
12462
- const document = new import_yaml6.Document({
13436
+ const document = new import_yaml7.Document({
12463
13437
  workflow,
12464
13438
  language: await projectLanguageDefault(),
12465
13439
  phase: "open",
@@ -12469,17 +13443,19 @@ async function init(output, name, workflow) {
12469
13443
  subagent_dispatch: null,
12470
13444
  tdd_mode: preset ? "direct" : null,
12471
13445
  review_mode: reviewMode,
12472
- isolation: preset ? "branch" : null,
13446
+ isolation: preset ? "current" : null,
12473
13447
  verify_mode: preset ? "light" : null,
12474
13448
  auto_transition: await autoTransition() === "true",
12475
13449
  base_ref: gitOutput(["rev-parse", "--verify", "HEAD"]),
12476
13450
  design_doc: null,
12477
13451
  plan: null,
12478
13452
  verify_result: "pending",
13453
+ verify_failures: 0,
12479
13454
  verification_report: null,
12480
13455
  branch_status: "pending",
12481
13456
  created_at: (/* @__PURE__ */ new Date()).toISOString().slice(0, 10),
12482
13457
  verified_at: null,
13458
+ archive_confirmation: null,
12483
13459
  archived: false
12484
13460
  });
12485
13461
  await atomicWrite2(file, document.toString());
@@ -12499,9 +13475,10 @@ async function requireBuildDecisions(name) {
12499
13475
  const subagentDispatch = await readField3(name, "subagent_dispatch");
12500
13476
  const tddMode = await readField3(name, "tdd_mode");
12501
13477
  const reviewMode = await readField3(name, "review_mode");
12502
- if (!["branch", "worktree"].includes(isolation)) {
13478
+ const allowedIsolation = workflow === "full" ? ["branch", "worktree"] : ["current", "branch", "worktree"];
13479
+ if (!allowedIsolation.includes(isolation)) {
12503
13480
  fail2(
12504
- `ERROR: Cannot transition '${name}': isolation must be branch or worktree, got '${isolation || "null"}'`
13481
+ `ERROR: Cannot transition '${name}': isolation must be ${workflow === "full" ? "branch or worktree" : "current, branch, or worktree"}, got '${isolation || "null"}'`
12505
13482
  );
12506
13483
  }
12507
13484
  if (!["subagent-driven-development", "executing-plans", "direct"].includes(buildMode)) {
@@ -12534,13 +13511,13 @@ async function requireOpenArtifacts(name) {
12534
13511
  const { directory } = await stateFile(name);
12535
13512
  const workflow = await readField3(name, "workflow");
12536
13513
  for (const artifact of ["proposal.md", "tasks.md"]) {
12537
- if (!await nonempty3(path17.join(directory, artifact))) {
13514
+ if (!await nonempty3(path21.join(directory, artifact))) {
12538
13515
  fail2(
12539
13516
  `ERROR: Cannot transition '${name}': ${artifact} must exist and be non-empty before leaving open`
12540
13517
  );
12541
13518
  }
12542
13519
  }
12543
- if (workflow === "full" && !await nonempty3(path17.join(directory, "design.md"))) {
13520
+ if (workflow === "full" && !await nonempty3(path21.join(directory, "design.md"))) {
12544
13521
  fail2(
12545
13522
  `ERROR: Cannot transition '${name}': design.md must exist and be non-empty before leaving open`
12546
13523
  );
@@ -12548,14 +13525,14 @@ async function requireOpenArtifacts(name) {
12548
13525
  }
12549
13526
  async function requireDesignEvidence(name) {
12550
13527
  const designDoc = await readField3(name, "design_doc");
12551
- if (!designDoc || designDoc === "null" || !await nonempty3(path17.resolve(designDoc))) {
13528
+ if (!designDoc || designDoc === "null" || !await nonempty3(path21.resolve(designDoc))) {
12552
13529
  fail2(
12553
13530
  `ERROR: Cannot transition '${name}': design_doc must point to an existing Design Doc before leaving design`
12554
13531
  );
12555
13532
  }
12556
13533
  }
12557
13534
  async function writeSparseTransitionEffects(directory, effects) {
12558
- const file = path17.join(directory, ".comet.yaml");
13535
+ const file = path21.join(directory, ".comet.yaml");
12559
13536
  const document = await readDocument2(file);
12560
13537
  for (const effect of effects) {
12561
13538
  const field2 = wireField2(effect.field);
@@ -12570,21 +13547,21 @@ async function applyTransitionEvent(output, name, event) {
12570
13547
  let sparse = false;
12571
13548
  if (!classic) {
12572
13549
  if (projection.run) fail2("ERROR: Classic state projection is missing");
12573
- const document = await readDocument2(path17.join(directory, ".comet.yaml"));
13550
+ const document = await readDocument2(path21.join(directory, ".comet.yaml"));
12574
13551
  classic = sparseClassicState(document.toJS());
12575
13552
  sparse = true;
12576
13553
  }
12577
- const result3 = applyClassicTransition(classic, event);
13554
+ const result5 = applyClassicTransition(classic, event);
12578
13555
  if (projection.run) {
12579
- await transitionClassicRuntimeRun(directory, result3.classic, projection.run, {
13556
+ await transitionClassicRuntimeRun(directory, result5.classic, projection.run, {
12580
13557
  event,
12581
13558
  source: "comet-state"
12582
13559
  });
12583
13560
  } else if (sparse) {
12584
- await writeSparseTransitionEffects(directory, result3.effects);
13561
+ await writeSparseTransitionEffects(directory, result5.effects);
12585
13562
  } else {
12586
13563
  await writeClassicState(directory, {
12587
- classic: result3.classic,
13564
+ classic: result5.classic,
12588
13565
  run: null,
12589
13566
  unknownKeys: projection.unknownKeys
12590
13567
  });
@@ -12594,10 +13571,10 @@ async function applyTransitionEvent(output, name, event) {
12594
13571
  event,
12595
13572
  source: "comet-state",
12596
13573
  from: classic,
12597
- to: result3.classic,
12598
- effects: result3.effects
13574
+ to: result5.classic,
13575
+ effects: result5.effects
12599
13576
  });
12600
- for (const effect of result3.effects) {
13577
+ for (const effect of result5.effects) {
12601
13578
  output.stderr.push(green4(`[SET] ${wireField2(effect.field)}=${wireValue2(effect.to)}`));
12602
13579
  }
12603
13580
  output.stderr.push(green4(`[TRANSITION] ${event}`));
@@ -12617,16 +13594,21 @@ async function transition(output, name, event) {
12617
13594
  } else if (event === "verify-pass") {
12618
13595
  await requirePhase(name, "verify");
12619
13596
  const report = await readField3(name, "verification_report");
12620
- if (!report || !await exists6(path17.resolve(report))) {
13597
+ if (!report || !await exists6(path21.resolve(report))) {
12621
13598
  fail2(
12622
13599
  `ERROR: Cannot transition '${name}': verification_report must point to an existing report file`
12623
13600
  );
12624
13601
  }
12625
- if (await readField3(name, "branch_status") !== "handled") {
12626
- fail2(`ERROR: Cannot transition '${name}': branch_status must be handled`);
12627
- }
12628
13602
  } else if (event === "verify-fail") {
12629
13603
  await requirePhase(name, "verify");
13604
+ } else if (event === "archive-confirm") {
13605
+ await requirePhase(name, "archive");
13606
+ if (await readField3(name, "verify_result") !== "pass") {
13607
+ fail2(`ERROR: Cannot transition '${name}': verify_result must be pass before archiving`);
13608
+ }
13609
+ if (await readField3(name, "archived") === "true") {
13610
+ fail2(`ERROR: Cannot transition '${name}': already archived`);
13611
+ }
12630
13612
  } else if (event === "preset-escalate") {
12631
13613
  await requirePhase(name, "build");
12632
13614
  const workflow = await readField3(name, "workflow");
@@ -12645,6 +13627,11 @@ async function transition(output, name, event) {
12645
13627
  if (await readField3(name, "verify_result") !== "pass") {
12646
13628
  fail2(`ERROR: Cannot transition '${name}': verify_result must be pass before archiving`);
12647
13629
  }
13630
+ if (await readField3(name, "archive_confirmation") !== "confirmed") {
13631
+ fail2(
13632
+ `ERROR: Cannot transition '${name}': archive_confirmation must be confirmed before archiving`
13633
+ );
13634
+ }
12648
13635
  }
12649
13636
  await applyTransitionEvent(output, name, event);
12650
13637
  }
@@ -12671,9 +13658,9 @@ async function next(output, name) {
12671
13658
  async function taskCheckoff(output, taskFile, taskText) {
12672
13659
  validateRelativePath(taskFile, "task file");
12673
13660
  if (!taskText) fail2("ERROR: Task text cannot be empty");
12674
- const file = path17.resolve(taskFile);
13661
+ const file = path21.resolve(taskFile);
12675
13662
  if (!await exists6(file)) fail2(`ERROR: Task file not found: ${taskFile}`);
12676
- const lines = (await fs16.readFile(file, "utf8")).split(/\r?\n/u);
13663
+ const lines = (await fs20.readFile(file, "utf8")).split(/\r?\n/u);
12677
13664
  const matches = lines.filter(
12678
13665
  (line) => [`- [ ] ${taskText}`, `- [x] ${taskText}`, `- [X] ${taskText}`].includes(line)
12679
13666
  );
@@ -12711,21 +13698,21 @@ async function check2(output, name, phase) {
12711
13698
  designDoc ? `design_doc=${designDoc} (expected: empty/null)` : "design_doc is empty/null"
12712
13699
  );
12713
13700
  for (const artifact of ["proposal.md", "design.md", "tasks.md"]) {
12714
- (await nonempty3(path17.join(directory, artifact)) ? pass2 : reject)(
12715
- `${artifact} ${await nonempty3(path17.join(directory, artifact)) ? "non-empty" : "missing or empty"}`
13701
+ (await nonempty3(path21.join(directory, artifact)) ? pass2 : reject)(
13702
+ `${artifact} ${await nonempty3(path21.join(directory, artifact)) ? "non-empty" : "missing or empty"}`
12716
13703
  );
12717
13704
  }
12718
13705
  } else if (phase === "build") {
12719
13706
  const workflow = await readField3(name, "workflow");
12720
13707
  const designDoc = await readField3(name, "design_doc");
12721
13708
  if (workflow === "full") {
12722
- (designDoc && designDoc !== "null" && await exists6(path17.resolve(designDoc)) ? pass2 : reject)(`design_doc=${designDoc} (expected: non-null and file exists)`);
13709
+ (designDoc && designDoc !== "null" && await exists6(path21.resolve(designDoc)) ? pass2 : reject)(`design_doc=${designDoc} (expected: non-null and file exists)`);
12723
13710
  } else {
12724
13711
  pass2(`workflow=${workflow} (design_doc not required)`);
12725
13712
  }
12726
13713
  for (const artifact of ["proposal.md", "tasks.md"]) {
12727
- (await nonempty3(path17.join(directory, artifact)) ? pass2 : reject)(
12728
- `${artifact} ${await nonempty3(path17.join(directory, artifact)) ? "non-empty" : "missing or empty"}`
13714
+ (await nonempty3(path21.join(directory, artifact)) ? pass2 : reject)(
13715
+ `${artifact} ${await nonempty3(path21.join(directory, artifact)) ? "non-empty" : "missing or empty"}`
12729
13716
  );
12730
13717
  }
12731
13718
  } else if (phase === "verify") {
@@ -12747,7 +13734,7 @@ async function check2(output, name, phase) {
12747
13734
  }
12748
13735
  function fieldStatus(field2, value, file) {
12749
13736
  if (!value || value === "null") return ` - ${field2}: PENDING`;
12750
- if (file && !existsSync3(path17.resolve(file))) {
13737
+ if (file && !existsSync3(path21.resolve(file))) {
12751
13738
  return ` - ${field2}: BROKEN (path ${value} does not exist)`;
12752
13739
  }
12753
13740
  return ` - ${field2}: DONE (${value})`;
@@ -12756,7 +13743,7 @@ async function recoverOpen(output, directory) {
12756
13743
  output.stdout.push(" Artifacts:");
12757
13744
  let complete = 0;
12758
13745
  for (const artifact of ["proposal.md", "design.md", "tasks.md"]) {
12759
- const done = await nonempty3(path17.join(directory, artifact));
13746
+ const done = await nonempty3(path21.join(directory, artifact));
12760
13747
  if (done) complete += 1;
12761
13748
  output.stdout.push(` - ${artifact}: ${done ? "DONE" : "PENDING"}`);
12762
13749
  }
@@ -12769,7 +13756,7 @@ async function recoverDesign(output, name, directory) {
12769
13756
  output.stdout.push(" Artifacts:");
12770
13757
  for (const artifact of ["proposal.md", "design.md", "tasks.md"]) {
12771
13758
  output.stdout.push(
12772
- ` - ${artifact}: ${await nonempty3(path17.join(directory, artifact)) ? "DONE" : "MISSING (unexpected in design phase)"}`
13759
+ ` - ${artifact}: ${await nonempty3(path21.join(directory, artifact)) ? "DONE" : "MISSING (unexpected in design phase)"}`
12773
13760
  );
12774
13761
  }
12775
13762
  const handoff = await readField3(name, "handoff_context");
@@ -12783,11 +13770,11 @@ async function recoverDesign(output, name, directory) {
12783
13770
  fieldStatus("design_doc", design, design),
12784
13771
  ""
12785
13772
  );
12786
- if (design && design !== "null" && await exists6(path17.resolve(design))) {
13773
+ if (design && design !== "null" && await exists6(path21.resolve(design))) {
12787
13774
  output.stdout.push(
12788
13775
  "Recovery action: Design Doc already created and linked. Run guard to transition to build."
12789
13776
  );
12790
- } else if (handoff && handoff !== "null" && await exists6(path17.resolve(handoff))) {
13777
+ } else if (handoff && handoff !== "null" && await exists6(path21.resolve(handoff))) {
12791
13778
  output.stdout.push(
12792
13779
  "Recovery action: Handoff generated but Design Doc not yet created. Resume from brainstorming confirmation (Step 1c)."
12793
13780
  );
@@ -12817,7 +13804,7 @@ async function recoverBuild(output, name, directory, workflow) {
12817
13804
  decisions.push(fieldStatus("subagent_dispatch", subagentDispatch));
12818
13805
  }
12819
13806
  output.stdout.push(...decisions, "", " Plan:", fieldStatus("plan", plan, plan), "");
12820
- const tasks = path17.join(directory, "tasks.md");
13807
+ const tasks = path21.join(directory, "tasks.md");
12821
13808
  if (!await exists6(tasks)) {
12822
13809
  output.stdout.push(
12823
13810
  " Tasks: tasks.md MISSING",
@@ -12826,14 +13813,14 @@ async function recoverBuild(output, name, directory, workflow) {
12826
13813
  );
12827
13814
  return;
12828
13815
  }
12829
- const lines = (await fs16.readFile(tasks, "utf8")).split(/\r?\n/u);
13816
+ const lines = (await fs20.readFile(tasks, "utf8")).split(/\r?\n/u);
12830
13817
  const total = lines.filter((line) => /^\s*- \[[ xX]\] /u.test(line)).length;
12831
13818
  const done = lines.filter((line) => /^\s*- \[[xX]\] /u.test(line)).length;
12832
13819
  const pending = total - done;
12833
13820
  let planTotal = 0;
12834
13821
  let planDone = 0;
12835
- if (plan && plan !== "null" && await exists6(path17.resolve(plan))) {
12836
- const planLines = (await fs16.readFile(path17.resolve(plan), "utf8")).split(/\r?\n/u);
13822
+ if (plan && plan !== "null" && await exists6(path21.resolve(plan))) {
13823
+ const planLines = (await fs20.readFile(path21.resolve(plan), "utf8")).split(/\r?\n/u);
12837
13824
  planTotal = planLines.filter((line) => /^\s*- \[[ xX]\] /u.test(line)).length;
12838
13825
  planDone = planLines.filter((line) => /^\s*- \[[xX]\] /u.test(line)).length;
12839
13826
  }
@@ -12871,7 +13858,7 @@ function resolveBuildRecoveryAction(workflow, isolation, buildMode, pause, subag
12871
13858
  }
12872
13859
  if (pause === "plan-ready") {
12873
13860
  if (buildMode === "subagent-driven-development" && (pending > 0 || planPending > 0)) {
12874
- return subagentDispatch === "confirmed" ? "Recovery action: Plan-ready pause is stale because build decisions are already selected. Clear build_pause to null, then inspect the first unchecked task (OpenSpec or plan additions) against recent git history/diff. If implemented, check it off; otherwise dispatch a real background subagent. Do not execute the pending task directly in the main window." : "Recovery action: Plan-ready pause is stale and subagent dispatch is not confirmed. Confirm a real background subagent/Task/multi-agent dispatcher and set subagent_dispatch to confirmed, or set build_mode to executing-plans before continuing.";
13861
+ return subagentDispatch === "confirmed" ? "Recovery action: Plan-ready pause is stale because build decisions are already selected. Clear build_pause to null, then inspect the first unchecked task (OpenSpec or plan additions) against recent git history/diff. If implemented, check it off; otherwise dispatch a real background subagent. Do not execute the pending task directly in the main window." : "Recovery action: Plan-ready pause is stale and subagent dispatch is not confirmed. Return to /comet-build Step 2 capability preflight. Confirm a real background subagent/Task/multi-agent dispatcher and set subagent_dispatch to confirmed, or remove the unavailable mode and set build_mode to executing-plans before continuing.";
12875
13862
  }
12876
13863
  if (pending > 0 || planPending > 0) {
12877
13864
  return "Recovery action: Plan-ready pause is stale because build decisions are already selected. Clear build_pause to null, then continue from the first unchecked task.";
@@ -12892,40 +13879,44 @@ function resolveBuildRecoveryAction(workflow, isolation, buildMode, pause, subag
12892
13879
  }
12893
13880
  if (pending > 0) {
12894
13881
  if (buildMode === "subagent-driven-development") {
12895
- return subagentDispatch === "confirmed" ? "Recovery action: Read tasks.md and the Superpowers plan (which may include additions beyond OpenSpec), then inspect the first unchecked task against recent git history/diff. If implemented, check it off; otherwise dispatch a real background subagent. Do not execute the pending task directly in the main window." : "Recovery action: Subagent dispatch is not confirmed. Confirm a real background subagent/Task/multi-agent dispatcher and set subagent_dispatch to confirmed, or set build_mode to executing-plans before continuing.";
13882
+ return subagentDispatch === "confirmed" ? "Recovery action: Read tasks.md and the Superpowers plan (which may include additions beyond OpenSpec), then inspect the first unchecked task against recent git history/diff. If implemented, check it off; otherwise dispatch a real background subagent. Do not execute the pending task directly in the main window." : "Recovery action: Subagent dispatch is not confirmed. Return to /comet-build Step 2 capability preflight. Confirm a real background subagent/Task/multi-agent dispatcher and set subagent_dispatch to confirmed, or remove the unavailable mode and set build_mode to executing-plans before continuing.";
12896
13883
  }
12897
13884
  return "Recovery action: Read tasks.md and continue from first unchecked task.";
12898
13885
  }
12899
13886
  if (planPending > 0) {
12900
13887
  if (buildMode === "subagent-driven-development") {
12901
- return subagentDispatch === "confirmed" ? "Recovery action: Read the Superpowers plan, then inspect the first unchecked Superpowers plan task against recent git history/diff. If implemented, check it off; otherwise dispatch a real background subagent. Do not execute the pending task directly in the main window." : "Recovery action: Subagent dispatch is not confirmed. Confirm a real background subagent/Task/multi-agent dispatcher and set subagent_dispatch to confirmed, or set build_mode to executing-plans before continuing.";
13888
+ return subagentDispatch === "confirmed" ? "Recovery action: Read the Superpowers plan, then inspect the first unchecked Superpowers plan task against recent git history/diff. If implemented, check it off; otherwise dispatch a real background subagent. Do not execute the pending task directly in the main window." : "Recovery action: Subagent dispatch is not confirmed. Return to /comet-build Step 2 capability preflight. Confirm a real background subagent/Task/multi-agent dispatcher and set subagent_dispatch to confirmed, or remove the unavailable mode and set build_mode to executing-plans before continuing.";
12902
13889
  }
12903
13890
  return "Recovery action: Read the Superpowers plan and continue from the first unchecked plan task.";
12904
13891
  }
12905
13892
  return "Recovery action: All tasks done. Run guard to transition to verify.";
12906
13893
  }
12907
13894
  async function recoverVerify(output, name) {
12908
- const result3 = await readField3(name, "verify_result");
13895
+ const result5 = await readField3(name, "verify_result");
13896
+ const failures = await readField3(name, "verify_failures");
12909
13897
  const mode = await readField3(name, "verify_mode");
12910
13898
  const report = await readField3(name, "verification_report");
12911
13899
  const branch = await readField3(name, "branch_status");
12912
13900
  output.stdout.push(
12913
13901
  " Verification:",
12914
- fieldStatus("verify_result", result3),
13902
+ fieldStatus("verify_result", result5),
13903
+ ` - verify_failures: ${failures || "0"}`,
12915
13904
  fieldStatus("verify_mode", mode),
12916
13905
  fieldStatus("verification_report", report, report),
12917
- fieldStatus("branch_status", branch),
13906
+ branch === "handled" ? " - branch_status: LEGACY (handled before archive; archive still owns final closure)" : " - branch_status: DEFERRED (handled after the archive commit)",
12918
13907
  "",
12919
- result3 === "pass" && branch === "handled" ? "Recovery action: Verification complete. Run guard to transition to archive." : result3 === "fail" ? "Recovery action: Verification failed and rolled back to build. Resume from /comet-build." : "Recovery action: Verification not yet started or in progress. Run scale assessment then verify."
13908
+ result5 === "pass" ? "Recovery action: Verification complete. Continue to archive; branch handling happens after archive changes are committed." : result5 === "fail" ? "Recovery action: Verification failed and rolled back to build. Resume from /comet-build." : "Recovery action: Verification not yet started or in progress. Run scale assessment then verify."
12920
13909
  );
12921
13910
  }
12922
13911
  async function recoverArchive(output, name) {
13912
+ const archiveConfirmation = await readField3(name, "archive_confirmation");
12923
13913
  output.stdout.push(
12924
13914
  " Archive:",
12925
13915
  fieldStatus("verify_result", await readField3(name, "verify_result")),
13916
+ fieldStatus("archive_confirmation", archiveConfirmation),
12926
13917
  fieldStatus("archived", await readField3(name, "archived")),
12927
13918
  "",
12928
- "Recovery action: Run /comet-archive to complete archiving."
13919
+ archiveConfirmation === "confirmed" ? "Recovery action: Archive is confirmed. Run /comet-archive to complete archiving." : "Recovery action: Ask for final archive confirmation in /comet-archive before running the archive command."
12929
13920
  );
12930
13921
  }
12931
13922
  async function recover(output, name) {
@@ -12960,19 +13951,19 @@ async function scale(output, name) {
12960
13951
  validateChangeName4(name);
12961
13952
  const { file, directory, label } = await stateFile(name);
12962
13953
  if (!await exists6(file)) fail2(`ERROR: .comet.yaml not found at ${label}/.comet.yaml`);
12963
- const tasksFile = path17.join(directory, "tasks.md");
12964
- const taskCount = await exists6(tasksFile) ? (await fs16.readFile(tasksFile, "utf8")).split(/\r?\n/u).filter((line) => /^- \[/u.test(line)).length : 0;
12965
- const specs = path17.join(directory, "specs");
13954
+ const tasksFile = path21.join(directory, "tasks.md");
13955
+ const taskCount = await exists6(tasksFile) ? (await fs20.readFile(tasksFile, "utf8")).split(/\r?\n/u).filter((line) => /^- \[/u.test(line)).length : 0;
13956
+ const specs = path21.join(directory, "specs");
12966
13957
  let deltaSpecs = 0;
12967
13958
  if (await exists6(specs)) {
12968
- for (const entry2 of await fs16.readdir(specs)) {
12969
- if (await exists6(path17.join(specs, entry2, "spec.md"))) deltaSpecs += 1;
13959
+ for (const entry2 of await fs20.readdir(specs)) {
13960
+ if (await exists6(path21.join(specs, entry2, "spec.md"))) deltaSpecs += 1;
12970
13961
  }
12971
13962
  }
12972
13963
  const plan = await readField3(name, "plan");
12973
13964
  let baseRef = "";
12974
- if (plan && plan !== "null" && await exists6(path17.resolve(plan))) {
12975
- const match = (await fs16.readFile(path17.resolve(plan), "utf8")).match(/^base-ref:\s*(.+)$/mu);
13965
+ if (plan && plan !== "null" && await exists6(path21.resolve(plan))) {
13966
+ const match = (await fs20.readFile(path21.resolve(plan), "utf8")).match(/^base-ref:\s*(.+)$/mu);
12976
13967
  baseRef = match?.[1].trim() ?? "";
12977
13968
  }
12978
13969
  if (!baseRef) baseRef = await readField3(name, "base_ref");
@@ -12982,19 +13973,102 @@ async function scale(output, name) {
12982
13973
  ...baseRef && baseRef !== "null" ? [`${baseRef}...HEAD`] : ["HEAD"]
12983
13974
  ]);
12984
13975
  const changedFiles = changed ? changed.split(/\r?\n/u).filter(Boolean).length : 0;
12985
- const result3 = taskCount > 3 || deltaSpecs > 1 || changedFiles > 8 ? "full" : "light";
12986
- await setField2(new CommandOutput(), name, "verify_mode", result3);
13976
+ const result5 = taskCount > 3 || deltaSpecs > 1 || changedFiles > 8 ? "full" : "light";
13977
+ await setField2(new CommandOutput(), name, "verify_mode", result5);
12987
13978
  output.stderr.push(
12988
13979
  `=== Scale Assessment: ${name} ===`,
12989
13980
  ` Tasks: ${taskCount} (threshold: 3)`,
12990
13981
  ` Delta specs: ${deltaSpecs} capabilities (threshold: 1)`,
12991
13982
  ` Changed files: ${changedFiles} (threshold: 8)`,
12992
- ` → Result: ${result3}`,
12993
- green4(`[SCALE] verify_mode=${result3}`)
13983
+ ` → Result: ${result5}`,
13984
+ green4(`[SCALE] verify_mode=${result5}`)
12994
13985
  );
12995
13986
  }
12996
- function required(args, count, usage2) {
12997
- if (args.length < count) fail2(usage2);
13987
+ function parseRecordCheckOptions(args) {
13988
+ let command;
13989
+ let exitCodeText;
13990
+ let cwd;
13991
+ for (let index = 0; index < args.length; index += 2) {
13992
+ const option = args[index];
13993
+ if (!["--command", "--exit-code", "--cwd"].includes(option)) {
13994
+ fail2(`ERROR: Unknown option: ${option}`);
13995
+ }
13996
+ const value = args[index + 1];
13997
+ if (value === void 0) fail2(`ERROR: Missing value for option: ${option}`);
13998
+ if (option === "--command") command = value;
13999
+ else if (option === "--exit-code") exitCodeText = value;
14000
+ else cwd = value;
14001
+ }
14002
+ if (command === void 0) fail2("ERROR: Missing option: --command");
14003
+ if (exitCodeText === void 0) fail2("ERROR: Missing option: --exit-code");
14004
+ if (!/^-?\d+$/u.test(exitCodeText)) fail2("ERROR: --exit-code must be an integer");
14005
+ return { command, exitCode: Number(exitCodeText), ...cwd === void 0 ? {} : { cwd } };
14006
+ }
14007
+ async function recordCheck(output, name, scopeText, args) {
14008
+ validateChangeName4(name);
14009
+ if (scopeText !== "build" && scopeText !== "verify") {
14010
+ fail2(`ERROR: Invalid command check scope: '${scopeText}'`);
14011
+ }
14012
+ const options = parseRecordCheckOptions(args);
14013
+ const { label, directory, file } = await stateFile(name);
14014
+ if (label !== `openspec/changes/${name}` || !await exists6(file)) {
14015
+ fail2(`ERROR: command checks require an active change: ${name}`);
14016
+ }
14017
+ try {
14018
+ const projection = await readClassicState(directory, { migrate: false });
14019
+ if (!projection.classic || !projection.run) {
14020
+ throw new Error("command checks require an existing synchronized Classic Run");
14021
+ }
14022
+ const { run } = await validateClassicRuntimeRun(directory, projection);
14023
+ const recorded = await recordCommandCheck(directory, run, {
14024
+ scope: scopeText,
14025
+ ...options
14026
+ });
14027
+ output.stderr.push(
14028
+ green4(
14029
+ `[RECORDED] ${recorded.scope} exit=${recorded.exitCode} cwd=${recorded.cwd} command=${recorded.command}`
14030
+ )
14031
+ );
14032
+ } catch (error) {
14033
+ fail2(`ERROR: ${error.message}`);
14034
+ }
14035
+ }
14036
+ function required(args, count, usage3) {
14037
+ if (args.length < count) fail2(usage3);
14038
+ }
14039
+ function requiredExact(args, count, usage3) {
14040
+ if (args.length !== count) fail2(usage3);
14041
+ }
14042
+ async function selectChange(output, name) {
14043
+ validateChangeName4(name);
14044
+ try {
14045
+ const selection = await selectCurrentChange(process.cwd(), name);
14046
+ output.stderr.push(
14047
+ green4(
14048
+ `[SELECTED] current change: ${selection.change}${selection.branch ? ` (branch: ${selection.branch})` : ""}`
14049
+ )
14050
+ );
14051
+ } catch (error) {
14052
+ fail2(`ERROR: ${error instanceof Error ? error.message : String(error)}`);
14053
+ }
14054
+ }
14055
+ async function currentChange(output) {
14056
+ const resolution = await resolveCurrentChange(process.cwd());
14057
+ if (resolution.status === "selected") {
14058
+ output.stdout.push(resolution.selection.change);
14059
+ return;
14060
+ }
14061
+ if (resolution.status === "missing") {
14062
+ fail2("ERROR: no current change selected\nUse: comet-state.mjs select <change-name>");
14063
+ }
14064
+ fail2(
14065
+ `ERROR: current change selection is stale: ${resolution.reason}
14066
+ Use: comet-state.mjs select <change-name>`
14067
+ );
14068
+ }
14069
+ async function clearSelection(output) {
14070
+ await clearCurrentChange(process.cwd());
14071
+ output.stderr.push(green4("[CLEARED] current change selection"));
12998
14072
  }
12999
14073
  var classicStateCommand = async (args) => {
13000
14074
  const output = new CommandOutput();
@@ -13021,9 +14095,25 @@ var classicStateCommand = async (args) => {
13021
14095
  } else if (subcommand === "scale") {
13022
14096
  required(rest, 1, "Usage: comet-state.mjs scale <change-name>");
13023
14097
  await scale(output, rest[0]);
14098
+ } else if (subcommand === "record-check") {
14099
+ required(
14100
+ rest,
14101
+ 2,
14102
+ "Usage: comet state record-check <change> <build|verify> --command <text> --exit-code <int> [--cwd <path>]"
14103
+ );
14104
+ await recordCheck(output, rest[0], rest[1], rest.slice(2));
13024
14105
  } else if (subcommand === "task-checkoff") {
13025
14106
  required(rest, 2, "Usage: comet-state.mjs task-checkoff <file> <task-text>");
13026
14107
  await taskCheckoff(output, rest[0], rest[1]);
14108
+ } else if (subcommand === "select") {
14109
+ requiredExact(rest, 1, "Usage: comet-state.mjs select <change-name>");
14110
+ await selectChange(output, rest[0]);
14111
+ } else if (subcommand === "current") {
14112
+ requiredExact(rest, 0, "Usage: comet-state.mjs current");
14113
+ await currentChange(output);
14114
+ } else if (subcommand === "clear-selection") {
14115
+ requiredExact(rest, 0, "Usage: comet-state.mjs clear-selection");
14116
+ await clearSelection(output);
13027
14117
  } else if (subcommand === "next") {
13028
14118
  required(rest, 1, "Usage: comet-state.mjs next <change-name>");
13029
14119
  await next(output, rest[0]);
@@ -13048,7 +14138,8 @@ var CLASSIC_COMMANDS = [
13048
14138
  "handoff",
13049
14139
  "archive",
13050
14140
  "hook-guard",
13051
- "intent"
14141
+ "intent",
14142
+ "resume-probe"
13052
14143
  ];
13053
14144
  var DEFAULT_HANDLERS = {
13054
14145
  state: classicStateCommand,
@@ -13057,7 +14148,8 @@ var DEFAULT_HANDLERS = {
13057
14148
  handoff: classicHandoffCommand,
13058
14149
  archive: classicArchiveCommand,
13059
14150
  "hook-guard": classicHookGuardCommand,
13060
- intent: classicIntentCommand
14151
+ intent: classicIntentCommand,
14152
+ "resume-probe": classicResumeProbeCommand
13061
14153
  };
13062
14154
  function isClassicCommand(value) {
13063
14155
  return CLASSIC_COMMANDS.includes(value);
@@ -13092,14 +14184,14 @@ async function dispatch(command, args, options, handlers) {
13092
14184
  };
13093
14185
  }
13094
14186
  }
13095
- function jsonResult(command, result3) {
14187
+ function jsonResult(command, result5) {
13096
14188
  return {
13097
- exitCode: result3.exitCode,
14189
+ exitCode: result5.exitCode,
13098
14190
  stdout: JSON.stringify({
13099
14191
  command: command ?? null,
13100
- exitCode: result3.exitCode,
13101
- ...result3.stdout === void 0 ? {} : { stdout: result3.stdout },
13102
- ...result3.stderr === void 0 ? {} : { stderr: result3.stderr }
14192
+ exitCode: result5.exitCode,
14193
+ ...result5.stdout === void 0 ? {} : { stdout: result5.stdout },
14194
+ ...result5.stderr === void 0 ? {} : { stderr: result5.stderr }
13103
14195
  }) + "\n"
13104
14196
  };
13105
14197
  }
@@ -13107,15 +14199,15 @@ async function runClassicCli(argv, handlers = DEFAULT_HANDLERS) {
13107
14199
  const json = argv.includes("--json");
13108
14200
  const args = argv.filter((argument) => argument !== "--json");
13109
14201
  const command = args.shift();
13110
- const result3 = await dispatch(command, args, { json }, handlers);
13111
- return json ? jsonResult(command, result3) : result3;
14202
+ const result5 = await dispatch(command, args, { json }, handlers);
14203
+ return json ? jsonResult(command, result5) : result5;
13112
14204
  }
13113
14205
  async function main(argv = process.argv.slice(2)) {
13114
- const result3 = await runClassicCli(argv);
13115
- if (result3.stdout) process.stdout.write(result3.stdout);
13116
- if (result3.stderr)
13117
- process.stderr.write(result3.stderr + (result3.stderr.endsWith("\n") ? "" : "\n"));
13118
- return result3.exitCode;
14206
+ const result5 = await runClassicCli(argv);
14207
+ if (result5.stdout) process.stdout.write(result5.stdout);
14208
+ if (result5.stderr)
14209
+ process.stderr.write(result5.stderr + (result5.stderr.endsWith("\n") ? "" : "\n"));
14210
+ return result5.exitCode;
13119
14211
  }
13120
14212
  var entry = process.argv[1];
13121
14213
  if (entry && import.meta.url === pathToFileURL(entry).href) {