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

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 (508) hide show
  1. package/README.md +10 -0
  2. package/assets/manifest.json +2 -1
  3. package/assets/skills/comet/SKILL.md +25 -1
  4. package/assets/skills/comet/reference/comet-yaml-fields.md +5 -2
  5. package/assets/skills/comet/reference/context-recovery.md +10 -0
  6. package/assets/skills/comet/reference/scripts.md +47 -15
  7. package/assets/skills/comet/rules/comet-phase-guard.en.md +8 -0
  8. package/assets/skills/comet/rules/comet-phase-guard.md +9 -1
  9. package/assets/skills/comet/scripts/comet-resume-probe.mjs +3 -0
  10. package/assets/skills/comet/scripts/comet-runtime.mjs +1387 -424
  11. package/assets/skills/comet-archive/SKILL.md +24 -11
  12. package/assets/skills/comet-build/SKILL.md +42 -25
  13. package/assets/skills/comet-design/SKILL.md +1 -0
  14. package/assets/skills/comet-hotfix/SKILL.md +3 -1
  15. package/assets/skills/comet-open/SKILL.md +11 -1
  16. package/assets/skills/comet-tweak/SKILL.md +3 -1
  17. package/assets/skills/comet-verify/SKILL.md +29 -20
  18. package/assets/skills-zh/comet/SKILL.md +25 -1
  19. package/assets/skills-zh/comet/reference/comet-yaml-fields.md +5 -2
  20. package/assets/skills-zh/comet/reference/context-recovery.md +10 -0
  21. package/assets/skills-zh/comet/reference/scripts.md +47 -15
  22. package/assets/skills-zh/comet-archive/SKILL.md +24 -11
  23. package/assets/skills-zh/comet-build/SKILL.md +42 -25
  24. package/assets/skills-zh/comet-design/SKILL.md +1 -0
  25. package/assets/skills-zh/comet-hotfix/SKILL.md +3 -1
  26. package/assets/skills-zh/comet-open/SKILL.md +11 -1
  27. package/assets/skills-zh/comet-tweak/SKILL.md +3 -1
  28. package/assets/skills-zh/comet-verify/SKILL.md +30 -21
  29. package/dist/app/cli/comet-banner.d.ts +25 -0
  30. package/dist/app/cli/comet-banner.d.ts.map +1 -0
  31. package/dist/app/cli/comet-banner.js +265 -0
  32. package/dist/app/cli/comet-banner.js.map +1 -0
  33. package/dist/app/cli/index.js +36 -2
  34. package/dist/app/cli/index.js.map +1 -1
  35. package/dist/app/commands/classic.d.ts +4 -0
  36. package/dist/app/commands/classic.d.ts.map +1 -0
  37. package/dist/app/commands/classic.js +11 -0
  38. package/dist/app/commands/classic.js.map +1 -0
  39. package/dist/app/commands/doctor.d.ts.map +1 -1
  40. package/dist/app/commands/doctor.js +39 -24
  41. package/dist/app/commands/doctor.js.map +1 -1
  42. package/dist/app/commands/eval.d.ts.map +1 -1
  43. package/dist/app/commands/eval.js +57 -20
  44. package/dist/app/commands/eval.js.map +1 -1
  45. package/dist/app/commands/i18n.d.ts +1 -1
  46. package/dist/app/commands/i18n.d.ts.map +1 -1
  47. package/dist/app/commands/i18n.js +12 -4
  48. package/dist/app/commands/i18n.js.map +1 -1
  49. package/dist/app/commands/init.d.ts.map +1 -1
  50. package/dist/app/commands/init.js +16 -13
  51. package/dist/app/commands/init.js.map +1 -1
  52. package/dist/app/commands/project-scope-selection.d.ts +13 -0
  53. package/dist/app/commands/project-scope-selection.d.ts.map +1 -0
  54. package/dist/app/commands/project-scope-selection.js +33 -0
  55. package/dist/app/commands/project-scope-selection.js.map +1 -0
  56. package/dist/app/commands/resume-probe.d.ts +11 -0
  57. package/dist/app/commands/resume-probe.d.ts.map +1 -0
  58. package/dist/app/commands/resume-probe.js +63 -0
  59. package/dist/app/commands/resume-probe.js.map +1 -0
  60. package/dist/app/commands/status.d.ts +31 -0
  61. package/dist/app/commands/status.d.ts.map +1 -1
  62. package/dist/app/commands/status.js +109 -20
  63. package/dist/app/commands/status.js.map +1 -1
  64. package/dist/app/commands/uninstall.d.ts +2 -0
  65. package/dist/app/commands/uninstall.d.ts.map +1 -1
  66. package/dist/app/commands/uninstall.js +217 -40
  67. package/dist/app/commands/uninstall.js.map +1 -1
  68. package/dist/app/commands/update.d.ts +6 -0
  69. package/dist/app/commands/update.d.ts.map +1 -1
  70. package/dist/app/commands/update.js +361 -68
  71. package/dist/app/commands/update.js.map +1 -1
  72. package/dist/config/repository-layout.json +4 -2
  73. package/dist/domains/bundle/bundle-platform.d.ts.map +1 -1
  74. package/dist/domains/bundle/bundle-platform.js +3 -1
  75. package/dist/domains/bundle/bundle-platform.js.map +1 -1
  76. package/dist/domains/bundle/eval-manifest-runtime.d.ts +6 -0
  77. package/dist/domains/bundle/eval-manifest-runtime.d.ts.map +1 -0
  78. package/dist/domains/bundle/eval-manifest-runtime.js +58 -0
  79. package/dist/domains/bundle/eval-manifest-runtime.js.map +1 -0
  80. package/dist/domains/bundle/types.d.ts +1 -1
  81. package/dist/domains/bundle/types.d.ts.map +1 -1
  82. package/dist/domains/comet-classic/classic-archive.d.ts +1 -0
  83. package/dist/domains/comet-classic/classic-archive.d.ts.map +1 -1
  84. package/dist/domains/comet-classic/classic-archive.js +35 -38
  85. package/dist/domains/comet-classic/classic-archive.js.map +1 -1
  86. package/dist/domains/comet-classic/classic-cli.d.ts +1 -1
  87. package/dist/domains/comet-classic/classic-cli.d.ts.map +1 -1
  88. package/dist/domains/comet-classic/classic-cli.js +3 -0
  89. package/dist/domains/comet-classic/classic-cli.js.map +1 -1
  90. package/dist/domains/comet-classic/classic-command-checks.d.ts +20 -0
  91. package/dist/domains/comet-classic/classic-command-checks.d.ts.map +1 -0
  92. package/dist/domains/comet-classic/classic-command-checks.js +97 -0
  93. package/dist/domains/comet-classic/classic-command-checks.js.map +1 -0
  94. package/dist/domains/comet-classic/classic-current-change.d.ts +19 -0
  95. package/dist/domains/comet-classic/classic-current-change.d.ts.map +1 -0
  96. package/dist/domains/comet-classic/classic-current-change.js +132 -0
  97. package/dist/domains/comet-classic/classic-current-change.js.map +1 -0
  98. package/dist/domains/comet-classic/classic-diagnostics.d.ts +2 -1
  99. package/dist/domains/comet-classic/classic-diagnostics.d.ts.map +1 -1
  100. package/dist/domains/comet-classic/classic-diagnostics.js +54 -1
  101. package/dist/domains/comet-classic/classic-diagnostics.js.map +1 -1
  102. package/dist/domains/comet-classic/classic-evidence.d.ts.map +1 -1
  103. package/dist/domains/comet-classic/classic-evidence.js +4 -0
  104. package/dist/domains/comet-classic/classic-evidence.js.map +1 -1
  105. package/dist/domains/comet-classic/classic-guard.d.ts.map +1 -1
  106. package/dist/domains/comet-classic/classic-guard.js +68 -69
  107. package/dist/domains/comet-classic/classic-guard.js.map +1 -1
  108. package/dist/domains/comet-classic/classic-hook-guard.d.ts.map +1 -1
  109. package/dist/domains/comet-classic/classic-hook-guard.js +66 -23
  110. package/dist/domains/comet-classic/classic-hook-guard.js.map +1 -1
  111. package/dist/domains/comet-classic/classic-project-config.d.ts +16 -0
  112. package/dist/domains/comet-classic/classic-project-config.d.ts.map +1 -0
  113. package/dist/domains/comet-classic/classic-project-config.js +40 -0
  114. package/dist/domains/comet-classic/classic-project-config.js.map +1 -0
  115. package/dist/domains/comet-classic/classic-resolver.d.ts.map +1 -1
  116. package/dist/domains/comet-classic/classic-resolver.js +3 -3
  117. package/dist/domains/comet-classic/classic-resolver.js.map +1 -1
  118. package/dist/domains/comet-classic/classic-resume-probe-command.d.ts +3 -0
  119. package/dist/domains/comet-classic/classic-resume-probe-command.d.ts.map +1 -0
  120. package/dist/domains/comet-classic/classic-resume-probe-command.js +58 -0
  121. package/dist/domains/comet-classic/classic-resume-probe-command.js.map +1 -0
  122. package/dist/domains/comet-classic/classic-resume-probe-entry.d.ts +2 -0
  123. package/dist/domains/comet-classic/classic-resume-probe-entry.d.ts.map +1 -0
  124. package/dist/domains/comet-classic/classic-resume-probe-entry.js +4 -0
  125. package/dist/domains/comet-classic/classic-resume-probe-entry.js.map +1 -0
  126. package/dist/domains/comet-classic/classic-resume-probe.d.ts +29 -0
  127. package/dist/domains/comet-classic/classic-resume-probe.d.ts.map +1 -0
  128. package/dist/domains/comet-classic/classic-resume-probe.js +386 -0
  129. package/dist/domains/comet-classic/classic-resume-probe.js.map +1 -0
  130. package/dist/domains/comet-classic/classic-runtime-run.d.ts +2 -1
  131. package/dist/domains/comet-classic/classic-runtime-run.d.ts.map +1 -1
  132. package/dist/domains/comet-classic/classic-runtime-run.js +38 -0
  133. package/dist/domains/comet-classic/classic-runtime-run.js.map +1 -1
  134. package/dist/domains/comet-classic/classic-state-command.d.ts.map +1 -1
  135. package/dist/domains/comet-classic/classic-state-command.js +128 -12
  136. package/dist/domains/comet-classic/classic-state-command.js.map +1 -1
  137. package/dist/domains/comet-classic/classic-state.d.ts +3 -1
  138. package/dist/domains/comet-classic/classic-state.d.ts.map +1 -1
  139. package/dist/domains/comet-classic/classic-state.js +4 -0
  140. package/dist/domains/comet-classic/classic-state.js.map +1 -1
  141. package/dist/domains/comet-classic/classic-store.d.ts +4 -1
  142. package/dist/domains/comet-classic/classic-store.d.ts.map +1 -1
  143. package/dist/domains/comet-classic/classic-store.js +4 -3
  144. package/dist/domains/comet-classic/classic-store.js.map +1 -1
  145. package/dist/domains/comet-classic/classic-transitions.d.ts +1 -1
  146. package/dist/domains/comet-classic/classic-transitions.d.ts.map +1 -1
  147. package/dist/domains/comet-classic/classic-transitions.js +20 -1
  148. package/dist/domains/comet-classic/classic-transitions.js.map +1 -1
  149. package/dist/domains/comet-classic/classic-validate-command.d.ts.map +1 -1
  150. package/dist/domains/comet-classic/classic-validate-command.js +1 -0
  151. package/dist/domains/comet-classic/classic-validate-command.js.map +1 -1
  152. package/dist/domains/comet-classic/index.d.ts +3 -0
  153. package/dist/domains/comet-classic/index.d.ts.map +1 -1
  154. package/dist/domains/comet-classic/index.js +3 -0
  155. package/dist/domains/comet-classic/index.js.map +1 -1
  156. package/dist/domains/dashboard/collector.js +10 -2
  157. package/dist/domains/dashboard/collector.js.map +1 -1
  158. package/dist/domains/dashboard/web/assets/{index-CjU3VXVu.js → index-CIvN-PL8.js} +11 -11
  159. package/dist/domains/dashboard/web/assets/{index-BcO3_QlT.css → index-DcyRPBnT.css} +1 -1
  160. package/dist/domains/dashboard/web/index.html +2 -2
  161. package/dist/domains/engine/types.d.ts +1 -1
  162. package/dist/domains/engine/types.d.ts.map +1 -1
  163. package/dist/domains/integrations/openspec.d.ts.map +1 -1
  164. package/dist/domains/integrations/openspec.js +6 -6
  165. package/dist/domains/integrations/openspec.js.map +1 -1
  166. package/dist/domains/skill/find.d.ts.map +1 -1
  167. package/dist/domains/skill/find.js +1 -6
  168. package/dist/domains/skill/find.js.map +1 -1
  169. package/dist/domains/skill/managed-markdown.d.ts +14 -0
  170. package/dist/domains/skill/managed-markdown.d.ts.map +1 -0
  171. package/dist/domains/skill/managed-markdown.js +126 -0
  172. package/dist/domains/skill/managed-markdown.js.map +1 -0
  173. package/dist/domains/skill/platform-install.d.ts +4 -3
  174. package/dist/domains/skill/platform-install.d.ts.map +1 -1
  175. package/dist/domains/skill/platform-install.js +96 -26
  176. package/dist/domains/skill/platform-install.js.map +1 -1
  177. package/dist/domains/skill/project-instructions.d.ts +22 -0
  178. package/dist/domains/skill/project-instructions.d.ts.map +1 -0
  179. package/dist/domains/skill/project-instructions.js +61 -0
  180. package/dist/domains/skill/project-instructions.js.map +1 -0
  181. package/dist/domains/skill/uninstall.d.ts +3 -1
  182. package/dist/domains/skill/uninstall.d.ts.map +1 -1
  183. package/dist/domains/skill/uninstall.js +86 -39
  184. package/dist/domains/skill/uninstall.js.map +1 -1
  185. package/dist/platform/install/detect.d.ts +2 -1
  186. package/dist/platform/install/detect.d.ts.map +1 -1
  187. package/dist/platform/install/detect.js +10 -1
  188. package/dist/platform/install/detect.js.map +1 -1
  189. package/dist/platform/install/platforms.d.ts +5 -1
  190. package/dist/platform/install/platforms.d.ts.map +1 -1
  191. package/dist/platform/install/platforms.js +21 -4
  192. package/dist/platform/install/platforms.js.map +1 -1
  193. package/dist/platform/install/project-registry.d.ts +37 -0
  194. package/dist/platform/install/project-registry.d.ts.map +1 -0
  195. package/dist/platform/install/project-registry.js +205 -0
  196. package/dist/platform/install/project-registry.js.map +1 -0
  197. package/eval/.env +28 -0
  198. package/eval/.env.example +52 -0
  199. package/eval/CLAUDE.md +43 -0
  200. package/eval/README.md +538 -0
  201. package/eval/langsmith/.env.example +16 -0
  202. package/eval/langsmith/README.md +93 -0
  203. package/eval/langsmith/skills/README.md +5 -0
  204. package/eval/langsmith/tasks/README.md +5 -0
  205. package/eval/langsmith/tests/conftest.py +187 -0
  206. package/eval/langsmith/tests/tasks/test_tasks.py +287 -0
  207. package/eval/langsmith/treatments/README.md +5 -0
  208. package/eval/local/README.md +80 -0
  209. package/eval/local/regression_baseline.json +13 -0
  210. package/eval/local/report-style-demo-assets/quality_cost.en.svg +41 -0
  211. package/eval/local/report-style-demo-assets/quality_cost.zh.svg +41 -0
  212. package/eval/local/report-style-demo-assets/rubric_delta.en.svg +56 -0
  213. package/eval/local/report-style-demo-assets/rubric_delta.zh.svg +56 -0
  214. package/eval/local/report-style-demo-assets/task_outcomes.en.svg +46 -0
  215. package/eval/local/report-style-demo-assets/task_outcomes.zh.svg +46 -0
  216. package/eval/local/report-style-demo.html +867 -0
  217. package/eval/local/scripts/compare_baselines.py +1018 -0
  218. package/eval/local/scripts/generate_report_style_demo_charts.py +322 -0
  219. package/eval/local/scripts/regression_check.py +171 -0
  220. package/eval/local/scripts/render_readme_benchmark_figures.py +416 -0
  221. package/eval/local/scripts/rescore_rubric.py +120 -0
  222. package/eval/local/skills/benchmarks/039-release/comet-classic-039/SKILL.md +282 -0
  223. package/eval/local/skills/benchmarks/039-release/comet-classic-039/reference/auto-transition.md +27 -0
  224. package/eval/local/skills/benchmarks/039-release/comet-classic-039/reference/comet-yaml-fields.md +68 -0
  225. package/eval/local/skills/benchmarks/039-release/comet-classic-039/reference/context-recovery.md +35 -0
  226. package/eval/local/skills/benchmarks/039-release/comet-classic-039/reference/debug-gate.md +17 -0
  227. package/eval/local/skills/benchmarks/039-release/comet-classic-039/reference/decision-point.md +20 -0
  228. package/eval/local/skills/benchmarks/039-release/comet-classic-039/reference/dirty-worktree.md +59 -0
  229. package/eval/local/skills/benchmarks/039-release/comet-classic-039/reference/file-structure.md +28 -0
  230. package/eval/local/skills/benchmarks/039-release/comet-classic-039/reference/subagent-dispatch.md +113 -0
  231. package/eval/local/skills/benchmarks/039-release/comet-classic-039/rules/comet-phase-guard.md +125 -0
  232. package/eval/local/skills/benchmarks/039-release/comet-classic-039/scripts/comet-archive.sh +311 -0
  233. package/eval/local/skills/benchmarks/039-release/comet-classic-039/scripts/comet-env.sh +110 -0
  234. package/eval/local/skills/benchmarks/039-release/comet-classic-039/scripts/comet-guard.sh +778 -0
  235. package/eval/local/skills/benchmarks/039-release/comet-classic-039/scripts/comet-handoff.sh +390 -0
  236. package/eval/local/skills/benchmarks/039-release/comet-classic-039/scripts/comet-hook-guard.sh +336 -0
  237. package/eval/local/skills/benchmarks/039-release/comet-classic-039/scripts/comet-state.sh +1338 -0
  238. package/eval/local/skills/benchmarks/039-release/comet-classic-039/scripts/comet-yaml-validate.sh +225 -0
  239. package/eval/local/skills/benchmarks/039-release/comet-classic-039-archive/SKILL.md +100 -0
  240. package/eval/local/skills/benchmarks/039-release/comet-classic-039-build/SKILL.md +304 -0
  241. package/eval/local/skills/benchmarks/039-release/comet-classic-039-design/SKILL.md +263 -0
  242. package/eval/local/skills/benchmarks/039-release/comet-classic-039-hotfix/SKILL.md +204 -0
  243. package/eval/local/skills/benchmarks/039-release/comet-classic-039-open/SKILL.md +220 -0
  244. package/eval/local/skills/benchmarks/039-release/comet-classic-039-tweak/SKILL.md +180 -0
  245. package/eval/local/skills/benchmarks/039-release/comet-classic-039-verify/SKILL.md +234 -0
  246. package/eval/local/skills/benchmarks/040-beta/comet/SKILL.md +261 -0
  247. package/eval/local/skills/benchmarks/040-beta/comet/reference/auto-transition.md +27 -0
  248. package/eval/local/skills/benchmarks/040-beta/comet/reference/comet-yaml-fields.md +73 -0
  249. package/eval/local/skills/benchmarks/040-beta/comet/reference/context-recovery.md +45 -0
  250. package/eval/local/skills/benchmarks/040-beta/comet/reference/debug-gate.md +33 -0
  251. package/eval/local/skills/benchmarks/040-beta/comet/reference/decision-point.md +31 -0
  252. package/eval/local/skills/benchmarks/040-beta/comet/reference/dirty-worktree.md +59 -0
  253. package/eval/local/skills/benchmarks/040-beta/comet/reference/file-structure.md +28 -0
  254. package/eval/local/skills/benchmarks/040-beta/comet/reference/intent-frame.md +74 -0
  255. package/eval/local/skills/benchmarks/040-beta/comet/reference/scripts.md +69 -0
  256. package/eval/local/skills/benchmarks/040-beta/comet/reference/subagent-dispatch.md +169 -0
  257. package/eval/local/skills/benchmarks/040-beta/comet/rules/comet-phase-guard.md +130 -0
  258. package/eval/local/skills/benchmarks/040-beta/comet/runtime/classic/checks.yaml +6 -0
  259. package/eval/local/skills/benchmarks/040-beta/comet/runtime/classic/guardrails.yaml +13 -0
  260. package/eval/local/skills/benchmarks/040-beta/comet/runtime/classic/skill.yaml +122 -0
  261. package/eval/local/skills/benchmarks/040-beta/comet/scripts/comet-archive.mjs +9515 -0
  262. package/eval/local/skills/benchmarks/040-beta/comet/scripts/comet-env.mjs +15 -0
  263. package/eval/local/skills/benchmarks/040-beta/comet/scripts/comet-guard.mjs +10173 -0
  264. package/eval/local/skills/benchmarks/040-beta/comet/scripts/comet-handoff.mjs +9491 -0
  265. package/eval/local/skills/benchmarks/040-beta/comet/scripts/comet-hook-guard.mjs +9175 -0
  266. package/eval/local/skills/benchmarks/040-beta/comet/scripts/comet-intent.mjs +404 -0
  267. package/eval/local/skills/benchmarks/040-beta/comet/scripts/comet-state.mjs +9273 -0
  268. package/eval/local/skills/benchmarks/040-beta/comet/scripts/comet-yaml-validate.mjs +7627 -0
  269. package/eval/local/skills/benchmarks/040-beta/comet-archive/SKILL.md +110 -0
  270. package/eval/local/skills/benchmarks/040-beta/comet-build/SKILL.md +315 -0
  271. package/eval/local/skills/benchmarks/040-beta/comet-design/SKILL.md +260 -0
  272. package/eval/local/skills/benchmarks/040-beta/comet-hotfix/SKILL.md +190 -0
  273. package/eval/local/skills/benchmarks/040-beta/comet-open/SKILL.md +210 -0
  274. package/eval/local/skills/benchmarks/040-beta/comet-tweak/SKILL.md +183 -0
  275. package/eval/local/skills/benchmarks/040-beta/comet-verify/SKILL.md +230 -0
  276. package/eval/local/skills/benchmarks/dependency/claude-md/comet-workflow/CLAUDE.md +12 -0
  277. package/eval/local/skills/benchmarks/dependency/openspec/openspec-apply-change/SKILL.md +156 -0
  278. package/eval/local/skills/benchmarks/dependency/openspec/openspec-archive-change/SKILL.md +114 -0
  279. package/eval/local/skills/benchmarks/dependency/openspec/openspec-bulk-archive-change/SKILL.md +246 -0
  280. package/eval/local/skills/benchmarks/dependency/openspec/openspec-continue-change/SKILL.md +118 -0
  281. package/eval/local/skills/benchmarks/dependency/openspec/openspec-explore/SKILL.md +288 -0
  282. package/eval/local/skills/benchmarks/dependency/openspec/openspec-ff-change/SKILL.md +101 -0
  283. package/eval/local/skills/benchmarks/dependency/openspec/openspec-new-change/SKILL.md +74 -0
  284. package/eval/local/skills/benchmarks/dependency/openspec/openspec-onboard/SKILL.md +554 -0
  285. package/eval/local/skills/benchmarks/dependency/openspec/openspec-propose/SKILL.md +110 -0
  286. package/eval/local/skills/benchmarks/dependency/openspec/openspec-sync-specs/SKILL.md +138 -0
  287. package/eval/local/skills/benchmarks/dependency/openspec/openspec-verify-change/SKILL.md +168 -0
  288. package/eval/local/skills/benchmarks/dependency/superpowers/brainstorming/SKILL.md +159 -0
  289. package/eval/local/skills/benchmarks/dependency/superpowers/brainstorming/scripts/frame-template.html +213 -0
  290. package/eval/local/skills/benchmarks/dependency/superpowers/brainstorming/scripts/helper.js +167 -0
  291. package/eval/local/skills/benchmarks/dependency/superpowers/brainstorming/scripts/server.cjs +723 -0
  292. package/eval/local/skills/benchmarks/dependency/superpowers/brainstorming/scripts/start-server.sh +209 -0
  293. package/eval/local/skills/benchmarks/dependency/superpowers/brainstorming/scripts/stop-server.sh +120 -0
  294. package/eval/local/skills/benchmarks/dependency/superpowers/brainstorming/spec-document-reviewer-prompt.md +49 -0
  295. package/eval/local/skills/benchmarks/dependency/superpowers/brainstorming/visual-companion.md +291 -0
  296. package/eval/local/skills/benchmarks/dependency/superpowers/dispatching-parallel-agents/SKILL.md +185 -0
  297. package/eval/local/skills/benchmarks/dependency/superpowers/executing-plans/SKILL.md +70 -0
  298. package/eval/local/skills/benchmarks/dependency/superpowers/finishing-a-development-branch/SKILL.md +241 -0
  299. package/eval/local/skills/benchmarks/dependency/superpowers/receiving-code-review/SKILL.md +213 -0
  300. package/eval/local/skills/benchmarks/dependency/superpowers/requesting-code-review/SKILL.md +103 -0
  301. package/eval/local/skills/benchmarks/dependency/superpowers/requesting-code-review/code-reviewer.md +172 -0
  302. package/eval/local/skills/benchmarks/dependency/superpowers/subagent-driven-development/SKILL.md +418 -0
  303. package/eval/local/skills/benchmarks/dependency/superpowers/subagent-driven-development/implementer-prompt.md +139 -0
  304. package/eval/local/skills/benchmarks/dependency/superpowers/subagent-driven-development/scripts/review-package +44 -0
  305. package/eval/local/skills/benchmarks/dependency/superpowers/subagent-driven-development/scripts/sdd-workspace +22 -0
  306. package/eval/local/skills/benchmarks/dependency/superpowers/subagent-driven-development/scripts/task-brief +40 -0
  307. package/eval/local/skills/benchmarks/dependency/superpowers/subagent-driven-development/task-reviewer-prompt.md +188 -0
  308. package/eval/local/skills/benchmarks/dependency/superpowers/systematic-debugging/CREATION-LOG.md +119 -0
  309. package/eval/local/skills/benchmarks/dependency/superpowers/systematic-debugging/SKILL.md +296 -0
  310. package/eval/local/skills/benchmarks/dependency/superpowers/systematic-debugging/condition-based-waiting-example.ts +158 -0
  311. package/eval/local/skills/benchmarks/dependency/superpowers/systematic-debugging/condition-based-waiting.md +115 -0
  312. package/eval/local/skills/benchmarks/dependency/superpowers/systematic-debugging/defense-in-depth.md +122 -0
  313. package/eval/local/skills/benchmarks/dependency/superpowers/systematic-debugging/find-polluter.sh +63 -0
  314. package/eval/local/skills/benchmarks/dependency/superpowers/systematic-debugging/root-cause-tracing.md +169 -0
  315. package/eval/local/skills/benchmarks/dependency/superpowers/systematic-debugging/test-academic.md +14 -0
  316. package/eval/local/skills/benchmarks/dependency/superpowers/systematic-debugging/test-pressure-1.md +58 -0
  317. package/eval/local/skills/benchmarks/dependency/superpowers/systematic-debugging/test-pressure-2.md +68 -0
  318. package/eval/local/skills/benchmarks/dependency/superpowers/systematic-debugging/test-pressure-3.md +69 -0
  319. package/eval/local/skills/benchmarks/dependency/superpowers/test-driven-development/SKILL.md +371 -0
  320. package/eval/local/skills/benchmarks/dependency/superpowers/test-driven-development/testing-anti-patterns.md +299 -0
  321. package/eval/local/skills/benchmarks/dependency/superpowers/using-git-worktrees/SKILL.md +202 -0
  322. package/eval/local/skills/benchmarks/dependency/superpowers/verification-before-completion/SKILL.md +139 -0
  323. package/eval/local/skills/benchmarks/dependency/superpowers/writing-plans/SKILL.md +174 -0
  324. package/eval/local/skills/benchmarks/dependency/superpowers/writing-plans/plan-document-reviewer-prompt.md +49 -0
  325. package/eval/local/skills/benchmarks/dependency/superpowers/writing-skills/SKILL.md +689 -0
  326. package/eval/local/skills/benchmarks/dependency/superpowers/writing-skills/anthropic-best-practices.md +1150 -0
  327. package/eval/local/skills/benchmarks/dependency/superpowers/writing-skills/examples/CLAUDE_MD_TESTING.md +189 -0
  328. package/eval/local/skills/benchmarks/dependency/superpowers/writing-skills/graphviz-conventions.dot +172 -0
  329. package/eval/local/skills/benchmarks/dependency/superpowers/writing-skills/persuasion-principles.md +187 -0
  330. package/eval/local/skills/benchmarks/dependency/superpowers/writing-skills/render-graphs.js +168 -0
  331. package/eval/local/skills/benchmarks/dependency/superpowers/writing-skills/testing-skills-with-subagents.md +384 -0
  332. package/eval/local/tasks/authoring-skill-smoke/environment/Dockerfile +2 -0
  333. package/eval/local/tasks/authoring-skill-smoke/instruction.md +4 -0
  334. package/eval/local/tasks/authoring-skill-smoke/task.toml +21 -0
  335. package/eval/local/tasks/authoring-skill-smoke/validation/test_authoring_skill_smoke.py +54 -0
  336. package/eval/local/tasks/comet-agent-memory-routing/environment/Dockerfile +28 -0
  337. package/eval/local/tasks/comet-agent-memory-routing/environment/agent_system.py +40 -0
  338. package/eval/local/tasks/comet-agent-memory-routing/environment/test_agent_system.py +29 -0
  339. package/eval/local/tasks/comet-agent-memory-routing/instruction.md +20 -0
  340. package/eval/local/tasks/comet-agent-memory-routing/task.toml +24 -0
  341. package/eval/local/tasks/comet-agent-memory-routing/validation/test_agent_memory_routing.py +24 -0
  342. package/eval/local/tasks/comet-api-cache-ttl/environment/Dockerfile +39 -0
  343. package/eval/local/tasks/comet-api-cache-ttl/environment/cache.py +39 -0
  344. package/eval/local/tasks/comet-api-cache-ttl/environment/test_cache.py +81 -0
  345. package/eval/local/tasks/comet-api-cache-ttl/instruction.md +33 -0
  346. package/eval/local/tasks/comet-api-cache-ttl/task.toml +24 -0
  347. package/eval/local/tasks/comet-api-cache-ttl/validation/test_api_cache_ttl.py +58 -0
  348. package/eval/local/tasks/comet-cross-file-refactor/environment/Dockerfile +15 -0
  349. package/eval/local/tasks/comet-cross-file-refactor/environment/cli.py +13 -0
  350. package/eval/local/tasks/comet-cross-file-refactor/environment/counting.py +13 -0
  351. package/eval/local/tasks/comet-cross-file-refactor/environment/test_textkit.py +21 -0
  352. package/eval/local/tasks/comet-cross-file-refactor/instruction.md +16 -0
  353. package/eval/local/tasks/comet-cross-file-refactor/task.toml +20 -0
  354. package/eval/local/tasks/comet-cross-file-refactor/validation/test_cross_file_refactor.py +20 -0
  355. package/eval/local/tasks/comet-dependency-confusion/environment/Dockerfile +28 -0
  356. package/eval/local/tasks/comet-dependency-confusion/environment/app.py +8 -0
  357. package/eval/local/tasks/comet-dependency-confusion/environment/settings_loader.py +14 -0
  358. package/eval/local/tasks/comet-dependency-confusion/environment/test_settings_service.py +19 -0
  359. package/eval/local/tasks/comet-dependency-confusion/instruction.md +18 -0
  360. package/eval/local/tasks/comet-dependency-confusion/task.toml +24 -0
  361. package/eval/local/tasks/comet-dependency-confusion/validation/test_dependency_confusion.py +24 -0
  362. package/eval/local/tasks/comet-fix-median/environment/Dockerfile +50 -0
  363. package/eval/local/tasks/comet-fix-median/environment/stats.py +54 -0
  364. package/eval/local/tasks/comet-fix-median/environment/test_stats.py +68 -0
  365. package/eval/local/tasks/comet-fix-median/instruction.md +25 -0
  366. package/eval/local/tasks/comet-fix-median/task.toml +24 -0
  367. package/eval/local/tasks/comet-fix-median/validation/test_fix_median.py +60 -0
  368. package/eval/local/tasks/comet-framework-selection/environment/Dockerfile +28 -0
  369. package/eval/local/tasks/comet-framework-selection/environment/architecture.py +12 -0
  370. package/eval/local/tasks/comet-framework-selection/environment/test_architecture.py +30 -0
  371. package/eval/local/tasks/comet-framework-selection/instruction.md +22 -0
  372. package/eval/local/tasks/comet-framework-selection/task.toml +24 -0
  373. package/eval/local/tasks/comet-framework-selection/validation/test_framework_selection.py +24 -0
  374. package/eval/local/tasks/comet-full-workflow/environment/Dockerfile +53 -0
  375. package/eval/local/tasks/comet-full-workflow/environment/test_wordcount.py +29 -0
  376. package/eval/local/tasks/comet-full-workflow/environment/wordcount.py +40 -0
  377. package/eval/local/tasks/comet-full-workflow/instruction.md +18 -0
  378. package/eval/local/tasks/comet-full-workflow/task.toml +24 -0
  379. package/eval/local/tasks/comet-full-workflow/validation/test_full_workflow.py +171 -0
  380. package/eval/local/tasks/comet-graph-execution-review/environment/Dockerfile +28 -0
  381. package/eval/local/tasks/comet-graph-execution-review/environment/pipeline.py +19 -0
  382. package/eval/local/tasks/comet-graph-execution-review/environment/test_pipeline.py +53 -0
  383. package/eval/local/tasks/comet-graph-execution-review/instruction.md +21 -0
  384. package/eval/local/tasks/comet-graph-execution-review/task.toml +24 -0
  385. package/eval/local/tasks/comet-graph-execution-review/validation/test_graph_execution_review.py +24 -0
  386. package/eval/local/tasks/comet-human-approval-flow/environment/Dockerfile +15 -0
  387. package/eval/local/tasks/comet-human-approval-flow/environment/approvals.py +17 -0
  388. package/eval/local/tasks/comet-human-approval-flow/environment/test_approvals.py +30 -0
  389. package/eval/local/tasks/comet-human-approval-flow/instruction.md +15 -0
  390. package/eval/local/tasks/comet-human-approval-flow/task.toml +20 -0
  391. package/eval/local/tasks/comet-human-approval-flow/validation/test_human_approval_flow.py +20 -0
  392. package/eval/local/tasks/comet-layered-streaming-fix/environment/Dockerfile +20 -0
  393. package/eval/local/tasks/comet-layered-streaming-fix/environment/chat_app.py +19 -0
  394. package/eval/local/tasks/comet-layered-streaming-fix/environment/test_chat_app.py +15 -0
  395. package/eval/local/tasks/comet-layered-streaming-fix/instruction.md +14 -0
  396. package/eval/local/tasks/comet-layered-streaming-fix/task.toml +20 -0
  397. package/eval/local/tasks/comet-layered-streaming-fix/validation/test_layered_streaming_fix.py +20 -0
  398. package/eval/local/tasks/comet-noise-distractor/environment/Dockerfile +15 -0
  399. package/eval/local/tasks/comet-noise-distractor/environment/distractor.md +4 -0
  400. package/eval/local/tasks/comet-noise-distractor/environment/invoice.py +5 -0
  401. package/eval/local/tasks/comet-noise-distractor/environment/test_invoice.py +18 -0
  402. package/eval/local/tasks/comet-noise-distractor/instruction.md +17 -0
  403. package/eval/local/tasks/comet-noise-distractor/task.toml +20 -0
  404. package/eval/local/tasks/comet-noise-distractor/validation/test_noise_distractor.py +20 -0
  405. package/eval/local/tasks/comet-observability-env-template/environment/Dockerfile +15 -0
  406. package/eval/local/tasks/comet-observability-env-template/environment/env_writer.py +17 -0
  407. package/eval/local/tasks/comet-observability-env-template/environment/test_env_writer.py +17 -0
  408. package/eval/local/tasks/comet-observability-env-template/instruction.md +20 -0
  409. package/eval/local/tasks/comet-observability-env-template/task.toml +20 -0
  410. package/eval/local/tasks/comet-observability-env-template/validation/test_observability_env_template.py +46 -0
  411. package/eval/local/tasks/comet-perf-dedupe/environment/Dockerfile +39 -0
  412. package/eval/local/tasks/comet-perf-dedupe/environment/dedupe.py +22 -0
  413. package/eval/local/tasks/comet-perf-dedupe/environment/test_dedupe.py +43 -0
  414. package/eval/local/tasks/comet-perf-dedupe/instruction.md +25 -0
  415. package/eval/local/tasks/comet-perf-dedupe/task.toml +24 -0
  416. package/eval/local/tasks/comet-perf-dedupe/validation/test_perf_dedupe.py +40 -0
  417. package/eval/local/tasks/comet-persistence-threading/environment/Dockerfile +15 -0
  418. package/eval/local/tasks/comet-persistence-threading/environment/session_store.py +15 -0
  419. package/eval/local/tasks/comet-persistence-threading/environment/test_session_store.py +21 -0
  420. package/eval/local/tasks/comet-persistence-threading/instruction.md +14 -0
  421. package/eval/local/tasks/comet-persistence-threading/task.toml +20 -0
  422. package/eval/local/tasks/comet-persistence-threading/validation/test_persistence_threading.py +20 -0
  423. package/eval/local/tasks/comet-refactor-counter/environment/Dockerfile +39 -0
  424. package/eval/local/tasks/comet-refactor-counter/environment/test_text_processor.py +57 -0
  425. package/eval/local/tasks/comet-refactor-counter/environment/text_processor.py +49 -0
  426. package/eval/local/tasks/comet-refactor-counter/instruction.md +31 -0
  427. package/eval/local/tasks/comet-refactor-counter/task.toml +24 -0
  428. package/eval/local/tasks/comet-refactor-counter/validation/test_refactor_counter.py +75 -0
  429. package/eval/local/tasks/comet-robust-config/environment/Dockerfile +39 -0
  430. package/eval/local/tasks/comet-robust-config/environment/config_loader.py +56 -0
  431. package/eval/local/tasks/comet-robust-config/environment/test_config_loader.py +72 -0
  432. package/eval/local/tasks/comet-robust-config/instruction.md +30 -0
  433. package/eval/local/tasks/comet-robust-config/task.toml +24 -0
  434. package/eval/local/tasks/comet-robust-config/validation/test_robust_config.py +37 -0
  435. package/eval/local/tasks/generic-skill-smoke/environment/Dockerfile +2 -0
  436. package/eval/local/tasks/generic-skill-smoke/instruction.md +7 -0
  437. package/eval/local/tasks/generic-skill-smoke/task.toml +21 -0
  438. package/eval/local/tasks/generic-skill-smoke/validation/test_generic_skill_smoke.py +36 -0
  439. package/eval/local/tasks/index.yaml +155 -0
  440. package/eval/local/tasks/workflow-overlay-contract/environment/Dockerfile +5 -0
  441. package/eval/local/tasks/workflow-overlay-contract/instruction.md +5 -0
  442. package/eval/local/tasks/workflow-overlay-contract/task.toml +21 -0
  443. package/eval/local/tasks/workflow-overlay-contract/validation/test_workflow_overlay_contract.py +235 -0
  444. package/eval/local/tasks/workflow-route-conformance/environment/Dockerfile +2 -0
  445. package/eval/local/tasks/workflow-route-conformance/instruction.md +5 -0
  446. package/eval/local/tasks/workflow-route-conformance/task.toml +21 -0
  447. package/eval/local/tasks/workflow-route-conformance/validation/test_workflow_route_conformance.py +84 -0
  448. package/eval/local/tests/conftest.py +1148 -0
  449. package/eval/local/tests/scaffold/test_attribution.py +48 -0
  450. package/eval/local/tests/scaffold/test_compare_baselines.py +999 -0
  451. package/eval/local/tests/scaffold/test_conftest_helpers.py +534 -0
  452. package/eval/local/tests/scaffold/test_evidence.py +15 -0
  453. package/eval/local/tests/scaffold/test_langsmith_conftest.py +244 -0
  454. package/eval/local/tests/scaffold/test_logging.py +243 -0
  455. package/eval/local/tests/scaffold/test_manifests.py +132 -0
  456. package/eval/local/tests/scaffold/test_profiles.py +866 -0
  457. package/eval/local/tests/scaffold/test_regression_check.py +19 -0
  458. package/eval/local/tests/scaffold/test_report_style_demo_charts.py +45 -0
  459. package/eval/local/tests/scaffold/test_sample_quality.py +211 -0
  460. package/eval/local/tests/scaffold/test_tasks.py +168 -0
  461. package/eval/local/tests/scaffold/test_treatments.py +244 -0
  462. package/eval/local/tests/scaffold/test_utils.py +139 -0
  463. package/eval/local/tests/tasks/test_tasks.py +445 -0
  464. package/eval/local/tests/tasks/test_validation_scripts.py +143 -0
  465. package/eval/local/treatments/comet/comet_full_039.yaml +141 -0
  466. package/eval/local/treatments/comet/comet_full_040_beta.yaml +140 -0
  467. package/eval/local/treatments/common/control.yaml +4 -0
  468. package/eval/pyproject.toml +41 -0
  469. package/eval/report-html-config.json +6 -0
  470. package/eval/scaffold/__init__.py +67 -0
  471. package/eval/scaffold/python/__init__.py +95 -0
  472. package/eval/scaffold/python/attribution.py +43 -0
  473. package/eval/scaffold/python/evidence.py +38 -0
  474. package/eval/scaffold/python/external_data_handler.py +18 -0
  475. package/eval/scaffold/python/generic_llm_judge.py +235 -0
  476. package/eval/scaffold/python/judge_config.py +168 -0
  477. package/eval/scaffold/python/llm_judge.py +191 -0
  478. package/eval/scaffold/python/logging.py +705 -0
  479. package/eval/scaffold/python/manifests.py +129 -0
  480. package/eval/scaffold/python/paper_charts.py +25 -0
  481. package/eval/scaffold/python/pass_at_k.py +107 -0
  482. package/eval/scaffold/python/paths.py +56 -0
  483. package/eval/scaffold/python/profiles.py +127 -0
  484. package/eval/scaffold/python/report_outputs.py +1391 -0
  485. package/eval/scaffold/python/sample_quality.py +339 -0
  486. package/eval/scaffold/python/schema.py +39 -0
  487. package/eval/scaffold/python/skill_parser.py +469 -0
  488. package/eval/scaffold/python/tasks.py +330 -0
  489. package/eval/scaffold/python/treatments.py +271 -0
  490. package/eval/scaffold/python/utils.py +366 -0
  491. package/eval/scaffold/python/validation/__init__.py +21 -0
  492. package/eval/scaffold/python/validation/authoring_rubric.py +326 -0
  493. package/eval/scaffold/python/validation/comet_workflow.py +187 -0
  494. package/eval/scaffold/python/validation/core.py +264 -0
  495. package/eval/scaffold/python/validation/dataset.py +337 -0
  496. package/eval/scaffold/python/validation/docker.py +106 -0
  497. package/eval/scaffold/python/validation/evaluator.py +549 -0
  498. package/eval/scaffold/python/validation/generic_rubric.py +169 -0
  499. package/eval/scaffold/python/validation/rubric.py +740 -0
  500. package/eval/scaffold/python/validation/runner.py +237 -0
  501. package/eval/scaffold/python/validation/scripts.py +58 -0
  502. package/eval/scaffold/python/validation/tracing.py +313 -0
  503. package/eval/scaffold/shell/common.sh +126 -0
  504. package/eval/scaffold/shell/docker.sh +482 -0
  505. package/eval/scaffold/shell/run-claude-loop.sh +181 -0
  506. package/eval/scaffold/shell/setup.sh +259 -0
  507. package/eval/simulator-instruction.md +9 -0
  508. package/package.json +24 -2
