@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
@@ -0,0 +1,1338 @@
1
+ #!/bin/bash
2
+ # Comet State — unified interface for .comet.yaml state management
3
+ # Usage: comet-state.sh <subcommand> <change-name> [args...]
4
+ #
5
+ # Subcommands:
6
+ # init <change-name> <workflow> — Initialize .comet.yaml with workflow defaults
7
+ # get <change-name> <field> — Read a field value from .comet.yaml
8
+ # set <change-name> <field> <val> — Update a field value
9
+ # transition <change-name> <event> — Apply a validated state transition
10
+ # check <change-name> <phase> — Verify entry requirements for a phase
11
+ # check <change-name> <phase> --recover — Output structured recovery context for compaction resume
12
+ # scale <change-name> — Assess and set verification mode based on metrics
13
+ # task-checkoff <file> <task-text> — Verify one unique task is checked
14
+ #
15
+ # Workflows: full, hotfix, tweak
16
+ # Phases for check: open, design, build, verify, archive
17
+
18
+ set -euo pipefail
19
+
20
+ # --- Color output helpers ---
21
+
22
+ red() { echo -e "\033[31m$1\033[0m" >&2; }
23
+ green() { echo -e "\033[32m$1\033[0m" >&2; }
24
+ yellow() { echo -e "\033[33m$1\033[0m" >&2; }
25
+
26
+ # --- Script location ---
27
+
28
+ # shellcheck disable=SC2034
29
+ SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
30
+
31
+ # --- Input validation ---
32
+
33
+ validate_change_name() {
34
+ local name="$1"
35
+ # Reject empty names
36
+ if [ -z "$name" ]; then
37
+ red "ERROR: Change name cannot be empty" >&2
38
+ exit 1
39
+ fi
40
+ # Only allow alphanumeric, hyphens, and underscores
41
+ if [[ ! "$name" =~ ^[a-zA-Z0-9_-]+$ ]]; then
42
+ red "ERROR: Invalid change name: '$name'" >&2
43
+ red "Valid characters: a-z, A-Z, 0-9, -, _" >&2
44
+ exit 1
45
+ fi
46
+ # Reject path traversal attempts
47
+ if [[ "$name" =~ \.\. ]]; then
48
+ red "ERROR: Change name cannot contain '..' (path traversal not allowed)" >&2
49
+ exit 1
50
+ fi
51
+ }
52
+
53
+ validate_enum() {
54
+ local value="$1"
55
+ shift
56
+ local valid_values=("$@")
57
+
58
+ for valid in "${valid_values[@]}"; do
59
+ if [ "$value" = "$valid" ]; then
60
+ return 0
61
+ fi
62
+ done
63
+
64
+ red "ERROR: Invalid value: '$value'" >&2
65
+ red "Valid values: ${valid_values[*]}" >&2
66
+ exit 1
67
+ }
68
+
69
+ validate_path_field() {
70
+ local value="$1"
71
+ local field="$2"
72
+ # null and empty are acceptable (means "not set")
73
+ if [ -z "$value" ] || [ "$value" = "null" ]; then
74
+ return 0
75
+ fi
76
+ # Reject absolute paths and home-directory references
77
+ case "$value" in
78
+ /*|~*|[A-Za-z]:*|\\*)
79
+ red "ERROR: $field must be a relative path within the repo: '$value'" >&2
80
+ exit 1
81
+ ;;
82
+ esac
83
+ if [[ "$value" =~ \.\. ]]; then
84
+ red "ERROR: $field cannot contain '..' (path traversal not allowed): '$value'" >&2
85
+ exit 1
86
+ fi
87
+ }
88
+
89
+ # --- Helper functions ---
90
+
91
+ yaml_field() {
92
+ local field="$1"
93
+ local yaml_file="$2"
94
+ if [ -f "$yaml_file" ]; then
95
+ local value
96
+ value=$(grep "^${field}:" "$yaml_file" 2>/dev/null | sed "s/^${field}: *//" || true)
97
+ value=$(strip_inline_comment "$value")
98
+ strip_wrapping_quotes "$value"
99
+ fi
100
+ }
101
+
102
+ strip_inline_comment() {
103
+ local value="$1"
104
+ printf '%s\n' "$value" | awk -v squote="'" '
105
+ {
106
+ out = ""
107
+ quote = ""
108
+ for (i = 1; i <= length($0); i++) {
109
+ c = substr($0, i, 1)
110
+ if (quote == "") {
111
+ if (c == "\"" || c == squote) {
112
+ quote = c
113
+ } else if (c == "#" && (i == 1 || substr($0, i - 1, 1) ~ /[[:space:]]/)) {
114
+ sub(/[[:space:]]+$/, "", out)
115
+ print out
116
+ next
117
+ }
118
+ } else if (c == quote) {
119
+ quote = ""
120
+ }
121
+ out = out c
122
+ }
123
+ print out
124
+ }
125
+ '
126
+ }
127
+
128
+ strip_wrapping_quotes() {
129
+ local value="$1"
130
+ case "$value" in
131
+ \"*\")
132
+ printf '%s\n' "${value:1:${#value}-2}"
133
+ ;;
134
+ \'*\')
135
+ printf '%s\n' "${value:1:${#value}-2}"
136
+ ;;
137
+ *)
138
+ printf '%s\n' "$value"
139
+ ;;
140
+ esac
141
+ }
142
+
143
+ replace_yaml_field() {
144
+ local yaml_file="$1"
145
+ local field="$2"
146
+ local value="$3"
147
+ local tmp_file
148
+
149
+ tmp_file=$(mktemp)
150
+ chmod 600 "$tmp_file"
151
+ # Replace the target field, then deduplicate all fields keeping only the
152
+ # last occurrence of each key. Prevents stale earlier values from
153
+ # persisting when a field is set multiple times.
154
+ awk -v field="$field" -v value="$value" '
155
+ index($0, field ":") == 1 { $0 = field ": " value }
156
+ { buf[NR] = $0; keys[NR] = $0; sub(/:.*$/, "", keys[NR]); n = NR }
157
+ END {
158
+ for (i = 1; i <= n; i++) last[keys[i]] = i
159
+ for (i = 1; i <= n; i++) if (last[keys[i]] == i) print buf[i]
160
+ }
161
+ ' "$yaml_file" > "$tmp_file"
162
+ mv "$tmp_file" "$yaml_file"
163
+ }
164
+
165
+ file_nonempty() {
166
+ [ -f "$1" ] && [ -s "$1" ]
167
+ }
168
+
169
+ change_dir_for() {
170
+ local change_name="$1"
171
+ if [ -d "openspec/changes/$change_name" ]; then
172
+ echo "openspec/changes/$change_name"
173
+ elif [ -d "openspec/changes/archive/$change_name" ]; then
174
+ echo "openspec/changes/archive/$change_name"
175
+ else
176
+ echo "openspec/changes/$change_name"
177
+ fi
178
+ }
179
+
180
+ yaml_file_for() {
181
+ local change_name="$1"
182
+ local change_dir
183
+ change_dir=$(change_dir_for "$change_name")
184
+ echo "$change_dir/.comet.yaml"
185
+ }
186
+
187
+ project_context_compression() {
188
+ local value="off"
189
+ local source="default"
190
+ if [ -n "${COMET_CONTEXT_COMPRESSION:-}" ]; then
191
+ value="$COMET_CONTEXT_COMPRESSION"
192
+ source="COMET_CONTEXT_COMPRESSION"
193
+ elif [ -f ".comet/config.yaml" ]; then
194
+ value=$(yaml_field "context_compression" ".comet/config.yaml")
195
+ value="${value:-off}"
196
+ source=".comet/config.yaml"
197
+ fi
198
+
199
+ case "$value" in
200
+ off|beta)
201
+ printf '%s\n' "$value"
202
+ ;;
203
+ *)
204
+ red "ERROR: Invalid context_compression from ${source}: '$value'" >&2
205
+ red "Valid values: off, beta" >&2
206
+ exit 1
207
+ ;;
208
+ esac
209
+ }
210
+
211
+ project_auto_transition_default() {
212
+ local value="true"
213
+ local source="default"
214
+ if [ -n "${COMET_AUTO_TRANSITION:-}" ]; then
215
+ value="$COMET_AUTO_TRANSITION"
216
+ source="COMET_AUTO_TRANSITION"
217
+ elif [ -f ".comet/config.yaml" ]; then
218
+ local raw
219
+ raw=$(yaml_field "auto_transition" ".comet/config.yaml" 2>/dev/null || true)
220
+ if [ -n "$raw" ]; then
221
+ value="$raw"
222
+ source=".comet/config.yaml"
223
+ fi
224
+ fi
225
+
226
+ case "$value" in
227
+ true|false)
228
+ printf '%s\n' "$value"
229
+ ;;
230
+ *)
231
+ red "ERROR: Invalid auto_transition from ${source}: '$value'" >&2
232
+ red "Valid values: true, false" >&2
233
+ exit 1
234
+ ;;
235
+ esac
236
+ }
237
+
238
+ project_review_mode_default() {
239
+ local value="null"
240
+ local source="default"
241
+ if [ -n "${COMET_REVIEW_MODE:-}" ]; then
242
+ value="$COMET_REVIEW_MODE"
243
+ source="COMET_REVIEW_MODE"
244
+ elif [ -f ".comet/config.yaml" ]; then
245
+ local raw
246
+ raw=$(yaml_field "review_mode" ".comet/config.yaml" 2>/dev/null || true)
247
+ if [ -n "$raw" ]; then
248
+ value="$raw"
249
+ source=".comet/config.yaml"
250
+ fi
251
+ fi
252
+
253
+ case "$value" in
254
+ null|off|standard|thorough)
255
+ printf '%s\n' "$value"
256
+ ;;
257
+ *)
258
+ red "ERROR: Invalid review_mode from ${source}: '$value'" >&2
259
+ red "Valid values: off, standard, thorough" >&2
260
+ exit 1
261
+ ;;
262
+ esac
263
+ }
264
+
265
+ # --- Subcommands ---
266
+
267
+ cmd_init() {
268
+ local change_name="$1"
269
+ local workflow="$2"
270
+
271
+ validate_change_name "$change_name"
272
+ validate_enum "$workflow" "full" "hotfix" "tweak"
273
+
274
+ local change_dir yaml_file
275
+ change_dir=$(change_dir_for "$change_name")
276
+ yaml_file=$(yaml_file_for "$change_name")
277
+
278
+ # Check if .comet.yaml already exists
279
+ if [ -f "$yaml_file" ]; then
280
+ red "ERROR: .comet.yaml already exists at $yaml_file"
281
+ exit 1
282
+ fi
283
+
284
+ # Create change directory if it doesn't exist
285
+ mkdir -p "$change_dir"
286
+
287
+ # Set workflow-appropriate defaults
288
+ local phase build_mode isolation verify_mode context_compression auto_transition review_mode
289
+ phase="open"
290
+ context_compression=$(project_context_compression)
291
+ auto_transition="$(project_auto_transition_default)"
292
+
293
+ case "$workflow" in
294
+ full)
295
+ build_mode="null"
296
+ tdd_mode="null"
297
+ review_mode="$(project_review_mode_default)"
298
+ isolation="null"
299
+ verify_mode="null"
300
+ ;;
301
+ hotfix|tweak)
302
+ build_mode="direct"
303
+ tdd_mode="direct"
304
+ review_mode="off"
305
+ isolation="branch"
306
+ verify_mode="light"
307
+ ;;
308
+ esac
309
+
310
+ # Write .comet.yaml
311
+ # Record current HEAD as base_ref for scale assessment fallback
312
+ local base_ref="null"
313
+ if git rev-parse --verify HEAD >/dev/null 2>&1; then
314
+ base_ref=$(git rev-parse HEAD 2>/dev/null || echo "null")
315
+ fi
316
+
317
+ cat > "$yaml_file" <<EOF
318
+ workflow: $workflow
319
+ phase: $phase
320
+ context_compression: $context_compression
321
+ build_mode: $build_mode
322
+ build_pause: null
323
+ subagent_dispatch: null
324
+ tdd_mode: $tdd_mode
325
+ review_mode: $review_mode
326
+ isolation: $isolation
327
+ verify_mode: $verify_mode
328
+ auto_transition: $auto_transition
329
+ base_ref: $base_ref
330
+ design_doc: null
331
+ plan: null
332
+ verify_result: pending
333
+ verification_report: null
334
+ branch_status: pending
335
+ created_at: $(date -u +%Y-%m-%d)
336
+ verified_at: null
337
+ archived: false
338
+ EOF
339
+
340
+ green "Initialized: $yaml_file (workflow=$workflow)"
341
+ }
342
+
343
+ cmd_get() {
344
+ local change_name="$1"
345
+ local field="$2"
346
+
347
+ validate_change_name "$change_name"
348
+
349
+ local yaml_file
350
+ yaml_file=$(yaml_file_for "$change_name")
351
+
352
+ # Check if .comet.yaml exists
353
+ if [ ! -f "$yaml_file" ]; then
354
+ red "ERROR: .comet.yaml not found at $yaml_file"
355
+ exit 1
356
+ fi
357
+
358
+ # Read and output the field value
359
+ local value
360
+ value=$(yaml_field "$field" "$yaml_file")
361
+ if [ "$field" = "auto_transition" ] && { [ -z "$value" ] || [ "$value" = "null" ]; }; then
362
+ value="$(project_auto_transition_default)"
363
+ fi
364
+ echo "${value:-}"
365
+ }
366
+
367
+ cmd_set() {
368
+ local change_name="$1"
369
+ local field="$2"
370
+ local value="$3"
371
+
372
+ validate_change_name "$change_name"
373
+
374
+ local yaml_file
375
+ yaml_file=$(yaml_file_for "$change_name")
376
+
377
+ # Check if .comet.yaml exists
378
+ if [ ! -f "$yaml_file" ]; then
379
+ red "ERROR: .comet.yaml not found at $yaml_file"
380
+ exit 1
381
+ fi
382
+
383
+ # Validate field name
384
+ case "$field" in
385
+ phase)
386
+ # Direct phase writes bypass state-machine evidence checks (open artifacts,
387
+ # design_doc, build decisions, verification evidence). Block them unless the
388
+ # call originates from cmd_transition (dynamic-scope flag) or the operator
389
+ # explicitly opts into the repair escape hatch.
390
+ if [ "${_COMET_IN_TRANSITION:-}" != "1" ] && [ "${COMET_FORCE_PHASE:-}" != "1" ]; then
391
+ red "ERROR: Setting 'phase' directly is not allowed; it bypasses state machine evidence checks." >&2
392
+ red " Use: comet-state.sh transition <change-name> <event>" >&2
393
+ red " Repair-only escape hatch: COMET_FORCE_PHASE=1 comet-state.sh set <change-name> phase <value>" >&2
394
+ exit 1
395
+ fi
396
+ validate_enum "$value" "open" "design" "build" "verify" "archive"
397
+ ;;
398
+ workflow|context_compression|build_mode|build_pause|subagent_dispatch|tdd_mode|review_mode|isolation|verify_mode|auto_transition|verify_result|verification_report|branch_status|archived|design_doc|plan|verified_at|created_at|direct_override|build_command|verify_command|handoff_context|handoff_hash|base_ref)
399
+ # Valid field
400
+ ;;
401
+ *)
402
+ red "ERROR: Unknown field: '$field'" >&2
403
+ red "Valid fields:" >&2
404
+ red " workflow, phase, context_compression, design_doc, plan, build_mode, build_pause, subagent_dispatch, tdd_mode, review_mode, isolation," >&2
405
+ red " verify_mode, auto_transition, verify_result, verification_report, branch_status," >&2
406
+ red " verified_at, created_at, archived, base_ref, direct_override," >&2
407
+ red " build_command, verify_command, handoff_context, handoff_hash" >&2
408
+ exit 1
409
+ ;;
410
+ esac
411
+
412
+ # Validate enum values
413
+ case "$field" in
414
+ workflow)
415
+ validate_enum "$value" "full" "hotfix" "tweak"
416
+ ;;
417
+ context_compression)
418
+ validate_enum "$value" "off" "beta"
419
+ ;;
420
+ phase)
421
+ validate_enum "$value" "open" "design" "build" "verify" "archive"
422
+ ;;
423
+ build_mode)
424
+ validate_enum "$value" "subagent-driven-development" "executing-plans" "direct"
425
+ ;;
426
+ build_pause)
427
+ validate_enum "$value" "null" "plan-ready"
428
+ ;;
429
+ subagent_dispatch)
430
+ validate_enum "$value" "null" "confirmed"
431
+ ;;
432
+ tdd_mode)
433
+ validate_enum "$value" "tdd" "direct"
434
+ ;;
435
+ review_mode)
436
+ validate_enum "$value" "off" "standard" "thorough"
437
+ ;;
438
+ isolation)
439
+ validate_enum "$value" "branch" "worktree"
440
+ ;;
441
+ verify_mode)
442
+ validate_enum "$value" "light" "full"
443
+ ;;
444
+ auto_transition)
445
+ validate_enum "$value" "true" "false"
446
+ ;;
447
+ verify_result)
448
+ validate_enum "$value" "pending" "pass" "fail"
449
+ ;;
450
+ branch_status)
451
+ validate_enum "$value" "pending" "handled"
452
+ ;;
453
+ archived)
454
+ validate_enum "$value" "true" "false"
455
+ ;;
456
+ direct_override)
457
+ validate_enum "$value" "true" "false"
458
+ ;;
459
+ design_doc|plan|verification_report|handoff_context|handoff_hash)
460
+ validate_path_field "$value" "$field"
461
+ ;;
462
+ verified_at|created_at|build_command|verify_command)
463
+ # No validation for date fields or project command strings
464
+ ;;
465
+ esac
466
+
467
+ # Write or update the field
468
+ if grep -q "^${field}:" "$yaml_file"; then
469
+ replace_yaml_field "$yaml_file" "$field" "$value"
470
+ else
471
+ # Field doesn't exist, append it
472
+ echo "${field}: ${value}" >> "$yaml_file"
473
+ fi
474
+
475
+ green "[SET] ${field}=${value}"
476
+ }
477
+
478
+ require_phase() {
479
+ local change_name="$1"
480
+ local expected="$2"
481
+ local actual
482
+ actual=$(cmd_get "$change_name" "phase")
483
+ if [ "$actual" != "$expected" ]; then
484
+ red "ERROR: Cannot transition '$change_name': expected phase ${expected}, got ${actual}" >&2
485
+ exit 1
486
+ fi
487
+ }
488
+
489
+ require_open_artifacts() {
490
+ local change_name="$1"
491
+ local change_dir workflow f
492
+ change_dir=$(change_dir_for "$change_name")
493
+ workflow=$(cmd_get "$change_name" "workflow")
494
+ for f in proposal.md tasks.md; do
495
+ if [ ! -s "$change_dir/$f" ]; then
496
+ red "ERROR: Cannot transition '$change_name': $f must exist and be non-empty before leaving open" >&2
497
+ exit 1
498
+ fi
499
+ done
500
+ if [ "$workflow" = "full" ] && [ ! -s "$change_dir/design.md" ]; then
501
+ red "ERROR: Cannot transition '$change_name': design.md must exist and be non-empty before leaving open" >&2
502
+ exit 1
503
+ fi
504
+ }
505
+
506
+ require_design_evidence() {
507
+ local change_name="$1"
508
+ local design_doc
509
+ design_doc=$(cmd_get "$change_name" "design_doc")
510
+ if [ -z "$design_doc" ] || [ "$design_doc" = "null" ] || [ ! -s "$design_doc" ]; then
511
+ red "ERROR: Cannot transition '$change_name': design_doc must point to an existing Design Doc before leaving design" >&2
512
+ exit 1
513
+ fi
514
+ }
515
+
516
+ require_verification_evidence() {
517
+ local change_name="$1"
518
+ local report branch_status
519
+ report=$(cmd_get "$change_name" "verification_report")
520
+ branch_status=$(cmd_get "$change_name" "branch_status")
521
+
522
+ if [ -z "$report" ] || [ "$report" = "null" ] || [ ! -f "$report" ]; then
523
+ red "ERROR: Cannot transition '$change_name': verification_report must point to an existing report file" >&2
524
+ exit 1
525
+ fi
526
+
527
+ if [ "$branch_status" != "handled" ]; then
528
+ red "ERROR: Cannot transition '$change_name': branch_status must be handled" >&2
529
+ exit 1
530
+ fi
531
+ }
532
+
533
+ require_build_decisions() {
534
+ local change_name="$1"
535
+ local workflow build_mode isolation direct_override subagent_dispatch tdd_mode review_mode
536
+ workflow=$(cmd_get "$change_name" "workflow")
537
+ build_mode=$(cmd_get "$change_name" "build_mode")
538
+ isolation=$(cmd_get "$change_name" "isolation")
539
+ direct_override=$(cmd_get "$change_name" "direct_override" 2>/dev/null || true)
540
+ subagent_dispatch=$(cmd_get "$change_name" "subagent_dispatch" 2>/dev/null || true)
541
+ tdd_mode=$(cmd_get "$change_name" "tdd_mode" 2>/dev/null || true)
542
+ review_mode=$(cmd_get "$change_name" "review_mode" 2>/dev/null || true)
543
+
544
+ case "$isolation" in
545
+ branch|worktree) ;;
546
+ *)
547
+ red "ERROR: Cannot transition '$change_name': isolation must be branch or worktree, got '${isolation:-null}'" >&2
548
+ exit 1
549
+ ;;
550
+ esac
551
+
552
+ case "$build_mode" in
553
+ subagent-driven-development|executing-plans|direct) ;;
554
+ *)
555
+ red "ERROR: Cannot transition '$change_name': build_mode must be selected before leaving build, got '${build_mode:-null}'" >&2
556
+ exit 1
557
+ ;;
558
+ esac
559
+
560
+ if [ "$build_mode" = "direct" ] && [ "$workflow" != "hotfix" ] && [ "$workflow" != "tweak" ] && [ "$direct_override" != "true" ]; then
561
+ red "ERROR: Cannot transition '$change_name': build_mode=direct is only allowed for hotfix/tweak unless direct_override=true" >&2
562
+ exit 1
563
+ fi
564
+
565
+ if [ "$build_mode" = "subagent-driven-development" ] && [ "$subagent_dispatch" != "confirmed" ]; then
566
+ red "ERROR: Cannot transition '$change_name': subagent_dispatch must be confirmed before using build_mode=subagent-driven-development" >&2
567
+ exit 1
568
+ fi
569
+
570
+ if [ "$workflow" = "full" ] && { [ "$tdd_mode" = "null" ] || [ -z "$tdd_mode" ]; }; then
571
+ red "ERROR: Cannot transition '$change_name': tdd_mode must be selected before leaving build (full workflow)" >&2
572
+ exit 1
573
+ fi
574
+
575
+ if [ "$workflow" = "full" ]; then
576
+ case "$review_mode" in
577
+ off|standard|thorough) ;;
578
+ *)
579
+ red "ERROR: Cannot transition '$change_name': review_mode must be selected before leaving build (full workflow); review_mode must be off, standard, or thorough, got '${review_mode:-null}'" >&2
580
+ exit 1
581
+ ;;
582
+ esac
583
+ fi
584
+ }
585
+
586
+ cmd_transition() {
587
+ local change_name="$1"
588
+ local event="$2"
589
+ # Dynamic-scope flag: authorizes the internal cmd_set phase writes below while
590
+ # still blocking direct `set <name> phase` from the CLI.
591
+ local _COMET_IN_TRANSITION=1
592
+
593
+ validate_change_name "$change_name"
594
+ validate_enum "$event" "open-complete" "design-complete" "build-complete" "verify-pass" "verify-fail" "archive-reopen" "archived"
595
+
596
+ case "$event" in
597
+ open-complete)
598
+ require_phase "$change_name" "open"
599
+ require_open_artifacts "$change_name"
600
+ local workflow
601
+ workflow=$(cmd_get "$change_name" "workflow")
602
+ if [ "$workflow" = "full" ]; then
603
+ cmd_set "$change_name" phase design
604
+ else
605
+ cmd_set "$change_name" phase build
606
+ fi
607
+ ;;
608
+ design-complete)
609
+ require_phase "$change_name" "design"
610
+ require_design_evidence "$change_name"
611
+ cmd_set "$change_name" phase build
612
+ ;;
613
+ build-complete)
614
+ require_phase "$change_name" "build"
615
+ require_build_decisions "$change_name"
616
+ local current_verify_result
617
+ current_verify_result=$(cmd_get "$change_name" "verify_result")
618
+ cmd_set "$change_name" phase verify
619
+ cmd_set "$change_name" verify_result pending
620
+ # Preserve verification evidence on re-verify (verify-fail → build → build-complete)
621
+ # so the fix can reference the original failure report
622
+ if [ "$current_verify_result" != "fail" ]; then
623
+ cmd_set "$change_name" verification_report null
624
+ cmd_set "$change_name" branch_status pending
625
+ fi
626
+ ;;
627
+ verify-pass)
628
+ require_phase "$change_name" "verify"
629
+ require_verification_evidence "$change_name"
630
+ cmd_set "$change_name" verify_result pass
631
+ cmd_set "$change_name" phase archive
632
+ cmd_set "$change_name" verified_at "$(date -u +%Y-%m-%d)"
633
+ ;;
634
+ verify-fail)
635
+ require_phase "$change_name" "verify"
636
+ cmd_set "$change_name" verify_result fail
637
+ cmd_set "$change_name" phase build
638
+ # Preserve branch_status so re-verify doesn't require re-handling branches
639
+ ;;
640
+ archive-reopen)
641
+ require_phase "$change_name" "archive"
642
+ local archived
643
+ archived=$(cmd_get "$change_name" "archived")
644
+ if [ "$archived" = "true" ]; then
645
+ red "ERROR: Cannot transition '$change_name': already archived" >&2
646
+ exit 1
647
+ fi
648
+ cmd_set "$change_name" verify_result pending
649
+ cmd_set "$change_name" phase verify
650
+ cmd_set "$change_name" verified_at null
651
+ ;;
652
+ archived)
653
+ require_phase "$change_name" "archive"
654
+ local archived_verify_result
655
+ archived_verify_result=$(cmd_get "$change_name" "verify_result")
656
+ if [ "$archived_verify_result" != "pass" ]; then
657
+ red "ERROR: Cannot transition '$change_name': verify_result must be pass before archiving" >&2
658
+ exit 1
659
+ fi
660
+ cmd_set "$change_name" archived true
661
+ ;;
662
+ esac
663
+
664
+ green "[TRANSITION] ${event}"
665
+ }
666
+
667
+ # --- Check helpers for entry verification ---
668
+
669
+ CHECK_BLOCK=0
670
+
671
+ check_pass() {
672
+ local msg="$1"
673
+ echo " $(green "[PASS]") $msg"
674
+ }
675
+
676
+ check_fail() {
677
+ local msg="$1"
678
+ echo " $(red "[FAIL]") $msg"
679
+ CHECK_BLOCK=1
680
+ }
681
+
682
+ check_nonempty() {
683
+ local desc="$1"
684
+ local path="$2"
685
+ if file_nonempty "$path"; then
686
+ check_pass "$desc non-empty"
687
+ else
688
+ check_fail "$desc missing or empty"
689
+ fi
690
+ }
691
+
692
+ check_yaml_is() {
693
+ local field="$1"
694
+ local expected="$2"
695
+ local change_name="$3"
696
+ local actual
697
+ actual=$(cmd_get "$change_name" "$field")
698
+ if [ "$actual" = "$expected" ]; then
699
+ check_pass "${field}=${actual} (expected: ${expected})"
700
+ else
701
+ check_fail "${field}=${actual} (expected: ${expected})"
702
+ fi
703
+ }
704
+
705
+ check_yaml_empty() {
706
+ local field="$1"
707
+ local change_name="$2"
708
+ local value
709
+ value=$(cmd_get "$change_name" "$field")
710
+ if [ -z "$value" ] || [ "$value" = "null" ]; then
711
+ check_pass "${field} is empty/null"
712
+ else
713
+ check_fail "${field}=${value} (expected: empty/null)"
714
+ fi
715
+ }
716
+
717
+ check_file_not_exists() {
718
+ local desc="$1"
719
+ local path="$2"
720
+ if [ ! -f "$path" ]; then
721
+ check_pass "$desc does not exist"
722
+ else
723
+ check_fail "$desc exists (should not exist)"
724
+ fi
725
+ }
726
+
727
+ cmd_check() {
728
+ local change_name="$1"
729
+ local phase="$2"
730
+
731
+ validate_change_name "$change_name"
732
+ validate_enum "$phase" "open" "design" "build" "verify" "archive"
733
+
734
+ local change_dir="openspec/changes/$change_name"
735
+ local yaml_file="$change_dir/.comet.yaml"
736
+ local proposal_file="$change_dir/proposal.md"
737
+ local design_file="$change_dir/design.md"
738
+ local tasks_file="$change_dir/tasks.md"
739
+
740
+ echo "=== Entry Check: comet-${phase} ==="
741
+
742
+ # .comet.yaml must exist for all phases (state machine core)
743
+ if [ ! -f "$yaml_file" ]; then
744
+ red "ERROR: .comet.yaml not found at $yaml_file"
745
+ exit 1
746
+ fi
747
+
748
+ # Phase-specific checks
749
+ case "$phase" in
750
+ open)
751
+ check_pass ".comet.yaml exists"
752
+ check_yaml_is "phase" "open" "$change_name"
753
+ ;;
754
+ design)
755
+ check_pass ".comet.yaml exists"
756
+ check_yaml_is "phase" "design" "$change_name"
757
+ check_yaml_is "workflow" "full" "$change_name"
758
+ check_yaml_empty "design_doc" "$change_name"
759
+ check_nonempty "proposal.md" "$proposal_file"
760
+ check_nonempty "design.md" "$design_file"
761
+ check_nonempty "tasks.md" "$tasks_file"
762
+ ;;
763
+ build)
764
+ check_pass ".comet.yaml exists"
765
+ check_yaml_is "phase" "build" "$change_name"
766
+ # design_doc required for full workflow only
767
+ local workflow
768
+ workflow=$(cmd_get "$change_name" "workflow")
769
+ if [ "$workflow" = "full" ]; then
770
+ local design_doc
771
+ design_doc=$(cmd_get "$change_name" "design_doc")
772
+ if [ -n "$design_doc" ] && [ "$design_doc" != "null" ] && [ -f "$design_doc" ]; then
773
+ check_pass "design_doc=${design_doc} (file exists)"
774
+ else
775
+ check_fail "design_doc=${design_doc} (expected: non-null and file exists)"
776
+ fi
777
+ else
778
+ check_pass "workflow=${workflow} (design_doc not required)"
779
+ fi
780
+ check_nonempty "proposal.md" "$proposal_file"
781
+ check_nonempty "tasks.md" "$tasks_file"
782
+ ;;
783
+ verify)
784
+ check_pass ".comet.yaml exists"
785
+ check_yaml_is "phase" "verify" "$change_name"
786
+ # Check verify_result is pending or null
787
+ local verify_result
788
+ verify_result=$(cmd_get "$change_name" "verify_result")
789
+ if [ "$verify_result" = "pending" ] || [ -z "$verify_result" ] || [ "$verify_result" = "null" ]; then
790
+ check_pass "verify_result=${verify_result} (expected: pending or null)"
791
+ else
792
+ check_fail "verify_result=${verify_result} (expected: pending or null)"
793
+ fi
794
+ ;;
795
+ archive)
796
+ check_pass ".comet.yaml exists"
797
+ check_yaml_is "phase" "archive" "$change_name"
798
+ check_yaml_is "verify_result" "pass" "$change_name"
799
+ # Check archived is NOT true
800
+ local archived
801
+ archived=$(cmd_get "$change_name" "archived")
802
+ if [ "$archived" != "true" ]; then
803
+ check_pass "archived=${archived} (expected: not true)"
804
+ else
805
+ check_fail "archived=${archived} (expected: not true)"
806
+ fi
807
+ ;;
808
+ *)
809
+ red "ERROR: Unknown phase for check: $phase"
810
+ exit 1
811
+ ;;
812
+ esac
813
+
814
+ echo ""
815
+ if [ "$CHECK_BLOCK" -eq 1 ]; then
816
+ red "BLOCKED — fix failing checks before proceeding"
817
+ exit 1
818
+ else
819
+ green "ALL CHECKS PASSED — ready to proceed"
820
+ exit 0
821
+ fi
822
+ }
823
+
824
+ # --- Recovery context for compaction resume ---
825
+
826
+ field_status() {
827
+ # Args: field_name value [file_path]
828
+ # Prints: "field_name: DONE (value)" or "field_name: PENDING"
829
+ local field="$1"
830
+ local value="$2"
831
+ local file_path="${3:-}"
832
+
833
+ if [ -z "$value" ] || [ "$value" = "null" ]; then
834
+ echo " - ${field}: PENDING"
835
+ elif [ -n "$file_path" ] && [ ! -f "$file_path" ]; then
836
+ echo " - ${field}: BROKEN (path ${value} does not exist)"
837
+ else
838
+ echo " - ${field}: DONE (${value})"
839
+ fi
840
+ }
841
+
842
+ cmd_recover() {
843
+ local change_name="$1"
844
+
845
+ validate_change_name "$change_name"
846
+
847
+ local change_dir="openspec/changes/$change_name"
848
+ local yaml_file="$change_dir/.comet.yaml"
849
+
850
+ if [ ! -f "$yaml_file" ]; then
851
+ red "ERROR: .comet.yaml not found at $yaml_file"
852
+ exit 1
853
+ fi
854
+
855
+ local phase workflow
856
+ phase=$(cmd_get "$change_name" "phase")
857
+ workflow=$(cmd_get "$change_name" "workflow")
858
+
859
+ echo "=== Recovery Context: ${change_name} ==="
860
+ echo "Phase: ${phase}"
861
+ echo "Workflow: ${workflow}"
862
+ echo ""
863
+
864
+ # Read all relevant fields
865
+ local design_doc plan verify_result verify_mode verification_report
866
+ local branch_status handoff_context handoff_hash isolation build_mode build_pause subagent_dispatch tdd_mode review_mode direct_override
867
+ design_doc=$(cmd_get "$change_name" "design_doc")
868
+ plan=$(cmd_get "$change_name" "plan")
869
+ verify_result=$(cmd_get "$change_name" "verify_result")
870
+ verify_mode=$(cmd_get "$change_name" "verify_mode")
871
+ verification_report=$(cmd_get "$change_name" "verification_report")
872
+ branch_status=$(cmd_get "$change_name" "branch_status")
873
+ handoff_context=$(cmd_get "$change_name" "handoff_context")
874
+ handoff_hash=$(cmd_get "$change_name" "handoff_hash")
875
+ isolation=$(cmd_get "$change_name" "isolation")
876
+ build_mode=$(cmd_get "$change_name" "build_mode")
877
+ build_pause=$(cmd_get "$change_name" "build_pause" 2>/dev/null || true)
878
+ subagent_dispatch=$(cmd_get "$change_name" "subagent_dispatch" 2>/dev/null || true)
879
+ tdd_mode=$(cmd_get "$change_name" "tdd_mode" 2>/dev/null || true)
880
+ review_mode=$(cmd_get "$change_name" "review_mode" 2>/dev/null || true)
881
+ direct_override=$(cmd_get "$change_name" "direct_override" 2>/dev/null || true)
882
+
883
+ echo "State fields:"
884
+
885
+ # Phase-specific field reporting
886
+ case "$phase" in
887
+ open)
888
+ echo " Artifacts:"
889
+ local artifacts_done=0
890
+ for f in proposal.md design.md tasks.md; do
891
+ if file_nonempty "$change_dir/$f"; then
892
+ echo " - ${f}: DONE"
893
+ artifacts_done=$((artifacts_done + 1))
894
+ else
895
+ echo " - ${f}: PENDING"
896
+ fi
897
+ done
898
+ echo ""
899
+ if [ "$artifacts_done" -eq 3 ]; then
900
+ echo "Recovery action: All artifacts complete. Run /comet-open user confirmation, then guard to transition."
901
+ elif [ "$artifacts_done" -eq 0 ]; then
902
+ echo "Recovery action: No artifacts created yet. Start from /comet-open Step 1 (explore and clarify)."
903
+ else
904
+ echo "Recovery action: Some artifacts incomplete. Resume /comet-open from the first missing artifact."
905
+ fi
906
+ ;;
907
+ design)
908
+ echo " Artifacts:"
909
+ for f in proposal.md design.md tasks.md; do
910
+ if file_nonempty "$change_dir/$f"; then
911
+ echo " - ${f}: DONE"
912
+ else
913
+ echo " - ${f}: MISSING (unexpected in design phase)"
914
+ fi
915
+ done
916
+ echo ""
917
+ echo " Design progress:"
918
+ field_status "handoff_context" "$handoff_context" "$handoff_context"
919
+ field_status "handoff_hash" "$handoff_hash"
920
+ field_status "design_doc" "$design_doc" "$design_doc"
921
+ echo ""
922
+ if [ -n "$design_doc" ] && [ "$design_doc" != "null" ] && [ -f "$design_doc" ]; then
923
+ echo "Recovery action: Design Doc already created and linked. Run guard to transition to build."
924
+ elif [ -n "$handoff_context" ] && [ "$handoff_context" != "null" ] && [ -f "$handoff_context" ]; then
925
+ echo "Recovery action: Handoff generated but Design Doc not yet created. Resume from brainstorming confirmation (Step 1c)."
926
+ else
927
+ echo "Recovery action: No handoff generated yet. Start from Step 1a (generate handoff package)."
928
+ fi
929
+ ;;
930
+ build)
931
+ echo " Build decisions:"
932
+ field_status "isolation" "$isolation"
933
+ field_status "build_mode" "$build_mode"
934
+ field_status "build_pause" "$build_pause"
935
+ field_status "tdd_mode" "$tdd_mode"
936
+ field_status "review_mode" "$review_mode"
937
+ if [ "$build_mode" = "subagent-driven-development" ] || { [ -n "$subagent_dispatch" ] && [ "$subagent_dispatch" != "null" ]; }; then
938
+ field_status "subagent_dispatch" "$subagent_dispatch"
939
+ fi
940
+ if [ "$build_mode" = "direct" ] && [ "$workflow" != "hotfix" ] && [ "$workflow" != "tweak" ]; then
941
+ field_status "direct_override" "$direct_override"
942
+ fi
943
+ echo ""
944
+ echo " Plan:"
945
+ field_status "plan" "$plan" "$plan"
946
+ echo ""
947
+ # Count completed vs pending tasks
948
+ local tasks_file="$change_dir/tasks.md"
949
+ local total=0 done=0 pending=0
950
+ local plan_total=0 plan_done=0 plan_pending=0
951
+ if [ -f "$tasks_file" ]; then
952
+ total=$(grep -c '^[[:space:]]*- \[' "$tasks_file" 2>/dev/null || true)
953
+ done=$(grep -c '^[[:space:]]*- \[x\]' "$tasks_file" 2>/dev/null || true)
954
+ total="${total:-0}"
955
+ done="${done:-0}"
956
+ pending=$((total - done))
957
+ echo " Tasks: ${done}/${total} done, ${pending} pending"
958
+ else
959
+ echo " Tasks: tasks.md MISSING"
960
+ fi
961
+ if [ -n "$plan" ] && [ "$plan" != "null" ] && [ -f "$plan" ]; then
962
+ plan_total=$(grep -c '^[[:space:]]*- \[' "$plan" 2>/dev/null || true)
963
+ plan_done=$(grep -c '^[[:space:]]*- \[x\]' "$plan" 2>/dev/null || true)
964
+ plan_total="${plan_total:-0}"
965
+ plan_done="${plan_done:-0}"
966
+ plan_pending=$((plan_total - plan_done))
967
+ if [ "$plan_total" -gt 0 ]; then
968
+ echo " Plan tasks: ${plan_done}/${plan_total} done, ${plan_pending} pending"
969
+ fi
970
+ fi
971
+ echo ""
972
+ if [ "$build_pause" = "plan-ready" ] && [ -n "$plan" ] && [ "$plan" != "null" ] && [ -f "$plan" ] && { [ "$isolation" = "null" ] || [ -z "$isolation" ] || [ "$build_mode" = "null" ] || [ -z "$build_mode" ]; }; then
973
+ echo "Recovery action: Plan-ready pause detected. Ask the user whether to continue, then choose isolation and build mode without regenerating the plan."
974
+ elif [ "$build_pause" = "plan-ready" ] && { [ -z "$plan" ] || [ "$plan" = "null" ] || [ ! -f "$plan" ]; }; then
975
+ echo "Recovery action: Plan-ready pause is recorded, but the plan file is missing. Restore the plan file or rerun writing-plans before choosing execution."
976
+ elif [ "$build_pause" = "plan-ready" ]; then
977
+ if [ "$build_mode" = "subagent-driven-development" ] && { [ "$pending" -gt 0 ] || [ "$plan_pending" -gt 0 ]; }; then
978
+ if [ "$subagent_dispatch" = "confirmed" ]; then
979
+ echo "Recovery action: Plan-ready pause is stale because build decisions are already selected. Clear build_pause to null, then inspect the first unchecked task (OpenSpec or plan additions) against recent git history/diff. If implemented, check it off; otherwise dispatch a real background subagent. Do not execute the pending task directly in the main window."
980
+ else
981
+ echo "Recovery action: Plan-ready pause is stale and subagent dispatch is not confirmed. Confirm a real background subagent/Task/multi-agent dispatcher and set subagent_dispatch to confirmed, or set build_mode to executing-plans before continuing."
982
+ fi
983
+ elif [ "$pending" -gt 0 ] || [ "$plan_pending" -gt 0 ]; then
984
+ echo "Recovery action: Plan-ready pause is stale because build decisions are already selected. Clear build_pause to null, then continue from the first unchecked task."
985
+ else
986
+ echo "Recovery action: Plan-ready pause is stale and all tasks are done. Clear build_pause to null, then run guard to transition to verify."
987
+ fi
988
+ elif [ "$isolation" = "null" ] || [ -z "$isolation" ]; then
989
+ echo "Recovery action: Isolation not selected. Use the current platform's user confirmation mechanism to ask user for branch/worktree choice."
990
+ elif [ "$build_mode" = "null" ] || [ -z "$build_mode" ]; then
991
+ echo "Recovery action: Build mode not selected. Use the current platform's user confirmation mechanism to ask user for execution method."
992
+ elif [ -z "$tdd_mode" ] || [ "$tdd_mode" = "null" ]; then
993
+ echo "Recovery action: TDD mode not selected. Use the current platform's user confirmation mechanism to ask user for tdd or direct."
994
+ elif [ ! -f "$tasks_file" ]; then
995
+ echo "Recovery action: tasks.md missing. Verify change directory integrity."
996
+ elif [ "$pending" -gt 0 ]; then
997
+ if [ "$build_mode" = "subagent-driven-development" ]; then
998
+ if [ "$subagent_dispatch" = "confirmed" ]; then
999
+ echo "Recovery action: Read tasks.md and the Superpowers plan (which may include additions beyond OpenSpec), then inspect the first unchecked task against recent git history/diff. If implemented, check it off; otherwise dispatch a real background subagent. Do not execute the pending task directly in the main window."
1000
+ else
1001
+ echo "Recovery action: Subagent dispatch is not confirmed. Confirm a real background subagent/Task/multi-agent dispatcher and set subagent_dispatch to confirmed, or set build_mode to executing-plans before continuing."
1002
+ fi
1003
+ else
1004
+ echo "Recovery action: Read tasks.md and continue from first unchecked task."
1005
+ fi
1006
+ elif [ "$plan_pending" -gt 0 ]; then
1007
+ if [ "$build_mode" = "subagent-driven-development" ]; then
1008
+ if [ "$subagent_dispatch" = "confirmed" ]; then
1009
+ echo "Recovery action: Read the Superpowers plan, then inspect the first unchecked Superpowers plan task against recent git history/diff. If implemented, check it off; otherwise dispatch a real background subagent. Do not execute the pending task directly in the main window."
1010
+ else
1011
+ echo "Recovery action: Subagent dispatch is not confirmed. Confirm a real background subagent/Task/multi-agent dispatcher and set subagent_dispatch to confirmed, or set build_mode to executing-plans before continuing."
1012
+ fi
1013
+ else
1014
+ echo "Recovery action: Read the Superpowers plan and continue from the first unchecked plan task."
1015
+ fi
1016
+ else
1017
+ echo "Recovery action: All tasks done. Run guard to transition to verify."
1018
+ fi
1019
+ ;;
1020
+ verify)
1021
+ echo " Verification:"
1022
+ field_status "verify_result" "$verify_result"
1023
+ field_status "verify_mode" "$verify_mode"
1024
+ field_status "verification_report" "$verification_report" "$verification_report"
1025
+ field_status "branch_status" "$branch_status"
1026
+ echo ""
1027
+ if [ "$verify_result" = "pass" ] && [ "$branch_status" = "handled" ]; then
1028
+ echo "Recovery action: Verification complete. Run guard to transition to archive."
1029
+ elif [ "$verify_result" = "pass" ]; then
1030
+ echo "Recovery action: Verification passed but branch not yet handled. Complete branch handling and set branch_status to handled."
1031
+ elif [ "$verify_result" = "fail" ]; then
1032
+ echo "Recovery action: Verification failed and rolled back to build. Resume from /comet-build."
1033
+ else
1034
+ echo "Recovery action: Verification not yet started or in progress. Run scale assessment then verify."
1035
+ fi
1036
+ ;;
1037
+ archive)
1038
+ echo " Archive:"
1039
+ field_status "verify_result" "$verify_result"
1040
+ field_status "archived" "$(cmd_get "$change_name" "archived")"
1041
+ echo ""
1042
+ echo "Recovery action: Run /comet-archive to complete archiving."
1043
+ ;;
1044
+ *)
1045
+ red "ERROR: Unknown phase: $phase"
1046
+ exit 1
1047
+ ;;
1048
+ esac
1049
+
1050
+ echo ""
1051
+ echo "=== End Recovery Context ==="
1052
+ }
1053
+
1054
+ cmd_scale() {
1055
+ local change_name="$1"
1056
+
1057
+ validate_change_name "$change_name"
1058
+
1059
+ local change_dir="openspec/changes/$change_name"
1060
+ local yaml_file="$change_dir/.comet.yaml"
1061
+
1062
+ # Verify .comet.yaml exists
1063
+ if [ ! -f "$yaml_file" ]; then
1064
+ red "ERROR: .comet.yaml not found at $yaml_file"
1065
+ exit 1
1066
+ fi
1067
+
1068
+ # Read metrics
1069
+ # 1. Task count: count lines matching `- [` in tasks.md
1070
+ local tasks_file="$change_dir/tasks.md"
1071
+ local task_count=0
1072
+ if [ -f "$tasks_file" ]; then
1073
+ task_count=$(grep -c '^\- \[' "$tasks_file" 2>/dev/null || echo "0")
1074
+ fi
1075
+
1076
+ # 2. Delta spec count: count files named spec.md under specs/*/spec.md
1077
+ local delta_spec_count=0
1078
+ if [ -d "$change_dir/specs" ]; then
1079
+ delta_spec_count=$(find "$change_dir/specs" -name "spec.md" -type f 2>/dev/null | wc -l | tr -d ' ')
1080
+ fi
1081
+
1082
+ # 3. Changed files: prefer plan base-ref, then .comet.yaml base_ref, fall back to worktree diff
1083
+ local changed_files=0
1084
+ if git rev-parse --git-dir > /dev/null 2>&1; then
1085
+ local plan_file base_ref=""
1086
+ plan_file=$(cmd_get "$change_name" "plan" 2>/dev/null || true)
1087
+ if [ -n "$plan_file" ] && [ "$plan_file" != "null" ] && [ -f "$plan_file" ]; then
1088
+ base_ref=$(grep '^base-ref:' "$plan_file" 2>/dev/null | head -1 | sed 's/^base-ref: *//' || true)
1089
+ fi
1090
+ # Fallback to base_ref stored in .comet.yaml (set during init)
1091
+ if [ -z "$base_ref" ] || [ "$base_ref" = "null" ]; then
1092
+ base_ref=$(cmd_get "$change_name" "base_ref" 2>/dev/null || true)
1093
+ fi
1094
+
1095
+ if [ -n "${base_ref:-}" ] && [ "$base_ref" != "null" ] && git rev-parse --verify "$base_ref" >/dev/null 2>&1; then
1096
+ changed_files=$(git diff --name-only "$base_ref"...HEAD 2>/dev/null | wc -l | tr -d ' ')
1097
+ else
1098
+ changed_files=$(git diff --name-only HEAD 2>/dev/null | wc -l | tr -d ' ')
1099
+ fi
1100
+ fi
1101
+
1102
+ # Decision rules
1103
+ local result="light"
1104
+ if [ "$task_count" -gt 3 ] || [ "$delta_spec_count" -gt 1 ] || [ "$changed_files" -gt 4 ]; then
1105
+ result="full"
1106
+ fi
1107
+
1108
+ # Output assessment to stderr
1109
+ echo "=== Scale Assessment: $change_name ===" >&2
1110
+ echo " Tasks: $task_count (threshold: 3)" >&2
1111
+ echo " Delta specs: $delta_spec_count capabilities (threshold: 1)" >&2
1112
+ echo " Changed files: $changed_files (threshold: 4)" >&2
1113
+ echo " → Result: $result" >&2
1114
+
1115
+ # Update verify_mode in .comet.yaml
1116
+ replace_yaml_field "$yaml_file" "verify_mode" "$result"
1117
+
1118
+ green "[SCALE] verify_mode=$result"
1119
+ }
1120
+
1121
+ cmd_task_checkoff() {
1122
+ local task_file="$1"
1123
+ local task_text="$2"
1124
+
1125
+ validate_path_field "$task_file" "task file"
1126
+
1127
+ if [ -z "$task_text" ]; then
1128
+ red "ERROR: Task text cannot be empty" >&2
1129
+ exit 1
1130
+ fi
1131
+
1132
+ if [ ! -f "$task_file" ]; then
1133
+ red "ERROR: Task file not found: $task_file" >&2
1134
+ exit 1
1135
+ fi
1136
+
1137
+ local counts
1138
+ counts=$(TASK_TEXT="$task_text" awk '
1139
+ BEGIN {
1140
+ task = ENVIRON["TASK_TEXT"]
1141
+ }
1142
+ {
1143
+ sub(/\r$/, "")
1144
+ if ($0 == "- [ ] " task || $0 == "- [x] " task || $0 == "- [X] " task) {
1145
+ total++
1146
+ }
1147
+ if ($0 == "- [x] " task || $0 == "- [X] " task) {
1148
+ checked++
1149
+ }
1150
+ }
1151
+ END {
1152
+ printf "%d %d\n", total + 0, checked + 0
1153
+ }
1154
+ ' "$task_file")
1155
+
1156
+ local total="${counts%% *}"
1157
+ local checked="${counts##* }"
1158
+
1159
+ if [ "$total" -ne 1 ]; then
1160
+ red "ERROR: task text must appear exactly once in $task_file (found $total): $task_text" >&2
1161
+ exit 1
1162
+ fi
1163
+
1164
+ if [ "$checked" -ne 1 ]; then
1165
+ red "ERROR: task is not checked in $task_file: $task_text" >&2
1166
+ exit 1
1167
+ fi
1168
+
1169
+ echo "TASK_CHECKOFF: PASS"
1170
+ echo "FILE: $task_file"
1171
+ echo "TASK: $task_text"
1172
+ }
1173
+
1174
+ # Resolve the next workflow step after a guard --apply phase advance.
1175
+ # Reads the (already advanced) phase, workflow, and auto_transition, then emits
1176
+ # a deterministic next-step contract so skills don't hardcode the next skill name.
1177
+ #
1178
+ # Output contract (stdout):
1179
+ # NEXT: auto|manual|done
1180
+ # SKILL: <skill-name> (omitted when NEXT=done)
1181
+ # HINT: <message> (only when NEXT=manual)
1182
+ cmd_next() {
1183
+ local change_name="$1"
1184
+ validate_change_name "$change_name"
1185
+
1186
+ local change_dir="openspec/changes/$change_name"
1187
+ local yaml_file="$change_dir/.comet.yaml"
1188
+ if [ ! -f "$yaml_file" ]; then
1189
+ red "ERROR: .comet.yaml not found at $yaml_file" >&2
1190
+ exit 1
1191
+ fi
1192
+
1193
+ local phase workflow auto_transition archived
1194
+ phase=$(cmd_get "$change_name" "phase" 2>/dev/null || true)
1195
+ workflow=$(cmd_get "$change_name" "workflow" 2>/dev/null || true)
1196
+ auto_transition=$(cmd_get "$change_name" "auto_transition" 2>/dev/null || true)
1197
+ archived=$(cmd_get "$change_name" "archived" 2>/dev/null || true)
1198
+
1199
+ # Change-level auto_transition overrides project-level; fall back to project default
1200
+ if [ -z "$auto_transition" ] || [ "$auto_transition" = "null" ]; then
1201
+ auto_transition="$(project_auto_transition_default)"
1202
+ fi
1203
+
1204
+ # Terminal state: archived change has no next step.
1205
+ if [ "$archived" = "true" ]; then
1206
+ echo "NEXT: done"
1207
+ return 0
1208
+ fi
1209
+
1210
+ # Map the current (post-advance) phase to the skill that owns it.
1211
+ local skill=""
1212
+ case "$phase" in
1213
+ open)
1214
+ skill="comet-open"
1215
+ ;;
1216
+ design)
1217
+ skill="comet-design"
1218
+ ;;
1219
+ build)
1220
+ case "$workflow" in
1221
+ hotfix) skill="comet-hotfix" ;;
1222
+ tweak) skill="comet-tweak" ;;
1223
+ *) skill="comet-build" ;;
1224
+ esac
1225
+ ;;
1226
+ verify)
1227
+ skill="comet-verify"
1228
+ ;;
1229
+ archive)
1230
+ skill="comet-archive"
1231
+ ;;
1232
+ *)
1233
+ red "ERROR: Cannot resolve next step for '$change_name': unknown phase '${phase:-null}'" >&2
1234
+ exit 1
1235
+ ;;
1236
+ esac
1237
+
1238
+ # auto_transition=false pauses the next skill invocation only; phase is already advanced.
1239
+ if [ "$auto_transition" = "false" ]; then
1240
+ echo "NEXT: manual"
1241
+ echo "SKILL: $skill"
1242
+ echo "HINT: phase is '$phase'; run /$skill manually to continue"
1243
+ else
1244
+ echo "NEXT: auto"
1245
+ echo "SKILL: $skill"
1246
+ fi
1247
+ }
1248
+
1249
+ # --- Main ---
1250
+
1251
+ SUBCOMMAND="${1:-}"
1252
+ shift || true
1253
+
1254
+ case "$SUBCOMMAND" in
1255
+ init)
1256
+ if [ $# -lt 2 ]; then
1257
+ red "Usage: comet-state.sh init <change-name> <workflow>" >&2
1258
+ red "Workflows: full, hotfix, tweak" >&2
1259
+ exit 1
1260
+ fi
1261
+ cmd_init "$@"
1262
+ ;;
1263
+ get)
1264
+ if [ $# -lt 2 ]; then
1265
+ red "Usage: comet-state.sh get <change-name> <field>" >&2
1266
+ exit 1
1267
+ fi
1268
+ cmd_get "$@"
1269
+ ;;
1270
+ set)
1271
+ if [ $# -lt 3 ]; then
1272
+ red "Usage: comet-state.sh set <change-name> <field> <value>" >&2
1273
+ exit 1
1274
+ fi
1275
+ cmd_set "$@"
1276
+ ;;
1277
+ transition)
1278
+ if [ $# -lt 2 ]; then
1279
+ red "Usage: comet-state.sh transition <change-name> <event>" >&2
1280
+ red "Events: open-complete, design-complete, build-complete, verify-pass, verify-fail, archive-reopen, archived" >&2
1281
+ exit 1
1282
+ fi
1283
+ cmd_transition "$@"
1284
+ ;;
1285
+ check)
1286
+ if [ $# -lt 2 ]; then
1287
+ red "Usage: comet-state.sh check <change-name> <phase> [--recover]" >&2
1288
+ red "Phases: open, design, build, verify, archive" >&2
1289
+ exit 1
1290
+ fi
1291
+ # Detect --recover flag (3rd argument)
1292
+ if [ "${3:-}" = "--recover" ]; then
1293
+ cmd_recover "$1"
1294
+ else
1295
+ cmd_check "$@"
1296
+ fi
1297
+ ;;
1298
+ scale)
1299
+ if [ $# -lt 1 ]; then
1300
+ red "Usage: comet-state.sh scale <change-name>" >&2
1301
+ exit 1
1302
+ fi
1303
+ cmd_scale "$@"
1304
+ ;;
1305
+ task-checkoff)
1306
+ if [ $# -lt 2 ]; then
1307
+ red "Usage: comet-state.sh task-checkoff <file> <task-text>" >&2
1308
+ exit 1
1309
+ fi
1310
+ cmd_task_checkoff "$@"
1311
+ ;;
1312
+ next)
1313
+ if [ $# -lt 1 ]; then
1314
+ red "Usage: comet-state.sh next <change-name>" >&2
1315
+ exit 1
1316
+ fi
1317
+ cmd_next "$@"
1318
+ ;;
1319
+ *)
1320
+ red "Unknown subcommand: $SUBCOMMAND" >&2
1321
+ echo "" >&2
1322
+ echo "Usage: comet-state.sh <subcommand> <change-name> [args...]" >&2
1323
+ echo "" >&2
1324
+ echo "Subcommands:" >&2
1325
+ echo " init <change-name> <workflow> — Initialize .comet.yaml with workflow defaults" >&2
1326
+ echo " get <change-name> <field> — Read a field value from .comet.yaml" >&2
1327
+ echo " set <change-name> <field> <val> — Update a field value in .comet.yaml" >&2
1328
+ echo " transition <change-name> <event> — Apply a validated state transition" >&2
1329
+ echo " check <change-name> <phase> — Verify entry requirements for a phase" >&2
1330
+ echo " scale <change-name> — Assess and set verification mode based on metrics" >&2
1331
+ echo " task-checkoff <file> <task-text> — Verify one unique task is checked" >&2
1332
+ echo " next <change-name> — Resolve the next workflow step (auto/manual/done)" >&2
1333
+ echo "" >&2
1334
+ echo "Workflows: full, hotfix, tweak" >&2
1335
+ echo "Phases for check: open, design, build, verify, archive" >&2
1336
+ exit 1
1337
+ ;;
1338
+ esac