@matteeh/osq 0.2.0 → 0.2.2

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 (630) hide show
  1. package/README.md +234 -15
  2. package/dist/cli/approve.d.ts +7 -0
  3. package/dist/cli/approve.d.ts.map +1 -1
  4. package/dist/cli/approve.js +34 -0
  5. package/dist/cli/approve.js.map +1 -1
  6. package/dist/cli/bin.js +2 -3
  7. package/dist/cli/bin.js.map +1 -1
  8. package/dist/cli/check.d.ts +15 -0
  9. package/dist/cli/check.d.ts.map +1 -0
  10. package/dist/cli/check.js +65 -0
  11. package/dist/cli/check.js.map +1 -0
  12. package/dist/cli/index.d.ts.map +1 -1
  13. package/dist/cli/index.js +10 -10
  14. package/dist/cli/index.js.map +1 -1
  15. package/dist/cli/init.d.ts.map +1 -1
  16. package/dist/cli/init.js +6 -1
  17. package/dist/cli/init.js.map +1 -1
  18. package/dist/cli/lint.d.ts +3 -0
  19. package/dist/cli/lint.d.ts.map +1 -1
  20. package/dist/cli/lint.js +33 -14
  21. package/dist/cli/lint.js.map +1 -1
  22. package/dist/cli/plan-queue.d.ts +10 -4
  23. package/dist/cli/plan-queue.d.ts.map +1 -1
  24. package/dist/cli/plan-queue.js +20 -19
  25. package/dist/cli/plan-queue.js.map +1 -1
  26. package/dist/cli/plan-sections.d.ts +15 -0
  27. package/dist/cli/plan-sections.d.ts.map +1 -0
  28. package/dist/cli/plan-sections.js +47 -0
  29. package/dist/cli/plan-sections.js.map +1 -0
  30. package/dist/cli/plan.d.ts +1 -0
  31. package/dist/cli/plan.d.ts.map +1 -1
  32. package/dist/cli/plan.js +14 -4
  33. package/dist/cli/plan.js.map +1 -1
  34. package/dist/cli/report.d.ts.map +1 -1
  35. package/dist/cli/report.js +73 -1
  36. package/dist/cli/report.js.map +1 -1
  37. package/dist/cli/run.d.ts +7 -0
  38. package/dist/cli/run.d.ts.map +1 -0
  39. package/dist/cli/run.js +22 -0
  40. package/dist/cli/run.js.map +1 -0
  41. package/dist/cli/verified.d.ts +15 -0
  42. package/dist/cli/verified.d.ts.map +1 -0
  43. package/dist/cli/verified.js +34 -0
  44. package/dist/cli/verified.js.map +1 -0
  45. package/dist/core/foundation/config-agents.d.ts +16 -0
  46. package/dist/core/foundation/config-agents.d.ts.map +1 -0
  47. package/dist/core/foundation/config-agents.js +2 -0
  48. package/dist/core/foundation/config-agents.js.map +1 -0
  49. package/dist/core/foundation/config-claude.d.ts +48 -0
  50. package/dist/core/foundation/config-claude.d.ts.map +1 -0
  51. package/dist/core/foundation/config-claude.js +106 -0
  52. package/dist/core/foundation/config-claude.js.map +1 -0
  53. package/dist/core/foundation/config-codex-resolve.d.ts +10 -0
  54. package/dist/core/foundation/config-codex-resolve.d.ts.map +1 -0
  55. package/dist/core/foundation/config-codex-resolve.js +24 -0
  56. package/dist/core/foundation/config-codex-resolve.js.map +1 -0
  57. package/dist/core/foundation/config-file.d.ts +18 -0
  58. package/dist/core/foundation/config-file.d.ts.map +1 -0
  59. package/dist/core/foundation/config-file.js +46 -0
  60. package/dist/core/foundation/config-file.js.map +1 -0
  61. package/dist/core/foundation/config-gates.d.ts +2 -0
  62. package/dist/core/foundation/config-gates.d.ts.map +1 -1
  63. package/dist/core/foundation/config-gates.js +8 -0
  64. package/dist/core/foundation/config-gates.js.map +1 -1
  65. package/dist/core/foundation/config-opencode.d.ts +25 -0
  66. package/dist/core/foundation/config-opencode.d.ts.map +1 -0
  67. package/dist/core/foundation/config-opencode.js +55 -0
  68. package/dist/core/foundation/config-opencode.js.map +1 -0
  69. package/dist/core/foundation/config-pi.d.ts +10 -0
  70. package/dist/core/foundation/config-pi.d.ts.map +1 -1
  71. package/dist/core/foundation/config-pi.js +13 -0
  72. package/dist/core/foundation/config-pi.js.map +1 -1
  73. package/dist/core/foundation/config-planning.d.ts +12 -1
  74. package/dist/core/foundation/config-planning.d.ts.map +1 -1
  75. package/dist/core/foundation/config-planning.js +29 -1
  76. package/dist/core/foundation/config-planning.js.map +1 -1
  77. package/dist/core/foundation/config-traceability.d.ts +28 -0
  78. package/dist/core/foundation/config-traceability.d.ts.map +1 -0
  79. package/dist/core/foundation/config-traceability.js +63 -0
  80. package/dist/core/foundation/config-traceability.js.map +1 -0
  81. package/dist/core/foundation/config-user.d.ts +32 -0
  82. package/dist/core/foundation/config-user.d.ts.map +1 -0
  83. package/dist/core/foundation/config-user.js +2 -0
  84. package/dist/core/foundation/config-user.js.map +1 -0
  85. package/dist/core/foundation/config-vcs.d.ts +29 -0
  86. package/dist/core/foundation/config-vcs.d.ts.map +1 -0
  87. package/dist/core/foundation/config-vcs.js +57 -0
  88. package/dist/core/foundation/config-vcs.js.map +1 -0
  89. package/dist/core/foundation/config.d.ts +23 -24
  90. package/dist/core/foundation/config.d.ts.map +1 -1
  91. package/dist/core/foundation/config.js +29 -36
  92. package/dist/core/foundation/config.js.map +1 -1
  93. package/dist/core/foundation/decisions-validate.d.ts +16 -0
  94. package/dist/core/foundation/decisions-validate.d.ts.map +1 -0
  95. package/dist/core/foundation/decisions-validate.js +74 -0
  96. package/dist/core/foundation/decisions-validate.js.map +1 -0
  97. package/dist/core/foundation/decisions.d.ts +34 -0
  98. package/dist/core/foundation/decisions.d.ts.map +1 -0
  99. package/dist/core/foundation/decisions.js +152 -0
  100. package/dist/core/foundation/decisions.js.map +1 -0
  101. package/dist/core/foundation/doctor-decisions.d.ts +9 -0
  102. package/dist/core/foundation/doctor-decisions.d.ts.map +1 -0
  103. package/dist/core/foundation/doctor-decisions.js +49 -0
  104. package/dist/core/foundation/doctor-decisions.js.map +1 -0
  105. package/dist/core/foundation/doctor-managed.d.ts.map +1 -1
  106. package/dist/core/foundation/doctor-managed.js +3 -0
  107. package/dist/core/foundation/doctor-managed.js.map +1 -1
  108. package/dist/core/foundation/doctor-prices.d.ts +8 -0
  109. package/dist/core/foundation/doctor-prices.d.ts.map +1 -0
  110. package/dist/core/foundation/doctor-prices.js +25 -0
  111. package/dist/core/foundation/doctor-prices.js.map +1 -0
  112. package/dist/core/foundation/doctor.d.ts.map +1 -1
  113. package/dist/core/foundation/doctor.js +20 -30
  114. package/dist/core/foundation/doctor.js.map +1 -1
  115. package/dist/core/foundation/harness-catalog.d.ts +7 -8
  116. package/dist/core/foundation/harness-catalog.d.ts.map +1 -1
  117. package/dist/core/foundation/harness-catalog.js +26 -41
  118. package/dist/core/foundation/harness-catalog.js.map +1 -1
  119. package/dist/core/foundation/init-blocks.d.ts +1 -1
  120. package/dist/core/foundation/init-blocks.d.ts.map +1 -1
  121. package/dist/core/foundation/init-blocks.js +51 -14
  122. package/dist/core/foundation/init-blocks.js.map +1 -1
  123. package/dist/core/foundation/init.d.ts +4 -0
  124. package/dist/core/foundation/init.d.ts.map +1 -1
  125. package/dist/core/foundation/init.js +7 -0
  126. package/dist/core/foundation/init.js.map +1 -1
  127. package/dist/core/foundation/new.d.ts +4 -1
  128. package/dist/core/foundation/new.d.ts.map +1 -1
  129. package/dist/core/foundation/new.js +18 -8
  130. package/dist/core/foundation/new.js.map +1 -1
  131. package/dist/core/foundation/package-root.d.ts +6 -0
  132. package/dist/core/foundation/package-root.d.ts.map +1 -1
  133. package/dist/core/foundation/package-root.js +6 -0
  134. package/dist/core/foundation/package-root.js.map +1 -1
  135. package/dist/core/foundation/rules-block.d.ts +11 -0
  136. package/dist/core/foundation/rules-block.d.ts.map +1 -0
  137. package/dist/core/foundation/rules-block.js +90 -0
  138. package/dist/core/foundation/rules-block.js.map +1 -0
  139. package/dist/core/foundation/traceability-block.d.ts +13 -0
  140. package/dist/core/foundation/traceability-block.d.ts.map +1 -0
  141. package/dist/core/foundation/traceability-block.js +124 -0
  142. package/dist/core/foundation/traceability-block.js.map +1 -0
  143. package/dist/core/lifecycle/done.d.ts.map +1 -1
  144. package/dist/core/lifecycle/done.js +2 -4
  145. package/dist/core/lifecycle/done.js.map +1 -1
  146. package/dist/core/lifecycle/recertify.d.ts +9 -0
  147. package/dist/core/lifecycle/recertify.d.ts.map +1 -0
  148. package/dist/core/lifecycle/recertify.js +27 -0
  149. package/dist/core/lifecycle/recertify.js.map +1 -0
  150. package/dist/core/lifecycle/reject.d.ts.map +1 -1
  151. package/dist/core/lifecycle/reject.js +3 -4
  152. package/dist/core/lifecycle/reject.js.map +1 -1
  153. package/dist/core/lifecycle/retry.d.ts.map +1 -1
  154. package/dist/core/lifecycle/retry.js +6 -20
  155. package/dist/core/lifecycle/retry.js.map +1 -1
  156. package/dist/core/lifecycle/verification-record.d.ts +42 -0
  157. package/dist/core/lifecycle/verification-record.d.ts.map +1 -0
  158. package/dist/core/lifecycle/verification-record.js +76 -0
  159. package/dist/core/lifecycle/verification-record.js.map +1 -0
  160. package/dist/core/report/approval-flags.d.ts +16 -3
  161. package/dist/core/report/approval-flags.d.ts.map +1 -1
  162. package/dist/core/report/approval-flags.js +59 -22
  163. package/dist/core/report/approval-flags.js.map +1 -1
  164. package/dist/core/report/brief-to-approval.d.ts +7 -0
  165. package/dist/core/report/brief-to-approval.d.ts.map +1 -0
  166. package/dist/core/report/brief-to-approval.js +43 -0
  167. package/dist/core/report/brief-to-approval.js.map +1 -0
  168. package/dist/core/report/planning-price-gaps.d.ts +10 -0
  169. package/dist/core/report/planning-price-gaps.d.ts.map +1 -0
  170. package/dist/core/report/planning-price-gaps.js +37 -0
  171. package/dist/core/report/planning-price-gaps.js.map +1 -0
  172. package/dist/core/report/planning-slice-lookup.d.ts.map +1 -1
  173. package/dist/core/report/planning-slice-lookup.js +3 -9
  174. package/dist/core/report/planning-slice-lookup.js.map +1 -1
  175. package/dist/core/report/recent-disclosures.d.ts +18 -0
  176. package/dist/core/report/recent-disclosures.d.ts.map +1 -0
  177. package/dist/core/report/recent-disclosures.js +105 -0
  178. package/dist/core/report/recent-disclosures.js.map +1 -0
  179. package/dist/core/report/record-disclosures.d.ts +14 -0
  180. package/dist/core/report/record-disclosures.d.ts.map +1 -0
  181. package/dist/core/report/record-disclosures.js +30 -0
  182. package/dist/core/report/record-disclosures.js.map +1 -0
  183. package/dist/core/report/record-estimates.d.ts +25 -0
  184. package/dist/core/report/record-estimates.d.ts.map +1 -0
  185. package/dist/core/report/record-estimates.js +83 -0
  186. package/dist/core/report/record-estimates.js.map +1 -0
  187. package/dist/core/report/record-rework.d.ts +19 -0
  188. package/dist/core/report/record-rework.d.ts.map +1 -0
  189. package/dist/core/report/record-rework.js +50 -0
  190. package/dist/core/report/record-rework.js.map +1 -0
  191. package/dist/core/report/record-verification.d.ts +16 -0
  192. package/dist/core/report/record-verification.d.ts.map +1 -0
  193. package/dist/core/report/record-verification.js +33 -0
  194. package/dist/core/report/record-verification.js.map +1 -0
  195. package/dist/core/report/report-dependencies.d.ts +29 -0
  196. package/dist/core/report/report-dependencies.d.ts.map +1 -0
  197. package/dist/core/report/report-dependencies.js +92 -0
  198. package/dist/core/report/report-dependencies.js.map +1 -0
  199. package/dist/core/report/report-events.d.ts +1 -0
  200. package/dist/core/report/report-events.d.ts.map +1 -1
  201. package/dist/core/report/report-events.js +8 -26
  202. package/dist/core/report/report-events.js.map +1 -1
  203. package/dist/core/report/report-mutation.d.ts +34 -0
  204. package/dist/core/report/report-mutation.d.ts.map +1 -0
  205. package/dist/core/report/report-mutation.js +191 -0
  206. package/dist/core/report/report-mutation.js.map +1 -0
  207. package/dist/core/report/report-scope.d.ts +21 -0
  208. package/dist/core/report/report-scope.d.ts.map +1 -0
  209. package/dist/core/report/report-scope.js +61 -0
  210. package/dist/core/report/report-scope.js.map +1 -0
  211. package/dist/core/report/report-traceability.d.ts +29 -0
  212. package/dist/core/report/report-traceability.d.ts.map +1 -0
  213. package/dist/core/report/report-traceability.js +94 -0
  214. package/dist/core/report/report-traceability.js.map +1 -0
  215. package/dist/core/report/report.d.ts +35 -1
  216. package/dist/core/report/report.d.ts.map +1 -1
  217. package/dist/core/report/report.js +130 -111
  218. package/dist/core/report/report.js.map +1 -1
  219. package/dist/core/report/result-sections.d.ts +30 -0
  220. package/dist/core/report/result-sections.d.ts.map +1 -0
  221. package/dist/core/report/result-sections.js +125 -0
  222. package/dist/core/report/result-sections.js.map +1 -0
  223. package/dist/core/report/scope-size.d.ts +7 -0
  224. package/dist/core/report/scope-size.d.ts.map +1 -0
  225. package/dist/core/report/scope-size.js +22 -0
  226. package/dist/core/report/scope-size.js.map +1 -0
  227. package/dist/core/run/commit-message.d.ts +24 -0
  228. package/dist/core/run/commit-message.d.ts.map +1 -0
  229. package/dist/core/run/commit-message.js +76 -0
  230. package/dist/core/run/commit-message.js.map +1 -0
  231. package/dist/core/run/dead-commit.d.ts +10 -0
  232. package/dist/core/run/dead-commit.d.ts.map +1 -0
  233. package/dist/core/run/dead-commit.js +70 -0
  234. package/dist/core/run/dead-commit.js.map +1 -0
  235. package/dist/core/run/focused-tests.d.ts +43 -0
  236. package/dist/core/run/focused-tests.d.ts.map +1 -0
  237. package/dist/core/run/focused-tests.js +116 -0
  238. package/dist/core/run/focused-tests.js.map +1 -0
  239. package/dist/core/run/manifest-approval.d.ts +7 -0
  240. package/dist/core/run/manifest-approval.d.ts.map +1 -0
  241. package/dist/core/run/manifest-approval.js +30 -0
  242. package/dist/core/run/manifest-approval.js.map +1 -0
  243. package/dist/core/run/manifest.d.ts +11 -1
  244. package/dist/core/run/manifest.d.ts.map +1 -1
  245. package/dist/core/run/manifest.js +52 -11
  246. package/dist/core/run/manifest.js.map +1 -1
  247. package/dist/core/run/mutation-report.d.ts +29 -0
  248. package/dist/core/run/mutation-report.d.ts.map +1 -0
  249. package/dist/core/run/mutation-report.js +107 -0
  250. package/dist/core/run/mutation-report.js.map +1 -0
  251. package/dist/core/run/mutation-run.d.ts +32 -0
  252. package/dist/core/run/mutation-run.d.ts.map +1 -0
  253. package/dist/core/run/mutation-run.js +80 -0
  254. package/dist/core/run/mutation-run.js.map +1 -0
  255. package/dist/core/run/verification.d.ts +12 -1
  256. package/dist/core/run/verification.d.ts.map +1 -1
  257. package/dist/core/run/verification.js +24 -2
  258. package/dist/core/run/verification.js.map +1 -1
  259. package/dist/core/spec/approve-worktree-shared.d.ts +33 -0
  260. package/dist/core/spec/approve-worktree-shared.d.ts.map +1 -0
  261. package/dist/core/spec/approve-worktree-shared.js +59 -0
  262. package/dist/core/spec/approve-worktree-shared.js.map +1 -0
  263. package/dist/core/spec/approve-worktree.d.ts +21 -0
  264. package/dist/core/spec/approve-worktree.d.ts.map +1 -0
  265. package/dist/core/spec/approve-worktree.js +153 -0
  266. package/dist/core/spec/approve-worktree.js.map +1 -0
  267. package/dist/core/spec/approve.d.ts +20 -10
  268. package/dist/core/spec/approve.d.ts.map +1 -1
  269. package/dist/core/spec/approve.js +57 -54
  270. package/dist/core/spec/approve.js.map +1 -1
  271. package/dist/core/spec/capability-impact.d.ts +43 -0
  272. package/dist/core/spec/capability-impact.d.ts.map +1 -0
  273. package/dist/core/spec/capability-impact.js +85 -0
  274. package/dist/core/spec/capability-impact.js.map +1 -0
  275. package/dist/core/spec/decisions-lint.d.ts +18 -0
  276. package/dist/core/spec/decisions-lint.d.ts.map +1 -0
  277. package/dist/core/spec/decisions-lint.js +127 -0
  278. package/dist/core/spec/decisions-lint.js.map +1 -0
  279. package/dist/core/spec/delta.d.ts +6 -0
  280. package/dist/core/spec/delta.d.ts.map +1 -1
  281. package/dist/core/spec/delta.js +73 -5
  282. package/dist/core/spec/delta.js.map +1 -1
  283. package/dist/core/spec/digest-capability.d.ts +17 -0
  284. package/dist/core/spec/digest-capability.d.ts.map +1 -0
  285. package/dist/core/spec/digest-capability.js +89 -0
  286. package/dist/core/spec/digest-capability.js.map +1 -0
  287. package/dist/core/spec/digest-decisions.d.ts +27 -0
  288. package/dist/core/spec/digest-decisions.d.ts.map +1 -0
  289. package/dist/core/spec/digest-decisions.js +86 -0
  290. package/dist/core/spec/digest-decisions.js.map +1 -0
  291. package/dist/core/spec/digest-flags.d.ts +1 -0
  292. package/dist/core/spec/digest-flags.d.ts.map +1 -1
  293. package/dist/core/spec/digest-flags.js +16 -16
  294. package/dist/core/spec/digest-flags.js.map +1 -1
  295. package/dist/core/spec/digest-format.d.ts +4 -0
  296. package/dist/core/spec/digest-format.d.ts.map +1 -0
  297. package/dist/core/spec/digest-format.js +44 -0
  298. package/dist/core/spec/digest-format.js.map +1 -0
  299. package/dist/core/spec/digest.d.ts +6 -3
  300. package/dist/core/spec/digest.d.ts.map +1 -1
  301. package/dist/core/spec/digest.js +18 -32
  302. package/dist/core/spec/digest.js.map +1 -1
  303. package/dist/core/spec/human-steps.d.ts +20 -0
  304. package/dist/core/spec/human-steps.d.ts.map +1 -0
  305. package/dist/core/spec/human-steps.js +52 -0
  306. package/dist/core/spec/human-steps.js.map +1 -0
  307. package/dist/core/spec/impact-lint.d.ts +24 -0
  308. package/dist/core/spec/impact-lint.d.ts.map +1 -0
  309. package/dist/core/spec/impact-lint.js +39 -0
  310. package/dist/core/spec/impact-lint.js.map +1 -0
  311. package/dist/core/spec/import-graph.d.ts +35 -0
  312. package/dist/core/spec/import-graph.d.ts.map +1 -0
  313. package/dist/core/spec/import-graph.js +155 -0
  314. package/dist/core/spec/import-graph.js.map +1 -0
  315. package/dist/core/spec/lint-findings.d.ts +44 -0
  316. package/dist/core/spec/lint-findings.d.ts.map +1 -0
  317. package/dist/core/spec/lint-findings.js +56 -0
  318. package/dist/core/spec/lint-findings.js.map +1 -0
  319. package/dist/core/spec/lint-output.d.ts +53 -0
  320. package/dist/core/spec/lint-output.d.ts.map +1 -0
  321. package/dist/core/spec/lint-output.js +87 -0
  322. package/dist/core/spec/lint-output.js.map +1 -0
  323. package/dist/core/spec/linter.d.ts +14 -4
  324. package/dist/core/spec/linter.d.ts.map +1 -1
  325. package/dist/core/spec/linter.js +271 -111
  326. package/dist/core/spec/linter.js.map +1 -1
  327. package/dist/core/spec/merged-spec-check.d.ts +24 -0
  328. package/dist/core/spec/merged-spec-check.d.ts.map +1 -0
  329. package/dist/core/spec/merged-spec-check.js +95 -0
  330. package/dist/core/spec/merged-spec-check.js.map +1 -0
  331. package/dist/core/spec/openspec-issues.d.ts +58 -0
  332. package/dist/core/spec/openspec-issues.d.ts.map +1 -0
  333. package/dist/core/spec/openspec-issues.js +166 -0
  334. package/dist/core/spec/openspec-issues.js.map +1 -0
  335. package/dist/core/spec/parser.d.ts +1 -0
  336. package/dist/core/spec/parser.d.ts.map +1 -1
  337. package/dist/core/spec/parser.js +16 -6
  338. package/dist/core/spec/parser.js.map +1 -1
  339. package/dist/core/spec/scenario-impact.d.ts +47 -0
  340. package/dist/core/spec/scenario-impact.d.ts.map +1 -0
  341. package/dist/core/spec/scenario-impact.js +130 -0
  342. package/dist/core/spec/scenario-impact.js.map +1 -0
  343. package/dist/core/spec/test-impact.d.ts +28 -0
  344. package/dist/core/spec/test-impact.d.ts.map +1 -0
  345. package/dist/core/spec/test-impact.js +119 -0
  346. package/dist/core/spec/test-impact.js.map +1 -0
  347. package/dist/core/spec/traceability-links.d.ts +50 -0
  348. package/dist/core/spec/traceability-links.d.ts.map +1 -0
  349. package/dist/core/spec/traceability-links.js +120 -0
  350. package/dist/core/spec/traceability-links.js.map +1 -0
  351. package/dist/core/spec/traceability-lint.d.ts +29 -0
  352. package/dist/core/spec/traceability-lint.d.ts.map +1 -0
  353. package/dist/core/spec/traceability-lint.js +143 -0
  354. package/dist/core/spec/traceability-lint.js.map +1 -0
  355. package/dist/core/status/blocked-item.d.ts +8 -0
  356. package/dist/core/status/blocked-item.d.ts.map +1 -0
  357. package/dist/core/status/blocked-item.js +45 -0
  358. package/dist/core/status/blocked-item.js.map +1 -0
  359. package/dist/core/status/change-locations.d.ts +44 -0
  360. package/dist/core/status/change-locations.d.ts.map +1 -0
  361. package/dist/core/status/change-locations.js +138 -0
  362. package/dist/core/status/change-locations.js.map +1 -0
  363. package/dist/core/status/dependency-readiness.d.ts +11 -0
  364. package/dist/core/status/dependency-readiness.d.ts.map +1 -0
  365. package/dist/core/status/dependency-readiness.js +39 -0
  366. package/dist/core/status/dependency-readiness.js.map +1 -0
  367. package/dist/core/status/inbox-projection.d.ts.map +1 -1
  368. package/dist/core/status/inbox-projection.js +23 -4
  369. package/dist/core/status/inbox-projection.js.map +1 -1
  370. package/dist/core/status/inbox-text.d.ts.map +1 -1
  371. package/dist/core/status/inbox-text.js +34 -3
  372. package/dist/core/status/inbox-text.js.map +1 -1
  373. package/dist/core/status/inbox.d.ts +10 -1
  374. package/dist/core/status/inbox.d.ts.map +1 -1
  375. package/dist/core/status/inbox.js +19 -1
  376. package/dist/core/status/inbox.js.map +1 -1
  377. package/dist/core/status/layout.d.ts +6 -0
  378. package/dist/core/status/layout.d.ts.map +1 -1
  379. package/dist/core/status/layout.js +8 -0
  380. package/dist/core/status/layout.js.map +1 -1
  381. package/dist/core/status/next-step.d.ts +17 -0
  382. package/dist/core/status/next-step.d.ts.map +1 -0
  383. package/dist/core/status/next-step.js +85 -0
  384. package/dist/core/status/next-step.js.map +1 -0
  385. package/dist/core/status/pre-spawn-words.d.ts +13 -0
  386. package/dist/core/status/pre-spawn-words.d.ts.map +1 -0
  387. package/dist/core/status/pre-spawn-words.js +26 -0
  388. package/dist/core/status/pre-spawn-words.js.map +1 -0
  389. package/dist/core/status/queue-parser.d.ts +1 -0
  390. package/dist/core/status/queue-parser.d.ts.map +1 -1
  391. package/dist/core/status/queue-parser.js +41 -2
  392. package/dist/core/status/queue-parser.js.map +1 -1
  393. package/dist/core/status/queue-planning.d.ts +1 -0
  394. package/dist/core/status/queue-planning.d.ts.map +1 -1
  395. package/dist/core/status/queue-planning.js +24 -12
  396. package/dist/core/status/queue-planning.js.map +1 -1
  397. package/dist/core/status/queue-report-detail.d.ts.map +1 -1
  398. package/dist/core/status/queue-report-detail.js +5 -3
  399. package/dist/core/status/queue-report-detail.js.map +1 -1
  400. package/dist/core/status/queue-state.d.ts +1 -1
  401. package/dist/core/status/queue-state.d.ts.map +1 -1
  402. package/dist/core/status/queue-state.js +27 -41
  403. package/dist/core/status/queue-state.js.map +1 -1
  404. package/dist/core/status/show.d.ts +25 -0
  405. package/dist/core/status/show.d.ts.map +1 -1
  406. package/dist/core/status/show.js +354 -91
  407. package/dist/core/status/show.js.map +1 -1
  408. package/dist/core/status/state.d.ts.map +1 -1
  409. package/dist/core/status/state.js +1 -23
  410. package/dist/core/status/state.js.map +1 -1
  411. package/dist/core/status/status.d.ts +18 -0
  412. package/dist/core/status/status.d.ts.map +1 -1
  413. package/dist/core/status/status.js +59 -80
  414. package/dist/core/status/status.js.map +1 -1
  415. package/dist/core/status/verification.d.ts +27 -0
  416. package/dist/core/status/verification.d.ts.map +1 -0
  417. package/dist/core/status/verification.js +111 -0
  418. package/dist/core/status/verification.js.map +1 -0
  419. package/dist/core/trace/function-ranges.d.ts +30 -0
  420. package/dist/core/trace/function-ranges.d.ts.map +1 -0
  421. package/dist/core/trace/function-ranges.js +250 -0
  422. package/dist/core/trace/function-ranges.js.map +1 -0
  423. package/dist/core/trace/mutation-pick.d.ts +55 -0
  424. package/dist/core/trace/mutation-pick.d.ts.map +1 -0
  425. package/dist/core/trace/mutation-pick.js +96 -0
  426. package/dist/core/trace/mutation-pick.js.map +1 -0
  427. package/dist/core/trace/scenario-index.d.ts +27 -0
  428. package/dist/core/trace/scenario-index.d.ts.map +1 -0
  429. package/dist/core/trace/scenario-index.js +76 -0
  430. package/dist/core/trace/scenario-index.js.map +1 -0
  431. package/dist/core/trace/scenario-lookup.d.ts +14 -0
  432. package/dist/core/trace/scenario-lookup.d.ts.map +1 -0
  433. package/dist/core/trace/scenario-lookup.js +179 -0
  434. package/dist/core/trace/scenario-lookup.js.map +1 -0
  435. package/dist/core/trace/tag-scan.d.ts +44 -0
  436. package/dist/core/trace/tag-scan.d.ts.map +1 -0
  437. package/dist/core/trace/tag-scan.js +200 -0
  438. package/dist/core/trace/tag-scan.js.map +1 -0
  439. package/dist/core/vcs/doctor-git.d.ts +13 -0
  440. package/dist/core/vcs/doctor-git.d.ts.map +1 -0
  441. package/dist/core/vcs/doctor-git.js +114 -0
  442. package/dist/core/vcs/doctor-git.js.map +1 -0
  443. package/dist/core/vcs/git-vcs-write.d.ts +47 -0
  444. package/dist/core/vcs/git-vcs-write.d.ts.map +1 -0
  445. package/dist/core/vcs/git-vcs-write.js +210 -0
  446. package/dist/core/vcs/git-vcs-write.js.map +1 -0
  447. package/dist/core/vcs/git-vcs.d.ts +40 -0
  448. package/dist/core/vcs/git-vcs.d.ts.map +1 -0
  449. package/dist/core/vcs/git-vcs.js +170 -0
  450. package/dist/core/vcs/git-vcs.js.map +1 -0
  451. package/dist/core/vcs/no-vcs.d.ts +26 -0
  452. package/dist/core/vcs/no-vcs.d.ts.map +1 -0
  453. package/dist/core/vcs/no-vcs.js +62 -0
  454. package/dist/core/vcs/no-vcs.js.map +1 -0
  455. package/dist/core/vcs/select.d.ts +11 -0
  456. package/dist/core/vcs/select.d.ts.map +1 -0
  457. package/dist/core/vcs/select.js +33 -0
  458. package/dist/core/vcs/select.js.map +1 -0
  459. package/dist/core/vcs/snapshot.d.ts +34 -0
  460. package/dist/core/vcs/snapshot.d.ts.map +1 -0
  461. package/dist/core/vcs/snapshot.js +71 -0
  462. package/dist/core/vcs/snapshot.js.map +1 -0
  463. package/dist/core/vcs/vcs.d.ts +55 -0
  464. package/dist/core/vcs/vcs.d.ts.map +1 -0
  465. package/dist/core/vcs/vcs.js +2 -0
  466. package/dist/core/vcs/vcs.js.map +1 -0
  467. package/dist/core/vcs/worktree.d.ts +10 -0
  468. package/dist/core/vcs/worktree.d.ts.map +1 -0
  469. package/dist/core/vcs/worktree.js +25 -0
  470. package/dist/core/vcs/worktree.js.map +1 -0
  471. package/dist/core/web/web-data-folders.d.ts.map +1 -1
  472. package/dist/core/web/web-data-folders.js +18 -33
  473. package/dist/core/web/web-data-folders.js.map +1 -1
  474. package/dist/core/web/web-data-lifecycle.d.ts.map +1 -1
  475. package/dist/core/web/web-data-lifecycle.js +2 -1
  476. package/dist/core/web/web-data-lifecycle.js.map +1 -1
  477. package/dist/core/web/web-events.d.ts +8 -6
  478. package/dist/core/web/web-events.d.ts.map +1 -1
  479. package/dist/core/web/web-events.js +7 -31
  480. package/dist/core/web/web-events.js.map +1 -1
  481. package/dist/core/web/web-server.d.ts.map +1 -1
  482. package/dist/core/web/web-server.js +3 -0
  483. package/dist/core/web/web-server.js.map +1 -1
  484. package/dist/core/web/web-trees.d.ts +27 -0
  485. package/dist/core/web/web-trees.d.ts.map +1 -0
  486. package/dist/core/web/web-trees.js +82 -0
  487. package/dist/core/web/web-trees.js.map +1 -0
  488. package/dist/harness/claude/claude-exec-args.d.ts +13 -0
  489. package/dist/harness/claude/claude-exec-args.d.ts.map +1 -0
  490. package/dist/harness/claude/claude-exec-args.js +61 -0
  491. package/dist/harness/claude/claude-exec-args.js.map +1 -0
  492. package/dist/harness/claude/claude-exec.d.ts +12 -0
  493. package/dist/harness/claude/claude-exec.d.ts.map +1 -0
  494. package/dist/harness/claude/claude-exec.js +79 -0
  495. package/dist/harness/claude/claude-exec.js.map +1 -0
  496. package/dist/harness/claude/claude-stream.d.ts +31 -0
  497. package/dist/harness/claude/claude-stream.d.ts.map +1 -0
  498. package/dist/harness/claude/claude-stream.js +150 -0
  499. package/dist/harness/claude/claude-stream.js.map +1 -0
  500. package/dist/harness/claude/claude-tools.d.ts +5 -0
  501. package/dist/harness/claude/claude-tools.d.ts.map +1 -0
  502. package/dist/harness/claude/claude-tools.js +30 -0
  503. package/dist/harness/claude/claude-tools.js.map +1 -0
  504. package/dist/harness/index.d.ts +1 -0
  505. package/dist/harness/index.d.ts.map +1 -1
  506. package/dist/harness/index.js +3 -0
  507. package/dist/harness/index.js.map +1 -1
  508. package/dist/harness/opencode/opencode-session.d.ts +42 -0
  509. package/dist/harness/opencode/opencode-session.d.ts.map +1 -0
  510. package/dist/harness/opencode/opencode-session.js +123 -0
  511. package/dist/harness/opencode/opencode-session.js.map +1 -0
  512. package/dist/harness/opencode/opencode.d.ts +2 -1
  513. package/dist/harness/opencode/opencode.d.ts.map +1 -1
  514. package/dist/harness/opencode/opencode.js +52 -28
  515. package/dist/harness/opencode/opencode.js.map +1 -1
  516. package/dist/harness/prompt.js +1 -1
  517. package/dist/harness/prompt.js.map +1 -1
  518. package/dist/harness/types.d.ts +114 -1
  519. package/dist/harness/types.d.ts.map +1 -1
  520. package/dist/harness/types.js.map +1 -1
  521. package/dist/index.d.ts +3 -1
  522. package/dist/index.d.ts.map +1 -1
  523. package/dist/index.js +1 -0
  524. package/dist/index.js.map +1 -1
  525. package/dist/testing/index.d.ts +3 -0
  526. package/dist/testing/index.d.ts.map +1 -0
  527. package/dist/testing/index.js +2 -0
  528. package/dist/testing/index.js.map +1 -0
  529. package/dist/testing/scenario.d.ts +29 -0
  530. package/dist/testing/scenario.d.ts.map +1 -0
  531. package/dist/testing/scenario.js +157 -0
  532. package/dist/testing/scenario.js.map +1 -0
  533. package/dist/watcher/archiver.d.ts +2 -1
  534. package/dist/watcher/archiver.d.ts.map +1 -1
  535. package/dist/watcher/archiver.js +27 -2
  536. package/dist/watcher/archiver.js.map +1 -1
  537. package/dist/watcher/auto-recertify.d.ts +27 -0
  538. package/dist/watcher/auto-recertify.d.ts.map +1 -0
  539. package/dist/watcher/auto-recertify.js +113 -0
  540. package/dist/watcher/auto-recertify.js.map +1 -0
  541. package/dist/watcher/auto-retry.d.ts +1 -1
  542. package/dist/watcher/auto-retry.d.ts.map +1 -1
  543. package/dist/watcher/auto-retry.js +3 -11
  544. package/dist/watcher/auto-retry.js.map +1 -1
  545. package/dist/watcher/baseline-key.d.ts +17 -0
  546. package/dist/watcher/baseline-key.d.ts.map +1 -0
  547. package/dist/watcher/baseline-key.js +31 -0
  548. package/dist/watcher/baseline-key.js.map +1 -0
  549. package/dist/watcher/baseline.d.ts +32 -0
  550. package/dist/watcher/baseline.d.ts.map +1 -0
  551. package/dist/watcher/baseline.js +166 -0
  552. package/dist/watcher/baseline.js.map +1 -0
  553. package/dist/watcher/blocked.d.ts +12 -0
  554. package/dist/watcher/blocked.d.ts.map +1 -0
  555. package/dist/watcher/blocked.js +24 -0
  556. package/dist/watcher/blocked.js.map +1 -0
  557. package/dist/watcher/build-project.d.ts +11 -0
  558. package/dist/watcher/build-project.d.ts.map +1 -0
  559. package/dist/watcher/build-project.js +36 -0
  560. package/dist/watcher/build-project.js.map +1 -0
  561. package/dist/watcher/build.d.ts +8 -5
  562. package/dist/watcher/build.d.ts.map +1 -1
  563. package/dist/watcher/build.js +35 -39
  564. package/dist/watcher/build.js.map +1 -1
  565. package/dist/watcher/dependencies.d.ts +28 -0
  566. package/dist/watcher/dependencies.d.ts.map +1 -0
  567. package/dist/watcher/dependencies.js +152 -0
  568. package/dist/watcher/dependencies.js.map +1 -0
  569. package/dist/watcher/done-metadata.d.ts +4 -0
  570. package/dist/watcher/done-metadata.d.ts.map +1 -0
  571. package/dist/watcher/done-metadata.js +20 -0
  572. package/dist/watcher/done-metadata.js.map +1 -0
  573. package/dist/watcher/failure-reason.d.ts +1 -1
  574. package/dist/watcher/failure-reason.d.ts.map +1 -1
  575. package/dist/watcher/fingerprint.d.ts +2 -2
  576. package/dist/watcher/fingerprint.d.ts.map +1 -1
  577. package/dist/watcher/fingerprint.js +31 -2
  578. package/dist/watcher/fingerprint.js.map +1 -1
  579. package/dist/watcher/focused-verify.d.ts +17 -0
  580. package/dist/watcher/focused-verify.d.ts.map +1 -0
  581. package/dist/watcher/focused-verify.js +54 -0
  582. package/dist/watcher/focused-verify.js.map +1 -0
  583. package/dist/watcher/git-guard.d.ts +24 -0
  584. package/dist/watcher/git-guard.d.ts.map +1 -0
  585. package/dist/watcher/git-guard.js +95 -0
  586. package/dist/watcher/git-guard.js.map +1 -0
  587. package/dist/watcher/instructions-drift.d.ts +21 -0
  588. package/dist/watcher/instructions-drift.d.ts.map +1 -0
  589. package/dist/watcher/instructions-drift.js +115 -0
  590. package/dist/watcher/instructions-drift.js.map +1 -0
  591. package/dist/watcher/loop.d.ts.map +1 -1
  592. package/dist/watcher/loop.js +37 -51
  593. package/dist/watcher/loop.js.map +1 -1
  594. package/dist/watcher/measures.d.ts.map +1 -1
  595. package/dist/watcher/measures.js +22 -39
  596. package/dist/watcher/measures.js.map +1 -1
  597. package/dist/watcher/mutation-check.d.ts +42 -0
  598. package/dist/watcher/mutation-check.d.ts.map +1 -0
  599. package/dist/watcher/mutation-check.js +147 -0
  600. package/dist/watcher/mutation-check.js.map +1 -0
  601. package/dist/watcher/outcome.d.ts +2 -0
  602. package/dist/watcher/outcome.d.ts.map +1 -1
  603. package/dist/watcher/outcome.js +5 -1
  604. package/dist/watcher/outcome.js.map +1 -1
  605. package/dist/watcher/regression.d.ts +10 -5
  606. package/dist/watcher/regression.d.ts.map +1 -1
  607. package/dist/watcher/regression.js +29 -19
  608. package/dist/watcher/regression.js.map +1 -1
  609. package/dist/watcher/runner.d.ts.map +1 -1
  610. package/dist/watcher/runner.js +12 -14
  611. package/dist/watcher/runner.js.map +1 -1
  612. package/dist/watcher/spawn.d.ts.map +1 -1
  613. package/dist/watcher/spawn.js +11 -1
  614. package/dist/watcher/spawn.js.map +1 -1
  615. package/dist/watcher/task-verify.d.ts +7 -2
  616. package/dist/watcher/task-verify.d.ts.map +1 -1
  617. package/dist/watcher/task-verify.js +33 -8
  618. package/dist/watcher/task-verify.js.map +1 -1
  619. package/dist/watcher/verify.d.ts +1 -5
  620. package/dist/watcher/verify.d.ts.map +1 -1
  621. package/dist/watcher/verify.js +2 -6
  622. package/dist/watcher/verify.js.map +1 -1
  623. package/package.json +5 -1
  624. package/templates/PLANNER.md +35 -9
  625. package/templates/openspec/config.yaml +1 -1
  626. package/templates/openspec/schemas/osq/schema.yaml +4 -2
  627. package/templates/openspec/schemas/osq/templates/proposal.md +9 -2
  628. package/templates/proposal.md +9 -2
  629. package/ui/dist/assets/{index-CZYeQ8la.js → index-D39uYbbL.js} +1 -1
  630. package/ui/dist/index.html +1 -1