@@ -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
 
@@ -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
 
@@ -7804,6 +7812,7 @@ var ISOLATIONS = ["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",
@@ -7825,6 +7834,7 @@ var CLASSIC_WIRE_KEYS = [
7825
7834
  "branch_status",
7826
7835
  "created_at",
7827
7836
  "verified_at",
7837
+ "archive_confirmation",
7828
7838
  "archived",
7829
7839
  "direct_override",
7830
7840
  "handoff_context",
@@ -7933,6 +7943,7 @@ function classicStateFromDocument(doc) {
7933
7943
  branchStatus: enumValue(doc, "branch_status", BRANCH_STATUSES),
7934
7944
  createdAt: nullableString(doc, "created_at"),
7935
7945
  verifiedAt: nullableString(doc, "verified_at"),
7946
+ archiveConfirmation: enumValue(doc, "archive_confirmation", ARCHIVE_CONFIRMATIONS),
7936
7947
  archived: booleanValue(doc, "archived", false),
7937
7948
  directOverride: booleanValue(doc, "direct_override"),
7938
7949
  handoffContext: relativePath(doc, "handoff_context"),
@@ -7996,6 +8007,7 @@ function classicStateToDocument(state) {
7996
8007
  branch_status: state.branchStatus,
7997
8008
  created_at: state.createdAt,
7998
8009
  verified_at: state.verifiedAt,
8010
+ archive_confirmation: state.archiveConfirmation,
7999
8011
  archived: state.archived,
8000
8012
  direct_override: state.directOverride,
8001
8013
  handoff_context: state.handoffContext,
@@ -8077,7 +8089,8 @@ async function readDocument(file) {
8077
8089
  documentRecord(document);
8078
8090
  return document;
8079
8091
  }
8080
- async function readClassicState(changeDir) {
8092
+ async function readClassicState(changeDir, options = {}) {
8093
+ const shouldMigrate = options.migrate !== false;
8081
8094
  const file = path4.join(changeDir, ".comet.yaml");
8082
8095
  const document = await readDocument(file);
8083
8096
  let doc = documentRecord(document);
@@ -8087,13 +8100,13 @@ async function readClassicState(changeDir) {
8087
8100
  if (!run && doc.run_id && doc.skill) {
8088
8101
  const { runStateFromDocument: runStateFromDocument2 } = await Promise.resolve().then(() => (init_state(), state_exports));
8089
8102
  run = runStateFromDocument2(doc);
8090
- if (run) {
8103
+ if (run && shouldMigrate) {
8091
8104
  await writeRunState(changeDir, run);
8092
8105
  stripLegacyRunFields(document);
8093
8106
  migrated = true;
8094
8107
  }
8095
8108
  }
8096
- if (migrated) {
8109
+ if (migrated && shouldMigrate) {
8097
8110
  const temporary = path4.join(changeDir, `.comet.yaml.${randomUUID2()}.tmp`);
8098
8111
  await fs4.writeFile(temporary, document.toString(), "utf8");
8099
8112
  await fs4.rename(temporary, file);
@@ -8830,13 +8843,13 @@ function artifactKey(code) {
8830
8843
  return code.replaceAll(".", "_").replaceAll("-", "_");
8831
8844
  }
8832
8845
  async function migrationArtifacts(changeDir, evidence) {
8833
- const projectRoot = projectRootFor2(changeDir);
8846
+ const projectRoot2 = projectRootFor2(changeDir);
8834
8847
  const artifacts = Object.fromEntries(
8835
8848
  evidence.filter((item) => item.satisfied && item.source).map((item) => [artifactKey(item.code), item.source])
8836
8849
  );
8837
8850
  const progress = path9.join(changeDir, "subagent-progress.md");
8838
8851
  if (await pathExists2(progress)) {
8839
- artifacts.subagent_progress = path9.relative(projectRoot, progress).split(path9.sep).join("/");
8852
+ artifacts.subagent_progress = path9.relative(projectRoot2, progress).split(path9.sep).join("/");
8840
8853
  }
8841
8854
  const handoff = evidence.find((item) => item.code === "design.handoff" && item.satisfied);
8842
8855
  if (handoff?.source) artifacts.handoff_context = handoff.source;
@@ -8928,11 +8941,11 @@ async function ensureClassicRun(changeDir, options) {
8928
8941
  classicMigration: CLASSIC_MIGRATION_VERSION
8929
8942
  };
8930
8943
  const artifacts = await migrationArtifacts(changeDir, evidence);
8931
- const projectRoot = projectRootFor2(changeDir);
8944
+ const projectRoot2 = projectRootFor2(changeDir);
8932
8945
  const handoff = evidence.find((item) => item.code === "design.handoff" && item.satisfied);
8933
8946
  let context = null;
8934
8947
  if (handoff?.source) {
8935
- context = await fs8.readFile(path9.resolve(projectRoot, handoff.source), "utf8");
8948
+ context = await fs8.readFile(path9.resolve(projectRoot2, handoff.source), "utf8");
8936
8949
  await writeContext(changeDir, run.contextRef, context);
8937
8950
  createdFiles.push(path9.resolve(changeDir, run.contextRef));
8938
8951
  }
@@ -9251,6 +9264,46 @@ async function ensureStrictClassicRuntimeRun(changeDir) {
9251
9264
  }
9252
9265
  return ensureClassicRuntimeRun(changeDir);
9253
9266
  }
9267
+ async function validateClassicRuntimeRun(changeDir, existingProjection) {
9268
+ const projection = existingProjection ?? await readClassicState(changeDir, { migrate: false });
9269
+ const unknownKeys = Array.from(new Set(projection.unknownKeys)).sort();
9270
+ if (unknownKeys.length > 0) {
9271
+ throw new Error(`Invalid Classic state: unknown field(s): ${unknownKeys.join(", ")}`);
9272
+ }
9273
+ if (!projection.classic || !projection.run) {
9274
+ throw new Error("Classic runtime validation requires synchronized Classic and Run projections");
9275
+ }
9276
+ if (projection.classic.classicMigration !== CLASSIC_MIGRATION_VERSION) {
9277
+ throw new Error("Classic Run exists without a supported classic_migration marker");
9278
+ }
9279
+ const root = await classicRuntimeRoot();
9280
+ const skillPackage = root ? await loadClassicRuntimePackage(root) : embeddedClassicRuntimePackage(path10.dirname(fileURLToPath(import.meta.url)));
9281
+ if (projection.run.skill !== skillPackage.definition.metadata.name) {
9282
+ throw new Error(
9283
+ `Classic Run skill mismatch: expected ${skillPackage.definition.metadata.name}, got ${projection.run.skill}`
9284
+ );
9285
+ }
9286
+ const snapshot = await readSkillSnapshot(changeDir, projection.run.skillHash);
9287
+ if (snapshot.definition.metadata.name !== projection.run.skill) {
9288
+ throw new Error(
9289
+ `Classic Run snapshot skill mismatch: expected ${projection.run.skill}, got ${snapshot.definition.metadata.name}`
9290
+ );
9291
+ }
9292
+ const evidence = await collectClassicEvidence(changeDir, projection);
9293
+ const currentStep = resolveClassicStepId(projection.classic, evidence);
9294
+ if (projection.run.currentStep !== currentStep) {
9295
+ throw new Error(
9296
+ `Classic Run step mismatch: expected ${currentStep}, got ${projection.run.currentStep}`
9297
+ );
9298
+ }
9299
+ return {
9300
+ classic: projection.classic,
9301
+ run: projection.run,
9302
+ evidence,
9303
+ migrated: false,
9304
+ snapshotDir: path10.join(changeDir, ".comet", "skill-snapshots", projection.run.skillHash)
9305
+ };
9306
+ }
9254
9307
  async function transitionClassicRuntimeRun(changeDir, classic, run, data) {
9255
9308
  const projection = await readClassicState(changeDir);
9256
9309
  if (!projection.classic || !projection.run) {
@@ -9313,6 +9366,7 @@ var CLASSIC_TRANSITION_EVENTS = [
9313
9366
  "build-complete",
9314
9367
  "verify-pass",
9315
9368
  "verify-fail",
9369
+ "archive-confirm",
9316
9370
  "archive-reopen",
9317
9371
  "archived",
9318
9372
  "preset-escalate"
@@ -9343,6 +9397,11 @@ var CLASSIC_TRANSITION_TABLE = {
9343
9397
  from: "verify",
9344
9398
  guardRefs: ["verification-failed"]
9345
9399
  },
9400
+ "archive-confirm": {
9401
+ event: "archive-confirm",
9402
+ from: "archive",
9403
+ guardRefs: ["archive-final-confirmation"]
9404
+ },
9346
9405
  "archive-reopen": {
9347
9406
  event: "archive-reopen",
9348
9407
  from: "archive",
@@ -9351,7 +9410,7 @@ var CLASSIC_TRANSITION_TABLE = {
9351
9410
  archived: {
9352
9411
  event: "archived",
9353
9412
  from: "archive",
9354
- guardRefs: ["verify-result-pass"]
9413
+ guardRefs: ["verify-result-pass", "archive-confirmed"]
9355
9414
  },
9356
9415
  "preset-escalate": {
9357
9416
  event: "preset-escalate",
@@ -9399,6 +9458,7 @@ function applyClassicTransition(current, event, options = {}) {
9399
9458
  setField(classic, effects, "verifyResult", "pass");
9400
9459
  setField(classic, effects, "phase", "archive");
9401
9460
  setField(classic, effects, "verifiedAt", dateOnly(now));
9461
+ setField(classic, effects, "archiveConfirmation", "pending");
9402
9462
  } else if (event === "verify-fail") {
9403
9463
  setField(classic, effects, "verifyResult", "fail");
9404
9464
  setField(classic, effects, "phase", "build");
@@ -9412,15 +9472,25 @@ function applyClassicTransition(current, event, options = {}) {
9412
9472
  setField(classic, effects, "classicProfile", "full");
9413
9473
  setField(classic, effects, "phase", "design");
9414
9474
  setField(classic, effects, "designDoc", null);
9475
+ } else if (event === "archive-confirm") {
9476
+ if (classic.verifyResult !== "pass") {
9477
+ throw new Error(`Cannot apply ${event}: verifyResult must be pass`);
9478
+ }
9479
+ if (classic.archived) throw new Error(`Cannot apply ${event}: already archived`);
9480
+ setField(classic, effects, "archiveConfirmation", "confirmed");
9415
9481
  } else if (event === "archive-reopen") {
9416
9482
  if (classic.archived) throw new Error(`Cannot apply ${event}: already archived`);
9417
9483
  setField(classic, effects, "verifyResult", "pending");
9418
9484
  setField(classic, effects, "phase", "verify");
9419
9485
  setField(classic, effects, "verifiedAt", null);
9486
+ setField(classic, effects, "archiveConfirmation", null);
9420
9487
  } else {
9421
9488
  if (classic.verifyResult !== "pass") {
9422
9489
  throw new Error(`Cannot apply ${event}: verifyResult must be pass`);
9423
9490
  }
9491
+ if (classic.archiveConfirmation !== "confirmed") {
9492
+ throw new Error(`Cannot apply ${event}: archiveConfirmation must be confirmed`);
9493
+ }
9424
9494
  setField(classic, effects, "archived", true);
9425
9495
  }
9426
9496
  return { classic, effects, definition };
@@ -9483,6 +9553,33 @@ function artifactsHash(artifacts) {
9483
9553
  )
9484
9554
  );
9485
9555
  }
9556
+ function exactlyOneFinalNewline(markdown) {
9557
+ return `${markdown.replace(/\n+$/u, "")}
9558
+ `;
9559
+ }
9560
+ function annotatedMarkdown(original, archiveName, extraFields) {
9561
+ const normalized2 = original.replace(/\r\n/gu, "\n");
9562
+ const lines = normalized2.split("\n");
9563
+ const closingDelimiter = lines[0] === "---" ? lines.indexOf("---", 1) : -1;
9564
+ const extraFieldName = extraFields.match(/^([^:\n]+):/u)?.[1]?.trim();
9565
+ if (closingDelimiter !== -1) {
9566
+ const frontmatter = lines.slice(1, closingDelimiter).filter((line) => {
9567
+ const fieldName = line.match(/^([^:\n]+):/u)?.[1]?.trim();
9568
+ if (fieldName === void 0) return true;
9569
+ return fieldName !== "archived-with" && fieldName !== extraFieldName;
9570
+ });
9571
+ frontmatter.push(`archived-with: ${archiveName}`);
9572
+ if (extraFields) frontmatter.push(extraFields);
9573
+ return exactlyOneFinalNewline(
9574
+ ["---", ...frontmatter, "---", ...lines.slice(closingDelimiter + 1)].join("\n")
9575
+ );
9576
+ }
9577
+ const header = ["---", `archived-with: ${archiveName}`];
9578
+ if (extraFields) header.push(extraFields);
9579
+ if (extraFieldName !== "status") header.push("status: final");
9580
+ header.push("---");
9581
+ return exactlyOneFinalNewline([...header, normalized2].join("\n"));
9582
+ }
9486
9583
  async function findArchiveDir(change, preferred) {
9487
9584
  if (await exists2(preferred)) return preferred;
9488
9585
  const archiveRoot = "openspec/changes/archive";
@@ -9521,37 +9618,7 @@ async function annotateFrontmatter(output, file, archiveName, extraFields, dryRu
9521
9618
  return;
9522
9619
  }
9523
9620
  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
- }
9621
+ const updated = annotatedMarkdown(original, archiveName, extraFields);
9555
9622
  await fs11.writeFile(file, updated);
9556
9623
  output.stderr.push(green(` [OK] Annotated: ${file}`));
9557
9624
  output.stepsOk += 1;
@@ -9636,6 +9703,13 @@ var classicArchiveCommand = async (args) => {
9636
9703
  if (runtime.run.pending && runtime.run.pending !== actionId) {
9637
9704
  throw new ArchiveFailure(red(`FATAL: another action is pending: ${runtime.run.pending}`));
9638
9705
  }
9706
+ if (!recovering && !classic.archived && classic.archiveConfirmation !== "confirmed") {
9707
+ throw new ArchiveFailure(
9708
+ red(
9709
+ `FATAL: archive_confirmation is '${classic.archiveConfirmation ?? "null"}', expected 'confirmed'. Run final archive confirmation first.`
9710
+ )
9711
+ );
9712
+ }
9639
9713
  if (!recovering) {
9640
9714
  const action = {
9641
9715
  id: actionId,
@@ -9707,7 +9781,10 @@ var classicArchiveCommand = async (args) => {
9707
9781
  archive_directory: archiveDir
9708
9782
  };
9709
9783
  await writeArtifacts(archiveDir, archivedProjection.run.artifactsRef, artifacts);
9710
- const archiveTransition = applyClassicTransition(archivedProjection.classic, "archived");
9784
+ const archiveTransition = applyClassicTransition(
9785
+ recovering && archivedProjection.classic.archiveConfirmation !== "confirmed" ? { ...archivedProjection.classic, archiveConfirmation: "confirmed" } : archivedProjection.classic,
9786
+ "archived"
9787
+ );
9711
9788
  const archivedClassic = archiveTransition.classic;
9712
9789
  let transitionedRun = archivedProjection.run;
9713
9790
  if (archivedProjection.run.currentStep !== "completed" || archivedProjection.run.status !== "completed") {
@@ -9805,11 +9882,98 @@ var classicArchiveCommand = async (args) => {
9805
9882
  };
9806
9883
 
9807
9884
  // domains/comet-classic/classic-guard.ts
9808
- var import_yaml4 = __toESM(require_dist(), 1);
9885
+ var import_yaml5 = __toESM(require_dist(), 1);
9809
9886
  import { spawnSync as spawnSync2 } from "child_process";
9810
9887
  import { createHash as createHash4 } from "crypto";
9811
- import { existsSync, promises as fs13, readFileSync } from "fs";
9812
- import path14 from "path";
9888
+ import { existsSync, promises as fs15, readFileSync } from "fs";
9889
+ import path16 from "path";
9890
+
9891
+ // domains/comet-classic/classic-command-checks.ts
9892
+ import path13 from "path";
9893
+ function validateScope(scope) {
9894
+ if (scope !== "build" && scope !== "verify") {
9895
+ throw new Error(`Invalid command check scope: '${String(scope)}'`);
9896
+ }
9897
+ }
9898
+ function projectRoot(changeDir) {
9899
+ return path13.resolve(changeDir, "..", "..", "..");
9900
+ }
9901
+ function normalizedCwd(changeDir, cwd = ".") {
9902
+ if (cwd.trim().length === 0) throw new Error("Command check cwd cannot be blank");
9903
+ const root = projectRoot(changeDir);
9904
+ const target = path13.resolve(root, cwd);
9905
+ if (target !== root && !target.startsWith(root + path13.sep)) {
9906
+ throw new Error(`Command check cwd must resolve within the project root: '${cwd}'`);
9907
+ }
9908
+ return path13.relative(root, target).replaceAll("\\", "/") || ".";
9909
+ }
9910
+ function validRecord(changeDir, event) {
9911
+ if (event.type !== "command_check_recorded") return null;
9912
+ const data = event.data;
9913
+ if (typeof data !== "object" || data === null || Array.isArray(data)) return null;
9914
+ const { scope, command, exitCode, cwd } = data;
9915
+ if (scope !== "build" && scope !== "verify" || typeof command !== "string" || command.trim().length === 0 || !Number.isInteger(exitCode) || typeof cwd !== "string") {
9916
+ return null;
9917
+ }
9918
+ let normalized2;
9919
+ try {
9920
+ normalized2 = normalizedCwd(changeDir, cwd);
9921
+ } catch {
9922
+ return null;
9923
+ }
9924
+ return {
9925
+ sequence: event.sequence,
9926
+ timestamp: event.timestamp,
9927
+ runId: event.runId,
9928
+ scope,
9929
+ command,
9930
+ exitCode,
9931
+ cwd: normalized2
9932
+ };
9933
+ }
9934
+ async function recordCommandCheck(changeDir, run, input) {
9935
+ validateScope(input.scope);
9936
+ if (typeof input.command !== "string" || input.command.trim().length === 0) {
9937
+ throw new Error("Command check command cannot be blank");
9938
+ }
9939
+ if (!Number.isInteger(input.exitCode)) {
9940
+ throw new Error("Command check exitCode must be an integer");
9941
+ }
9942
+ const trajectory = await readTrajectory(changeDir, run.trajectoryRef);
9943
+ const recorded = {
9944
+ sequence: trajectory.reduce((maximum, event) => Math.max(maximum, event.sequence), 0) + 1,
9945
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
9946
+ runId: run.runId,
9947
+ scope: input.scope,
9948
+ command: input.command,
9949
+ exitCode: input.exitCode,
9950
+ cwd: normalizedCwd(changeDir, input.cwd)
9951
+ };
9952
+ await appendTrajectory(changeDir, run.trajectoryRef, {
9953
+ sequence: recorded.sequence,
9954
+ timestamp: recorded.timestamp,
9955
+ type: "command_check_recorded",
9956
+ runId: recorded.runId,
9957
+ data: {
9958
+ scope: recorded.scope,
9959
+ command: recorded.command,
9960
+ exitCode: recorded.exitCode,
9961
+ cwd: recorded.cwd
9962
+ }
9963
+ });
9964
+ return recorded;
9965
+ }
9966
+ async function latestCommandCheck(changeDir, run, scope) {
9967
+ validateScope(scope);
9968
+ const trajectory = await readTrajectory(changeDir, run.trajectoryRef);
9969
+ for (let index = trajectory.length - 1; index >= 0; index -= 1) {
9970
+ const event = trajectory[index];
9971
+ if (event.runId !== run.runId) continue;
9972
+ const record = validRecord(changeDir, event);
9973
+ if (record?.scope === scope) return record;
9974
+ }
9975
+ return null;
9976
+ }
9813
9977
 
9814
9978
  // domains/comet-classic/classic-runtime-evals.ts
9815
9979
  var STEP_EVIDENCE = {
@@ -9904,7 +10068,7 @@ async function inspectClassicChange(changeDir, name) {
9904
10068
  // domains/comet-classic/classic-validate-command.ts
9905
10069
  var import_yaml3 = __toESM(require_dist(), 1);
9906
10070
  import { promises as fs12 } from "fs";
9907
- import path13 from "path";
10071
+ import path14 from "path";
9908
10072
  var GREEN2 = "\x1B[32m";
9909
10073
  var RED2 = "\x1B[31m";
9910
10074
  var YELLOW2 = "\x1B[33m";
@@ -9936,6 +10100,7 @@ var ENUMS = {
9936
10100
  auto_transition: ["true", "false"],
9937
10101
  verify_result: ["pending", "pass", "fail"],
9938
10102
  branch_status: ["pending", "handled"],
10103
+ archive_confirmation: ["pending", "confirmed"],
9939
10104
  archived: ["true", "false"],
9940
10105
  direct_override: ["true", "false"],
9941
10106
  classic_profile: ["full", "hotfix", "tweak"],
@@ -9974,7 +10139,7 @@ var classicValidateCommand = async (args) => {
9974
10139
  };
9975
10140
  }
9976
10141
  const { directory, label } = await resolveClassicChangeDirectory(name);
9977
- const yamlFile = path13.join(directory, ".comet.yaml");
10142
+ const yamlFile = path14.join(directory, ".comet.yaml");
9978
10143
  const lines = [`[VALIDATE] ${label}/.comet.yaml`];
9979
10144
  let errors = 0;
9980
10145
  let warnings = 0;
@@ -10025,7 +10190,7 @@ var classicValidateCommand = async (args) => {
10025
10190
  }
10026
10191
  for (const field2 of ["design_doc", "plan", "handoff_context"]) {
10027
10192
  const value = text(record[field2]);
10028
- if (value && !await exists3(path13.resolve(value))) {
10193
+ if (value && !await exists3(path14.resolve(value))) {
10029
10194
  fail3(`${field2}='${value}' does not exist on disk`);
10030
10195
  }
10031
10196
  }
@@ -10047,6 +10212,62 @@ var classicValidateCommand = async (args) => {
10047
10212
  return { exitCode: 0, stderr: lines.join("\n") };
10048
10213
  };
10049
10214
 
10215
+ // domains/comet-classic/classic-project-config.ts
10216
+ var import_yaml4 = __toESM(require_dist(), 1);
10217
+ import os from "os";
10218
+ import { promises as fs14 } from "fs";
10219
+ import path15 from "path";
10220
+
10221
+ // platform/fs/file-system.ts
10222
+ import { promises as fs13 } from "fs";
10223
+ async function fileExists3(filePath) {
10224
+ try {
10225
+ await fs13.access(filePath);
10226
+ return true;
10227
+ } catch {
10228
+ return false;
10229
+ }
10230
+ }
10231
+ async function readDir(dirPath) {
10232
+ try {
10233
+ return await fs13.readdir(dirPath);
10234
+ } catch (error) {
10235
+ const code = error?.code;
10236
+ if (code === "ENOENT" || code === "ENOTDIR") {
10237
+ return [];
10238
+ }
10239
+ throw error;
10240
+ }
10241
+ }
10242
+
10243
+ // domains/comet-classic/classic-project-config.ts
10244
+ function configCandidates(options = {}) {
10245
+ const cwd = options.cwd ?? process.cwd();
10246
+ const homeDir = options.homeDir ?? os.homedir();
10247
+ const candidates = [
10248
+ { file: path15.resolve(cwd, ".comet", "config.yaml"), source: ".comet/config.yaml" },
10249
+ {
10250
+ file: path15.resolve(homeDir, ".comet", "config.yaml"),
10251
+ source: "~/.comet/config.yaml"
10252
+ }
10253
+ ];
10254
+ return candidates.filter(
10255
+ (candidate, index) => candidates.findIndex((entry2) => entry2.file === candidate.file) === index
10256
+ );
10257
+ }
10258
+ async function readClassicConfigValue(field2, options = {}) {
10259
+ for (const candidate of configCandidates(options)) {
10260
+ if (!await fileExists3(candidate.file)) continue;
10261
+ const document = (0, import_yaml4.parseDocument)(await fs14.readFile(candidate.file, "utf8"), {
10262
+ uniqueKeys: false
10263
+ });
10264
+ const value = document.get(field2);
10265
+ if (value === null || value === void 0) continue;
10266
+ return { value: String(value), source: candidate.source };
10267
+ }
10268
+ return null;
10269
+ }
10270
+
10050
10271
  // domains/comet-classic/classic-guard.ts
10051
10272
  var GREEN3 = "\x1B[32m";
10052
10273
  var RED3 = "\x1B[31m";
@@ -10111,7 +10332,7 @@ var GuardOutput = class {
10111
10332
  };
10112
10333
  async function exists4(file) {
10113
10334
  try {
10114
- await fs13.access(file);
10335
+ await fs15.access(file);
10115
10336
  return true;
10116
10337
  } catch (error) {
10117
10338
  if (error.code === "ENOENT") return false;
@@ -10120,7 +10341,7 @@ async function exists4(file) {
10120
10341
  }
10121
10342
  async function nonempty(file) {
10122
10343
  try {
10123
- return (await fs13.stat(file)).size > 0;
10344
+ return (await fs15.stat(file)).size > 0;
10124
10345
  } catch (error) {
10125
10346
  if (error.code === "ENOENT") return false;
10126
10347
  throw error;
@@ -10133,32 +10354,9 @@ function validateChangeName2(name) {
10133
10354
  async function resolveChangeDir(name) {
10134
10355
  return (await resolveClassicChangeDirectory(name)).label;
10135
10356
  }
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
10357
  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 });
10358
+ const file = path16.join(changeDir, ".comet.yaml");
10359
+ const document = (0, import_yaml5.parseDocument)(await fs15.readFile(file, "utf8"), { uniqueKeys: false });
10162
10360
  if (document.errors.length > 0) {
10163
10361
  throw new GuardFailure(`ERROR: Invalid .comet.yaml: ${document.errors[0].message}`);
10164
10362
  }
@@ -10171,18 +10369,7 @@ async function readField(changeDir, field2) {
10171
10369
  async function projectConfigValue(field2, changeDir) {
10172
10370
  const changeValue = await readField(changeDir, field2);
10173
10371
  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 "";
10372
+ return (await readClassicConfigValue(field2))?.value ?? "";
10186
10373
  }
10187
10374
  async function configuredLanguage(changeDir) {
10188
10375
  const language = await projectConfigValue("language", changeDir);
@@ -10210,7 +10397,7 @@ function countEnglishWords(source) {
10210
10397
  }
10211
10398
  async function documentLanguageMatchesConfigured(changeDir, file) {
10212
10399
  const language = await configuredLanguage(changeDir);
10213
- const source = stripFencedCodeBlocks(await fs13.readFile(file, "utf8"));
10400
+ const source = stripFencedCodeBlocks(await fs15.readFile(file, "utf8"));
10214
10401
  const cjk = countCjkChars(source);
10215
10402
  const englishWords = countEnglishWords(source);
10216
10403
  if (language === "zh-CN" && cjk < 20 && englishWords >= 20) {
@@ -10234,7 +10421,7 @@ async function handoffSourceFiles(changeDir) {
10234
10421
  const files = [`${changeDir}/proposal.md`, `${changeDir}/design.md`, `${changeDir}/tasks.md`];
10235
10422
  const specs = `${changeDir}/specs`;
10236
10423
  if (await exists4(specs)) {
10237
- for (const entry2 of (await fs13.readdir(specs)).sort()) {
10424
+ for (const entry2 of (await fs15.readdir(specs)).sort()) {
10238
10425
  const spec = `${specs}/${entry2}/spec.md`;
10239
10426
  if (await exists4(spec)) files.push(spec);
10240
10427
  }
@@ -10254,13 +10441,13 @@ async function preflight(changeDir, name) {
10254
10441
  if (!await exists4(changeDir)) {
10255
10442
  throw new GuardFailure(red2(`FATAL: change directory not found: ${changeDir}`));
10256
10443
  }
10257
- if (!await exists4(path14.join(changeDir, ".comet.yaml"))) {
10444
+ if (!await exists4(path16.join(changeDir, ".comet.yaml"))) {
10258
10445
  throw new GuardFailure(red2(`FATAL: .comet.yaml not found in ${changeDir}`));
10259
10446
  }
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}
10447
+ const result5 = await classicValidateCommand([name], { json: false });
10448
+ if (result5.exitCode !== 0) {
10449
+ if (result5.stderr)
10450
+ process.stderr.write(result5.stderr.endsWith("\n") ? result5.stderr : `${result5.stderr}
10264
10451
  `);
10265
10452
  throw new GuardFailure(red2("FATAL: .comet.yaml schema validation failed"));
10266
10453
  }
@@ -10275,6 +10462,9 @@ async function preflight(changeDir, name) {
10275
10462
  function pushCheck(output, outcome) {
10276
10463
  if (outcome.passed) {
10277
10464
  output.stderr.push(green2(` [PASS] ${outcome.description}`));
10465
+ if (outcome.detail) {
10466
+ for (const line of outcome.detail.split("\n")) output.stderr.push(green2(` ${line}`));
10467
+ }
10278
10468
  } else {
10279
10469
  output.stderr.push(red2(` [FAIL] ${outcome.description}`));
10280
10470
  if (outcome.detail) {
@@ -10285,11 +10475,11 @@ function pushCheck(output, outcome) {
10285
10475
  function check(description, run) {
10286
10476
  return async () => {
10287
10477
  try {
10288
- const result3 = await run();
10478
+ const result5 = await run();
10289
10479
  return {
10290
10480
  description,
10291
- passed: result3.passed,
10292
- detail: ("detail" in result3 ? result3.detail : "") ?? ""
10481
+ passed: result5.passed,
10482
+ detail: ("detail" in result5 ? result5.detail : "") ?? ""
10293
10483
  };
10294
10484
  } catch (error) {
10295
10485
  return {
@@ -10300,8 +10490,8 @@ function check(description, run) {
10300
10490
  }
10301
10491
  };
10302
10492
  }
10303
- function pass() {
10304
- return { passed: true };
10493
+ function pass(detail) {
10494
+ return { passed: true, ...detail ? { detail } : {} };
10305
10495
  }
10306
10496
  function fail(detail) {
10307
10497
  return { passed: false, detail };
@@ -10315,10 +10505,15 @@ async function runChecks(output, builders) {
10315
10505
  }
10316
10506
  return blocked2;
10317
10507
  }
10508
+ var INFERRED_COMMAND_SOURCES = [
10509
+ "package.json with a build script",
10510
+ "pom.xml",
10511
+ "Cargo.toml"
10512
+ ];
10318
10513
  async function removedProjectCommandField(field2) {
10319
- const config = path14.join(".comet", "config.yaml");
10514
+ const config = path16.join(".comet", "config.yaml");
10320
10515
  if (!await exists4(config)) return false;
10321
- const document = (0, import_yaml4.parseDocument)(await fs13.readFile(config, "utf8"));
10516
+ const document = (0, import_yaml5.parseDocument)(await fs15.readFile(config, "utf8"));
10322
10517
  if (document.errors.length > 0) {
10323
10518
  throw new Error(
10324
10519
  `.comet/config.yaml is invalid YAML (${document.errors[0].message}); cannot check for removed "${field2}" field. Fix the config and retry.`
@@ -10334,47 +10529,79 @@ function removedProjectCommandRun(field2) {
10334
10529
  };
10335
10530
  }
10336
10531
  function runInferred(command) {
10337
- const result3 = spawnSync2(command, { shell: true, encoding: "utf8", timeout: 3e5 });
10532
+ const result5 = spawnSync2(command, { shell: true, encoding: "utf8", timeout: 3e5 });
10338
10533
  return {
10339
- status: result3.status ?? 1,
10340
- output: `${result3.stdout ?? ""}${result3.stderr ?? ""}`.replace(/\n+$/u, "")
10534
+ status: result5.status ?? 1,
10535
+ output: `${result5.stdout ?? ""}${result5.stderr ?? ""}`.replace(/\n+$/u, "")
10341
10536
  };
10342
10537
  }
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");
10538
+ async function inferredBuildCommand() {
10539
+ if (await exists4("package.json") && (() => {
10540
+ const parsed = JSON.parse(readFileSync("package.json", "utf8"));
10541
+ return typeof parsed.scripts?.build === "string";
10542
+ })()) {
10543
+ return "npm run build";
10350
10544
  }
10351
10545
  if (await exists4("pom.xml")) {
10352
10546
  if (process.platform === "win32") {
10353
- if (existsSync("mvnw.cmd")) return runInferred("mvnw.cmd compile -q");
10354
- return runInferred("mvn.cmd compile -q");
10547
+ if (existsSync("mvnw.cmd")) return "mvnw.cmd compile -q";
10548
+ return "mvn.cmd compile -q";
10355
10549
  }
10356
- if (existsSync("mvnw")) return runInferred("./mvnw compile -q");
10357
- return runInferred("mvn compile -q");
10550
+ if (existsSync("mvnw")) return "./mvnw compile -q";
10551
+ return "mvn compile -q";
10358
10552
  }
10359
- if (await exists4("Cargo.toml")) return runInferred("cargo build");
10360
- return { status: 1, output: "" };
10553
+ if (await exists4("Cargo.toml")) return "cargo build";
10554
+ return null;
10555
+ }
10556
+ function evidenceDetail(record) {
10557
+ return `Evidence: recorded command-check at ${record.timestamp}; command: ${record.command}; cwd: ${record.cwd}`;
10558
+ }
10559
+ function recoveryCommand(change, scope, command) {
10560
+ return `comet state record-check ${change} ${scope} --command "${command}" --exit-code 0`;
10361
10561
  }
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");
10562
+ async function commandCheckPasses(changeDir, change, run, scope) {
10563
+ if (process.env.COMET_SKIP_BUILD === "1") {
10564
+ return { status: 0, output: "SKIPPED via COMET_SKIP_BUILD=1" };
10366
10565
  }
10367
- return buildPasses();
10566
+ const removedFields = scope === "build" ? ["build_command"] : ["verify_command", "build_command"];
10567
+ for (const removedField of removedFields) {
10568
+ if (await removedProjectCommandField(removedField)) {
10569
+ return removedProjectCommandRun(removedField);
10570
+ }
10571
+ }
10572
+ const inferred = scope === "build" ? await inferredBuildCommand() : null;
10573
+ if (inferred) return runInferred(inferred);
10574
+ const recorded = await latestCommandCheck(changeDir, run, scope);
10575
+ if (!recorded) {
10576
+ return {
10577
+ status: 1,
10578
+ output: scope === "build" ? `No inferred build command or recorded build check. Detection searched: ${INFERRED_COMMAND_SOURCES.join(", ")}.
10579
+ Next: run the required command, then record it with:
10580
+ ${recoveryCommand(change, scope, "<command>")}` : `No recorded verify check.
10581
+ Next: run the required verification command, then record it with:
10582
+ ${recoveryCommand(change, scope, "<command>")}`
10583
+ };
10584
+ }
10585
+ if (recorded.exitCode !== 0) {
10586
+ return {
10587
+ status: recorded.exitCode,
10588
+ output: `Latest recorded ${scope} check failed with exit code ${recorded.exitCode}.
10589
+ ${evidenceDetail(recorded)}
10590
+ Next: rerun the command successfully, then record it with:
10591
+ ${recoveryCommand(change, scope, recorded.command)}`
10592
+ };
10593
+ }
10594
+ return { status: 0, output: evidenceDetail(recorded) };
10368
10595
  }
10369
10596
  async function tasksAllDone(changeDir) {
10370
- const tasks = path14.join(changeDir, "tasks.md");
10597
+ const tasks = path16.join(changeDir, "tasks.md");
10371
10598
  if (!await exists4(tasks)) {
10372
10599
  return fail(
10373
10600
  `tasks.md is missing at ${tasks}
10374
10601
  Next: restore or create tasks.md for this change before leaving build.`
10375
10602
  );
10376
10603
  }
10377
- const source = await fs13.readFile(tasks, "utf8");
10604
+ const source = await fs15.readFile(tasks, "utf8");
10378
10605
  if (!/- \[x\]/u.test(source)) {
10379
10606
  return fail(
10380
10607
  "tasks.md has no completed tasks.\nNext: complete implementation tasks and mark them with '- [x]'."
@@ -10391,9 +10618,9 @@ Next: complete or explicitly remove unfinished tasks, then mark tasks.md with '-
10391
10618
  return pass();
10392
10619
  }
10393
10620
  async function tasksHasAny(changeDir) {
10394
- const tasks = path14.join(changeDir, "tasks.md");
10621
+ const tasks = path16.join(changeDir, "tasks.md");
10395
10622
  if (!await exists4(tasks)) return false;
10396
- return /- \[/u.test(await fs13.readFile(tasks, "utf8"));
10623
+ return /- \[/u.test(await fs15.readFile(tasks, "utf8"));
10397
10624
  }
10398
10625
  async function planTasksAllDone(changeDir) {
10399
10626
  const plan = await readField(changeDir, "plan");
@@ -10404,7 +10631,7 @@ async function planTasksAllDone(changeDir) {
10404
10631
  Next: restore the Superpowers plan file or update .comet.yaml plan before leaving build.`
10405
10632
  );
10406
10633
  }
10407
- const source = await fs13.readFile(plan, "utf8");
10634
+ const source = await fs15.readFile(plan, "utf8");
10408
10635
  const unfinished = source.split(/\r?\n/u).map((line, index) => ({ line, number: index + 1 })).filter((entry2) => /^\s*- \[ \]/u.test(entry2.line));
10409
10636
  if (unfinished.length > 0) {
10410
10637
  return fail(
@@ -10493,7 +10720,7 @@ async function archivedIsTrue(changeDir) {
10493
10720
  return await readField(changeDir, "archived") === "true";
10494
10721
  }
10495
10722
  async function designDocFrontmatterHas(designDoc, field2, expected) {
10496
- const source = (await fs13.readFile(designDoc, "utf8")).replace(/^\uFEFF/u, "");
10723
+ const source = (await fs15.readFile(designDoc, "utf8")).replace(/^\uFEFF/u, "");
10497
10724
  let inFrontmatter = false;
10498
10725
  for (const line of source.split(/\r?\n/u)) {
10499
10726
  if (!inFrontmatter) {
@@ -10558,7 +10785,7 @@ async function designHandoffMarkdownTraceable(changeDir) {
10558
10785
  const markdown = `${context.replace(/\.json$/u, "")}.md`;
10559
10786
  if (!await nonempty(markdown))
10560
10787
  return fail(`design handoff markdown is missing or empty: ${markdown}`);
10561
- const source = await fs13.readFile(markdown, "utf8");
10788
+ const source = await fs15.readFile(markdown, "utf8");
10562
10789
  const problems = [];
10563
10790
  if (!/^Generated-by: comet-handoff\.sh$/mu.test(source)) {
10564
10791
  problems.push("handoff markdown is missing Generated-by marker");
@@ -10585,7 +10812,7 @@ async function betaSpecJsonStructurallyValid(changeDir) {
10585
10812
  const context = await readField(changeDir, "handoff_context");
10586
10813
  if (!context || context === "null") return fail("handoff_context is missing from .comet.yaml");
10587
10814
  if (!await nonempty(context)) return fail(`spec-context.json is missing or empty: ${context}`);
10588
- const source = await fs13.readFile(context, "utf8");
10815
+ const source = await fs15.readFile(context, "utf8");
10589
10816
  const problems = [];
10590
10817
  let parsed;
10591
10818
  try {
@@ -10622,19 +10849,19 @@ async function guardOpenChecks(output, changeDir) {
10622
10849
  const checks = [
10623
10850
  check(
10624
10851
  "proposal.md exists and non-empty",
10625
- async () => await nonempty(path14.join(changeDir, "proposal.md")) ? pass() : fail("")
10852
+ async () => await nonempty(path16.join(changeDir, "proposal.md")) ? pass() : fail("")
10626
10853
  ),
10627
10854
  check(
10628
10855
  "proposal.md matches configured language",
10629
- () => documentLanguageMatchesConfigured(changeDir, path14.join(changeDir, "proposal.md"))
10856
+ () => documentLanguageMatchesConfigured(changeDir, path16.join(changeDir, "proposal.md"))
10630
10857
  ),
10631
10858
  check(
10632
10859
  "tasks.md exists and non-empty",
10633
- async () => await nonempty(path14.join(changeDir, "tasks.md")) ? pass() : fail("")
10860
+ async () => await nonempty(path16.join(changeDir, "tasks.md")) ? pass() : fail("")
10634
10861
  ),
10635
10862
  check(
10636
10863
  "tasks.md matches configured language",
10637
- () => documentLanguageMatchesConfigured(changeDir, path14.join(changeDir, "tasks.md"))
10864
+ () => documentLanguageMatchesConfigured(changeDir, path16.join(changeDir, "tasks.md"))
10638
10865
  ),
10639
10866
  check(
10640
10867
  "tasks.md has at least one task",
@@ -10647,11 +10874,11 @@ async function guardOpenChecks(output, changeDir) {
10647
10874
  0,
10648
10875
  check(
10649
10876
  "design.md exists and non-empty",
10650
- async () => await nonempty(path14.join(changeDir, "design.md")) ? pass() : fail("")
10877
+ async () => await nonempty(path16.join(changeDir, "design.md")) ? pass() : fail("")
10651
10878
  ),
10652
10879
  check(
10653
10880
  "design.md matches configured language",
10654
- () => documentLanguageMatchesConfigured(changeDir, path14.join(changeDir, "design.md"))
10881
+ () => documentLanguageMatchesConfigured(changeDir, path16.join(changeDir, "design.md"))
10655
10882
  )
10656
10883
  );
10657
10884
  }
@@ -10663,27 +10890,27 @@ async function guardDesignChecks(output, changeDir, change) {
10663
10890
  const builders = [
10664
10891
  check(
10665
10892
  "proposal.md exists",
10666
- async () => await nonempty(path14.join(changeDir, "proposal.md")) ? pass() : fail("")
10893
+ async () => await nonempty(path16.join(changeDir, "proposal.md")) ? pass() : fail("")
10667
10894
  ),
10668
10895
  check(
10669
10896
  "proposal.md matches configured language",
10670
- () => documentLanguageMatchesConfigured(changeDir, path14.join(changeDir, "proposal.md"))
10897
+ () => documentLanguageMatchesConfigured(changeDir, path16.join(changeDir, "proposal.md"))
10671
10898
  ),
10672
10899
  check(
10673
10900
  "design.md exists",
10674
- async () => await nonempty(path14.join(changeDir, "design.md")) ? pass() : fail("")
10901
+ async () => await nonempty(path16.join(changeDir, "design.md")) ? pass() : fail("")
10675
10902
  ),
10676
10903
  check(
10677
10904
  "design.md matches configured language",
10678
- () => documentLanguageMatchesConfigured(changeDir, path14.join(changeDir, "design.md"))
10905
+ () => documentLanguageMatchesConfigured(changeDir, path16.join(changeDir, "design.md"))
10679
10906
  ),
10680
10907
  check(
10681
10908
  "tasks.md exists",
10682
- async () => await nonempty(path14.join(changeDir, "tasks.md")) ? pass() : fail("")
10909
+ async () => await nonempty(path16.join(changeDir, "tasks.md")) ? pass() : fail("")
10683
10910
  ),
10684
10911
  check(
10685
10912
  "tasks.md matches configured language",
10686
- () => documentLanguageMatchesConfigured(changeDir, path14.join(changeDir, "tasks.md"))
10913
+ () => documentLanguageMatchesConfigured(changeDir, path16.join(changeDir, "tasks.md"))
10687
10914
  ),
10688
10915
  check("design handoff context exists", () => designHandoffContextValid(changeDir, change)),
10689
10916
  check("design handoff markdown is traceable", () => designHandoffMarkdownTraceable(changeDir))
@@ -10732,7 +10959,7 @@ async function guardDesignChecks(output, changeDir, change) {
10732
10959
  }
10733
10960
  return blocked2;
10734
10961
  }
10735
- async function guardBuildChecks(output, changeDir, change) {
10962
+ async function guardBuildChecks(output, changeDir, change, run) {
10736
10963
  return runChecks(output, [
10737
10964
  check("isolation selected", () => isolationSelected(changeDir, change)),
10738
10965
  check("build_mode selected", () => buildModeSelected(changeDir, change)),
@@ -10744,11 +10971,11 @@ async function guardBuildChecks(output, changeDir, change) {
10744
10971
  check("Superpowers plan all tasks checked", () => planTasksAllDone(changeDir)),
10745
10972
  check(
10746
10973
  "proposal.md exists",
10747
- async () => await nonempty(path14.join(changeDir, "proposal.md")) ? pass() : fail("")
10974
+ async () => await nonempty(path16.join(changeDir, "proposal.md")) ? pass() : fail("")
10748
10975
  ),
10749
10976
  check(
10750
10977
  "proposal.md matches configured language",
10751
- () => documentLanguageMatchesConfigured(changeDir, path14.join(changeDir, "proposal.md"))
10978
+ () => documentLanguageMatchesConfigured(changeDir, path16.join(changeDir, "proposal.md"))
10752
10979
  ),
10753
10980
  check("Superpowers plan matches configured language", async () => {
10754
10981
  const plan = await readField(changeDir, "plan");
@@ -10758,19 +10985,19 @@ async function guardBuildChecks(output, changeDir, change) {
10758
10985
  // Build check runs last — only after all config checks pass — to avoid
10759
10986
  // wasting time on a build that would be rejected by a config failure.
10760
10987
  check("Build passes", async () => {
10761
- const buildResult = await buildPasses();
10762
- return buildResult.status === 0 ? pass() : fail(buildResult.output);
10988
+ const buildResult = await commandCheckPasses(changeDir, change, run, "build");
10989
+ return buildResult.status === 0 ? pass(buildResult.output) : fail(buildResult.output);
10763
10990
  })
10764
10991
  ]);
10765
10992
  }
10766
- async function guardVerifyChecks(output, changeDir) {
10993
+ async function guardVerifyChecks(output, changeDir, change, run) {
10767
10994
  return runChecks(output, [
10768
10995
  check("tasks.md all tasks checked", () => tasksAllDone(changeDir)),
10769
10996
  // Verification command runs after tasks check — no point running tests
10770
10997
  // if tasks.md is incomplete.
10771
10998
  check("Verification passes", async () => {
10772
- const verifyResult = await verificationCommandPasses();
10773
- return verifyResult.status === 0 ? pass() : fail(verifyResult.output);
10999
+ const verifyResult = await commandCheckPasses(changeDir, change, run, "verify");
11000
+ return verifyResult.status === 0 ? pass(verifyResult.output) : fail(verifyResult.output);
10774
11001
  }),
10775
11002
  check(
10776
11003
  "verification_report exists",
@@ -10792,11 +11019,11 @@ async function guardArchiveChecks(output, changeDir) {
10792
11019
  check("archived is true", async () => await archivedIsTrue(changeDir) ? pass() : fail("")),
10793
11020
  check(
10794
11021
  "proposal.md exists",
10795
- async () => await nonempty(path14.join(changeDir, "proposal.md")) ? pass() : fail("")
11022
+ async () => await nonempty(path16.join(changeDir, "proposal.md")) ? pass() : fail("")
10796
11023
  ),
10797
11024
  check(
10798
11025
  "design.md exists",
10799
- async () => await nonempty(path14.join(changeDir, "design.md")) ? pass() : fail("")
11026
+ async () => await nonempty(path16.join(changeDir, "design.md")) ? pass() : fail("")
10800
11027
  ),
10801
11028
  check("tasks.md all tasks checked", () => tasksAllDone(changeDir))
10802
11029
  ]);
@@ -10804,8 +11031,8 @@ async function guardArchiveChecks(output, changeDir) {
10804
11031
  async function applyStateUpdate(output, change, changeDir, phase, context) {
10805
11032
  const event = CLASSIC_GUARD_TRANSITION_EVENT[phase];
10806
11033
  if (!event) return;
10807
- const result3 = applyClassicTransition(context.classic, event);
10808
- await transitionClassicRuntimeRun(changeDir, result3.classic, context.run, {
11034
+ const result5 = applyClassicTransition(context.classic, event);
11035
+ await transitionClassicRuntimeRun(changeDir, result5.classic, context.run, {
10809
11036
  event,
10810
11037
  phase,
10811
11038
  source: "comet-guard"
@@ -10815,15 +11042,15 @@ async function applyStateUpdate(output, change, changeDir, phase, context) {
10815
11042
  event,
10816
11043
  source: "comet-guard",
10817
11044
  from: context.classic,
10818
- to: result3.classic,
10819
- effects: result3.effects
11045
+ to: result5.classic,
11046
+ effects: result5.effects
10820
11047
  });
10821
- for (const effect of result3.effects) {
11048
+ for (const effect of result5.effects) {
10822
11049
  output.stderr.push(green2(`[SET] ${wireField(effect.field)}=${wireValue(effect.to)}`));
10823
11050
  }
10824
11051
  output.stderr.push(green2(`[TRANSITION] ${event}`));
10825
11052
  const template = APPLY_MESSAGE[phase];
10826
- const message = phase === "open" ? template.replace("PLACEHOLDER", result3.classic.phase) : template;
11053
+ const message = phase === "open" ? template.replace("PLACEHOLDER", result5.classic.phase) : template;
10827
11054
  output.stderr.push(green2(message));
10828
11055
  }
10829
11056
  var classicGuardCommand = async (args, options) => {
@@ -10853,8 +11080,10 @@ Valid phases: open, design, build, verify, archive`
10853
11080
  let blocked2;
10854
11081
  if (phase === "open") blocked2 = await guardOpenChecks(output, changeDir);
10855
11082
  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);
11083
+ else if (phase === "build")
11084
+ blocked2 = await guardBuildChecks(output, changeDir, change, runContext.run);
11085
+ else if (phase === "verify")
11086
+ blocked2 = await guardVerifyChecks(output, changeDir, change, runContext.run);
10858
11087
  else blocked2 = await guardArchiveChecks(output, changeDir);
10859
11088
  if (blocked2) {
10860
11089
  output.stderr.push("");
@@ -10877,10 +11106,10 @@ Valid phases: open, design, build, verify, archive`
10877
11106
  };
10878
11107
 
10879
11108
  // domains/comet-classic/classic-handoff.ts
10880
- var import_yaml5 = __toESM(require_dist(), 1);
11109
+ var import_yaml6 = __toESM(require_dist(), 1);
10881
11110
  import { createHash as createHash5 } from "crypto";
10882
- import { promises as fs14, readFileSync as readFileSync2 } from "fs";
10883
- import path15 from "path";
11111
+ import { promises as fs16, readFileSync as readFileSync2 } from "fs";
11112
+ import path17 from "path";
10884
11113
  var GREEN4 = "\x1B[32m";
10885
11114
  var RED4 = "\x1B[31m";
10886
11115
  var YELLOW4 = "\x1B[33m";
@@ -10914,7 +11143,7 @@ var HandoffOutput = class {
10914
11143
  };
10915
11144
  async function exists5(file) {
10916
11145
  try {
10917
- await fs14.access(file);
11146
+ await fs16.access(file);
10918
11147
  return true;
10919
11148
  } catch (error) {
10920
11149
  if (error.code === "ENOENT") return false;
@@ -10923,7 +11152,7 @@ async function exists5(file) {
10923
11152
  }
10924
11153
  async function nonempty2(file) {
10925
11154
  try {
10926
- return (await fs14.stat(file)).size > 0;
11155
+ return (await fs16.stat(file)).size > 0;
10927
11156
  } catch (error) {
10928
11157
  if (error.code === "ENOENT") return false;
10929
11158
  throw error;
@@ -10952,7 +11181,7 @@ async function handoffSourceFiles2(changeDir) {
10952
11181
  const files = [`${changeDir}/proposal.md`, `${changeDir}/design.md`, `${changeDir}/tasks.md`];
10953
11182
  const specs = `${changeDir}/specs`;
10954
11183
  if (await exists5(specs)) {
10955
- for (const entry2 of (await fs14.readdir(specs)).sort()) {
11184
+ for (const entry2 of (await fs16.readdir(specs)).sort()) {
10956
11185
  const spec = `${specs}/${entry2}/spec.md`;
10957
11186
  if (await exists5(spec)) files.push(spec);
10958
11187
  }
@@ -11000,7 +11229,7 @@ async function writeMarkdownContext(changeDir, change, mode, contextHash, output
11000
11229
  ];
11001
11230
  for (const file of await handoffSourceFiles2(changeDir)) {
11002
11231
  if (!await exists5(file)) continue;
11003
- const content = await fs14.readFile(file, "utf8");
11232
+ const content = await fs16.readFile(file, "utf8");
11004
11233
  const total = lineCount(content);
11005
11234
  lines.push(
11006
11235
  `## ${file}`,
@@ -11025,7 +11254,7 @@ async function writeMarkdownContext(changeDir, change, mode, contextHash, output
11025
11254
  }
11026
11255
  lines.push("");
11027
11256
  }
11028
- await fs14.writeFile(output, lines.join("\n"));
11257
+ await fs16.writeFile(output, lines.join("\n"));
11029
11258
  }
11030
11259
  async function writeJsonContext(changeDir, change, mode, contextHash, output) {
11031
11260
  const entries = [];
@@ -11048,7 +11277,7 @@ async function writeJsonContext(changeDir, change, mode, contextHash, output) {
11048
11277
  "}",
11049
11278
  ""
11050
11279
  ].join("\n");
11051
- await fs14.writeFile(output, document);
11280
+ await fs16.writeFile(output, document);
11052
11281
  }
11053
11282
  async function writeSpecProjectionForFile(file, content) {
11054
11283
  return [
@@ -11088,11 +11317,11 @@ async function writeSpecMarkdownContext(changeDir, change, contextHash, output)
11088
11317
  const specs = `${changeDir}/specs`;
11089
11318
  let projected = false;
11090
11319
  if (await exists5(specs)) {
11091
- for (const entry2 of (await fs14.readdir(specs)).sort()) {
11320
+ for (const entry2 of (await fs16.readdir(specs)).sort()) {
11092
11321
  const spec = `${specs}/${entry2}/spec.md`;
11093
11322
  if (!await exists5(spec)) continue;
11094
11323
  projected = true;
11095
- lines.push(...await writeSpecProjectionForFile(spec, await fs14.readFile(spec, "utf8")));
11324
+ lines.push(...await writeSpecProjectionForFile(spec, await fs16.readFile(spec, "utf8")));
11096
11325
  }
11097
11326
  }
11098
11327
  if (!projected) {
@@ -11101,7 +11330,7 @@ async function writeSpecMarkdownContext(changeDir, change, contextHash, output)
11101
11330
  lines.push(
11102
11331
  "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
11332
  );
11104
- await fs14.writeFile(output, lines.join("\n"));
11333
+ await fs16.writeFile(output, lines.join("\n"));
11105
11334
  }
11106
11335
  async function writeSpecJsonContext(changeDir, change, contextHash, output) {
11107
11336
  const entries = [];
@@ -11110,7 +11339,7 @@ async function writeSpecJsonContext(changeDir, change, contextHash, output) {
11110
11339
  const role = /\/specs\/[^/]+\/spec\.md$/u.test(file) ? "spec" : "supporting";
11111
11340
  entries.push({ path: file, sha256: hashFile2(file), role });
11112
11341
  }
11113
- await fs14.writeFile(
11342
+ await fs16.writeFile(
11114
11343
  output,
11115
11344
  `${JSON.stringify(
11116
11345
  {
@@ -11129,8 +11358,8 @@ async function writeSpecJsonContext(changeDir, change, contextHash, output) {
11129
11358
  );
11130
11359
  }
11131
11360
  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 });
11361
+ const file = path17.join(changeDir, ".comet.yaml");
11362
+ const document = (0, import_yaml6.parseDocument)(await fs16.readFile(file, "utf8"), { uniqueKeys: false });
11134
11363
  if (document.errors.length > 0) {
11135
11364
  throw new HandoffFailure(`ERROR: Invalid .comet.yaml: ${document.errors[0].message}`);
11136
11365
  }
@@ -11164,7 +11393,7 @@ async function completedHandoffIsCurrent(changeDir, run, contextHash, contextJso
11164
11393
  readCheckpoint(changeDir, run.checkpointRef)
11165
11394
  ]);
11166
11395
  if (!await exists5(contextJson) || !await exists5(contextMd)) return false;
11167
- if (context !== await fs14.readFile(contextMd, "utf8")) return false;
11396
+ if (context !== await fs16.readFile(contextMd, "utf8")) return false;
11168
11397
  if (artifacts.handoff_context !== contextJson || artifacts.handoff_markdown !== contextMd) {
11169
11398
  return false;
11170
11399
  }
@@ -11287,7 +11516,7 @@ var classicHandoffCommand = async (args) => {
11287
11516
  run: pendingRun,
11288
11517
  unknownKeys: (await readClassicState(changeDir)).unknownKeys
11289
11518
  });
11290
- await fs14.mkdir(handoffDir, { recursive: true });
11519
+ await fs16.mkdir(handoffDir, { recursive: true });
11291
11520
  if (handoffMode === "beta") {
11292
11521
  await writeSpecMarkdownContext(changeDir, change, contextHash, contextMd);
11293
11522
  await writeSpecJsonContext(changeDir, change, contextHash, contextJson);
@@ -11295,7 +11524,7 @@ var classicHandoffCommand = async (args) => {
11295
11524
  await writeMarkdownContext(changeDir, change, handoffMode, contextHash, contextMd);
11296
11525
  await writeJsonContext(changeDir, change, handoffMode, contextHash, contextJson);
11297
11526
  }
11298
- const context = await fs14.readFile(contextMd, "utf8");
11527
+ const context = await fs16.readFile(contextMd, "utf8");
11299
11528
  await writeContext(changeDir, pendingRun.contextRef, context);
11300
11529
  const artifacts = {
11301
11530
  ...await readArtifacts(changeDir, pendingRun.artifactsRef),
@@ -11352,8 +11581,140 @@ var classicHandoffCommand = async (args) => {
11352
11581
  };
11353
11582
 
11354
11583
  // 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";
11584
+ import { existsSync as existsSync2, promises as fs18, readFileSync as readFileSync3 } from "fs";
11585
+ import path19 from "path";
11586
+
11587
+ // domains/comet-classic/classic-current-change.ts
11588
+ import { execFileSync } from "child_process";
11589
+ import { randomUUID as randomUUID6 } from "crypto";
11590
+ import { promises as fs17 } from "fs";
11591
+ import path18 from "path";
11592
+ function currentChangeFile(projectRoot2) {
11593
+ return path18.join(projectRoot2, ".comet", "current-change.json");
11594
+ }
11595
+ function currentBranch(projectRoot2) {
11596
+ try {
11597
+ const branch = execFileSync("git", ["rev-parse", "--abbrev-ref", "HEAD"], {
11598
+ cwd: projectRoot2,
11599
+ encoding: "utf8",
11600
+ stdio: ["ignore", "pipe", "ignore"]
11601
+ }).trim();
11602
+ return branch && branch !== "HEAD" ? branch : null;
11603
+ } catch {
11604
+ return null;
11605
+ }
11606
+ }
11607
+ function changeDirectory(projectRoot2, changeName) {
11608
+ return path18.join(projectRoot2, "openspec", "changes", changeName);
11609
+ }
11610
+ async function validateActiveChange(projectRoot2, changeName) {
11611
+ assertOpenSpecChangeName(changeName);
11612
+ const changeDir = changeDirectory(projectRoot2, changeName);
11613
+ try {
11614
+ await fs17.access(path18.join(changeDir, ".comet.yaml"));
11615
+ } catch (error) {
11616
+ if (error.code === "ENOENT") {
11617
+ throw new Error(
11618
+ `Cannot select current change '${changeName}': active change state not found`,
11619
+ {
11620
+ cause: error
11621
+ }
11622
+ );
11623
+ }
11624
+ throw error;
11625
+ }
11626
+ const projection = await readClassicState(changeDir, { migrate: false });
11627
+ if (!projection.classic) {
11628
+ throw new Error(`Cannot select current change '${changeName}': Classic state is incomplete`);
11629
+ }
11630
+ if (projection.classic.archived) {
11631
+ throw new Error(`Cannot select current change '${changeName}': change is archived`);
11632
+ }
11633
+ }
11634
+ function parseSelection(source) {
11635
+ let value;
11636
+ try {
11637
+ value = JSON.parse(source);
11638
+ } catch (error) {
11639
+ throw new Error(
11640
+ `current change selection contains invalid JSON: ${error instanceof Error ? error.message : String(error)}`,
11641
+ { cause: error }
11642
+ );
11643
+ }
11644
+ if (!value || typeof value !== "object" || Array.isArray(value)) {
11645
+ throw new Error("current change selection must be a JSON object");
11646
+ }
11647
+ const record = value;
11648
+ if (record.version !== 1) {
11649
+ throw new Error("current change selection version must be 1");
11650
+ }
11651
+ if (typeof record.change !== "string") {
11652
+ throw new Error("current change selection change must be a string");
11653
+ }
11654
+ assertOpenSpecChangeName(record.change);
11655
+ if (record.branch !== null && typeof record.branch !== "string") {
11656
+ throw new Error("current change selection branch must be a string or null");
11657
+ }
11658
+ return {
11659
+ version: 1,
11660
+ change: record.change,
11661
+ branch: record.branch
11662
+ };
11663
+ }
11664
+ async function selectCurrentChange(projectRoot2, changeName) {
11665
+ await validateActiveChange(projectRoot2, changeName);
11666
+ const selection = {
11667
+ version: 1,
11668
+ change: changeName,
11669
+ branch: currentBranch(projectRoot2)
11670
+ };
11671
+ const file = currentChangeFile(projectRoot2);
11672
+ const temporary = `${file}.${randomUUID6()}.tmp`;
11673
+ await fs17.mkdir(path18.dirname(file), { recursive: true });
11674
+ try {
11675
+ await fs17.writeFile(temporary, JSON.stringify(selection, null, 2) + "\n", "utf8");
11676
+ await fs17.rename(temporary, file);
11677
+ } catch (error) {
11678
+ await fs17.rm(temporary, { force: true });
11679
+ throw error;
11680
+ }
11681
+ return selection;
11682
+ }
11683
+ async function resolveCurrentChange(projectRoot2) {
11684
+ let source;
11685
+ try {
11686
+ source = await fs17.readFile(currentChangeFile(projectRoot2), "utf8");
11687
+ } catch (error) {
11688
+ if (error.code === "ENOENT") return { status: "missing" };
11689
+ return {
11690
+ status: "stale",
11691
+ reason: `cannot read current change selection: ${error instanceof Error ? error.message : String(error)}`
11692
+ };
11693
+ }
11694
+ let selection;
11695
+ try {
11696
+ selection = parseSelection(source);
11697
+ await validateActiveChange(projectRoot2, selection.change);
11698
+ } catch (error) {
11699
+ return {
11700
+ status: "stale",
11701
+ reason: error instanceof Error ? error.message : String(error)
11702
+ };
11703
+ }
11704
+ const branch = currentBranch(projectRoot2);
11705
+ if (selection.branch !== null && branch !== selection.branch) {
11706
+ return {
11707
+ status: "stale",
11708
+ reason: `current change '${selection.change}' was selected on branch '${selection.branch}', current branch is '${branch ?? "detached HEAD"}'`
11709
+ };
11710
+ }
11711
+ return { status: "selected", selection };
11712
+ }
11713
+ async function clearCurrentChange(projectRoot2) {
11714
+ await fs17.rm(currentChangeFile(projectRoot2), { force: true });
11715
+ }
11716
+
11717
+ // domains/comet-classic/classic-hook-guard.ts
11357
11718
  function result(exitCode, message) {
11358
11719
  return { exitCode, stderr: message + "\n" };
11359
11720
  }
@@ -11378,52 +11739,52 @@ function normalized(value) {
11378
11739
  function parseProjectRoot(args) {
11379
11740
  const index = args.indexOf("--project-root");
11380
11741
  const value = index >= 0 ? args[index + 1] : void 0;
11381
- return path16.resolve(value && !value.startsWith("--") ? value : process.cwd());
11742
+ return path19.resolve(value && !value.startsWith("--") ? value : process.cwd());
11382
11743
  }
11383
- function relativeToProjectRoot(target, projectRoot) {
11384
- const relative = normalized(path16.relative(projectRoot, target));
11744
+ function relativeToProjectRoot(target, projectRoot2) {
11745
+ const relative = normalized(path19.relative(projectRoot2, target));
11385
11746
  if (relative === "") return "";
11386
- if (relative.startsWith("../") || relative === ".." || path16.isAbsolute(relative)) return null;
11747
+ if (relative.startsWith("../") || relative === ".." || path19.isAbsolute(relative)) return null;
11387
11748
  return relative;
11388
11749
  }
11389
11750
  async function physicalPathForPossiblyMissingTarget(target) {
11390
- const resolved = path16.resolve(target);
11391
- const root = path16.parse(resolved).root;
11751
+ const resolved = path19.resolve(target);
11752
+ const root = path19.parse(resolved).root;
11392
11753
  const missingSegments = [];
11393
11754
  let cursor = resolved;
11394
11755
  while (cursor && cursor !== root) {
11395
11756
  try {
11396
- const physicalBase = await fs15.realpath(cursor);
11397
- return path16.join(physicalBase, ...missingSegments.reverse());
11757
+ const physicalBase = await fs18.realpath(cursor);
11758
+ return path19.join(physicalBase, ...missingSegments.reverse());
11398
11759
  } catch (error) {
11399
11760
  const code = error.code;
11400
11761
  if (code !== "ENOENT" && code !== "ENOTDIR") throw error;
11401
- missingSegments.push(path16.basename(cursor));
11402
- cursor = path16.dirname(cursor);
11762
+ missingSegments.push(path19.basename(cursor));
11763
+ cursor = path19.dirname(cursor);
11403
11764
  }
11404
11765
  }
11405
11766
  try {
11406
- const physicalRoot = await fs15.realpath(root);
11407
- return path16.join(physicalRoot, ...missingSegments.reverse());
11767
+ const physicalRoot = await fs18.realpath(root);
11768
+ return path19.join(physicalRoot, ...missingSegments.reverse());
11408
11769
  } catch {
11409
11770
  return null;
11410
11771
  }
11411
11772
  }
11412
- async function projectRelative(target, projectRoot) {
11413
- const rawCandidate = path16.isAbsolute(target) ? target : path16.resolve(process.cwd(), target);
11773
+ async function projectRelative(target, projectRoot2) {
11774
+ const rawCandidate = path19.isAbsolute(target) ? target : path19.resolve(process.cwd(), target);
11414
11775
  let candidate = normalized(rawCandidate);
11415
- const rootRelative = relativeToProjectRoot(rawCandidate, projectRoot);
11776
+ const rootRelative = relativeToProjectRoot(rawCandidate, projectRoot2);
11416
11777
  if (rootRelative !== null) return rootRelative;
11417
11778
  try {
11418
11779
  const physicalCandidate = await physicalPathForPossiblyMissingTarget(rawCandidate);
11419
- const physicalRoot = await fs15.realpath(projectRoot);
11780
+ const physicalRoot = await fs18.realpath(projectRoot2);
11420
11781
  if (physicalCandidate) {
11421
11782
  const physicalRootRelative = relativeToProjectRoot(physicalCandidate, physicalRoot);
11422
11783
  if (physicalRootRelative !== null) return physicalRootRelative;
11423
11784
  candidate = normalized(physicalCandidate);
11424
11785
  }
11425
11786
  } catch {
11426
- if (!path16.isAbsolute(target)) return normalized(target).replace(/^\.\//u, "");
11787
+ if (!path19.isAbsolute(target)) return normalized(target).replace(/^\.\//u, "");
11427
11788
  }
11428
11789
  return candidate.replace(/^\.\//u, "");
11429
11790
  }
@@ -11447,28 +11808,22 @@ async function loadGoverningChange(changeDir) {
11447
11808
  };
11448
11809
  }
11449
11810
  }
11450
- async function activeChanges(projectRoot) {
11451
- const changesDir = path16.join(projectRoot, "openspec", "changes");
11811
+ async function activeChanges(projectRoot2) {
11812
+ const changesDir = path19.join(projectRoot2, "openspec", "changes");
11452
11813
  const governingChanges = [];
11453
11814
  if (!existsSync2(changesDir)) return governingChanges;
11454
- for (const entry2 of (await fs15.readdir(changesDir, { withFileTypes: true })).sort(
11815
+ for (const entry2 of (await fs18.readdir(changesDir, { withFileTypes: true })).sort(
11455
11816
  (left, right) => left.name.localeCompare(right.name)
11456
11817
  )) {
11457
11818
  if (!entry2.isDirectory() || entry2.name === "archive") continue;
11458
- const changeDir = path16.join(changesDir, entry2.name);
11459
- if (!existsSync2(path16.join(changeDir, ".comet.yaml"))) continue;
11819
+ const changeDir = path19.join(changesDir, entry2.name);
11820
+ if (!existsSync2(path19.join(changeDir, ".comet.yaml"))) continue;
11460
11821
  const governing = await loadGoverningChange(changeDir);
11461
11822
  if (!governing || governing.archived) continue;
11462
11823
  governingChanges.push(governing);
11463
11824
  }
11464
11825
  return governingChanges;
11465
11826
  }
11466
- function blocksSourceWrites(governing) {
11467
- if (governing.phase === "open" || governing.phase === "design" || governing.phase === "archive") {
11468
- return true;
11469
- }
11470
- return governing.phase === "build" && governing.classic?.workflow === "full" && !governing.classic.designDoc;
11471
- }
11472
11827
  function isSuperpowersArtifactPath(relativePath2) {
11473
11828
  return relativePath2.startsWith("docs/superpowers/");
11474
11829
  }
@@ -11476,7 +11831,7 @@ function allowsSuperpowersArtifacts(governing) {
11476
11831
  return governing.phase === "design" || governing.phase === "build" || governing.phase === "verify";
11477
11832
  }
11478
11833
  function governingChangeName(governing) {
11479
- return governing.changeDir ? path16.basename(governing.changeDir) : null;
11834
+ return governing.changeDir ? path19.basename(governing.changeDir) : null;
11480
11835
  }
11481
11836
  var SUPERPOWERS_ARTIFACT_SUFFIXES = /* @__PURE__ */ new Set([
11482
11837
  "design",
@@ -11507,8 +11862,8 @@ function matchesSuperpowersArtifactName(relativePath2, changeName) {
11507
11862
  const pattern = new RegExp(`(^|[-_.])${escapeRegex(changeName)}[-_.](${suffixes})$`, "u");
11508
11863
  return pattern.test(stem);
11509
11864
  }
11510
- async function superpowersArtifactGoverningChange(relativePath2, projectRoot) {
11511
- const active = await activeChanges(projectRoot);
11865
+ async function superpowersArtifactGoverningChange(relativePath2, projectRoot2) {
11866
+ const active = await activeChanges(projectRoot2);
11512
11867
  const recorded = active.find(
11513
11868
  (governing) => matchesRecordedSuperpowersArtifact(relativePath2, governing)
11514
11869
  );
@@ -11523,18 +11878,41 @@ async function superpowersArtifactGoverningChange(relativePath2, projectRoot) {
11523
11878
  if (named) return named;
11524
11879
  return null;
11525
11880
  }
11526
- async function repoSourceGoverningChange(projectRoot) {
11527
- const active = await activeChanges(projectRoot);
11528
- return active.find(blocksSourceWrites) ?? active[0] ?? null;
11881
+ async function repoSourceGoverningChange(projectRoot2, relativePath2) {
11882
+ const active = await activeChanges(projectRoot2);
11883
+ if (active.length === 0) return null;
11884
+ const current = await resolveCurrentChange(projectRoot2);
11885
+ if (current.status === "stale") {
11886
+ return { blockedResult: blockedStaleSelection(relativePath2, current.reason) };
11887
+ }
11888
+ if (current.status === "selected") {
11889
+ const selected = active.find(
11890
+ (governing) => governingChangeName(governing) === current.selection.change
11891
+ );
11892
+ if (selected) return selected;
11893
+ return {
11894
+ blockedResult: blockedStaleSelection(
11895
+ relativePath2,
11896
+ `selected change '${current.selection.change}' is no longer active`
11897
+ )
11898
+ };
11899
+ }
11900
+ if (active.length === 1) return active[0];
11901
+ return {
11902
+ blockedResult: blockedMultipleChanges(
11903
+ relativePath2,
11904
+ active.map((governing) => governingChangeName(governing)).filter(Boolean)
11905
+ )
11906
+ };
11529
11907
  }
11530
- async function governingChange(relativePath2, projectRoot) {
11908
+ async function governingChange(relativePath2, projectRoot2) {
11531
11909
  const prefix = "openspec/changes/";
11532
11910
  if (relativePath2.startsWith(prefix)) {
11533
11911
  const rest = relativePath2.slice(prefix.length);
11534
11912
  const [name] = rest.split("/");
11535
11913
  if (name && name !== "archive") {
11536
- const changeDir = path16.join(projectRoot, "openspec", "changes", name);
11537
- const stateFile2 = path16.join(changeDir, ".comet.yaml");
11914
+ const changeDir = path19.join(projectRoot2, "openspec", "changes", name);
11915
+ const stateFile2 = path19.join(changeDir, ".comet.yaml");
11538
11916
  if (existsSync2(stateFile2)) {
11539
11917
  const governing = await loadGoverningChange(changeDir);
11540
11918
  if (governing) return governing;
@@ -11544,12 +11922,12 @@ async function governingChange(relativePath2, projectRoot) {
11544
11922
  }
11545
11923
  }
11546
11924
  if (isSuperpowersArtifactPath(relativePath2)) {
11547
- const superpowers = await superpowersArtifactGoverningChange(relativePath2, projectRoot);
11925
+ const superpowers = await superpowersArtifactGoverningChange(relativePath2, projectRoot2);
11548
11926
  if (superpowers) return { ...superpowers, superpowersArtifact: "matched" };
11549
- const fallback = await repoSourceGoverningChange(projectRoot);
11927
+ const fallback = (await activeChanges(projectRoot2))[0] ?? null;
11550
11928
  return fallback ? { ...fallback, superpowersArtifact: "unmatched" } : null;
11551
11929
  }
11552
- return repoSourceGoverningChange(projectRoot);
11930
+ return repoSourceGoverningChange(projectRoot2, relativePath2);
11553
11931
  }
11554
11932
  function isRootMarkdown(relativePath2) {
11555
11933
  return !relativePath2.includes("/") && relativePath2.endsWith(".md");
@@ -11653,22 +12031,47 @@ function blockedUnmatchedSuperpowersArtifact(relativePath2, phase) {
11653
12031
  ].join("\n")
11654
12032
  );
11655
12033
  }
12034
+ function blockedMultipleChanges(relativePath2, changeNames) {
12035
+ return result(
12036
+ 2,
12037
+ [
12038
+ "",
12039
+ "╔══════════════════════════════════════════╗",
12040
+ "║ COMET PHASE GUARD — WRITE BLOCKED ║",
12041
+ "╚══════════════════════════════════════════╝",
12042
+ "",
12043
+ " BLOCKED: multiple active changes require a current change",
12044
+ ` Target file: ${relativePath2}`,
12045
+ ` Active changes: ${changeNames.join(", ")}`,
12046
+ "",
12047
+ " NEXT: run comet state select <change-name>, then retry the source write",
12048
+ ""
12049
+ ].join("\n")
12050
+ );
12051
+ }
12052
+ function blockedStaleSelection(relativePath2, reason) {
12053
+ return result(
12054
+ 2,
12055
+ [
12056
+ "",
12057
+ "╔══════════════════════════════════════════╗",
12058
+ "║ COMET PHASE GUARD — WRITE BLOCKED ║",
12059
+ "╚══════════════════════════════════════════╝",
12060
+ "",
12061
+ " BLOCKED: current change selection is stale or invalid",
12062
+ ` Target file: ${relativePath2}`,
12063
+ ` Reason: ${reason}`,
12064
+ "",
12065
+ " NEXT: run comet state select <change-name>, then retry the source write",
12066
+ ""
12067
+ ].join("\n")
12068
+ );
12069
+ }
11656
12070
  var classicHookGuardCommand = async (args) => {
11657
- const projectRoot = parseProjectRoot(args);
12071
+ const projectRoot2 = parseProjectRoot(args);
11658
12072
  const target = inputTarget();
11659
12073
  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)`);
12074
+ const relativePath2 = await projectRelative(target, projectRoot2);
11672
12075
  if (isCometConfig(relativePath2)) {
11673
12076
  return allowed(`${relativePath2} (whitelist: comet config)`);
11674
12077
  }
@@ -11681,6 +12084,18 @@ var classicHookGuardCommand = async (args) => {
11681
12084
  if (relativePath2 === "CLAUDE.md" || relativePath2 === "CHANGELOG.md" || relativePath2 === "README.md" || isRootMarkdown(relativePath2)) {
11682
12085
  return allowed(`${relativePath2} (whitelist: root markdown)`);
11683
12086
  }
12087
+ let governing;
12088
+ try {
12089
+ governing = await governingChange(relativePath2, projectRoot2);
12090
+ } catch (error) {
12091
+ return result(
12092
+ 2,
12093
+ `[COMET-HOOK] blocked: ${error instanceof Error ? error.message : String(error)}`
12094
+ );
12095
+ }
12096
+ if (!governing) return allowed("no active comet change");
12097
+ if ("blockedResult" in governing) return governing.blockedResult;
12098
+ if (governing.archived) return allowed(`${relativePath2} (own change archived)`);
11684
12099
  const phase = governing.phase;
11685
12100
  const openSpec = openSpecAllowed(relativePath2, phase);
11686
12101
  if (openSpec) return allowed(openSpec);
@@ -12069,12 +12484,438 @@ var classicIntentCommand = async (args, _options) => {
12069
12484
  }
12070
12485
  };
12071
12486
 
12487
+ // domains/comet-classic/classic-resume-probe.ts
12488
+ import path20 from "path";
12489
+ import { promises as fs19 } from "fs";
12490
+ import { spawn } from "child_process";
12491
+ var COMET_RESUME_PROBE_SCHEMA_VERSION = "comet.resume_probe.v1";
12492
+ function isRecord2(value) {
12493
+ return typeof value === "object" && value !== null && !Array.isArray(value);
12494
+ }
12495
+ function normalizeInput(input) {
12496
+ if (!isRecord2(input)) {
12497
+ throw new Error("Invalid CometResumeProbeInput: input must be an object");
12498
+ }
12499
+ if (input.schema_version !== COMET_RESUME_PROBE_SCHEMA_VERSION) {
12500
+ throw new Error(
12501
+ `Invalid CometResumeProbeInput: schema_version must be ${COMET_RESUME_PROBE_SCHEMA_VERSION}`
12502
+ );
12503
+ }
12504
+ if (typeof input.utterance !== "string") {
12505
+ throw new Error("Invalid CometResumeProbeInput: utterance must be a string");
12506
+ }
12507
+ const context = isRecord2(input.agent_context) ? input.agent_context : {};
12508
+ return {
12509
+ schema_version: COMET_RESUME_PROBE_SCHEMA_VERSION,
12510
+ utterance: input.utterance,
12511
+ locale: typeof input.locale === "string" ? input.locale : "unknown",
12512
+ agent_context: {
12513
+ non_trivial_work: context.non_trivial_work === true,
12514
+ already_in_comet_flow: context.already_in_comet_flow === true
12515
+ }
12516
+ };
12517
+ }
12518
+ function result3(action, change, confidence, reason, evidence = []) {
12519
+ return {
12520
+ schema_version: COMET_RESUME_PROBE_SCHEMA_VERSION,
12521
+ action,
12522
+ changeName: change?.name ?? null,
12523
+ phase: change?.phase ?? null,
12524
+ nextCommand: action === "auto_resume" || action === "ask_user" ? change?.nextCommand ?? null : null,
12525
+ confidence,
12526
+ reason,
12527
+ evidence
12528
+ };
12529
+ }
12530
+ async function readIfExists(filePath) {
12531
+ if (!await fileExists3(filePath)) return "";
12532
+ return fs19.readFile(filePath, "utf8");
12533
+ }
12534
+ async function changeSearchText(changeDir, classic) {
12535
+ const files = ["proposal.md", "design.md", "tasks.md"];
12536
+ const parts = [classic.name, classic.workflow, classic.phase];
12537
+ for (const file of files) {
12538
+ parts.push(await readIfExists(path20.join(changeDir, file)));
12539
+ }
12540
+ return parts.join("\n").toLowerCase();
12541
+ }
12542
+ function nextCommandForPhase2(phase) {
12543
+ switch (phase) {
12544
+ case "open":
12545
+ return "/comet-open";
12546
+ case "design":
12547
+ return "/comet-design";
12548
+ case "build":
12549
+ return "/comet-build";
12550
+ case "verify":
12551
+ return "/comet-verify";
12552
+ case "archive":
12553
+ return "/comet-archive";
12554
+ default:
12555
+ return null;
12556
+ }
12557
+ }
12558
+ function diagnosticFromProjection(changeDir, name, projection) {
12559
+ const classic = projection.classic;
12560
+ const unknownKeys = projection.unknownKeys.filter((key) => key !== "run_id");
12561
+ if (!classic) {
12562
+ return {
12563
+ name,
12564
+ valid: false,
12565
+ workflow: "unknown",
12566
+ phase: "invalid",
12567
+ currentStep: null,
12568
+ nextCommand: null,
12569
+ runtimeMode: "invalid",
12570
+ runtimeEval: null,
12571
+ evidence: [],
12572
+ error: `${changeDir} does not contain valid Comet state`
12573
+ };
12574
+ }
12575
+ if (unknownKeys.length > 0) {
12576
+ return {
12577
+ name,
12578
+ valid: false,
12579
+ workflow: classic.workflow,
12580
+ phase: classic.phase,
12581
+ currentStep: null,
12582
+ nextCommand: null,
12583
+ runtimeMode: "invalid",
12584
+ runtimeEval: null,
12585
+ evidence: [],
12586
+ error: `unknown field(s): ${unknownKeys.join(", ")}`
12587
+ };
12588
+ }
12589
+ return {
12590
+ name,
12591
+ valid: true,
12592
+ workflow: classic.workflow,
12593
+ phase: classic.phase,
12594
+ currentStep: null,
12595
+ nextCommand: nextCommandForPhase2(classic.phase),
12596
+ runtimeMode: "engine-projection",
12597
+ runtimeEval: null,
12598
+ evidence: []
12599
+ };
12600
+ }
12601
+ async function hasOpenSpecChangeFiles(changeDir) {
12602
+ return await fileExists3(path20.join(changeDir, "proposal.md")) || await fileExists3(path20.join(changeDir, "design.md")) || await fileExists3(path20.join(changeDir, "tasks.md"));
12603
+ }
12604
+ async function discoverActiveChanges(projectRoot2) {
12605
+ const changesDir = path20.join(projectRoot2, "openspec", "changes");
12606
+ if (!await fileExists3(changesDir)) return [];
12607
+ const entries = await readDir(changesDir);
12608
+ const changes = [];
12609
+ for (const entry2 of entries) {
12610
+ if (entry2 === "archive") continue;
12611
+ const changeDir = path20.join(changesDir, entry2);
12612
+ const stat = await fs19.stat(changeDir).catch(() => null);
12613
+ if (!stat?.isDirectory()) continue;
12614
+ const hasCometState = await fileExists3(path20.join(changeDir, ".comet.yaml"));
12615
+ if (!hasCometState) {
12616
+ if (!await hasOpenSpecChangeFiles(changeDir)) continue;
12617
+ const missingStateChange = {
12618
+ name: entry2,
12619
+ workflow: "unknown",
12620
+ phase: "invalid",
12621
+ nextCommand: null,
12622
+ diagnostic: {
12623
+ name: entry2,
12624
+ valid: false,
12625
+ workflow: "unknown",
12626
+ phase: "invalid",
12627
+ currentStep: null,
12628
+ nextCommand: null,
12629
+ runtimeMode: "invalid",
12630
+ runtimeEval: null,
12631
+ evidence: [],
12632
+ error: "missing Comet state"
12633
+ },
12634
+ buildPause: null,
12635
+ hasClassicProjection: false,
12636
+ verifyResult: null,
12637
+ text: "",
12638
+ missingCometState: true
12639
+ };
12640
+ missingStateChange.text = await changeSearchText(changeDir, missingStateChange);
12641
+ changes.push(missingStateChange);
12642
+ continue;
12643
+ }
12644
+ const projection = await readClassicState(changeDir, { migrate: false });
12645
+ const classic = projection.classic;
12646
+ const diagnostic = diagnosticFromProjection(changeDir, entry2, projection);
12647
+ const hasClassicProjection = Boolean(classic);
12648
+ const phase = classic?.phase ?? diagnostic.phase;
12649
+ const workflow = classic?.workflow ?? diagnostic.workflow;
12650
+ if (phase === "archive" || classic?.archived) continue;
12651
+ const change = {
12652
+ name: entry2,
12653
+ workflow,
12654
+ phase,
12655
+ nextCommand: diagnostic.nextCommand,
12656
+ diagnostic,
12657
+ buildPause: classic?.buildPause ?? null,
12658
+ hasClassicProjection,
12659
+ verifyResult: classic?.verifyResult ?? null,
12660
+ text: "",
12661
+ missingCometState: false
12662
+ };
12663
+ change.text = await changeSearchText(changeDir, change);
12664
+ changes.push(change);
12665
+ }
12666
+ return changes;
12667
+ }
12668
+ var RESUME_WORDS = [
12669
+ "continue",
12670
+ "resume",
12671
+ "carry on",
12672
+ "finish",
12673
+ "run it",
12674
+ "commit",
12675
+ "verify",
12676
+ "archive",
12677
+ "继续",
12678
+ "接着",
12679
+ "恢复",
12680
+ "跑完",
12681
+ "提交",
12682
+ "验证",
12683
+ "归档",
12684
+ "修刚才"
12685
+ ];
12686
+ var QUESTION_WORDS = [
12687
+ "what",
12688
+ "why",
12689
+ "how",
12690
+ "explain",
12691
+ "summarize",
12692
+ "reliable",
12693
+ "靠谱吗",
12694
+ "是什么",
12695
+ "为什么",
12696
+ "解释",
12697
+ "总结",
12698
+ "取名",
12699
+ "命名"
12700
+ ];
12701
+ var GENERIC_RELATED_TOKENS = /* @__PURE__ */ new Set([
12702
+ "add",
12703
+ "build",
12704
+ "cache",
12705
+ "change",
12706
+ "code",
12707
+ "design",
12708
+ "docs",
12709
+ "file",
12710
+ "fix",
12711
+ "implement",
12712
+ "plan",
12713
+ "readme",
12714
+ "task",
12715
+ "test",
12716
+ "update",
12717
+ "修改",
12718
+ "更新",
12719
+ "修复",
12720
+ "添加",
12721
+ "文档",
12722
+ "任务",
12723
+ "计划",
12724
+ "实现"
12725
+ ]);
12726
+ var OPT_OUT_WORDS = [
12727
+ "do not resume",
12728
+ "don't resume",
12729
+ "without comet",
12730
+ "skip comet",
12731
+ "不要恢复",
12732
+ "不走 comet",
12733
+ "不要走 comet",
12734
+ "直接解释",
12735
+ "只回答"
12736
+ ];
12737
+ function includesAny(text2, words) {
12738
+ return words.some((word) => text2.includes(word));
12739
+ }
12740
+ function hasDecisionPoint(change) {
12741
+ if (change.missingCometState) return true;
12742
+ if (!change.hasClassicProjection) return true;
12743
+ if (!change.diagnostic.valid) return true;
12744
+ if (change.phase === "archive") return true;
12745
+ if (change.verifyResult === "fail") return true;
12746
+ if (change.diagnostic.runtimeEval && !change.diagnostic.runtimeEval.passed) return true;
12747
+ if (change.phase !== "build") return false;
12748
+ if (change.buildPause === "plan-ready") return true;
12749
+ return false;
12750
+ }
12751
+ function relatedEvidence(utterance, change) {
12752
+ const text2 = utterance.toLowerCase();
12753
+ const evidence = [];
12754
+ if (text2.includes(change.name.toLowerCase())) {
12755
+ evidence.push({ source: "user", quote: change.name });
12756
+ }
12757
+ 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));
12758
+ const matched = [...new Set(tokens.filter((token) => text2.includes(token)))].slice(0, 3);
12759
+ for (const token of matched) {
12760
+ evidence.push({ source: "repo", quote: token });
12761
+ }
12762
+ return evidence;
12763
+ }
12764
+ async function gitDirtyFiles(projectRoot2) {
12765
+ return new Promise((resolve) => {
12766
+ const child = spawn("git", ["status", "--short", "--untracked-files=all"], {
12767
+ cwd: projectRoot2,
12768
+ stdio: ["ignore", "pipe", "ignore"],
12769
+ shell: false
12770
+ });
12771
+ const chunks = [];
12772
+ child.stdout.on("data", (chunk) => {
12773
+ chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(String(chunk)));
12774
+ });
12775
+ child.on("error", () => resolve([]));
12776
+ child.on("exit", (code) => {
12777
+ if (code !== 0) {
12778
+ resolve([]);
12779
+ return;
12780
+ }
12781
+ const dirtyFiles = Buffer.concat(chunks).toString("utf8").split(/\r?\n/u).map((line) => line.trim()).filter(Boolean);
12782
+ resolve(dirtyFiles);
12783
+ });
12784
+ });
12785
+ }
12786
+ async function resolveCometResumeProbe(projectRoot2, rawInput) {
12787
+ const input = normalizeInput(rawInput);
12788
+ const utterance = input.utterance.trim();
12789
+ const lower = utterance.toLowerCase();
12790
+ if (input.agent_context.already_in_comet_flow) {
12791
+ return result3("out_of_scope", null, "low", "already in Comet flow");
12792
+ }
12793
+ if (includesAny(lower, OPT_OUT_WORDS)) {
12794
+ return result3("out_of_scope", null, "low", "user opted out of Comet resume", [
12795
+ { source: "user", quote: utterance }
12796
+ ]);
12797
+ }
12798
+ const changes = await discoverActiveChanges(projectRoot2);
12799
+ if (changes.length === 0) {
12800
+ return result3("none", null, "none", "no active Comet changes");
12801
+ }
12802
+ const dirtyFiles = await gitDirtyFiles(projectRoot2);
12803
+ if (changes.length > 1) {
12804
+ const named = changes.find((change2) => lower.includes(change2.name.toLowerCase()));
12805
+ if (!named) {
12806
+ return result3("ask_user", null, "low", "multiple active changes require a change name");
12807
+ }
12808
+ if (dirtyFiles.length > 0) {
12809
+ return result3("ask_user", named, "low", "uncommitted worktree changes require attribution", [
12810
+ { source: "repo", quote: `${dirtyFiles.length} dirty file(s)` }
12811
+ ]);
12812
+ }
12813
+ 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", [
12814
+ { source: "user", quote: named.name }
12815
+ ]);
12816
+ }
12817
+ const [change] = changes;
12818
+ if (dirtyFiles.length > 0) {
12819
+ return result3("ask_user", change, "low", "uncommitted worktree changes require attribution", [
12820
+ { source: "repo", quote: `${dirtyFiles.length} dirty file(s)` }
12821
+ ]);
12822
+ }
12823
+ if (hasDecisionPoint(change)) {
12824
+ if (change.missingCometState) {
12825
+ return result3("ask_user", change, "low", "active OpenSpec change is missing Comet state");
12826
+ }
12827
+ return result3("ask_user", change, "low", "active change is at a decision point", [
12828
+ { source: "state", quote: `phase: ${change.phase}` }
12829
+ ]);
12830
+ }
12831
+ const resumeLike = includesAny(lower, RESUME_WORDS);
12832
+ const questionLike = !input.agent_context.non_trivial_work && includesAny(lower, QUESTION_WORDS);
12833
+ if (questionLike && !resumeLike) {
12834
+ return result3("out_of_scope", change, "low", "user asked a question without workflow work");
12835
+ }
12836
+ const evidence = relatedEvidence(utterance, change);
12837
+ if (resumeLike || evidence.length > 0) {
12838
+ return result3("auto_resume", change, "high", "single active change and request is related", [
12839
+ { source: "state", quote: `phase: ${change.phase}` },
12840
+ ...evidence
12841
+ ]);
12842
+ }
12843
+ if (input.agent_context.non_trivial_work) {
12844
+ return result3(
12845
+ "ask_user",
12846
+ change,
12847
+ "low",
12848
+ "single active change exists but request looks unrelated"
12849
+ );
12850
+ }
12851
+ return result3("out_of_scope", change, "low", "request is not workflow work");
12852
+ }
12853
+
12854
+ // domains/comet-classic/classic-resume-probe-command.ts
12855
+ function result4(exitCode, stdout, stderr) {
12856
+ return {
12857
+ exitCode,
12858
+ ...stdout === void 0 ? {} : { stdout },
12859
+ ...stderr === void 0 ? {} : { stderr }
12860
+ };
12861
+ }
12862
+ function usage2() {
12863
+ return result4(
12864
+ 64,
12865
+ void 0,
12866
+ "Usage: comet-resume-probe.mjs probe <input-json>\nUsage: comet-resume-probe.mjs probe --stdin"
12867
+ );
12868
+ }
12869
+ async function readStdin2() {
12870
+ const chunks = [];
12871
+ for await (const chunk of process.stdin) {
12872
+ chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(String(chunk)));
12873
+ }
12874
+ return Buffer.concat(chunks).toString("utf8");
12875
+ }
12876
+ function rawUtteranceInput(utterance) {
12877
+ return {
12878
+ schema_version: COMET_RESUME_PROBE_SCHEMA_VERSION,
12879
+ utterance,
12880
+ locale: "unknown",
12881
+ agent_context: {
12882
+ non_trivial_work: true,
12883
+ already_in_comet_flow: false
12884
+ }
12885
+ };
12886
+ }
12887
+ function parseStdinInput(source) {
12888
+ try {
12889
+ return JSON.parse(source);
12890
+ } catch {
12891
+ return rawUtteranceInput(source);
12892
+ }
12893
+ }
12894
+ var classicResumeProbeCommand = async (args) => {
12895
+ const [subcommand, input] = args;
12896
+ if (subcommand !== "probe") return usage2();
12897
+ const fromStdin = input === "--stdin";
12898
+ const source = fromStdin ? await readStdin2() : input;
12899
+ if (!source) return usage2();
12900
+ try {
12901
+ const parsedInput = fromStdin ? parseStdinInput(source) : JSON.parse(source);
12902
+ const resolution = await resolveCometResumeProbe(process.cwd(), parsedInput);
12903
+ return result4(0, `${JSON.stringify(resolution, null, 2)}
12904
+ `);
12905
+ } catch (error) {
12906
+ if (error instanceof SyntaxError) {
12907
+ return result4(1, void 0, `Invalid JSON: ${error.message}`);
12908
+ }
12909
+ return result4(1, void 0, error instanceof Error ? error.message : String(error));
12910
+ }
12911
+ };
12912
+
12072
12913
  // domains/comet-classic/classic-state-command.ts
12073
- var import_yaml6 = __toESM(require_dist(), 1);
12914
+ var import_yaml7 = __toESM(require_dist(), 1);
12074
12915
  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";
12916
+ import { randomUUID as randomUUID7 } from "crypto";
12917
+ import { existsSync as existsSync3, promises as fs20 } from "fs";
12918
+ import path21 from "path";
12078
12919
  init_state();
12079
12920
  var GREEN5 = "\x1B[32m";
12080
12921
  var RED5 = "\x1B[31m";
@@ -12086,6 +12927,7 @@ var ARTIFACT_LANGUAGES2 = ["en", "zh-CN"];
12086
12927
  var EVENTS = CLASSIC_TRANSITION_EVENTS;
12087
12928
  var MACHINE_OWNED_FIELDS = /* @__PURE__ */ new Set([
12088
12929
  ...RUN_WIRE_KEYS,
12930
+ "archive_confirmation",
12089
12931
  "classic_profile",
12090
12932
  "classic_migration"
12091
12933
  ]);
@@ -12106,6 +12948,7 @@ var FIELD_ENUMS = {
12106
12948
  auto_transition: ["true", "false"],
12107
12949
  verify_result: ["pending", "pass", "fail"],
12108
12950
  branch_status: ["pending", "handled"],
12951
+ archive_confirmation: ["pending", "confirmed"],
12109
12952
  archived: ["true", "false"],
12110
12953
  direct_override: ["true", "false"],
12111
12954
  classic_profile: PROFILES,
@@ -12121,6 +12964,7 @@ var CLASSIC_FIELD_WIRE_NAMES2 = {
12121
12964
  phase: "phase",
12122
12965
  verificationReport: "verification_report",
12123
12966
  verifiedAt: "verified_at",
12967
+ archiveConfirmation: "archive_confirmation",
12124
12968
  verifyResult: "verify_result",
12125
12969
  workflow: "workflow"
12126
12970
  };
@@ -12182,7 +13026,7 @@ function validateRelativePath(value, field2) {
12182
13026
  }
12183
13027
  async function exists6(file) {
12184
13028
  try {
12185
- await fs16.access(file);
13029
+ await fs20.access(file);
12186
13030
  return true;
12187
13031
  } catch (error) {
12188
13032
  if (error.code === "ENOENT") return false;
@@ -12191,39 +13035,39 @@ async function exists6(file) {
12191
13035
  }
12192
13036
  async function nonempty3(file) {
12193
13037
  try {
12194
- return (await fs16.stat(file)).size > 0;
13038
+ return (await fs20.stat(file)).size > 0;
12195
13039
  } catch (error) {
12196
13040
  if (error.code === "ENOENT") return false;
12197
13041
  throw error;
12198
13042
  }
12199
13043
  }
12200
- async function changeDirectory(name) {
13044
+ async function changeDirectory2(name) {
12201
13045
  return resolveClassicChangeDirectory(name);
12202
13046
  }
12203
13047
  async function readDocument2(file) {
12204
13048
  let source;
12205
13049
  try {
12206
- source = await fs16.readFile(file, "utf8");
13050
+ source = await fs20.readFile(file, "utf8");
12207
13051
  } catch (error) {
12208
13052
  if (error.code === "ENOENT") {
12209
13053
  fail2(
12210
- `ERROR: .comet.yaml not found at ${path17.relative(process.cwd(), file).replaceAll("\\", "/")}`
13054
+ `ERROR: .comet.yaml not found at ${path21.relative(process.cwd(), file).replaceAll("\\", "/")}`
12211
13055
  );
12212
13056
  }
12213
13057
  throw error;
12214
13058
  }
12215
- const document = (0, import_yaml6.parseDocument)(source, { uniqueKeys: false });
13059
+ const document = (0, import_yaml7.parseDocument)(source, { uniqueKeys: false });
12216
13060
  if (document.errors.length > 0) fail2(`ERROR: Invalid .comet.yaml: ${document.errors[0].message}`);
12217
13061
  return document;
12218
13062
  }
12219
13063
  async function atomicWrite2(file, content) {
12220
- await fs16.mkdir(path17.dirname(file), { recursive: true });
12221
- const temporary = `${file}.${randomUUID6()}.tmp`;
13064
+ await fs20.mkdir(path21.dirname(file), { recursive: true });
13065
+ const temporary = `${file}.${randomUUID7()}.tmp`;
12222
13066
  try {
12223
- await fs16.writeFile(temporary, content, "utf8");
12224
- await fs16.rename(temporary, file);
13067
+ await fs20.writeFile(temporary, content, "utf8");
13068
+ await fs20.rename(temporary, file);
12225
13069
  } catch (error) {
12226
- await fs16.rm(temporary, { force: true });
13070
+ await fs20.rm(temporary, { force: true });
12227
13071
  throw error;
12228
13072
  }
12229
13073
  }
@@ -12299,6 +13143,12 @@ function sparseClassicState(record) {
12299
13143
  branchStatus: enumRecordValue(record, "branch_status", ["pending", "handled"], null),
12300
13144
  createdAt: nullableRecordString(record, "created_at"),
12301
13145
  verifiedAt: nullableRecordString(record, "verified_at"),
13146
+ archiveConfirmation: enumRecordValue(
13147
+ record,
13148
+ "archive_confirmation",
13149
+ ["pending", "confirmed"],
13150
+ null
13151
+ ),
12302
13152
  archived: nullableRecordBoolean(record, "archived") ?? false,
12303
13153
  directOverride: nullableRecordBoolean(record, "direct_override"),
12304
13154
  handoffContext: nullableRecordString(record, "handoff_context"),
@@ -12308,17 +13158,13 @@ function sparseClassicState(record) {
12308
13158
  };
12309
13159
  }
12310
13160
  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);
13161
+ return (await readClassicConfigValue(field2))?.value ?? null;
12316
13162
  }
12317
13163
  async function projectLanguageDefault() {
12318
13164
  if (process.env.COMET_LANGUAGE)
12319
13165
  return validateLanguage(process.env.COMET_LANGUAGE, "COMET_LANGUAGE");
12320
- const value = await projectConfigValue2("language");
12321
- if (value) return validateLanguage(value, ".comet/config.yaml");
13166
+ const configured = await readClassicConfigValue("language");
13167
+ if (configured) return validateLanguage(configured.value, configured.source);
12322
13168
  return "en";
12323
13169
  }
12324
13170
  async function contextCompression() {
@@ -12346,14 +13192,14 @@ Valid values: off, standard, thorough`);
12346
13192
  return value === "null" ? null : value;
12347
13193
  }
12348
13194
  function gitOutput(args) {
12349
- const result3 = spawnSync3("git", args, { encoding: "utf8" });
12350
- return result3.status === 0 ? result3.stdout.trim() : null;
13195
+ const result5 = spawnSync3("git", args, { encoding: "utf8" });
13196
+ return result5.status === 0 ? result5.stdout.trim() : null;
12351
13197
  }
12352
13198
  async function stateFile(name) {
12353
- const change = await changeDirectory(name);
13199
+ const change = await changeDirectory2(name);
12354
13200
  return {
12355
13201
  ...change,
12356
- file: path17.join(change.directory, ".comet.yaml")
13202
+ file: path21.join(change.directory, ".comet.yaml")
12357
13203
  };
12358
13204
  }
12359
13205
  async function readField3(name, field2) {
@@ -12371,7 +13217,7 @@ async function readField3(name, field2) {
12371
13217
  return scalar(value);
12372
13218
  }
12373
13219
  function parsedValue(field2, value) {
12374
- const document = (0, import_yaml6.parseDocument)(`${field2}: ${value}
13220
+ const document = (0, import_yaml7.parseDocument)(`${field2}: ${value}
12375
13221
  `);
12376
13222
  if (document.errors.length > 0) fail2(`ERROR: Invalid value: '${value}'`);
12377
13223
  return document.get(field2);
@@ -12393,7 +13239,7 @@ function validateSetValue(field2, value) {
12393
13239
  }
12394
13240
  async function setField2(output, name, field2, value, options = {}) {
12395
13241
  if (MACHINE_OWNED_FIELDS.has(field2) && !options.machineOwned) {
12396
- fail2(`ERROR: '${field2}' is a machine-owned Run field and cannot be set directly`);
13242
+ fail2(`ERROR: '${field2}' is a machine-owned field and cannot be set directly`);
12397
13243
  }
12398
13244
  if (!SETTABLE_FIELDS.has(field2) && !MACHINE_OWNED_FIELDS.has(field2)) {
12399
13245
  fail2(`ERROR: Unknown field: '${field2}'`);
@@ -12456,10 +13302,10 @@ async function init(output, name, workflow) {
12456
13302
  validateEnum(workflow, PROFILES);
12457
13303
  const { file, label, directory } = await stateFile(name);
12458
13304
  if (await exists6(file)) fail2(`ERROR: .comet.yaml already exists at ${label}/.comet.yaml`);
12459
- await fs16.mkdir(directory, { recursive: true });
13305
+ await fs20.mkdir(directory, { recursive: true });
12460
13306
  const preset = workflow !== "full";
12461
13307
  const reviewMode = preset ? "off" : await reviewModeDefault();
12462
- const document = new import_yaml6.Document({
13308
+ const document = new import_yaml7.Document({
12463
13309
  workflow,
12464
13310
  language: await projectLanguageDefault(),
12465
13311
  phase: "open",
@@ -12480,6 +13326,7 @@ async function init(output, name, workflow) {
12480
13326
  branch_status: "pending",
12481
13327
  created_at: (/* @__PURE__ */ new Date()).toISOString().slice(0, 10),
12482
13328
  verified_at: null,
13329
+ archive_confirmation: null,
12483
13330
  archived: false
12484
13331
  });
12485
13332
  await atomicWrite2(file, document.toString());
@@ -12534,13 +13381,13 @@ async function requireOpenArtifacts(name) {
12534
13381
  const { directory } = await stateFile(name);
12535
13382
  const workflow = await readField3(name, "workflow");
12536
13383
  for (const artifact of ["proposal.md", "tasks.md"]) {
12537
- if (!await nonempty3(path17.join(directory, artifact))) {
13384
+ if (!await nonempty3(path21.join(directory, artifact))) {
12538
13385
  fail2(
12539
13386
  `ERROR: Cannot transition '${name}': ${artifact} must exist and be non-empty before leaving open`
12540
13387
  );
12541
13388
  }
12542
13389
  }
12543
- if (workflow === "full" && !await nonempty3(path17.join(directory, "design.md"))) {
13390
+ if (workflow === "full" && !await nonempty3(path21.join(directory, "design.md"))) {
12544
13391
  fail2(
12545
13392
  `ERROR: Cannot transition '${name}': design.md must exist and be non-empty before leaving open`
12546
13393
  );
@@ -12548,14 +13395,14 @@ async function requireOpenArtifacts(name) {
12548
13395
  }
12549
13396
  async function requireDesignEvidence(name) {
12550
13397
  const designDoc = await readField3(name, "design_doc");
12551
- if (!designDoc || designDoc === "null" || !await nonempty3(path17.resolve(designDoc))) {
13398
+ if (!designDoc || designDoc === "null" || !await nonempty3(path21.resolve(designDoc))) {
12552
13399
  fail2(
12553
13400
  `ERROR: Cannot transition '${name}': design_doc must point to an existing Design Doc before leaving design`
12554
13401
  );
12555
13402
  }
12556
13403
  }
12557
13404
  async function writeSparseTransitionEffects(directory, effects) {
12558
- const file = path17.join(directory, ".comet.yaml");
13405
+ const file = path21.join(directory, ".comet.yaml");
12559
13406
  const document = await readDocument2(file);
12560
13407
  for (const effect of effects) {
12561
13408
  const field2 = wireField2(effect.field);
@@ -12570,21 +13417,21 @@ async function applyTransitionEvent(output, name, event) {
12570
13417
  let sparse = false;
12571
13418
  if (!classic) {
12572
13419
  if (projection.run) fail2("ERROR: Classic state projection is missing");
12573
- const document = await readDocument2(path17.join(directory, ".comet.yaml"));
13420
+ const document = await readDocument2(path21.join(directory, ".comet.yaml"));
12574
13421
  classic = sparseClassicState(document.toJS());
12575
13422
  sparse = true;
12576
13423
  }
12577
- const result3 = applyClassicTransition(classic, event);
13424
+ const result5 = applyClassicTransition(classic, event);
12578
13425
  if (projection.run) {
12579
- await transitionClassicRuntimeRun(directory, result3.classic, projection.run, {
13426
+ await transitionClassicRuntimeRun(directory, result5.classic, projection.run, {
12580
13427
  event,
12581
13428
  source: "comet-state"
12582
13429
  });
12583
13430
  } else if (sparse) {
12584
- await writeSparseTransitionEffects(directory, result3.effects);
13431
+ await writeSparseTransitionEffects(directory, result5.effects);
12585
13432
  } else {
12586
13433
  await writeClassicState(directory, {
12587
- classic: result3.classic,
13434
+ classic: result5.classic,
12588
13435
  run: null,
12589
13436
  unknownKeys: projection.unknownKeys
12590
13437
  });
@@ -12594,10 +13441,10 @@ async function applyTransitionEvent(output, name, event) {
12594
13441
  event,
12595
13442
  source: "comet-state",
12596
13443
  from: classic,
12597
- to: result3.classic,
12598
- effects: result3.effects
13444
+ to: result5.classic,
13445
+ effects: result5.effects
12599
13446
  });
12600
- for (const effect of result3.effects) {
13447
+ for (const effect of result5.effects) {
12601
13448
  output.stderr.push(green4(`[SET] ${wireField2(effect.field)}=${wireValue2(effect.to)}`));
12602
13449
  }
12603
13450
  output.stderr.push(green4(`[TRANSITION] ${event}`));
@@ -12617,7 +13464,7 @@ async function transition(output, name, event) {
12617
13464
  } else if (event === "verify-pass") {
12618
13465
  await requirePhase(name, "verify");
12619
13466
  const report = await readField3(name, "verification_report");
12620
- if (!report || !await exists6(path17.resolve(report))) {
13467
+ if (!report || !await exists6(path21.resolve(report))) {
12621
13468
  fail2(
12622
13469
  `ERROR: Cannot transition '${name}': verification_report must point to an existing report file`
12623
13470
  );
@@ -12627,6 +13474,14 @@ async function transition(output, name, event) {
12627
13474
  }
12628
13475
  } else if (event === "verify-fail") {
12629
13476
  await requirePhase(name, "verify");
13477
+ } else if (event === "archive-confirm") {
13478
+ await requirePhase(name, "archive");
13479
+ if (await readField3(name, "verify_result") !== "pass") {
13480
+ fail2(`ERROR: Cannot transition '${name}': verify_result must be pass before archiving`);
13481
+ }
13482
+ if (await readField3(name, "archived") === "true") {
13483
+ fail2(`ERROR: Cannot transition '${name}': already archived`);
13484
+ }
12630
13485
  } else if (event === "preset-escalate") {
12631
13486
  await requirePhase(name, "build");
12632
13487
  const workflow = await readField3(name, "workflow");
@@ -12645,6 +13500,11 @@ async function transition(output, name, event) {
12645
13500
  if (await readField3(name, "verify_result") !== "pass") {
12646
13501
  fail2(`ERROR: Cannot transition '${name}': verify_result must be pass before archiving`);
12647
13502
  }
13503
+ if (await readField3(name, "archive_confirmation") !== "confirmed") {
13504
+ fail2(
13505
+ `ERROR: Cannot transition '${name}': archive_confirmation must be confirmed before archiving`
13506
+ );
13507
+ }
12648
13508
  }
12649
13509
  await applyTransitionEvent(output, name, event);
12650
13510
  }
@@ -12671,9 +13531,9 @@ async function next(output, name) {
12671
13531
  async function taskCheckoff(output, taskFile, taskText) {
12672
13532
  validateRelativePath(taskFile, "task file");
12673
13533
  if (!taskText) fail2("ERROR: Task text cannot be empty");
12674
- const file = path17.resolve(taskFile);
13534
+ const file = path21.resolve(taskFile);
12675
13535
  if (!await exists6(file)) fail2(`ERROR: Task file not found: ${taskFile}`);
12676
- const lines = (await fs16.readFile(file, "utf8")).split(/\r?\n/u);
13536
+ const lines = (await fs20.readFile(file, "utf8")).split(/\r?\n/u);
12677
13537
  const matches = lines.filter(
12678
13538
  (line) => [`- [ ] ${taskText}`, `- [x] ${taskText}`, `- [X] ${taskText}`].includes(line)
12679
13539
  );
@@ -12711,21 +13571,21 @@ async function check2(output, name, phase) {
12711
13571
  designDoc ? `design_doc=${designDoc} (expected: empty/null)` : "design_doc is empty/null"
12712
13572
  );
12713
13573
  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"}`
13574
+ (await nonempty3(path21.join(directory, artifact)) ? pass2 : reject)(
13575
+ `${artifact} ${await nonempty3(path21.join(directory, artifact)) ? "non-empty" : "missing or empty"}`
12716
13576
  );
12717
13577
  }
12718
13578
  } else if (phase === "build") {
12719
13579
  const workflow = await readField3(name, "workflow");
12720
13580
  const designDoc = await readField3(name, "design_doc");
12721
13581
  if (workflow === "full") {
12722
- (designDoc && designDoc !== "null" && await exists6(path17.resolve(designDoc)) ? pass2 : reject)(`design_doc=${designDoc} (expected: non-null and file exists)`);
13582
+ (designDoc && designDoc !== "null" && await exists6(path21.resolve(designDoc)) ? pass2 : reject)(`design_doc=${designDoc} (expected: non-null and file exists)`);
12723
13583
  } else {
12724
13584
  pass2(`workflow=${workflow} (design_doc not required)`);
12725
13585
  }
12726
13586
  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"}`
13587
+ (await nonempty3(path21.join(directory, artifact)) ? pass2 : reject)(
13588
+ `${artifact} ${await nonempty3(path21.join(directory, artifact)) ? "non-empty" : "missing or empty"}`
12729
13589
  );
12730
13590
  }
12731
13591
  } else if (phase === "verify") {
@@ -12747,7 +13607,7 @@ async function check2(output, name, phase) {
12747
13607
  }
12748
13608
  function fieldStatus(field2, value, file) {
12749
13609
  if (!value || value === "null") return ` - ${field2}: PENDING`;
12750
- if (file && !existsSync3(path17.resolve(file))) {
13610
+ if (file && !existsSync3(path21.resolve(file))) {
12751
13611
  return ` - ${field2}: BROKEN (path ${value} does not exist)`;
12752
13612
  }
12753
13613
  return ` - ${field2}: DONE (${value})`;
@@ -12756,7 +13616,7 @@ async function recoverOpen(output, directory) {
12756
13616
  output.stdout.push(" Artifacts:");
12757
13617
  let complete = 0;
12758
13618
  for (const artifact of ["proposal.md", "design.md", "tasks.md"]) {
12759
- const done = await nonempty3(path17.join(directory, artifact));
13619
+ const done = await nonempty3(path21.join(directory, artifact));
12760
13620
  if (done) complete += 1;
12761
13621
  output.stdout.push(` - ${artifact}: ${done ? "DONE" : "PENDING"}`);
12762
13622
  }
@@ -12769,7 +13629,7 @@ async function recoverDesign(output, name, directory) {
12769
13629
  output.stdout.push(" Artifacts:");
12770
13630
  for (const artifact of ["proposal.md", "design.md", "tasks.md"]) {
12771
13631
  output.stdout.push(
12772
- ` - ${artifact}: ${await nonempty3(path17.join(directory, artifact)) ? "DONE" : "MISSING (unexpected in design phase)"}`
13632
+ ` - ${artifact}: ${await nonempty3(path21.join(directory, artifact)) ? "DONE" : "MISSING (unexpected in design phase)"}`
12773
13633
  );
12774
13634
  }
12775
13635
  const handoff = await readField3(name, "handoff_context");
@@ -12783,11 +13643,11 @@ async function recoverDesign(output, name, directory) {
12783
13643
  fieldStatus("design_doc", design, design),
12784
13644
  ""
12785
13645
  );
12786
- if (design && design !== "null" && await exists6(path17.resolve(design))) {
13646
+ if (design && design !== "null" && await exists6(path21.resolve(design))) {
12787
13647
  output.stdout.push(
12788
13648
  "Recovery action: Design Doc already created and linked. Run guard to transition to build."
12789
13649
  );
12790
- } else if (handoff && handoff !== "null" && await exists6(path17.resolve(handoff))) {
13650
+ } else if (handoff && handoff !== "null" && await exists6(path21.resolve(handoff))) {
12791
13651
  output.stdout.push(
12792
13652
  "Recovery action: Handoff generated but Design Doc not yet created. Resume from brainstorming confirmation (Step 1c)."
12793
13653
  );
@@ -12817,7 +13677,7 @@ async function recoverBuild(output, name, directory, workflow) {
12817
13677
  decisions.push(fieldStatus("subagent_dispatch", subagentDispatch));
12818
13678
  }
12819
13679
  output.stdout.push(...decisions, "", " Plan:", fieldStatus("plan", plan, plan), "");
12820
- const tasks = path17.join(directory, "tasks.md");
13680
+ const tasks = path21.join(directory, "tasks.md");
12821
13681
  if (!await exists6(tasks)) {
12822
13682
  output.stdout.push(
12823
13683
  " Tasks: tasks.md MISSING",
@@ -12826,14 +13686,14 @@ async function recoverBuild(output, name, directory, workflow) {
12826
13686
  );
12827
13687
  return;
12828
13688
  }
12829
- const lines = (await fs16.readFile(tasks, "utf8")).split(/\r?\n/u);
13689
+ const lines = (await fs20.readFile(tasks, "utf8")).split(/\r?\n/u);
12830
13690
  const total = lines.filter((line) => /^\s*- \[[ xX]\] /u.test(line)).length;
12831
13691
  const done = lines.filter((line) => /^\s*- \[[xX]\] /u.test(line)).length;
12832
13692
  const pending = total - done;
12833
13693
  let planTotal = 0;
12834
13694
  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);
13695
+ if (plan && plan !== "null" && await exists6(path21.resolve(plan))) {
13696
+ const planLines = (await fs20.readFile(path21.resolve(plan), "utf8")).split(/\r?\n/u);
12837
13697
  planTotal = planLines.filter((line) => /^\s*- \[[ xX]\] /u.test(line)).length;
12838
13698
  planDone = planLines.filter((line) => /^\s*- \[[xX]\] /u.test(line)).length;
12839
13699
  }
@@ -12905,27 +13765,29 @@ function resolveBuildRecoveryAction(workflow, isolation, buildMode, pause, subag
12905
13765
  return "Recovery action: All tasks done. Run guard to transition to verify.";
12906
13766
  }
12907
13767
  async function recoverVerify(output, name) {
12908
- const result3 = await readField3(name, "verify_result");
13768
+ const result5 = await readField3(name, "verify_result");
12909
13769
  const mode = await readField3(name, "verify_mode");
12910
13770
  const report = await readField3(name, "verification_report");
12911
13771
  const branch = await readField3(name, "branch_status");
12912
13772
  output.stdout.push(
12913
13773
  " Verification:",
12914
- fieldStatus("verify_result", result3),
13774
+ fieldStatus("verify_result", result5),
12915
13775
  fieldStatus("verify_mode", mode),
12916
13776
  fieldStatus("verification_report", report, report),
12917
13777
  fieldStatus("branch_status", branch),
12918
13778
  "",
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."
13779
+ result5 === "pass" && branch === "handled" ? "Recovery action: Verification complete. Run guard to transition to archive." : 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
13780
  );
12921
13781
  }
12922
13782
  async function recoverArchive(output, name) {
13783
+ const archiveConfirmation = await readField3(name, "archive_confirmation");
12923
13784
  output.stdout.push(
12924
13785
  " Archive:",
12925
13786
  fieldStatus("verify_result", await readField3(name, "verify_result")),
13787
+ fieldStatus("archive_confirmation", archiveConfirmation),
12926
13788
  fieldStatus("archived", await readField3(name, "archived")),
12927
13789
  "",
12928
- "Recovery action: Run /comet-archive to complete archiving."
13790
+ 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
13791
  );
12930
13792
  }
12931
13793
  async function recover(output, name) {
@@ -12960,19 +13822,19 @@ async function scale(output, name) {
12960
13822
  validateChangeName4(name);
12961
13823
  const { file, directory, label } = await stateFile(name);
12962
13824
  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");
13825
+ const tasksFile = path21.join(directory, "tasks.md");
13826
+ const taskCount = await exists6(tasksFile) ? (await fs20.readFile(tasksFile, "utf8")).split(/\r?\n/u).filter((line) => /^- \[/u.test(line)).length : 0;
13827
+ const specs = path21.join(directory, "specs");
12966
13828
  let deltaSpecs = 0;
12967
13829
  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;
13830
+ for (const entry2 of await fs20.readdir(specs)) {
13831
+ if (await exists6(path21.join(specs, entry2, "spec.md"))) deltaSpecs += 1;
12970
13832
  }
12971
13833
  }
12972
13834
  const plan = await readField3(name, "plan");
12973
13835
  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);
13836
+ if (plan && plan !== "null" && await exists6(path21.resolve(plan))) {
13837
+ const match = (await fs20.readFile(path21.resolve(plan), "utf8")).match(/^base-ref:\s*(.+)$/mu);
12976
13838
  baseRef = match?.[1].trim() ?? "";
12977
13839
  }
12978
13840
  if (!baseRef) baseRef = await readField3(name, "base_ref");
@@ -12982,19 +13844,102 @@ async function scale(output, name) {
12982
13844
  ...baseRef && baseRef !== "null" ? [`${baseRef}...HEAD`] : ["HEAD"]
12983
13845
  ]);
12984
13846
  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);
13847
+ const result5 = taskCount > 3 || deltaSpecs > 1 || changedFiles > 8 ? "full" : "light";
13848
+ await setField2(new CommandOutput(), name, "verify_mode", result5);
12987
13849
  output.stderr.push(
12988
13850
  `=== Scale Assessment: ${name} ===`,
12989
13851
  ` Tasks: ${taskCount} (threshold: 3)`,
12990
13852
  ` Delta specs: ${deltaSpecs} capabilities (threshold: 1)`,
12991
13853
  ` Changed files: ${changedFiles} (threshold: 8)`,
12992
- ` → Result: ${result3}`,
12993
- green4(`[SCALE] verify_mode=${result3}`)
13854
+ ` → Result: ${result5}`,
13855
+ green4(`[SCALE] verify_mode=${result5}`)
13856
+ );
13857
+ }
13858
+ function parseRecordCheckOptions(args) {
13859
+ let command;
13860
+ let exitCodeText;
13861
+ let cwd;
13862
+ for (let index = 0; index < args.length; index += 2) {
13863
+ const option = args[index];
13864
+ if (!["--command", "--exit-code", "--cwd"].includes(option)) {
13865
+ fail2(`ERROR: Unknown option: ${option}`);
13866
+ }
13867
+ const value = args[index + 1];
13868
+ if (value === void 0) fail2(`ERROR: Missing value for option: ${option}`);
13869
+ if (option === "--command") command = value;
13870
+ else if (option === "--exit-code") exitCodeText = value;
13871
+ else cwd = value;
13872
+ }
13873
+ if (command === void 0) fail2("ERROR: Missing option: --command");
13874
+ if (exitCodeText === void 0) fail2("ERROR: Missing option: --exit-code");
13875
+ if (!/^-?\d+$/u.test(exitCodeText)) fail2("ERROR: --exit-code must be an integer");
13876
+ return { command, exitCode: Number(exitCodeText), ...cwd === void 0 ? {} : { cwd } };
13877
+ }
13878
+ async function recordCheck(output, name, scopeText, args) {
13879
+ validateChangeName4(name);
13880
+ if (scopeText !== "build" && scopeText !== "verify") {
13881
+ fail2(`ERROR: Invalid command check scope: '${scopeText}'`);
13882
+ }
13883
+ const options = parseRecordCheckOptions(args);
13884
+ const { label, directory, file } = await stateFile(name);
13885
+ if (label !== `openspec/changes/${name}` || !await exists6(file)) {
13886
+ fail2(`ERROR: command checks require an active change: ${name}`);
13887
+ }
13888
+ try {
13889
+ const projection = await readClassicState(directory, { migrate: false });
13890
+ if (!projection.classic || !projection.run) {
13891
+ throw new Error("command checks require an existing synchronized Classic Run");
13892
+ }
13893
+ const { run } = await validateClassicRuntimeRun(directory, projection);
13894
+ const recorded = await recordCommandCheck(directory, run, {
13895
+ scope: scopeText,
13896
+ ...options
13897
+ });
13898
+ output.stderr.push(
13899
+ green4(
13900
+ `[RECORDED] ${recorded.scope} exit=${recorded.exitCode} cwd=${recorded.cwd} command=${recorded.command}`
13901
+ )
13902
+ );
13903
+ } catch (error) {
13904
+ fail2(`ERROR: ${error.message}`);
13905
+ }
13906
+ }
13907
+ function required(args, count, usage3) {
13908
+ if (args.length < count) fail2(usage3);
13909
+ }
13910
+ function requiredExact(args, count, usage3) {
13911
+ if (args.length !== count) fail2(usage3);
13912
+ }
13913
+ async function selectChange(output, name) {
13914
+ validateChangeName4(name);
13915
+ try {
13916
+ const selection = await selectCurrentChange(process.cwd(), name);
13917
+ output.stderr.push(
13918
+ green4(
13919
+ `[SELECTED] current change: ${selection.change}${selection.branch ? ` (branch: ${selection.branch})` : ""}`
13920
+ )
13921
+ );
13922
+ } catch (error) {
13923
+ fail2(`ERROR: ${error instanceof Error ? error.message : String(error)}`);
13924
+ }
13925
+ }
13926
+ async function currentChange(output) {
13927
+ const resolution = await resolveCurrentChange(process.cwd());
13928
+ if (resolution.status === "selected") {
13929
+ output.stdout.push(resolution.selection.change);
13930
+ return;
13931
+ }
13932
+ if (resolution.status === "missing") {
13933
+ fail2("ERROR: no current change selected\nUse: comet-state.mjs select <change-name>");
13934
+ }
13935
+ fail2(
13936
+ `ERROR: current change selection is stale: ${resolution.reason}
13937
+ Use: comet-state.mjs select <change-name>`
12994
13938
  );
12995
13939
  }
12996
- function required(args, count, usage2) {
12997
- if (args.length < count) fail2(usage2);
13940
+ async function clearSelection(output) {
13941
+ await clearCurrentChange(process.cwd());
13942
+ output.stderr.push(green4("[CLEARED] current change selection"));
12998
13943
  }
12999
13944
  var classicStateCommand = async (args) => {
13000
13945
  const output = new CommandOutput();
@@ -13021,9 +13966,25 @@ var classicStateCommand = async (args) => {
13021
13966
  } else if (subcommand === "scale") {
13022
13967
  required(rest, 1, "Usage: comet-state.mjs scale <change-name>");
13023
13968
  await scale(output, rest[0]);
13969
+ } else if (subcommand === "record-check") {
13970
+ required(
13971
+ rest,
13972
+ 2,
13973
+ "Usage: comet state record-check <change> <build|verify> --command <text> --exit-code <int> [--cwd <path>]"
13974
+ );
13975
+ await recordCheck(output, rest[0], rest[1], rest.slice(2));
13024
13976
  } else if (subcommand === "task-checkoff") {
13025
13977
  required(rest, 2, "Usage: comet-state.mjs task-checkoff <file> <task-text>");
13026
13978
  await taskCheckoff(output, rest[0], rest[1]);
13979
+ } else if (subcommand === "select") {
13980
+ requiredExact(rest, 1, "Usage: comet-state.mjs select <change-name>");
13981
+ await selectChange(output, rest[0]);
13982
+ } else if (subcommand === "current") {
13983
+ requiredExact(rest, 0, "Usage: comet-state.mjs current");
13984
+ await currentChange(output);
13985
+ } else if (subcommand === "clear-selection") {
13986
+ requiredExact(rest, 0, "Usage: comet-state.mjs clear-selection");
13987
+ await clearSelection(output);
13027
13988
  } else if (subcommand === "next") {
13028
13989
  required(rest, 1, "Usage: comet-state.mjs next <change-name>");
13029
13990
  await next(output, rest[0]);
@@ -13048,7 +14009,8 @@ var CLASSIC_COMMANDS = [
13048
14009
  "handoff",
13049
14010
  "archive",
13050
14011
  "hook-guard",
13051
- "intent"
14012
+ "intent",
14013
+ "resume-probe"
13052
14014
  ];
13053
14015
  var DEFAULT_HANDLERS = {
13054
14016
  state: classicStateCommand,
@@ -13057,7 +14019,8 @@ var DEFAULT_HANDLERS = {
13057
14019
  handoff: classicHandoffCommand,
13058
14020
  archive: classicArchiveCommand,
13059
14021
  "hook-guard": classicHookGuardCommand,
13060
- intent: classicIntentCommand
14022
+ intent: classicIntentCommand,
14023
+ "resume-probe": classicResumeProbeCommand
13061
14024
  };
13062
14025
  function isClassicCommand(value) {
13063
14026
  return CLASSIC_COMMANDS.includes(value);
@@ -13092,14 +14055,14 @@ async function dispatch(command, args, options, handlers) {
13092
14055
  };
13093
14056
  }
13094
14057
  }
13095
- function jsonResult(command, result3) {
14058
+ function jsonResult(command, result5) {
13096
14059
  return {
13097
- exitCode: result3.exitCode,
14060
+ exitCode: result5.exitCode,
13098
14061
  stdout: JSON.stringify({
13099
14062
  command: command ?? null,
13100
- exitCode: result3.exitCode,
13101
- ...result3.stdout === void 0 ? {} : { stdout: result3.stdout },
13102
- ...result3.stderr === void 0 ? {} : { stderr: result3.stderr }
14063
+ exitCode: result5.exitCode,
14064
+ ...result5.stdout === void 0 ? {} : { stdout: result5.stdout },
14065
+ ...result5.stderr === void 0 ? {} : { stderr: result5.stderr }
13103
14066
  }) + "\n"
13104
14067
  };
13105
14068
  }
@@ -13107,15 +14070,15 @@ async function runClassicCli(argv, handlers = DEFAULT_HANDLERS) {
13107
14070
  const json = argv.includes("--json");
13108
14071
  const args = argv.filter((argument) => argument !== "--json");
13109
14072
  const command = args.shift();
13110
- const result3 = await dispatch(command, args, { json }, handlers);
13111
- return json ? jsonResult(command, result3) : result3;
14073
+ const result5 = await dispatch(command, args, { json }, handlers);
14074
+ return json ? jsonResult(command, result5) : result5;
13112
14075
  }
13113
14076
  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;
14077
+ const result5 = await runClassicCli(argv);
14078
+ if (result5.stdout) process.stdout.write(result5.stdout);
14079
+ if (result5.stderr)
14080
+ process.stderr.write(result5.stderr + (result5.stderr.endsWith("\n") ? "" : "\n"));
14081
+ return result5.exitCode;
13119
14082
  }
13120
14083
  var entry = process.argv[1];
13121
14084
  if (entry && import.meta.url === pathToFileURL(entry).href) {