openspecui 0.0.0

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 (311) hide show
  1. package/.gitmodules +3 -0
  2. package/CHAT.md +3 -0
  3. package/package.json +12 -0
  4. package/references/openspec/.changeset/README.md +6 -0
  5. package/references/openspec/.changeset/config.json +12 -0
  6. package/references/openspec/.coderabbit.yaml +11 -0
  7. package/references/openspec/.devcontainer/README.md +92 -0
  8. package/references/openspec/.devcontainer/devcontainer.json +68 -0
  9. package/references/openspec/.github/CODEOWNERS +2 -0
  10. package/references/openspec/.github/workflows/ci.yml +222 -0
  11. package/references/openspec/.github/workflows/release-prepare.yml +50 -0
  12. package/references/openspec/AGENTS.md +18 -0
  13. package/references/openspec/CHANGELOG.md +205 -0
  14. package/references/openspec/LICENSE +22 -0
  15. package/references/openspec/README.md +374 -0
  16. package/references/openspec/assets/openspec_dashboard.png +0 -0
  17. package/references/openspec/assets/openspec_pixel_dark.svg +89 -0
  18. package/references/openspec/assets/openspec_pixel_light.svg +89 -0
  19. package/references/openspec/bin/openspec.js +3 -0
  20. package/references/openspec/build.js +31 -0
  21. package/references/openspec/openspec/AGENTS.md +454 -0
  22. package/references/openspec/openspec/changes/IMPLEMENTATION_ORDER.md +68 -0
  23. package/references/openspec/openspec/changes/add-antigravity-support/proposal.md +11 -0
  24. package/references/openspec/openspec/changes/add-antigravity-support/specs/cli-init/spec.md +9 -0
  25. package/references/openspec/openspec/changes/add-antigravity-support/specs/cli-update/spec.md +8 -0
  26. package/references/openspec/openspec/changes/add-antigravity-support/tasks.md +12 -0
  27. package/references/openspec/openspec/changes/add-scaffold-command/proposal.md +11 -0
  28. package/references/openspec/openspec/changes/add-scaffold-command/specs/cli-scaffold/spec.md +36 -0
  29. package/references/openspec/openspec/changes/add-scaffold-command/tasks.md +12 -0
  30. package/references/openspec/openspec/changes/archive/2025-01-11-add-update-command/design.md +86 -0
  31. package/references/openspec/openspec/changes/archive/2025-01-11-add-update-command/proposal.md +29 -0
  32. package/references/openspec/openspec/changes/archive/2025-01-11-add-update-command/specs/cli-update/spec.md +59 -0
  33. package/references/openspec/openspec/changes/archive/2025-01-11-add-update-command/tasks.md +20 -0
  34. package/references/openspec/openspec/changes/archive/2025-01-13-add-list-command/proposal.md +20 -0
  35. package/references/openspec/openspec/changes/archive/2025-01-13-add-list-command/specs/cli-list/spec.md +69 -0
  36. package/references/openspec/openspec/changes/archive/2025-01-13-add-list-command/tasks.md +26 -0
  37. package/references/openspec/openspec/changes/archive/2025-08-05-initialize-typescript-project/design.md +64 -0
  38. package/references/openspec/openspec/changes/archive/2025-08-05-initialize-typescript-project/proposal.md +18 -0
  39. package/references/openspec/openspec/changes/archive/2025-08-05-initialize-typescript-project/tasks.md +25 -0
  40. package/references/openspec/openspec/changes/archive/2025-08-06-add-init-command/design.md +104 -0
  41. package/references/openspec/openspec/changes/archive/2025-08-06-add-init-command/proposal.md +30 -0
  42. package/references/openspec/openspec/changes/archive/2025-08-06-add-init-command/specs/cli-init/spec.md +148 -0
  43. package/references/openspec/openspec/changes/archive/2025-08-06-add-init-command/tasks.md +38 -0
  44. package/references/openspec/openspec/changes/archive/2025-08-06-adopt-future-state-storage/proposal.md +24 -0
  45. package/references/openspec/openspec/changes/archive/2025-08-06-adopt-future-state-storage/specs/openspec-conventions/spec.md +120 -0
  46. package/references/openspec/openspec/changes/archive/2025-08-06-adopt-future-state-storage/tasks.md +38 -0
  47. package/references/openspec/openspec/changes/archive/2025-08-11-add-complexity-guidelines/proposal.md +13 -0
  48. package/references/openspec/openspec/changes/archive/2025-08-11-add-complexity-guidelines/specs/openspec-docs/README.md +472 -0
  49. package/references/openspec/openspec/changes/archive/2025-08-11-add-complexity-guidelines/tasks.md +9 -0
  50. package/references/openspec/openspec/changes/archive/2025-08-13-add-archive-command/proposal.md +15 -0
  51. package/references/openspec/openspec/changes/archive/2025-08-13-add-archive-command/specs/cli-archive/spec.md +111 -0
  52. package/references/openspec/openspec/changes/archive/2025-08-13-add-archive-command/tasks.md +44 -0
  53. package/references/openspec/openspec/changes/archive/2025-08-13-add-diff-command/proposal.md +19 -0
  54. package/references/openspec/openspec/changes/archive/2025-08-13-add-diff-command/specs/cli-diff/spec.md +77 -0
  55. package/references/openspec/openspec/changes/archive/2025-08-13-add-diff-command/tasks.md +23 -0
  56. package/references/openspec/openspec/changes/archive/2025-08-19-add-change-commands/design.md +56 -0
  57. package/references/openspec/openspec/changes/archive/2025-08-19-add-change-commands/proposal.md +17 -0
  58. package/references/openspec/openspec/changes/archive/2025-08-19-add-change-commands/specs/cli-change/spec.md +48 -0
  59. package/references/openspec/openspec/changes/archive/2025-08-19-add-change-commands/specs/cli-list/spec.md +12 -0
  60. package/references/openspec/openspec/changes/archive/2025-08-19-add-change-commands/tasks.md +34 -0
  61. package/references/openspec/openspec/changes/archive/2025-08-19-add-interactive-show-command/proposal.md +20 -0
  62. package/references/openspec/openspec/changes/archive/2025-08-19-add-interactive-show-command/specs/cli-change/spec.md +23 -0
  63. package/references/openspec/openspec/changes/archive/2025-08-19-add-interactive-show-command/specs/cli-show/spec.md +83 -0
  64. package/references/openspec/openspec/changes/archive/2025-08-19-add-interactive-show-command/specs/cli-spec/spec.md +23 -0
  65. package/references/openspec/openspec/changes/archive/2025-08-19-add-interactive-show-command/tasks.md +142 -0
  66. package/references/openspec/openspec/changes/archive/2025-08-19-add-skip-specs-archive-option/proposal.md +13 -0
  67. package/references/openspec/openspec/changes/archive/2025-08-19-add-skip-specs-archive-option/specs/cli-archive/spec.md +191 -0
  68. package/references/openspec/openspec/changes/archive/2025-08-19-add-skip-specs-archive-option/tasks.md +57 -0
  69. package/references/openspec/openspec/changes/archive/2025-08-19-add-spec-commands/design.md +45 -0
  70. package/references/openspec/openspec/changes/archive/2025-08-19-add-spec-commands/proposal.md +19 -0
  71. package/references/openspec/openspec/changes/archive/2025-08-19-add-spec-commands/specs/cli-spec/spec.md +43 -0
  72. package/references/openspec/openspec/changes/archive/2025-08-19-add-spec-commands/tasks.md +22 -0
  73. package/references/openspec/openspec/changes/archive/2025-08-19-add-zod-validation/design.md +104 -0
  74. package/references/openspec/openspec/changes/archive/2025-08-19-add-zod-validation/proposal.md +22 -0
  75. package/references/openspec/openspec/changes/archive/2025-08-19-add-zod-validation/specs/cli-archive/spec.md +18 -0
  76. package/references/openspec/openspec/changes/archive/2025-08-19-add-zod-validation/specs/cli-diff/spec.md +12 -0
  77. package/references/openspec/openspec/changes/archive/2025-08-19-add-zod-validation/tasks.md +59 -0
  78. package/references/openspec/openspec/changes/archive/2025-08-19-adopt-delta-based-changes/proposal.md +93 -0
  79. package/references/openspec/openspec/changes/archive/2025-08-19-adopt-delta-based-changes/specs/cli-archive/spec.md +48 -0
  80. package/references/openspec/openspec/changes/archive/2025-08-19-adopt-delta-based-changes/specs/cli-diff/spec.md +45 -0
  81. package/references/openspec/openspec/changes/archive/2025-08-19-adopt-delta-based-changes/specs/openspec-conventions/spec.md +101 -0
  82. package/references/openspec/openspec/changes/archive/2025-08-19-adopt-delta-based-changes/tasks.md +55 -0
  83. package/references/openspec/openspec/changes/archive/2025-08-19-adopt-verb-noun-cli-structure/design.md +19 -0
  84. package/references/openspec/openspec/changes/archive/2025-08-19-adopt-verb-noun-cli-structure/proposal.md +67 -0
  85. package/references/openspec/openspec/changes/archive/2025-08-19-adopt-verb-noun-cli-structure/specs/cli-list/spec.md +57 -0
  86. package/references/openspec/openspec/changes/archive/2025-08-19-adopt-verb-noun-cli-structure/specs/openspec-conventions/spec.md +23 -0
  87. package/references/openspec/openspec/changes/archive/2025-08-19-adopt-verb-noun-cli-structure/tasks.md +27 -0
  88. package/references/openspec/openspec/changes/archive/2025-08-19-bulk-validation-interactive-selection/proposal.md +20 -0
  89. package/references/openspec/openspec/changes/archive/2025-08-19-bulk-validation-interactive-selection/specs/cli-change/spec.md +22 -0
  90. package/references/openspec/openspec/changes/archive/2025-08-19-bulk-validation-interactive-selection/specs/cli-spec/spec.md +23 -0
  91. package/references/openspec/openspec/changes/archive/2025-08-19-bulk-validation-interactive-selection/specs/cli-validate/spec.md +149 -0
  92. package/references/openspec/openspec/changes/archive/2025-08-19-bulk-validation-interactive-selection/tasks.md +81 -0
  93. package/references/openspec/openspec/changes/archive/2025-08-19-fix-update-tool-selection/proposal.md +40 -0
  94. package/references/openspec/openspec/changes/archive/2025-08-19-fix-update-tool-selection/specs/cli-update/spec.md +23 -0
  95. package/references/openspec/openspec/changes/archive/2025-08-19-fix-update-tool-selection/tasks.md +21 -0
  96. package/references/openspec/openspec/changes/archive/2025-08-19-improve-validate-error-messages/proposal.md +25 -0
  97. package/references/openspec/openspec/changes/archive/2025-08-19-improve-validate-error-messages/specs/cli-validate/spec.md +55 -0
  98. package/references/openspec/openspec/changes/archive/2025-08-19-improve-validate-error-messages/tasks.md +21 -0
  99. package/references/openspec/openspec/changes/archive/2025-08-19-structured-spec-format/proposal.md +36 -0
  100. package/references/openspec/openspec/changes/archive/2025-08-19-structured-spec-format/specs/openspec-conventions/spec.md +192 -0
  101. package/references/openspec/openspec/changes/archive/2025-08-19-structured-spec-format/tasks.md +19 -0
  102. package/references/openspec/openspec/changes/archive/2025-09-12-add-view-dashboard-command/proposal.md +38 -0
  103. package/references/openspec/openspec/changes/archive/2025-09-12-add-view-dashboard-command/specs/cli-view/spec.md +109 -0
  104. package/references/openspec/openspec/changes/archive/2025-09-12-add-view-dashboard-command/tasks.md +47 -0
  105. package/references/openspec/openspec/changes/archive/2025-09-29-add-agents-md-config/proposal.md +28 -0
  106. package/references/openspec/openspec/changes/archive/2025-09-29-add-agents-md-config/specs/cli-init/spec.md +71 -0
  107. package/references/openspec/openspec/changes/archive/2025-09-29-add-agents-md-config/specs/cli-update/spec.md +41 -0
  108. package/references/openspec/openspec/changes/archive/2025-09-29-add-agents-md-config/tasks.md +17 -0
  109. package/references/openspec/openspec/changes/archive/2025-09-29-add-multi-agent-init/proposal.md +35 -0
  110. package/references/openspec/openspec/changes/archive/2025-09-29-add-multi-agent-init/specs/cli-init/spec.md +45 -0
  111. package/references/openspec/openspec/changes/archive/2025-09-29-add-multi-agent-init/tasks.md +16 -0
  112. package/references/openspec/openspec/changes/archive/2025-09-29-add-slash-command-support/proposal.md +119 -0
  113. package/references/openspec/openspec/changes/archive/2025-09-29-add-slash-command-support/specs/cli-init/spec.md +21 -0
  114. package/references/openspec/openspec/changes/archive/2025-09-29-add-slash-command-support/specs/cli-update/spec.md +22 -0
  115. package/references/openspec/openspec/changes/archive/2025-09-29-add-slash-command-support/tasks.md +20 -0
  116. package/references/openspec/openspec/changes/archive/2025-09-29-improve-cli-e2e-plan/proposal.md +19 -0
  117. package/references/openspec/openspec/changes/archive/2025-09-29-improve-cli-e2e-plan/tasks.md +9 -0
  118. package/references/openspec/openspec/changes/archive/2025-09-29-improve-deterministic-tests/proposal.md +78 -0
  119. package/references/openspec/openspec/changes/archive/2025-09-29-improve-deterministic-tests/tasks.md +25 -0
  120. package/references/openspec/openspec/changes/archive/2025-09-29-improve-init-onboarding/proposal.md +13 -0
  121. package/references/openspec/openspec/changes/archive/2025-09-29-improve-init-onboarding/specs/cli-init/spec.md +92 -0
  122. package/references/openspec/openspec/changes/archive/2025-09-29-improve-init-onboarding/tasks.md +12 -0
  123. package/references/openspec/openspec/changes/archive/2025-09-29-remove-diff-command/proposal.md +81 -0
  124. package/references/openspec/openspec/changes/archive/2025-09-29-remove-diff-command/tasks.md +37 -0
  125. package/references/openspec/openspec/changes/archive/2025-09-29-sort-active-changes-by-progress/proposal.md +25 -0
  126. package/references/openspec/openspec/changes/archive/2025-09-29-sort-active-changes-by-progress/specs/cli-view/spec.md +9 -0
  127. package/references/openspec/openspec/changes/archive/2025-09-29-sort-active-changes-by-progress/tasks.md +8 -0
  128. package/references/openspec/openspec/changes/archive/2025-09-29-update-agent-file-name/proposal.md +29 -0
  129. package/references/openspec/openspec/changes/archive/2025-09-29-update-agent-file-name/specs/cli-init/spec.md +40 -0
  130. package/references/openspec/openspec/changes/archive/2025-09-29-update-agent-file-name/specs/cli-update/spec.md +22 -0
  131. package/references/openspec/openspec/changes/archive/2025-09-29-update-agent-file-name/specs/openspec-conventions/spec.md +27 -0
  132. package/references/openspec/openspec/changes/archive/2025-09-29-update-agent-file-name/tasks.md +22 -0
  133. package/references/openspec/openspec/changes/archive/2025-09-29-update-agent-instructions/design.md +130 -0
  134. package/references/openspec/openspec/changes/archive/2025-09-29-update-agent-instructions/proposal.md +117 -0
  135. package/references/openspec/openspec/changes/archive/2025-09-29-update-agent-instructions/tasks.md +69 -0
  136. package/references/openspec/openspec/changes/archive/2025-09-29-update-markdown-parser-crlf/proposal.md +19 -0
  137. package/references/openspec/openspec/changes/archive/2025-09-29-update-markdown-parser-crlf/specs/cli-validate/spec.md +9 -0
  138. package/references/openspec/openspec/changes/archive/2025-09-29-update-markdown-parser-crlf/tasks.md +11 -0
  139. package/references/openspec/openspec/changes/archive/2025-10-14-add-codex-slash-command-support/proposal.md +25 -0
  140. package/references/openspec/openspec/changes/archive/2025-10-14-add-codex-slash-command-support/specs/cli-init/spec.md +56 -0
  141. package/references/openspec/openspec/changes/archive/2025-10-14-add-codex-slash-command-support/specs/cli-update/spec.md +41 -0
  142. package/references/openspec/openspec/changes/archive/2025-10-14-add-codex-slash-command-support/tasks.md +19 -0
  143. package/references/openspec/openspec/changes/archive/2025-10-14-add-github-copilot-prompts/proposal.md +25 -0
  144. package/references/openspec/openspec/changes/archive/2025-10-14-add-github-copilot-prompts/specs/cli-init/spec.md +48 -0
  145. package/references/openspec/openspec/changes/archive/2025-10-14-add-github-copilot-prompts/specs/cli-update/spec.md +48 -0
  146. package/references/openspec/openspec/changes/archive/2025-10-14-add-github-copilot-prompts/tasks.md +30 -0
  147. package/references/openspec/openspec/changes/archive/2025-10-14-add-kilocode-workflows/proposal.md +17 -0
  148. package/references/openspec/openspec/changes/archive/2025-10-14-add-kilocode-workflows/specs/cli-init/spec.md +43 -0
  149. package/references/openspec/openspec/changes/archive/2025-10-14-add-kilocode-workflows/specs/cli-update/spec.md +27 -0
  150. package/references/openspec/openspec/changes/archive/2025-10-14-add-kilocode-workflows/tasks.md +15 -0
  151. package/references/openspec/openspec/changes/archive/2025-10-14-add-non-interactive-init-options/proposal.md +12 -0
  152. package/references/openspec/openspec/changes/archive/2025-10-14-add-non-interactive-init-options/specs/cli-init/spec.md +39 -0
  153. package/references/openspec/openspec/changes/archive/2025-10-14-add-non-interactive-init-options/tasks.md +17 -0
  154. package/references/openspec/openspec/changes/archive/2025-10-14-add-windsurf-workflows/proposal.md +17 -0
  155. package/references/openspec/openspec/changes/archive/2025-10-14-add-windsurf-workflows/specs/cli-init/spec.md +42 -0
  156. package/references/openspec/openspec/changes/archive/2025-10-14-add-windsurf-workflows/specs/cli-update/spec.md +27 -0
  157. package/references/openspec/openspec/changes/archive/2025-10-14-add-windsurf-workflows/tasks.md +17 -0
  158. package/references/openspec/openspec/changes/archive/2025-10-14-enhance-validation-error-messages/proposal.md +12 -0
  159. package/references/openspec/openspec/changes/archive/2025-10-14-enhance-validation-error-messages/specs/cli-validate/spec.md +39 -0
  160. package/references/openspec/openspec/changes/archive/2025-10-14-enhance-validation-error-messages/tasks.md +12 -0
  161. package/references/openspec/openspec/changes/archive/2025-10-14-improve-agent-instruction-usability/proposal.md +12 -0
  162. package/references/openspec/openspec/changes/archive/2025-10-14-improve-agent-instruction-usability/specs/docs-agent-instructions/spec.md +33 -0
  163. package/references/openspec/openspec/changes/archive/2025-10-14-improve-agent-instruction-usability/tasks.md +11 -0
  164. package/references/openspec/openspec/changes/archive/2025-10-14-slim-root-agents-file/proposal.md +13 -0
  165. package/references/openspec/openspec/changes/archive/2025-10-14-slim-root-agents-file/tasks.md +15 -0
  166. package/references/openspec/openspec/changes/archive/2025-10-14-update-cli-init-enter-selection/proposal.md +14 -0
  167. package/references/openspec/openspec/changes/archive/2025-10-14-update-cli-init-enter-selection/specs/cli-init/spec.md +10 -0
  168. package/references/openspec/openspec/changes/archive/2025-10-14-update-cli-init-enter-selection/tasks.md +8 -0
  169. package/references/openspec/openspec/changes/archive/2025-10-14-update-cli-init-root-agents/proposal.md +15 -0
  170. package/references/openspec/openspec/changes/archive/2025-10-14-update-cli-init-root-agents/specs/cli-init/spec.md +32 -0
  171. package/references/openspec/openspec/changes/archive/2025-10-14-update-cli-init-root-agents/specs/cli-update/spec.md +10 -0
  172. package/references/openspec/openspec/changes/archive/2025-10-14-update-cli-init-root-agents/tasks.md +11 -0
  173. package/references/openspec/openspec/changes/archive/2025-10-14-update-release-automation/proposal.md +49 -0
  174. package/references/openspec/openspec/changes/archive/2025-10-14-update-release-automation/tasks.md +12 -0
  175. package/references/openspec/openspec/changes/archive/2025-10-22-add-archive-command-arguments/proposal.md +17 -0
  176. package/references/openspec/openspec/changes/archive/2025-10-22-add-archive-command-arguments/specs/cli-update/spec.md +32 -0
  177. package/references/openspec/openspec/changes/archive/2025-10-22-add-archive-command-arguments/tasks.md +15 -0
  178. package/references/openspec/openspec/changes/archive/2025-10-22-add-cline-support/proposal.md +15 -0
  179. package/references/openspec/openspec/changes/archive/2025-10-22-add-cline-support/specs/cli-init/spec.md +97 -0
  180. package/references/openspec/openspec/changes/archive/2025-10-22-add-cline-support/tasks.md +19 -0
  181. package/references/openspec/openspec/changes/archive/2025-10-22-add-crush-support/proposal.md +13 -0
  182. package/references/openspec/openspec/changes/archive/2025-10-22-add-crush-support/specs/cli-init/spec.md +67 -0
  183. package/references/openspec/openspec/changes/archive/2025-10-22-add-crush-support/tasks.md +7 -0
  184. package/references/openspec/openspec/changes/archive/2025-10-22-add-factory-slash-commands/proposal.md +12 -0
  185. package/references/openspec/openspec/changes/archive/2025-10-22-add-factory-slash-commands/specs/cli-init/spec.md +54 -0
  186. package/references/openspec/openspec/changes/archive/2025-10-22-add-factory-slash-commands/specs/cli-update/spec.md +54 -0
  187. package/references/openspec/openspec/changes/archive/2025-10-22-add-factory-slash-commands/tasks.md +11 -0
  188. package/references/openspec/openspec/changes/fix-cline-workflows-implementation/proposal.md +13 -0
  189. package/references/openspec/openspec/changes/fix-cline-workflows-implementation/specs/cli-init/spec.md +11 -0
  190. package/references/openspec/openspec/changes/fix-cline-workflows-implementation/tasks.md +13 -0
  191. package/references/openspec/openspec/changes/make-validation-scope-aware/proposal.md +12 -0
  192. package/references/openspec/openspec/changes/make-validation-scope-aware/specs/cli-validate/spec.md +25 -0
  193. package/references/openspec/openspec/changes/make-validation-scope-aware/tasks.md +16 -0
  194. package/references/openspec/openspec/project.md +53 -0
  195. package/references/openspec/openspec/specs/cli-archive/spec.md +210 -0
  196. package/references/openspec/openspec/specs/cli-change/spec.md +91 -0
  197. package/references/openspec/openspec/specs/cli-init/spec.md +311 -0
  198. package/references/openspec/openspec/specs/cli-list/spec.md +103 -0
  199. package/references/openspec/openspec/specs/cli-show/spec.md +85 -0
  200. package/references/openspec/openspec/specs/cli-spec/spec.md +87 -0
  201. package/references/openspec/openspec/specs/cli-update/spec.md +190 -0
  202. package/references/openspec/openspec/specs/cli-validate/spec.md +218 -0
  203. package/references/openspec/openspec/specs/cli-view/spec.md +105 -0
  204. package/references/openspec/openspec/specs/docs-agent-instructions/spec.md +38 -0
  205. package/references/openspec/openspec/specs/openspec-conventions/spec.md +474 -0
  206. package/references/openspec/openspec-parallel-merge-plan.md +98 -0
  207. package/references/openspec/package.json +73 -0
  208. package/references/openspec/pnpm-lock.yaml +2324 -0
  209. package/references/openspec/scripts/pack-version-check.mjs +111 -0
  210. package/references/openspec/src/cli/index.ts +253 -0
  211. package/references/openspec/src/commands/change.ts +291 -0
  212. package/references/openspec/src/commands/show.ts +139 -0
  213. package/references/openspec/src/commands/spec.ts +250 -0
  214. package/references/openspec/src/commands/validate.ts +305 -0
  215. package/references/openspec/src/core/archive.ts +606 -0
  216. package/references/openspec/src/core/config.ts +41 -0
  217. package/references/openspec/src/core/configurators/agents.ts +23 -0
  218. package/references/openspec/src/core/configurators/base.ts +6 -0
  219. package/references/openspec/src/core/configurators/claude.ts +23 -0
  220. package/references/openspec/src/core/configurators/cline.ts +23 -0
  221. package/references/openspec/src/core/configurators/codebuddy.ts +24 -0
  222. package/references/openspec/src/core/configurators/costrict.ts +23 -0
  223. package/references/openspec/src/core/configurators/iflow.ts +23 -0
  224. package/references/openspec/src/core/configurators/qoder.ts +53 -0
  225. package/references/openspec/src/core/configurators/qwen.ts +47 -0
  226. package/references/openspec/src/core/configurators/registry.ts +49 -0
  227. package/references/openspec/src/core/configurators/slash/amazon-q.ts +51 -0
  228. package/references/openspec/src/core/configurators/slash/antigravity.ts +28 -0
  229. package/references/openspec/src/core/configurators/slash/auggie.ts +37 -0
  230. package/references/openspec/src/core/configurators/slash/base.ts +95 -0
  231. package/references/openspec/src/core/configurators/slash/claude.ts +42 -0
  232. package/references/openspec/src/core/configurators/slash/cline.ts +27 -0
  233. package/references/openspec/src/core/configurators/slash/codebuddy.ts +43 -0
  234. package/references/openspec/src/core/configurators/slash/codex.ts +126 -0
  235. package/references/openspec/src/core/configurators/slash/costrict.ts +36 -0
  236. package/references/openspec/src/core/configurators/slash/crush.ts +42 -0
  237. package/references/openspec/src/core/configurators/slash/cursor.ts +42 -0
  238. package/references/openspec/src/core/configurators/slash/factory.ts +41 -0
  239. package/references/openspec/src/core/configurators/slash/gemini.ts +27 -0
  240. package/references/openspec/src/core/configurators/slash/github-copilot.ts +39 -0
  241. package/references/openspec/src/core/configurators/slash/iflow.ts +42 -0
  242. package/references/openspec/src/core/configurators/slash/kilocode.ts +21 -0
  243. package/references/openspec/src/core/configurators/slash/opencode.ts +83 -0
  244. package/references/openspec/src/core/configurators/slash/qoder.ts +84 -0
  245. package/references/openspec/src/core/configurators/slash/qwen.ts +55 -0
  246. package/references/openspec/src/core/configurators/slash/registry.ts +81 -0
  247. package/references/openspec/src/core/configurators/slash/roocode.ts +27 -0
  248. package/references/openspec/src/core/configurators/slash/toml-base.ts +66 -0
  249. package/references/openspec/src/core/configurators/slash/windsurf.ts +27 -0
  250. package/references/openspec/src/core/converters/json-converter.ts +61 -0
  251. package/references/openspec/src/core/index.ts +2 -0
  252. package/references/openspec/src/core/init.ts +986 -0
  253. package/references/openspec/src/core/list.ts +104 -0
  254. package/references/openspec/src/core/parsers/change-parser.ts +234 -0
  255. package/references/openspec/src/core/parsers/markdown-parser.ts +237 -0
  256. package/references/openspec/src/core/parsers/requirement-blocks.ts +234 -0
  257. package/references/openspec/src/core/schemas/base.schema.ts +20 -0
  258. package/references/openspec/src/core/schemas/change.schema.ts +42 -0
  259. package/references/openspec/src/core/schemas/index.ts +20 -0
  260. package/references/openspec/src/core/schemas/spec.schema.ts +17 -0
  261. package/references/openspec/src/core/styles/palette.ts +8 -0
  262. package/references/openspec/src/core/templates/agents-root-stub.ts +16 -0
  263. package/references/openspec/src/core/templates/agents-template.ts +457 -0
  264. package/references/openspec/src/core/templates/claude-template.ts +1 -0
  265. package/references/openspec/src/core/templates/cline-template.ts +1 -0
  266. package/references/openspec/src/core/templates/costrict-template.ts +1 -0
  267. package/references/openspec/src/core/templates/index.ts +50 -0
  268. package/references/openspec/src/core/templates/project-template.ts +38 -0
  269. package/references/openspec/src/core/templates/slash-command-templates.ts +60 -0
  270. package/references/openspec/src/core/update.ts +129 -0
  271. package/references/openspec/src/core/validation/constants.ts +48 -0
  272. package/references/openspec/src/core/validation/types.ts +19 -0
  273. package/references/openspec/src/core/validation/validator.ts +448 -0
  274. package/references/openspec/src/core/view.ts +189 -0
  275. package/references/openspec/src/index.ts +2 -0
  276. package/references/openspec/src/utils/file-system.ts +187 -0
  277. package/references/openspec/src/utils/index.ts +2 -0
  278. package/references/openspec/src/utils/interactive.ts +7 -0
  279. package/references/openspec/src/utils/item-discovery.ts +45 -0
  280. package/references/openspec/src/utils/match.ts +26 -0
  281. package/references/openspec/src/utils/task-progress.ts +43 -0
  282. package/references/openspec/test/cli-e2e/basic.test.ts +156 -0
  283. package/references/openspec/test/commands/change.interactive-show.test.ts +45 -0
  284. package/references/openspec/test/commands/change.interactive-validate.test.ts +48 -0
  285. package/references/openspec/test/commands/show.test.ts +123 -0
  286. package/references/openspec/test/commands/spec.interactive-show.test.ts +44 -0
  287. package/references/openspec/test/commands/spec.interactive-validate.test.ts +44 -0
  288. package/references/openspec/test/commands/spec.test.ts +324 -0
  289. package/references/openspec/test/commands/validate.enriched-output.test.ts +49 -0
  290. package/references/openspec/test/commands/validate.test.ts +133 -0
  291. package/references/openspec/test/core/archive.test.ts +680 -0
  292. package/references/openspec/test/core/commands/change-command.list.test.ts +76 -0
  293. package/references/openspec/test/core/commands/change-command.show-validate.test.ts +111 -0
  294. package/references/openspec/test/core/converters/json-converter.test.ts +184 -0
  295. package/references/openspec/test/core/init.test.ts +1710 -0
  296. package/references/openspec/test/core/list.test.ts +165 -0
  297. package/references/openspec/test/core/parsers/change-parser.test.ts +52 -0
  298. package/references/openspec/test/core/parsers/markdown-parser.test.ts +291 -0
  299. package/references/openspec/test/core/update.test.ts +1642 -0
  300. package/references/openspec/test/core/validation.enriched-messages.test.ts +74 -0
  301. package/references/openspec/test/core/validation.test.ts +489 -0
  302. package/references/openspec/test/core/view.test.ts +79 -0
  303. package/references/openspec/test/fixtures/tmp-init/openspec/changes/c1/proposal.md +7 -0
  304. package/references/openspec/test/fixtures/tmp-init/openspec/changes/c1/specs/alpha/spec.md +8 -0
  305. package/references/openspec/test/fixtures/tmp-init/openspec/specs/alpha/spec.md +12 -0
  306. package/references/openspec/test/helpers/run-cli.ts +139 -0
  307. package/references/openspec/test/utils/file-system.test.ts +211 -0
  308. package/references/openspec/test/utils/marker-updates.test.ts +287 -0
  309. package/references/openspec/tsconfig.json +21 -0
  310. package/references/openspec/vitest.config.ts +25 -0
  311. package/references/openspec/vitest.setup.ts +6 -0