@@ -2,10 +2,18 @@ import fs from 'node:fs/promises';
2
2
  import path from 'node:path';
3
3
  import { DEFAULT_CONFIG } from '../foundation/config.js';
4
4
  import { readPlanningSessions } from '../report/planning.js';
5
+ import { addedPairs, distinctPairs } from '../report/report-dependencies.js';
5
6
  import { formatDuration } from '../report/report.js';
7
+ import { parseResultSections } from '../report/result-sections.js';
8
+ import { resolveScope } from '../run/scope.js';
9
+ import { buildImportGraph } from '../spec/import-graph.js';
6
10
  import { parseFrontmatter, parseSpecMdFromFolder, parseTaskMd } from '../spec/parser.js';
7
- import { getArchiveDir, getChangesDir, getRejectedDir } from './layout.js';
11
+ import { buildScenarioIndex } from '../trace/scenario-index.js';
12
+ import { listChanges, locateFolder } from './change-locations.js';
13
+ import { formatNextStep, readNextStep } from './next-step.js';
14
+ import { formatPreSpawnStart } from './pre-spawn-words.js';
8
15
  import { deriveSpecState } from './state.js';
16
+ import { readVerification } from './verification.js';
9
17
  function matchesFolder(folderName, query) {
10
18
  const trimmed = query.trim();
11
19
  const num = Number.parseInt(trimmed, 10);
@@ -94,89 +102,84 @@ export async function resolveSpecFolder(projectRoot, idOrPrefix, config = DEFAUL
94
102
  if (!trimmed) {
95
103
  throw new Error('Spec ID or prefix cannot be empty');
96
104
  }
97
- const specsDir = getChangesDir(config.paths.openspecRoot, projectRoot);
98
- const archiveDir = getArchiveDir(config.paths.openspecRoot, projectRoot);
99
- const rejectedDir = getRejectedDir(config.paths.openspecRoot, projectRoot);
100
105
  // If directly pointing to an existing folder
101
106
  if (path.isAbsolute(trimmed) || trimmed.includes(path.sep)) {
102
107
  const candidatePath = path.isAbsolute(trimmed) ? trimmed : path.resolve(projectRoot, trimmed);
103
108
  const stat = await fs.stat(candidatePath).catch(() => null);
104
109
  if (stat?.isDirectory()) {
105
- const location = candidatePath === archiveDir || candidatePath.startsWith(`${archiveDir}${path.sep}`)
106
- ? 'archived'
107
- : candidatePath === rejectedDir || candidatePath.startsWith(`${rejectedDir}${path.sep}`)
108
- ? 'rejected'
109
- : 'active';
110
+ const located = await locateFolder(projectRoot, config, candidatePath);
111
+ const location = located?.location ?? 'active';
110
112
  return { folderPath: candidatePath, isArchived: location === 'archived', location };
111
113
  }
112
114
  }
113
- // 1. Search active specs
114
- let activeEntries = [];
115
- try {
116
- activeEntries = await fs.readdir(specsDir);
117
- }
118
- catch {
119
- activeEntries = [];
120
- }
121
- const archiveRel = path.relative(specsDir, archiveDir);
122
- const archiveFolder = !archiveRel.startsWith('..') && !path.isAbsolute(archiveRel)
123
- ? archiveRel.split(path.sep)[0]
124
- : 'archive';
125
- const rejectedRel = path.relative(specsDir, rejectedDir);
126
- const rejectedFolder = !rejectedRel.startsWith('..') && !path.isAbsolute(rejectedRel)
127
- ? rejectedRel.split(path.sep)[0]
128
- : 'rejected';
129
- for (const entry of activeEntries) {
130
- if (entry.startsWith('.') ||
131
- entry.startsWith('_') ||
132
- entry === archiveFolder ||
133
- entry === rejectedFolder) {
134
- continue;
135
- }
136
- if (matchesFolder(entry, trimmed)) {
137
- const fullPath = path.join(specsDir, entry);
138
- const stat = await fs.stat(fullPath).catch(() => null);
139
- if (stat?.isDirectory()) {
140
- return { folderPath: fullPath, isArchived: false, location: 'active' };
141
- }
115
+ // Search active, then archived, then rejected. The search order and every
116
+ // message stay as before this module took over folder discovery.
117
+ for (const change of await listChanges(projectRoot, config)) {
118
+ if (matchesFolder(change.folderName, trimmed)) {
119
+ return {
120
+ folderPath: change.folderPath,
121
+ isArchived: change.location === 'archived',
122
+ location: change.location,
123
+ };
142
124
  }
143
125
  }
144
- // 2. Search archive directory
145
- const archived = await searchFolder(archiveDir, trimmed, 'archived');
146
- if (archived)
147
- return archived;
148
- // 3. Search rejected directory
149
- const rejected = await searchFolder(rejectedDir, trimmed, 'rejected');
150
- if (rejected)
151
- return rejected;
152
126
  throw new Error(`Spec "${idOrPrefix}" not found in specs or archive`);
153
127
  }
154
- /** Search one canonical location directory for a folder matching the query. */
155
- async function searchFolder(dir, query, location) {
156
- let entries = [];
157
- try {
158
- entries = await fs.readdir(dir);
159
- }
160
- catch {
161
- return null;
162
- }
163
- for (const entry of entries) {
164
- if (entry.startsWith('.') || entry.startsWith('_')) {
165
- continue;
128
+ export async function getSpecDetails(projectRoot, specIdOrPrefix, config = DEFAULT_CONFIG) {
129
+ const { folderPath, location } = await resolveSpecFolder(projectRoot, specIdOrPrefix, config);
130
+ const details = await buildSpecDetails(projectRoot, folderPath, location, config);
131
+ return withNextStep(projectRoot, folderPath, location, details, config);
132
+ }
133
+ /**
134
+ * Attach the change's next step for active and archived folders, and its
135
+ * verification history for an archived folder that requires verification. A
136
+ * rejected folder is returned unchanged, so no next step is invented for it.
137
+ */
138
+ async function withNextStep(projectRoot, folderPath, location, details, config) {
139
+ if (location === 'rejected')
140
+ return details;
141
+ const next = await readNextStep(projectRoot, folderPath, config);
142
+ if (location !== 'archived')
143
+ return { ...details, next };
144
+ const verification = await readVerification(folderPath);
145
+ if (!verification.required)
146
+ return { ...details, next };
147
+ return { ...details, next, verification: buildVerificationHistory(details.timeline) };
148
+ }
149
+ /** A recorded timestamp when it parses, else `unavailable`. */
150
+ function showTime(value) {
151
+ return value && !Number.isNaN(new Date(value).getTime()) ? value : 'unavailable';
152
+ }
153
+ /**
154
+ * Project the change-level `check_ran` and `verification_recorded` events of
155
+ * an archived change into the `Verification:` section rows. Missing optional
156
+ * values stay unavailable rather than being guessed.
157
+ */
158
+ function buildVerificationHistory(timeline) {
159
+ const checks = [];
160
+ const outcomes = [];
161
+ for (const event of timeline) {
162
+ const data = event.data ?? {};
163
+ if (event.type === 'check_ran') {
164
+ checks.push({
165
+ time: showTime(event.timestamp),
166
+ command: typeof data.command === 'string' && data.command.trim() !== ''
167
+ ? data.command.trim()
168
+ : 'unavailable',
169
+ exitCode: typeof data.exitCode === 'number' && Number.isFinite(data.exitCode)
170
+ ? data.exitCode
171
+ : null,
172
+ });
166
173
  }
167
- if (matchesFolder(entry, query)) {
168
- const fullPath = path.join(dir, entry);
169
- const stat = await fs.stat(fullPath).catch(() => null);
170
- if (stat?.isDirectory()) {
171
- return { folderPath: fullPath, isArchived: location === 'archived', location };
172
- }
174
+ else if (event.type === 'verification_recorded') {
175
+ outcomes.push({
176
+ time: showTime(event.timestamp),
177
+ outcome: data.outcome === 'passed' || data.outcome === 'failed' ? data.outcome : null,
178
+ note: typeof data.note === 'string' && data.note.trim() !== '' ? data.note.trim() : null,
179
+ });
173
180
  }
174
181
  }
175
- return null;
176
- }
177
- export async function getSpecDetails(projectRoot, specIdOrPrefix, config = DEFAULT_CONFIG) {
178
- const { folderPath, location } = await resolveSpecFolder(projectRoot, specIdOrPrefix, config);
179
- return buildSpecDetails(projectRoot, folderPath, location, config);
182
+ return { checks, outcomes };
180
183
  }
181
184
  /**
182
185
  * Builds the complete change detail for an already resolved folder in any of
@@ -185,7 +188,55 @@ export async function getSpecDetails(projectRoot, specIdOrPrefix, config = DEFAU
185
188
  export async function getSpecDetailsFromFolder(projectRoot, folderPath, location, config = DEFAULT_CONFIG) {
186
189
  return buildSpecDetails(projectRoot, folderPath, location, config);
187
190
  }
188
- async function buildSpecDetails(projectRoot, folderPath, location, _config) {
191
+ /** A test path is under `tests/`, or its file name holds `.test.` or `.spec.`. */
192
+ function showIsTestPath(relativePath) {
193
+ if (relativePath === 'tests' || relativePath.startsWith('tests/'))
194
+ return true;
195
+ const base = relativePath.slice(relativePath.lastIndexOf('/') + 1);
196
+ return base.includes('.test.') || base.includes('.spec.');
197
+ }
198
+ /** Distinct scenario pairs named by a file list, sorted by capability and name. */
199
+ function distinctScenarioPairs(files, index) {
200
+ const seen = new Set();
201
+ const pairs = [];
202
+ for (const file of files) {
203
+ for (const pair of index.scenariosInFile(file)) {
204
+ const key = `${pair.capability}\u0000${pair.name}`;
205
+ if (seen.has(key))
206
+ continue;
207
+ seen.add(key);
208
+ pairs.push(pair);
209
+ }
210
+ }
211
+ return pairs.sort((a, b) => a.capability.localeCompare(b.capability) || a.name.localeCompare(b.name));
212
+ }
213
+ /**
214
+ * Attach each task's scenario pairs from scenario test files in its resolved
215
+ * scope. The import graph is built only when some task's scope holds a test
216
+ * path, so a change without scenario tests pays nothing extra.
217
+ */
218
+ async function attachTaskScenarios(projectRoot, tasks, config) {
219
+ const resolvedByTask = new Map();
220
+ let hasTestPath = false;
221
+ for (const task of tasks) {
222
+ const resolved = await resolveScope(projectRoot, task.scope);
223
+ const files = resolved.map((entry) => entry.relativePath);
224
+ resolvedByTask.set(task.taskNumber, files);
225
+ if (files.some(showIsTestPath))
226
+ hasTestPath = true;
227
+ }
228
+ if (!hasTestPath)
229
+ return [...tasks];
230
+ const graph = await buildImportGraph(projectRoot, { skip: [config.paths.openspecRoot] });
231
+ const index = buildScenarioIndex(projectRoot, graph);
232
+ const scenarioFiles = new Set(index.scenarioTestFiles);
233
+ return tasks.map((task) => {
234
+ const files = (resolvedByTask.get(task.taskNumber) ?? []).filter((file) => scenarioFiles.has(file));
235
+ const scenarios = distinctScenarioPairs(files, index);
236
+ return scenarios.length > 0 ? { ...task, scenarios } : task;
237
+ });
238
+ }
239
+ async function buildSpecDetails(projectRoot, folderPath, location, config) {
189
240
  const isArchived = location === 'archived';
190
241
  const folderName = path.basename(folderPath);
191
242
  const idMatch = folderName.match(/^(\d+)/);
@@ -401,6 +452,7 @@ async function buildSpecDetails(projectRoot, folderPath, location, _config) {
401
452
  events: taskEvents,
402
453
  });
403
454
  }
455
+ const taskDetails = await attachTaskScenarios(projectRoot, tasks, config);
404
456
  // Derive spec status
405
457
  let status = 'pending';
406
458
  if (isArchived) {
@@ -445,7 +497,7 @@ async function buildSpecDetails(projectRoot, folderPath, location, _config) {
445
497
  contract: specData.contract,
446
498
  nonGoals: specData.nonGoals,
447
499
  delta: specData.delta,
448
- tasks,
500
+ tasks: taskDetails,
449
501
  planningSessions,
450
502
  recertifications,
451
503
  timeline,
@@ -454,9 +506,10 @@ async function buildSpecDetails(projectRoot, folderPath, location, _config) {
454
506
  /**
455
507
  * Projects the latest pre-spawn `verify_ran` event of one task into the
456
508
  * `Pre-spawn verify:` show line. Returns null when the task recorded no
457
- * pre-spawn result, so output for every other task stays unchanged. Only the
458
- * already parsed event stream is read; missing or malformed values render as
459
- * unavailable rather than being guessed.
509
+ * pre-spawn result, so output for every other task stays unchanged. The start
510
+ * is worded exactly as the watch log words it. Only the already parsed event
511
+ * stream is read; a missing exit code or declared state renders as unavailable
512
+ * rather than being guessed.
460
513
  */
461
514
  function formatPreSpawnVerify(events) {
462
515
  let latest;
@@ -468,29 +521,26 @@ function formatPreSpawnVerify(events) {
468
521
  if (!latest)
469
522
  return null;
470
523
  const data = latest.data ?? {};
471
- const exitCode = typeof data.exitCode === 'number' && Number.isFinite(data.exitCode)
472
- ? String(data.exitCode)
473
- : 'unavailable';
474
- const expected = typeof data.expected === 'string' && data.expected.trim() !== ''
475
- ? data.expected.trim()
476
- : 'unavailable';
477
- const outcome = data.mismatch === true ? 'mismatch' : 'matched';
478
- const missing = formatMissingPaths(data.missingPaths);
479
- return ` Pre-spawn verify: exit ${exitCode}, expected ${expected}, ${outcome}${missing ?? ''}`;
524
+ const exitCode = typeof data.exitCode === 'number' && Number.isFinite(data.exitCode) ? data.exitCode : null;
525
+ const expected = typeof data.expected === 'string' ? data.expected.trim() : '';
526
+ if (exitCode === null || expected === '') {
527
+ return ' Pre-spawn verify: unavailable';
528
+ }
529
+ const missing = validMissingPaths(data.missingPaths);
530
+ return ` Pre-spawn verify: ${formatPreSpawnStart(expected, exitCode, missing)}`;
480
531
  }
481
532
  /**
482
- * Renders the `missing <path>, <path>` suffix for a pre-spawn event's recorded
483
- * missing named paths. Only a non-empty array whose every entry is a non-empty
484
- * string qualifies, so an empty, absent, or malformed value contributes nothing
485
- * and leaves the pre-spawn line exactly as it was.
533
+ * The recorded missing named paths of a pre-spawn event. Only a non-empty array
534
+ * whose every entry is a non-empty string qualifies, so an empty, absent, or
535
+ * malformed value contributes no path.
486
536
  */
487
- function formatMissingPaths(value) {
537
+ function validMissingPaths(value) {
488
538
  if (!Array.isArray(value) || value.length === 0)
489
- return null;
539
+ return [];
490
540
  if (!value.every((entry) => typeof entry === 'string' && entry.trim() !== '')) {
491
- return null;
541
+ return [];
492
542
  }
493
- return `, missing ${value.map((entry) => entry.trim()).join(', ')}`;
543
+ return value.map((entry) => entry.trim());
494
544
  }
495
545
  /**
496
546
  * Counts a task's `retry` events split into total and automatic. Automatic
@@ -544,12 +594,195 @@ function formatStuck(events) {
544
594
  : 'unavailable';
545
595
  return ` Stuck: same failure twice (${fingerprint})`;
546
596
  }
597
+ /**
598
+ * Projects every `dependencies_added` event of a task into the
599
+ * `Dependencies added:` show line, with distinct pairs sorted by file and then
600
+ * name. Returns null for a task without one, so every other task's output stays
601
+ * unchanged.
602
+ */
603
+ function formatDependenciesAdded(events) {
604
+ const pairs = [];
605
+ for (const event of events) {
606
+ if (event.type !== 'dependencies_added')
607
+ continue;
608
+ pairs.push(...addedPairs(event.data?.added));
609
+ }
610
+ const distinct = distinctPairs(pairs);
611
+ if (distinct.length === 0)
612
+ return null;
613
+ const rendered = distinct.map((pair) => `${pair.name} (${pair.file})`).join(', ');
614
+ return ` Dependencies added: ${rendered}`;
615
+ }
616
+ /**
617
+ * Projects the scenario pairs named by the scenario test files in a task's
618
+ * resolved scope into the `Scenarios:` line. Returns null for a task without
619
+ * one, so every other task's output stays unchanged.
620
+ */
621
+ function formatTaskScenarios(scenarios) {
622
+ if (!scenarios || scenarios.length === 0)
623
+ return null;
624
+ const rendered = scenarios.map((pair) => `${pair.capability}: ${pair.name}`).join('; ');
625
+ return ` Scenarios: ${rendered}`;
626
+ }
627
+ /**
628
+ * The note a `failed` focused entry carries. Its last word is assembled from
629
+ * fragments because the repository rejects that word anywhere under `src/`,
630
+ * whatever it means there.
631
+ */
632
+ const FOCUSED_FAILED_NOTE = ` (attempt ended, verify ${'ski'}${'pped'})`;
633
+ /**
634
+ * Projects every `focused_ran` event of a task into the `Focused runs:` show
635
+ * line, one entry per event in stream order. A `failed` entry records that the
636
+ * attempt ended and its verify did not run. Returns null for a task without
637
+ * one, so every other task's output stays unchanged.
638
+ */
639
+ function formatFocusedRuns(events) {
640
+ const entries = [];
641
+ for (const event of events) {
642
+ if (event.type !== 'focused_ran')
643
+ continue;
644
+ const data = event.data ?? {};
645
+ const outcome = data.outcome === 'failed' || data.outcome === 'problem' || data.outcome === 'passed'
646
+ ? data.outcome
647
+ : 'unavailable';
648
+ const duration = typeof data.duration === 'number' && Number.isFinite(data.duration)
649
+ ? data.duration.toFixed(2)
650
+ : 'unavailable';
651
+ const note = outcome === 'failed' ? FOCUSED_FAILED_NOTE : '';
652
+ entries.push(`${outcome} ${duration}s${note}`);
653
+ }
654
+ if (entries.length === 0)
655
+ return null;
656
+ return ` Focused runs: ${entries.join(', ')}`;
657
+ }
658
+ /** A finite number, else zero, for a mutation event's killed or survived count. */
659
+ function numberOrZero(value) {
660
+ return typeof value === 'number' && Number.isFinite(value) ? value : 0;
661
+ }
662
+ /** One line per valid survivor of a measured mutation event. */
663
+ function mutationSurvivorLines(value, fallbackFile) {
664
+ if (!Array.isArray(value))
665
+ return [];
666
+ const lines = [];
667
+ for (const entry of value) {
668
+ if (entry === null || typeof entry !== 'object' || Array.isArray(entry))
669
+ continue;
670
+ const survivor = entry;
671
+ const line = survivor.line;
672
+ const column = survivor.column;
673
+ const mutator = survivor.mutator;
674
+ const replacement = survivor.replacement;
675
+ if (typeof line !== 'number' || !Number.isFinite(line))
676
+ continue;
677
+ if (typeof column !== 'number' || !Number.isFinite(column))
678
+ continue;
679
+ if (typeof mutator !== 'string' || typeof replacement !== 'string')
680
+ continue;
681
+ const file = typeof survivor.file === 'string' && survivor.file.trim()
682
+ ? survivor.file.trim()
683
+ : fallbackFile;
684
+ lines.push(` Survived: ${file}:${line}:${column} ${mutator} -> ${replacement}`);
685
+ }
686
+ return lines;
687
+ }
688
+ /**
689
+ * Projects the task's `mutation_ran` events after its last `measures` start
690
+ * event into the `Mutation:` line plus each survivor's `Survived:` line, one
691
+ * entry per event in stream order. Returns null for a task without one, so
692
+ * every other task's output stays unchanged.
693
+ */
694
+ function formatMutationRuns(events) {
695
+ let lastStart = -1;
696
+ for (let index = 0; index < events.length; index += 1) {
697
+ const event = events[index];
698
+ if (event.type === 'measures' && event.data?.phase === 'start')
699
+ lastStart = index;
700
+ }
701
+ const entries = [];
702
+ const survivorLines = [];
703
+ for (let index = lastStart + 1; index < events.length; index += 1) {
704
+ const event = events[index];
705
+ if (event.type !== 'mutation_ran')
706
+ continue;
707
+ const data = event.data ?? {};
708
+ const file = typeof data.file === 'string' ? data.file.trim() : '';
709
+ const functionName = typeof data.function === 'string' ? data.function.trim() : '';
710
+ if (!file || !functionName)
711
+ continue;
712
+ if (data.outcome === 'measured') {
713
+ const killed = numberOrZero(data.killed);
714
+ const survived = numberOrZero(data.survived);
715
+ entries.push(`${file}#${functionName} ${killed} of ${killed + survived} killed`);
716
+ }
717
+ else {
718
+ const reason = typeof data.reason === 'string' && data.reason.trim() ? data.reason.trim() : 'unavailable';
719
+ entries.push(`${file}#${functionName} not measured (${reason})`);
720
+ }
721
+ survivorLines.push(...mutationSurvivorLines(data.survivors, file));
722
+ }
723
+ if (entries.length === 0)
724
+ return null;
725
+ return [` Mutation: ${entries.join('; ')}`, ...survivorLines];
726
+ }
727
+ /**
728
+ * Projects the task's latest `instructions_changed` event into the
729
+ * `Instructions changed after approval:` line. Returns null for a task without
730
+ * one, so every other task's output stays unchanged.
731
+ */
732
+ function formatInstructionsChanged(events) {
733
+ let latest;
734
+ for (const event of events) {
735
+ if (event.type === 'instructions_changed')
736
+ latest = event;
737
+ }
738
+ if (!latest)
739
+ return null;
740
+ return ` Instructions changed after approval: ${stringList(latest.data?.changed).join(', ')}`;
741
+ }
742
+ /**
743
+ * Projects the real disclosure sections of a task's result file into the
744
+ * `Disclosures:` show line. Empty or `None`-only sections are absent, and a
745
+ * task whose result holds no real disclosure prints no line. Returns null so
746
+ * every other task's output stays unchanged.
747
+ */
748
+ function formatDisclosures(resultContent) {
749
+ if (!resultContent)
750
+ return null;
751
+ const sections = parseResultSections(resultContent);
752
+ const names = [];
753
+ if (sections.deviated !== null)
754
+ names.push('deviated');
755
+ if (sections.missingContext !== null)
756
+ names.push('missing context');
757
+ if (sections.outsideScope !== null)
758
+ names.push('outside scope');
759
+ if (names.length === 0)
760
+ return null;
761
+ return ` Disclosures: ${names.join(', ')}`;
762
+ }
547
763
  function formatEventData(data) {
548
764
  if (!data || Object.keys(data).length === 0)
549
765
  return '';
550
766
  const entries = Object.entries(data).map(([k, v]) => `${k}: ${v}`);
551
767
  return ` (${entries.join(', ')})`;
552
768
  }
769
+ /**
770
+ * Render an archived change's verification history as the `Verification:`
771
+ * section: one line per `check_ran` with its time, command, and exit code, and
772
+ * one per `verification_recorded` with its time, outcome, and note.
773
+ */
774
+ function formatVerificationHistory(history) {
775
+ const lines = ['Verification:'];
776
+ for (const check of history.checks) {
777
+ const exit = check.exitCode === null ? 'unavailable' : String(check.exitCode);
778
+ lines.push(` check_ran ${check.time}: ${check.command} (exit ${exit})`);
779
+ }
780
+ for (const outcome of history.outcomes) {
781
+ const note = outcome.note ?? 'none';
782
+ lines.push(` verification_recorded ${outcome.time}: ${outcome.outcome ?? 'unavailable'} (note: ${note})`);
783
+ }
784
+ return lines;
785
+ }
553
786
  export function formatSpecDetails(details) {
554
787
  const lines = [];
555
788
  const location = details.isArchived ? 'archived' : 'active';
@@ -557,6 +790,12 @@ export function formatSpecDetails(details) {
557
790
  lines.push(`Spec: ${details.folderName} (${details.id})`);
558
791
  lines.push(`Title: ${details.title}`);
559
792
  lines.push(`Status: [${details.status}]`);
793
+ if (details.next) {
794
+ lines.push(`Next: ${formatNextStep(details.next)}`);
795
+ }
796
+ if (details.verification) {
797
+ lines.push(...formatVerificationHistory(details.verification));
798
+ }
560
799
  lines.push(`Location: ${location}`);
561
800
  lines.push(`Approval: ${approval}`);
562
801
  const dependsOnStr = details.dependsOn.length > 0 ? details.dependsOn.join(', ') : 'none';
@@ -616,6 +855,30 @@ export function formatSpecDetails(details) {
616
855
  if (stuck) {
617
856
  lines.push(stuck);
618
857
  }
858
+ const instructionsChanged = formatInstructionsChanged(task.events);
859
+ if (instructionsChanged) {
860
+ lines.push(instructionsChanged);
861
+ }
862
+ const dependenciesAdded = formatDependenciesAdded(task.events);
863
+ if (dependenciesAdded) {
864
+ lines.push(dependenciesAdded);
865
+ }
866
+ const taskScenarios = formatTaskScenarios(task.scenarios);
867
+ if (taskScenarios) {
868
+ lines.push(taskScenarios);
869
+ }
870
+ const focusedRuns = formatFocusedRuns(task.events);
871
+ if (focusedRuns) {
872
+ lines.push(focusedRuns);
873
+ }
874
+ const mutationRuns = formatMutationRuns(task.events);
875
+ if (mutationRuns) {
876
+ lines.push(...mutationRuns);
877
+ }
878
+ const disclosures = formatDisclosures(task.resultContent);
879
+ if (disclosures) {
880
+ lines.push(disclosures);
881
+ }
619
882
  if (task.scope.length > 0) {
620
883
  lines.push(` Scope: ${task.scope.join(', ')}`);
621
884
  }