@@ -0,0 +1,74 @@
1
+ import { describe, it, expect, beforeEach, afterEach } from 'vitest';
2
+ import { promises as fs } from 'fs';
3
+ import path from 'path';
4
+ import { Validator } from '../../src/core/validation/validator.js';
5
+
6
+ describe('Validator enriched messages', () => {
7
+ const testDir = path.join(process.cwd(), 'test-validation-enriched-tmp');
8
+
9
+ beforeEach(async () => {
10
+ await fs.mkdir(testDir, { recursive: true });
11
+ });
12
+
13
+ afterEach(async () => {
14
+ await fs.rm(testDir, { recursive: true, force: true });
15
+ });
16
+
17
+ it('adds guidance for no deltas in change', async () => {
18
+ const changeContent = `# Test Change
19
+
20
+ ## Why
21
+ This is a sufficiently long explanation to pass the why length requirement for validation purposes.
22
+
23
+ ## What Changes
24
+ There are changes proposed, but no delta specs provided yet.`;
25
+ const changePath = path.join(testDir, 'proposal.md');
26
+ await fs.writeFile(changePath, changeContent);
27
+
28
+ const validator = new Validator();
29
+ const report = await validator.validateChange(changePath);
30
+ expect(report.valid).toBe(false);
31
+ const msg = report.issues.map(i => i.message).join('\n');
32
+ expect(msg).toContain('Change must have at least one delta');
33
+ expect(msg).toContain('Ensure your change has a specs/ directory');
34
+ expect(msg).toContain('## ADDED/MODIFIED/REMOVED/RENAMED Requirements');
35
+ });
36
+
37
+ it('adds guidance when spec missing Purpose/Requirements', async () => {
38
+ const specContent = `# Test Spec\n\n## Requirements\n\n### Requirement: Foo\nFoo SHALL ...\n\n#### Scenario: Bar\nWhen...`;
39
+ const specPath = path.join(testDir, 'spec.md');
40
+ await fs.writeFile(specPath, specContent);
41
+
42
+ const validator = new Validator();
43
+ const report = await validator.validateSpec(specPath);
44
+ expect(report.valid).toBe(false);
45
+ const msg = report.issues.map(i => i.message).join('\n');
46
+ expect(msg).toContain('Spec must have a Purpose section');
47
+ expect(msg).toContain('Expected headers: "## Purpose" and "## Requirements"');
48
+ });
49
+
50
+ it('warns with scenario conversion template when missing scenarios', async () => {
51
+ const specContent = `# Test Spec
52
+
53
+ ## Purpose
54
+ This is a sufficiently long purpose section to avoid warnings about brevity.
55
+
56
+ ## Requirements
57
+
58
+ ### Requirement: Foo SHALL be described
59
+ Text of requirement
60
+ `;
61
+ const specPath = path.join(testDir, 'spec.md');
62
+ await fs.writeFile(specPath, specContent);
63
+
64
+ const validator = new Validator();
65
+ const report = await validator.validateSpec(specPath);
66
+ expect(report.valid).toBe(false);
67
+ const warn = report.issues.find(i => i.path.includes('requirements[0].scenarios'));
68
+ expect(warn?.message).toContain('Requirement must have at least one scenario');
69
+ expect(warn?.message).toContain('Scenarios must use level-4 headers');
70
+ expect(warn?.message).toContain('#### Scenario:');
71
+ });
72
+ });
73
+
74
+
@@ -0,0 +1,489 @@
1
+ import { describe, it, expect, beforeEach, afterEach } from 'vitest';
2
+ import { promises as fs } from 'fs';
3
+ import path from 'path';
4
+ import { Validator } from '../../src/core/validation/validator.js';
5
+ import {
6
+ ScenarioSchema,
7
+ RequirementSchema,
8
+ SpecSchema,
9
+ ChangeSchema,
10
+ DeltaSchema
11
+ } from '../../src/core/schemas/index.js';
12
+
13
+ describe('Validation Schemas', () => {
14
+ describe('ScenarioSchema', () => {
15
+ it('should validate a valid scenario', () => {
16
+ const scenario = {
17
+ rawText: 'Given a user is logged in\nWhen they click logout\nThen they are redirected to login page',
18
+ };
19
+
20
+ const result = ScenarioSchema.safeParse(scenario);
21
+ expect(result.success).toBe(true);
22
+ });
23
+
24
+ it('should reject scenario with empty text', () => {
25
+ const scenario = {
26
+ rawText: '',
27
+ };
28
+
29
+ const result = ScenarioSchema.safeParse(scenario);
30
+ expect(result.success).toBe(false);
31
+ if (!result.success) {
32
+ expect(result.error.issues[0].message).toBe('Scenario text cannot be empty');
33
+ }
34
+ });
35
+ });
36
+
37
+ describe('RequirementSchema', () => {
38
+ it('should validate a valid requirement', () => {
39
+ const requirement = {
40
+ text: 'The system SHALL provide user authentication',
41
+ scenarios: [
42
+ {
43
+ rawText: 'Given a user with valid credentials\nWhen they submit the login form\nThen they are authenticated',
44
+ },
45
+ ],
46
+ };
47
+
48
+ const result = RequirementSchema.safeParse(requirement);
49
+ expect(result.success).toBe(true);
50
+ });
51
+
52
+ it('should reject requirement without SHALL or MUST', () => {
53
+ const requirement = {
54
+ text: 'The system provides user authentication',
55
+ scenarios: [
56
+ {
57
+ rawText: 'Given a user\nWhen they login\nThen authenticated',
58
+ },
59
+ ],
60
+ };
61
+
62
+ const result = RequirementSchema.safeParse(requirement);
63
+ expect(result.success).toBe(false);
64
+ if (!result.success) {
65
+ expect(result.error.issues[0].message).toBe('Requirement must contain SHALL or MUST keyword');
66
+ }
67
+ });
68
+
69
+ it('should reject requirement without scenarios', () => {
70
+ const requirement = {
71
+ text: 'The system SHALL provide user authentication',
72
+ scenarios: [],
73
+ };
74
+
75
+ const result = RequirementSchema.safeParse(requirement);
76
+ expect(result.success).toBe(false);
77
+ if (!result.success) {
78
+ expect(result.error.issues[0].message).toBe('Requirement must have at least one scenario');
79
+ }
80
+ });
81
+ });
82
+
83
+ describe('SpecSchema', () => {
84
+ it('should validate a valid spec', () => {
85
+ const spec = {
86
+ name: 'user-auth',
87
+ overview: 'This spec defines user authentication requirements',
88
+ requirements: [
89
+ {
90
+ text: 'The system SHALL provide user authentication',
91
+ scenarios: [
92
+ {
93
+ rawText: 'Given a user with valid credentials\nWhen they submit the login form\nThen they are authenticated',
94
+ },
95
+ ],
96
+ },
97
+ ],
98
+ };
99
+
100
+ const result = SpecSchema.safeParse(spec);
101
+ expect(result.success).toBe(true);
102
+ });
103
+
104
+ it('should reject spec without requirements', () => {
105
+ const spec = {
106
+ name: 'user-auth',
107
+ overview: 'This spec defines user authentication requirements',
108
+ requirements: [],
109
+ };
110
+
111
+ const result = SpecSchema.safeParse(spec);
112
+ expect(result.success).toBe(false);
113
+ if (!result.success) {
114
+ expect(result.error.issues[0].message).toBe('Spec must have at least one requirement');
115
+ }
116
+ });
117
+ });
118
+
119
+ describe('ChangeSchema', () => {
120
+ it('should validate a valid change', () => {
121
+ const change = {
122
+ name: 'add-user-auth',
123
+ why: 'We need user authentication to secure the application and protect user data',
124
+ whatChanges: 'Add authentication module with login and logout capabilities',
125
+ deltas: [
126
+ {
127
+ spec: 'user-auth',
128
+ operation: 'ADDED',
129
+ description: 'Add new user authentication spec',
130
+ },
131
+ ],
132
+ };
133
+
134
+ const result = ChangeSchema.safeParse(change);
135
+ expect(result.success).toBe(true);
136
+ });
137
+
138
+ it('should reject change with short why section', () => {
139
+ const change = {
140
+ name: 'add-user-auth',
141
+ why: 'Need auth',
142
+ whatChanges: 'Add authentication',
143
+ deltas: [
144
+ {
145
+ spec: 'user-auth',
146
+ operation: 'ADDED',
147
+ description: 'Add auth',
148
+ },
149
+ ],
150
+ };
151
+
152
+ const result = ChangeSchema.safeParse(change);
153
+ expect(result.success).toBe(false);
154
+ if (!result.success) {
155
+ expect(result.error.issues[0].message).toBe('Why section must be at least 50 characters');
156
+ }
157
+ });
158
+
159
+ it('should warn about too many deltas', () => {
160
+ const deltas = Array.from({ length: 11 }, (_, i) => ({
161
+ spec: `spec-${i}`,
162
+ operation: 'ADDED' as const,
163
+ description: `Add spec ${i}`,
164
+ }));
165
+
166
+ const change = {
167
+ name: 'massive-change',
168
+ why: 'This is a massive change that affects many parts of the system',
169
+ whatChanges: 'Update everything',
170
+ deltas,
171
+ };
172
+
173
+ const result = ChangeSchema.safeParse(change);
174
+ expect(result.success).toBe(false);
175
+ if (!result.success) {
176
+ expect(result.error.issues[0].message).toBe('Consider splitting changes with more than 10 deltas');
177
+ }
178
+ });
179
+ });
180
+ });
181
+
182
+ describe('Validator', () => {
183
+ const testDir = path.join(process.cwd(), 'test-validation-tmp');
184
+
185
+ beforeEach(async () => {
186
+ await fs.mkdir(testDir, { recursive: true });
187
+ });
188
+
189
+ afterEach(async () => {
190
+ await fs.rm(testDir, { recursive: true, force: true });
191
+ });
192
+
193
+ describe('validateSpec', () => {
194
+ it('should validate a valid spec file', async () => {
195
+ const specContent = `# User Authentication Spec
196
+
197
+ ## Purpose
198
+ This specification defines the requirements for user authentication in the system.
199
+
200
+ ## Requirements
201
+
202
+ ### The system SHALL provide secure user authentication
203
+ The system SHALL provide secure user authentication mechanisms.
204
+
205
+ #### Scenario: Successful login
206
+ Given a user with valid credentials
207
+ When they submit the login form
208
+ Then they are authenticated and redirected to the dashboard
209
+
210
+ ### The system SHALL handle invalid login attempts
211
+ The system SHALL gracefully handle incorrect credentials.
212
+
213
+ #### Scenario: Invalid credentials
214
+ Given a user with invalid credentials
215
+ When they submit the login form
216
+ Then they see an error message`;
217
+
218
+ const specPath = path.join(testDir, 'spec.md');
219
+ await fs.writeFile(specPath, specContent);
220
+
221
+ const validator = new Validator();
222
+ const report = await validator.validateSpec(specPath);
223
+
224
+ expect(report.valid).toBe(true);
225
+ expect(report.summary.errors).toBe(0);
226
+ });
227
+
228
+ it('should detect missing overview section', async () => {
229
+ const specContent = `# User Authentication Spec
230
+
231
+ ## Requirements
232
+
233
+ ### The system SHALL provide secure user authentication
234
+
235
+ #### Scenario: Login
236
+ Given a user
237
+ When they login
238
+ Then authenticated`;
239
+
240
+ const specPath = path.join(testDir, 'spec.md');
241
+ await fs.writeFile(specPath, specContent);
242
+
243
+ const validator = new Validator();
244
+ const report = await validator.validateSpec(specPath);
245
+
246
+ expect(report.valid).toBe(false);
247
+ expect(report.summary.errors).toBeGreaterThan(0);
248
+ expect(report.issues.some(i => i.message.includes('Purpose'))).toBe(true);
249
+ });
250
+ });
251
+
252
+ describe('validateChange', () => {
253
+ it('should validate a valid change file', async () => {
254
+ const changeContent = `# Add User Authentication
255
+
256
+ ## Why
257
+ We need to implement user authentication to secure the application and protect user data from unauthorized access.
258
+
259
+ ## What Changes
260
+ - **user-auth:** Add new user authentication specification
261
+ - **api-endpoints:** Modify to include auth endpoints`;
262
+
263
+ const changePath = path.join(testDir, 'change.md');
264
+ await fs.writeFile(changePath, changeContent);
265
+
266
+ const validator = new Validator();
267
+ const report = await validator.validateChange(changePath);
268
+
269
+ expect(report.valid).toBe(true);
270
+ expect(report.summary.errors).toBe(0);
271
+ });
272
+
273
+ it('should detect missing why section', async () => {
274
+ const changeContent = `# Add User Authentication
275
+
276
+ ## What Changes
277
+ - **user-auth:** Add new user authentication specification`;
278
+
279
+ const changePath = path.join(testDir, 'change.md');
280
+ await fs.writeFile(changePath, changeContent);
281
+
282
+ const validator = new Validator();
283
+ const report = await validator.validateChange(changePath);
284
+
285
+ expect(report.valid).toBe(false);
286
+ expect(report.summary.errors).toBeGreaterThan(0);
287
+ expect(report.issues.some(i => i.message.includes('Why'))).toBe(true);
288
+ });
289
+ });
290
+
291
+ describe('strict mode', () => {
292
+ it('should fail on warnings in strict mode', async () => {
293
+ const specContent = `# Test Spec
294
+
295
+ ## Purpose
296
+ Brief overview
297
+
298
+ ## Requirements
299
+
300
+ ### The system SHALL do something
301
+
302
+ #### Scenario: Test
303
+ Given test
304
+ When action
305
+ Then result`;
306
+
307
+ const specPath = path.join(testDir, 'spec.md');
308
+ await fs.writeFile(specPath, specContent);
309
+
310
+ const validator = new Validator(true); // strict mode
311
+ const report = await validator.validateSpec(specPath);
312
+
313
+ expect(report.valid).toBe(false); // Should fail due to brief overview warning
314
+ });
315
+
316
+ it('should pass warnings in non-strict mode', async () => {
317
+ const specContent = `# Test Spec
318
+
319
+ ## Purpose
320
+ Brief overview
321
+
322
+ ## Requirements
323
+
324
+ ### The system SHALL do something
325
+
326
+ #### Scenario: Test
327
+ Given test
328
+ When action
329
+ Then result`;
330
+
331
+ const specPath = path.join(testDir, 'spec.md');
332
+ await fs.writeFile(specPath, specContent);
333
+
334
+ const validator = new Validator(false); // non-strict mode
335
+ const report = await validator.validateSpec(specPath);
336
+
337
+ expect(report.valid).toBe(true); // Should pass despite warnings
338
+ expect(report.summary.warnings).toBeGreaterThan(0);
339
+ });
340
+ });
341
+
342
+ describe('validateChangeDeltaSpecs with metadata', () => {
343
+ it('should validate requirement with metadata before SHALL/MUST text', async () => {
344
+ const changeDir = path.join(testDir, 'test-change');
345
+ const specsDir = path.join(changeDir, 'specs', 'test-spec');
346
+ await fs.mkdir(specsDir, { recursive: true });
347
+
348
+ const deltaSpec = `# Test Spec
349
+
350
+ ## ADDED Requirements
351
+
352
+ ### Requirement: Circuit Breaker State Management SHALL be implemented
353
+ **ID**: REQ-CB-001
354
+ **Priority**: P1 (High)
355
+
356
+ The system MUST implement a circuit breaker with three states.
357
+
358
+ #### Scenario: Normal operation
359
+ **Given** the circuit breaker is in CLOSED state
360
+ **When** a request is made
361
+ **Then** the request is executed normally`;
362
+
363
+ const specPath = path.join(specsDir, 'spec.md');
364
+ await fs.writeFile(specPath, deltaSpec);
365
+
366
+ const validator = new Validator(true);
367
+ const report = await validator.validateChangeDeltaSpecs(changeDir);
368
+
369
+ expect(report.valid).toBe(true);
370
+ expect(report.summary.errors).toBe(0);
371
+ });
372
+
373
+ it('should validate requirement with SHALL in text but not in header', async () => {
374
+ const changeDir = path.join(testDir, 'test-change-2');
375
+ const specsDir = path.join(changeDir, 'specs', 'test-spec');
376
+ await fs.mkdir(specsDir, { recursive: true });
377
+
378
+ const deltaSpec = `# Test Spec
379
+
380
+ ## ADDED Requirements
381
+
382
+ ### Requirement: Error Handling
383
+ **ID**: REQ-ERR-001
384
+ **Priority**: P2
385
+
386
+ The system SHALL handle all errors gracefully.
387
+
388
+ #### Scenario: Error occurs
389
+ **Given** an error condition
390
+ **When** an error occurs
391
+ **Then** the error is logged and user is notified`;
392
+
393
+ const specPath = path.join(specsDir, 'spec.md');
394
+ await fs.writeFile(specPath, deltaSpec);
395
+
396
+ const validator = new Validator(true);
397
+ const report = await validator.validateChangeDeltaSpecs(changeDir);
398
+
399
+ expect(report.valid).toBe(true);
400
+ expect(report.summary.errors).toBe(0);
401
+ });
402
+
403
+ it('should fail when requirement text lacks SHALL/MUST', async () => {
404
+ const changeDir = path.join(testDir, 'test-change-3');
405
+ const specsDir = path.join(changeDir, 'specs', 'test-spec');
406
+ await fs.mkdir(specsDir, { recursive: true });
407
+
408
+ const deltaSpec = `# Test Spec
409
+
410
+ ## ADDED Requirements
411
+
412
+ ### Requirement: Logging Feature
413
+ **ID**: REQ-LOG-001
414
+
415
+ The system will log all events.
416
+
417
+ #### Scenario: Event occurs
418
+ **Given** an event
419
+ **When** it occurs
420
+ **Then** it is logged`;
421
+
422
+ const specPath = path.join(specsDir, 'spec.md');
423
+ await fs.writeFile(specPath, deltaSpec);
424
+
425
+ const validator = new Validator(true);
426
+ const report = await validator.validateChangeDeltaSpecs(changeDir);
427
+
428
+ expect(report.valid).toBe(false);
429
+ expect(report.summary.errors).toBeGreaterThan(0);
430
+ expect(report.issues.some(i => i.message.includes('must contain SHALL or MUST'))).toBe(true);
431
+ });
432
+
433
+ it('should handle requirements without metadata fields', async () => {
434
+ const changeDir = path.join(testDir, 'test-change-4');
435
+ const specsDir = path.join(changeDir, 'specs', 'test-spec');
436
+ await fs.mkdir(specsDir, { recursive: true });
437
+
438
+ const deltaSpec = `# Test Spec
439
+
440
+ ## ADDED Requirements
441
+
442
+ ### Requirement: Simple Feature
443
+ The system SHALL implement this feature.
444
+
445
+ #### Scenario: Basic usage
446
+ **Given** a condition
447
+ **When** an action occurs
448
+ **Then** a result happens`;
449
+
450
+ const specPath = path.join(specsDir, 'spec.md');
451
+ await fs.writeFile(specPath, deltaSpec);
452
+
453
+ const validator = new Validator(true);
454
+ const report = await validator.validateChangeDeltaSpecs(changeDir);
455
+
456
+ expect(report.valid).toBe(true);
457
+ expect(report.summary.errors).toBe(0);
458
+ });
459
+
460
+ it('should treat delta headers case-insensitively', async () => {
461
+ const changeDir = path.join(testDir, 'test-change-mixed-case');
462
+ const specsDir = path.join(changeDir, 'specs', 'test-spec');
463
+ await fs.mkdir(specsDir, { recursive: true });
464
+
465
+ const deltaSpec = `# Test Spec
466
+
467
+ ## Added Requirements
468
+
469
+ ### Requirement: Mixed Case Handling
470
+ The system MUST support mixed case delta headers.
471
+
472
+ #### Scenario: Case insensitive parsing
473
+ **Given** a delta file with mixed case headers
474
+ **When** validation runs
475
+ **Then** the delta is detected`;
476
+
477
+ const specPath = path.join(specsDir, 'spec.md');
478
+ await fs.writeFile(specPath, deltaSpec);
479
+
480
+ const validator = new Validator(true);
481
+ const report = await validator.validateChangeDeltaSpecs(changeDir);
482
+
483
+ expect(report.valid).toBe(true);
484
+ expect(report.summary.errors).toBe(0);
485
+ expect(report.summary.warnings).toBe(0);
486
+ expect(report.summary.info).toBe(0);
487
+ });
488
+ });
489
+ });
@@ -0,0 +1,79 @@
1
+ import { describe, it, expect, beforeEach, afterEach } from 'vitest';
2
+ import { promises as fs } from 'fs';
3
+ import path from 'path';
4
+ import os from 'os';
5
+ import { ViewCommand } from '../../src/core/view.js';
6
+
7
+ const stripAnsi = (input: string): string => input.replace(/\u001b\[[0-9;]*m/g, '');
8
+
9
+ describe('ViewCommand', () => {
10
+ let tempDir: string;
11
+ let originalLog: typeof console.log;
12
+ let logOutput: string[] = [];
13
+
14
+ beforeEach(async () => {
15
+ tempDir = path.join(os.tmpdir(), `openspec-view-test-${Date.now()}`);
16
+ await fs.mkdir(tempDir, { recursive: true });
17
+
18
+ originalLog = console.log;
19
+ console.log = (...args: any[]) => {
20
+ logOutput.push(args.join(' '));
21
+ };
22
+
23
+ logOutput = [];
24
+ });
25
+
26
+ afterEach(async () => {
27
+ console.log = originalLog;
28
+ await fs.rm(tempDir, { recursive: true, force: true });
29
+ });
30
+
31
+ it('sorts active changes by completion percentage ascending with deterministic tie-breakers', async () => {
32
+ const changesDir = path.join(tempDir, 'openspec', 'changes');
33
+ await fs.mkdir(changesDir, { recursive: true });
34
+
35
+ await fs.mkdir(path.join(changesDir, 'gamma-change'), { recursive: true });
36
+ await fs.writeFile(
37
+ path.join(changesDir, 'gamma-change', 'tasks.md'),
38
+ '- [x] Done\n- [x] Also done\n- [ ] Not done\n'
39
+ );
40
+
41
+ await fs.mkdir(path.join(changesDir, 'beta-change'), { recursive: true });
42
+ await fs.writeFile(
43
+ path.join(changesDir, 'beta-change', 'tasks.md'),
44
+ '- [x] Task 1\n- [ ] Task 2\n'
45
+ );
46
+
47
+ await fs.mkdir(path.join(changesDir, 'delta-change'), { recursive: true });
48
+ await fs.writeFile(
49
+ path.join(changesDir, 'delta-change', 'tasks.md'),
50
+ '- [x] Task 1\n- [ ] Task 2\n'
51
+ );
52
+
53
+ await fs.mkdir(path.join(changesDir, 'alpha-change'), { recursive: true });
54
+ await fs.writeFile(
55
+ path.join(changesDir, 'alpha-change', 'tasks.md'),
56
+ '- [ ] Task 1\n- [ ] Task 2\n'
57
+ );
58
+
59
+ const viewCommand = new ViewCommand();
60
+ await viewCommand.execute(tempDir);
61
+
62
+ const activeLines = logOutput
63
+ .map(stripAnsi)
64
+ .filter(line => line.includes('◉'));
65
+
66
+ const activeOrder = activeLines.map(line => {
67
+ const afterBullet = line.split('◉')[1] ?? '';
68
+ return afterBullet.split('[')[0]?.trim();
69
+ });
70
+
71
+ expect(activeOrder).toEqual([
72
+ 'alpha-change',
73
+ 'beta-change',
74
+ 'delta-change',
75
+ 'gamma-change'
76
+ ]);
77
+ });
78
+ });
79
+
@@ -0,0 +1,7 @@
1
+ # Test Change
2
+
3
+ ## Why
4
+ Because reasons that are sufficiently long for validation.
5
+
6
+ ## What Changes
7
+ - **alpha:** Add something
@@ -0,0 +1,8 @@
1
+ ## ADDED Requirements
2
+ ### Requirement: Parser SHALL accept CRLF change proposals
3
+ The parser SHALL accept CRLF change proposals without manual edits.
4
+
5
+ #### Scenario: Validate CRLF change
6
+ - **GIVEN** a change proposal saved with CRLF line endings
7
+ - **WHEN** a developer runs openspec validate on the proposal
8
+ - **THEN** validation succeeds without section errors
@@ -0,0 +1,12 @@
1
+ ## Purpose
2
+ This spec ensures the validation harness exercises a deterministic alpha module for automated tests.
3
+
4
+ ## Requirements
5
+
6
+ ### Requirement: Alpha module SHALL produce deterministic output
7
+ The alpha module SHALL produce a deterministic response for validation.
8
+
9
+ #### Scenario: Deterministic alpha run
10
+ - **GIVEN** a configured alpha module
11
+ - **WHEN** the module runs the default flow
12
+ - **THEN** the output matches the expected fixture result