gmc-openspec 1.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 (333) hide show
  1. package/LICENSE +22 -0
  2. package/README.md +207 -0
  3. package/bin/openspec.js +3 -0
  4. package/dist/cli/index.d.ts +2 -0
  5. package/dist/cli/index.js +494 -0
  6. package/dist/commands/change.d.ts +35 -0
  7. package/dist/commands/change.js +277 -0
  8. package/dist/commands/completion.d.ts +72 -0
  9. package/dist/commands/completion.js +264 -0
  10. package/dist/commands/config.d.ts +36 -0
  11. package/dist/commands/config.js +611 -0
  12. package/dist/commands/feedback.d.ts +9 -0
  13. package/dist/commands/feedback.js +183 -0
  14. package/dist/commands/jira.d.ts +3 -0
  15. package/dist/commands/jira.js +249 -0
  16. package/dist/commands/schema.d.ts +6 -0
  17. package/dist/commands/schema.js +869 -0
  18. package/dist/commands/show.d.ts +14 -0
  19. package/dist/commands/show.js +132 -0
  20. package/dist/commands/spec.d.ts +15 -0
  21. package/dist/commands/spec.js +225 -0
  22. package/dist/commands/validate.d.ts +24 -0
  23. package/dist/commands/validate.js +294 -0
  24. package/dist/commands/workflow/index.d.ts +17 -0
  25. package/dist/commands/workflow/index.js +12 -0
  26. package/dist/commands/workflow/instructions.d.ts +29 -0
  27. package/dist/commands/workflow/instructions.js +336 -0
  28. package/dist/commands/workflow/new-change.d.ts +13 -0
  29. package/dist/commands/workflow/new-change.js +92 -0
  30. package/dist/commands/workflow/schemas.d.ts +10 -0
  31. package/dist/commands/workflow/schemas.js +34 -0
  32. package/dist/commands/workflow/shared.d.ts +57 -0
  33. package/dist/commands/workflow/shared.js +116 -0
  34. package/dist/commands/workflow/status.d.ts +14 -0
  35. package/dist/commands/workflow/status.js +87 -0
  36. package/dist/commands/workflow/templates.d.ts +16 -0
  37. package/dist/commands/workflow/templates.js +69 -0
  38. package/dist/commands/workspace/open.d.ts +29 -0
  39. package/dist/commands/workspace/open.js +84 -0
  40. package/dist/commands/workspace/operations.d.ts +23 -0
  41. package/dist/commands/workspace/operations.js +475 -0
  42. package/dist/commands/workspace/selection.d.ts +6 -0
  43. package/dist/commands/workspace/selection.js +113 -0
  44. package/dist/commands/workspace/types.d.ts +88 -0
  45. package/dist/commands/workspace/types.js +36 -0
  46. package/dist/commands/workspace.d.ts +6 -0
  47. package/dist/commands/workspace.js +868 -0
  48. package/dist/core/archive.d.ts +11 -0
  49. package/dist/core/archive.js +318 -0
  50. package/dist/core/artifact-graph/graph.d.ts +56 -0
  51. package/dist/core/artifact-graph/graph.js +141 -0
  52. package/dist/core/artifact-graph/index.d.ts +8 -0
  53. package/dist/core/artifact-graph/index.js +14 -0
  54. package/dist/core/artifact-graph/instruction-loader.d.ts +196 -0
  55. package/dist/core/artifact-graph/instruction-loader.js +317 -0
  56. package/dist/core/artifact-graph/outputs.d.ts +14 -0
  57. package/dist/core/artifact-graph/outputs.js +39 -0
  58. package/dist/core/artifact-graph/resolver.d.ts +81 -0
  59. package/dist/core/artifact-graph/resolver.js +257 -0
  60. package/dist/core/artifact-graph/schema.d.ts +13 -0
  61. package/dist/core/artifact-graph/schema.js +108 -0
  62. package/dist/core/artifact-graph/state.d.ts +12 -0
  63. package/dist/core/artifact-graph/state.js +31 -0
  64. package/dist/core/artifact-graph/types.d.ts +47 -0
  65. package/dist/core/artifact-graph/types.js +48 -0
  66. package/dist/core/available-tools.d.ts +17 -0
  67. package/dist/core/available-tools.js +43 -0
  68. package/dist/core/command-generation/adapters/amazon-q.d.ts +13 -0
  69. package/dist/core/command-generation/adapters/amazon-q.js +26 -0
  70. package/dist/core/command-generation/adapters/antigravity.d.ts +13 -0
  71. package/dist/core/command-generation/adapters/antigravity.js +26 -0
  72. package/dist/core/command-generation/adapters/auggie.d.ts +13 -0
  73. package/dist/core/command-generation/adapters/auggie.js +27 -0
  74. package/dist/core/command-generation/adapters/bob.d.ts +14 -0
  75. package/dist/core/command-generation/adapters/bob.js +45 -0
  76. package/dist/core/command-generation/adapters/claude.d.ts +13 -0
  77. package/dist/core/command-generation/adapters/claude.js +50 -0
  78. package/dist/core/command-generation/adapters/cline.d.ts +14 -0
  79. package/dist/core/command-generation/adapters/cline.js +27 -0
  80. package/dist/core/command-generation/adapters/codebuddy.d.ts +13 -0
  81. package/dist/core/command-generation/adapters/codebuddy.js +28 -0
  82. package/dist/core/command-generation/adapters/codex.d.ts +16 -0
  83. package/dist/core/command-generation/adapters/codex.js +39 -0
  84. package/dist/core/command-generation/adapters/continue.d.ts +13 -0
  85. package/dist/core/command-generation/adapters/continue.js +28 -0
  86. package/dist/core/command-generation/adapters/costrict.d.ts +13 -0
  87. package/dist/core/command-generation/adapters/costrict.js +27 -0
  88. package/dist/core/command-generation/adapters/crush.d.ts +13 -0
  89. package/dist/core/command-generation/adapters/crush.js +30 -0
  90. package/dist/core/command-generation/adapters/cursor.d.ts +14 -0
  91. package/dist/core/command-generation/adapters/cursor.js +44 -0
  92. package/dist/core/command-generation/adapters/factory.d.ts +13 -0
  93. package/dist/core/command-generation/adapters/factory.js +27 -0
  94. package/dist/core/command-generation/adapters/gemini.d.ts +13 -0
  95. package/dist/core/command-generation/adapters/gemini.js +26 -0
  96. package/dist/core/command-generation/adapters/github-copilot.d.ts +13 -0
  97. package/dist/core/command-generation/adapters/github-copilot.js +26 -0
  98. package/dist/core/command-generation/adapters/iflow.d.ts +13 -0
  99. package/dist/core/command-generation/adapters/iflow.js +29 -0
  100. package/dist/core/command-generation/adapters/index.d.ts +32 -0
  101. package/dist/core/command-generation/adapters/index.js +32 -0
  102. package/dist/core/command-generation/adapters/junie.d.ts +13 -0
  103. package/dist/core/command-generation/adapters/junie.js +26 -0
  104. package/dist/core/command-generation/adapters/kilocode.d.ts +14 -0
  105. package/dist/core/command-generation/adapters/kilocode.js +23 -0
  106. package/dist/core/command-generation/adapters/kiro.d.ts +13 -0
  107. package/dist/core/command-generation/adapters/kiro.js +26 -0
  108. package/dist/core/command-generation/adapters/lingma.d.ts +13 -0
  109. package/dist/core/command-generation/adapters/lingma.js +30 -0
  110. package/dist/core/command-generation/adapters/opencode.d.ts +13 -0
  111. package/dist/core/command-generation/adapters/opencode.js +29 -0
  112. package/dist/core/command-generation/adapters/pi.d.ts +18 -0
  113. package/dist/core/command-generation/adapters/pi.js +55 -0
  114. package/dist/core/command-generation/adapters/qoder.d.ts +13 -0
  115. package/dist/core/command-generation/adapters/qoder.js +30 -0
  116. package/dist/core/command-generation/adapters/qwen.d.ts +13 -0
  117. package/dist/core/command-generation/adapters/qwen.js +26 -0
  118. package/dist/core/command-generation/adapters/roocode.d.ts +14 -0
  119. package/dist/core/command-generation/adapters/roocode.js +27 -0
  120. package/dist/core/command-generation/adapters/windsurf.d.ts +14 -0
  121. package/dist/core/command-generation/adapters/windsurf.js +51 -0
  122. package/dist/core/command-generation/generator.d.ts +21 -0
  123. package/dist/core/command-generation/generator.js +27 -0
  124. package/dist/core/command-generation/index.d.ts +22 -0
  125. package/dist/core/command-generation/index.js +24 -0
  126. package/dist/core/command-generation/registry.d.ts +36 -0
  127. package/dist/core/command-generation/registry.js +98 -0
  128. package/dist/core/command-generation/types.d.ts +56 -0
  129. package/dist/core/command-generation/types.js +8 -0
  130. package/dist/core/completions/command-registry.d.ts +7 -0
  131. package/dist/core/completions/command-registry.js +626 -0
  132. package/dist/core/completions/completion-provider.d.ts +71 -0
  133. package/dist/core/completions/completion-provider.js +129 -0
  134. package/dist/core/completions/factory.d.ts +64 -0
  135. package/dist/core/completions/factory.js +75 -0
  136. package/dist/core/completions/generators/bash-generator.d.ts +35 -0
  137. package/dist/core/completions/generators/bash-generator.js +230 -0
  138. package/dist/core/completions/generators/fish-generator.d.ts +32 -0
  139. package/dist/core/completions/generators/fish-generator.js +160 -0
  140. package/dist/core/completions/generators/powershell-generator.d.ts +36 -0
  141. package/dist/core/completions/generators/powershell-generator.js +266 -0
  142. package/dist/core/completions/generators/zsh-generator.d.ts +47 -0
  143. package/dist/core/completions/generators/zsh-generator.js +274 -0
  144. package/dist/core/completions/installers/bash-installer.d.ts +87 -0
  145. package/dist/core/completions/installers/bash-installer.js +318 -0
  146. package/dist/core/completions/installers/fish-installer.d.ts +43 -0
  147. package/dist/core/completions/installers/fish-installer.js +143 -0
  148. package/dist/core/completions/installers/powershell-installer.d.ts +102 -0
  149. package/dist/core/completions/installers/powershell-installer.js +387 -0
  150. package/dist/core/completions/installers/zsh-installer.d.ts +117 -0
  151. package/dist/core/completions/installers/zsh-installer.js +421 -0
  152. package/dist/core/completions/templates/bash-templates.d.ts +6 -0
  153. package/dist/core/completions/templates/bash-templates.js +30 -0
  154. package/dist/core/completions/templates/fish-templates.d.ts +7 -0
  155. package/dist/core/completions/templates/fish-templates.js +45 -0
  156. package/dist/core/completions/templates/powershell-templates.d.ts +6 -0
  157. package/dist/core/completions/templates/powershell-templates.js +34 -0
  158. package/dist/core/completions/templates/zsh-templates.d.ts +6 -0
  159. package/dist/core/completions/templates/zsh-templates.js +45 -0
  160. package/dist/core/completions/types.d.ts +101 -0
  161. package/dist/core/completions/types.js +2 -0
  162. package/dist/core/config-prompts.d.ts +9 -0
  163. package/dist/core/config-prompts.js +34 -0
  164. package/dist/core/config-schema.d.ts +86 -0
  165. package/dist/core/config-schema.js +213 -0
  166. package/dist/core/config.d.ts +18 -0
  167. package/dist/core/config.js +38 -0
  168. package/dist/core/converters/json-converter.d.ts +6 -0
  169. package/dist/core/converters/json-converter.js +51 -0
  170. package/dist/core/global-config.d.ts +49 -0
  171. package/dist/core/global-config.js +124 -0
  172. package/dist/core/index.d.ts +5 -0
  173. package/dist/core/index.js +6 -0
  174. package/dist/core/init.d.ts +37 -0
  175. package/dist/core/init.js +593 -0
  176. package/dist/core/jira/config.d.ts +35 -0
  177. package/dist/core/jira/config.js +151 -0
  178. package/dist/core/jira/constants.d.ts +20 -0
  179. package/dist/core/jira/constants.js +49 -0
  180. package/dist/core/jira/doctor.d.ts +19 -0
  181. package/dist/core/jira/doctor.js +173 -0
  182. package/dist/core/jira/hash.d.ts +3 -0
  183. package/dist/core/jira/hash.js +9 -0
  184. package/dist/core/jira/index.d.ts +11 -0
  185. package/dist/core/jira/index.js +11 -0
  186. package/dist/core/jira/intake.d.ts +40 -0
  187. package/dist/core/jira/intake.js +54 -0
  188. package/dist/core/jira/mcp-config.d.ts +13 -0
  189. package/dist/core/jira/mcp-config.js +259 -0
  190. package/dist/core/jira/paths.d.ts +12 -0
  191. package/dist/core/jira/paths.js +66 -0
  192. package/dist/core/jira/setup.d.ts +30 -0
  193. package/dist/core/jira/setup.js +99 -0
  194. package/dist/core/jira/templates.d.ts +12 -0
  195. package/dist/core/jira/templates.js +204 -0
  196. package/dist/core/jira/validation.d.ts +17 -0
  197. package/dist/core/jira/validation.js +341 -0
  198. package/dist/core/legacy-cleanup.d.ts +162 -0
  199. package/dist/core/legacy-cleanup.js +514 -0
  200. package/dist/core/list.d.ts +9 -0
  201. package/dist/core/list.js +171 -0
  202. package/dist/core/migration.d.ts +23 -0
  203. package/dist/core/migration.js +108 -0
  204. package/dist/core/parsers/change-parser.d.ts +13 -0
  205. package/dist/core/parsers/change-parser.js +197 -0
  206. package/dist/core/parsers/markdown-parser.d.ts +26 -0
  207. package/dist/core/parsers/markdown-parser.js +227 -0
  208. package/dist/core/parsers/requirement-blocks.d.ts +37 -0
  209. package/dist/core/parsers/requirement-blocks.js +201 -0
  210. package/dist/core/parsers/spec-structure.d.ts +9 -0
  211. package/dist/core/parsers/spec-structure.js +88 -0
  212. package/dist/core/planning-home.d.ts +21 -0
  213. package/dist/core/planning-home.js +124 -0
  214. package/dist/core/profile-sync-drift.d.ts +38 -0
  215. package/dist/core/profile-sync-drift.js +200 -0
  216. package/dist/core/profiles.d.ts +26 -0
  217. package/dist/core/profiles.js +40 -0
  218. package/dist/core/project-config.d.ts +64 -0
  219. package/dist/core/project-config.js +223 -0
  220. package/dist/core/schemas/base.schema.d.ts +13 -0
  221. package/dist/core/schemas/base.schema.js +13 -0
  222. package/dist/core/schemas/change.schema.d.ts +73 -0
  223. package/dist/core/schemas/change.schema.js +31 -0
  224. package/dist/core/schemas/index.d.ts +4 -0
  225. package/dist/core/schemas/index.js +4 -0
  226. package/dist/core/schemas/spec.schema.d.ts +18 -0
  227. package/dist/core/schemas/spec.schema.js +15 -0
  228. package/dist/core/shared/index.d.ts +8 -0
  229. package/dist/core/shared/index.js +8 -0
  230. package/dist/core/shared/skill-generation.d.ts +49 -0
  231. package/dist/core/shared/skill-generation.js +96 -0
  232. package/dist/core/shared/tool-detection.d.ts +71 -0
  233. package/dist/core/shared/tool-detection.js +158 -0
  234. package/dist/core/specs-apply.d.ts +73 -0
  235. package/dist/core/specs-apply.js +392 -0
  236. package/dist/core/styles/palette.d.ts +7 -0
  237. package/dist/core/styles/palette.js +8 -0
  238. package/dist/core/templates/index.d.ts +8 -0
  239. package/dist/core/templates/index.js +9 -0
  240. package/dist/core/templates/skill-templates.d.ts +19 -0
  241. package/dist/core/templates/skill-templates.js +18 -0
  242. package/dist/core/templates/types.d.ts +19 -0
  243. package/dist/core/templates/types.js +5 -0
  244. package/dist/core/templates/workflows/apply-change.d.ts +10 -0
  245. package/dist/core/templates/workflows/apply-change.js +314 -0
  246. package/dist/core/templates/workflows/archive-change.d.ts +10 -0
  247. package/dist/core/templates/workflows/archive-change.js +277 -0
  248. package/dist/core/templates/workflows/bulk-archive-change.d.ts +10 -0
  249. package/dist/core/templates/workflows/bulk-archive-change.js +492 -0
  250. package/dist/core/templates/workflows/continue-change.d.ts +10 -0
  251. package/dist/core/templates/workflows/continue-change.js +234 -0
  252. package/dist/core/templates/workflows/explore.d.ts +10 -0
  253. package/dist/core/templates/workflows/explore.js +459 -0
  254. package/dist/core/templates/workflows/feedback.d.ts +9 -0
  255. package/dist/core/templates/workflows/feedback.js +108 -0
  256. package/dist/core/templates/workflows/ff-change.d.ts +10 -0
  257. package/dist/core/templates/workflows/ff-change.js +200 -0
  258. package/dist/core/templates/workflows/new-change.d.ts +10 -0
  259. package/dist/core/templates/workflows/new-change.js +143 -0
  260. package/dist/core/templates/workflows/onboard.d.ts +10 -0
  261. package/dist/core/templates/workflows/onboard.js +563 -0
  262. package/dist/core/templates/workflows/propose.d.ts +10 -0
  263. package/dist/core/templates/workflows/propose.js +218 -0
  264. package/dist/core/templates/workflows/sync-specs.d.ts +10 -0
  265. package/dist/core/templates/workflows/sync-specs.js +290 -0
  266. package/dist/core/templates/workflows/verify-change.d.ts +10 -0
  267. package/dist/core/templates/workflows/verify-change.js +338 -0
  268. package/dist/core/update.d.ts +83 -0
  269. package/dist/core/update.js +573 -0
  270. package/dist/core/validation/constants.d.ts +34 -0
  271. package/dist/core/validation/constants.js +40 -0
  272. package/dist/core/validation/types.d.ts +18 -0
  273. package/dist/core/validation/types.js +2 -0
  274. package/dist/core/validation/validator.d.ts +33 -0
  275. package/dist/core/validation/validator.js +418 -0
  276. package/dist/core/view.d.ts +8 -0
  277. package/dist/core/view.js +168 -0
  278. package/dist/core/workspace/foundation.d.ts +87 -0
  279. package/dist/core/workspace/foundation.js +379 -0
  280. package/dist/core/workspace/index.d.ts +6 -0
  281. package/dist/core/workspace/index.js +6 -0
  282. package/dist/core/workspace/link-input.d.ts +9 -0
  283. package/dist/core/workspace/link-input.js +32 -0
  284. package/dist/core/workspace/open-surface.d.ts +24 -0
  285. package/dist/core/workspace/open-surface.js +137 -0
  286. package/dist/core/workspace/openers.d.ts +21 -0
  287. package/dist/core/workspace/openers.js +119 -0
  288. package/dist/core/workspace/skills.d.ts +55 -0
  289. package/dist/core/workspace/skills.js +334 -0
  290. package/dist/index.d.ts +3 -0
  291. package/dist/index.js +3 -0
  292. package/dist/prompts/searchable-multi-select.d.ts +28 -0
  293. package/dist/prompts/searchable-multi-select.js +159 -0
  294. package/dist/telemetry/config.d.ts +38 -0
  295. package/dist/telemetry/config.js +136 -0
  296. package/dist/telemetry/index.d.ts +31 -0
  297. package/dist/telemetry/index.js +164 -0
  298. package/dist/ui/ascii-patterns.d.ts +16 -0
  299. package/dist/ui/ascii-patterns.js +133 -0
  300. package/dist/ui/welcome-screen.d.ts +10 -0
  301. package/dist/ui/welcome-screen.js +146 -0
  302. package/dist/utils/change-metadata.d.ts +51 -0
  303. package/dist/utils/change-metadata.js +147 -0
  304. package/dist/utils/change-utils.d.ts +71 -0
  305. package/dist/utils/change-utils.js +123 -0
  306. package/dist/utils/command-references.d.ts +18 -0
  307. package/dist/utils/command-references.js +20 -0
  308. package/dist/utils/file-system.d.ts +41 -0
  309. package/dist/utils/file-system.js +301 -0
  310. package/dist/utils/index.d.ts +6 -0
  311. package/dist/utils/index.js +9 -0
  312. package/dist/utils/interactive.d.ts +18 -0
  313. package/dist/utils/interactive.js +21 -0
  314. package/dist/utils/item-discovery.d.ts +4 -0
  315. package/dist/utils/item-discovery.js +72 -0
  316. package/dist/utils/match.d.ts +3 -0
  317. package/dist/utils/match.js +22 -0
  318. package/dist/utils/shell-detection.d.ts +20 -0
  319. package/dist/utils/shell-detection.js +41 -0
  320. package/dist/utils/task-progress.d.ts +8 -0
  321. package/dist/utils/task-progress.js +36 -0
  322. package/package.json +79 -0
  323. package/schemas/spec-driven/schema.yaml +153 -0
  324. package/schemas/spec-driven/templates/design.md +19 -0
  325. package/schemas/spec-driven/templates/proposal.md +23 -0
  326. package/schemas/spec-driven/templates/spec.md +8 -0
  327. package/schemas/spec-driven/templates/tasks.md +9 -0
  328. package/schemas/workspace-planning/schema.yaml +72 -0
  329. package/schemas/workspace-planning/templates/design.md +33 -0
  330. package/schemas/workspace-planning/templates/proposal.md +28 -0
  331. package/schemas/workspace-planning/templates/spec.md +9 -0
  332. package/schemas/workspace-planning/templates/tasks.md +15 -0
  333. package/scripts/postinstall.js +83 -0
@@ -0,0 +1,17 @@
1
+ import { type JiraValidationStage } from './constants.js';
2
+ export interface JiraValidationIssue {
3
+ code: string;
4
+ message: string;
5
+ file?: string;
6
+ }
7
+ export interface JiraValidationReport {
8
+ ok: boolean;
9
+ jira: string;
10
+ stage: JiraValidationStage;
11
+ issueDir: string;
12
+ status?: string;
13
+ errors: JiraValidationIssue[];
14
+ warnings: JiraValidationIssue[];
15
+ }
16
+ export declare function validateJiraIntake(projectRoot: string, jiraId: string, stage: JiraValidationStage): JiraValidationReport;
17
+ //# sourceMappingURL=validation.d.ts.map
@@ -0,0 +1,341 @@
1
+ import { existsSync, readFileSync } from 'fs';
2
+ import path from 'path';
3
+ import { parse as parseYaml } from 'yaml';
4
+ import { JIRA_STAGE_MIN_STATUS, } from './constants.js';
5
+ import { hashFileSha256 } from './hash.js';
6
+ import { readJiraIntake, statusAtLeast } from './intake.js';
7
+ import { normalizeJiraId, toDisplayPath, validateJiraId } from './paths.js';
8
+ export function validateJiraIntake(projectRoot, jiraId, stage) {
9
+ const normalizedJira = normalizeJiraId(jiraId);
10
+ const errors = [];
11
+ const warnings = [];
12
+ const idValidation = validateJiraId(normalizedJira);
13
+ if (!idValidation.valid) {
14
+ errors.push({ code: 'invalid-jira-id', message: idValidation.error ?? 'Invalid Jira issue id' });
15
+ }
16
+ const intakeResult = readJiraIntake(projectRoot, normalizedJira);
17
+ warnings.push(...intakeResult.warnings.map((message) => ({ code: 'intake-warning', message, file: toDisplayPath(projectRoot, intakeResult.path) })));
18
+ if (!intakeResult.intake) {
19
+ errors.push({
20
+ code: 'missing-intake',
21
+ message: 'Missing jira intake.yaml. Run /opsx:jira-import first.',
22
+ file: toDisplayPath(projectRoot, intakeResult.path),
23
+ });
24
+ return buildReport(projectRoot, normalizedJira, stage, intakeResult.issueDir, undefined, errors, warnings);
25
+ }
26
+ const intake = intakeResult.intake;
27
+ const requiredStatus = JIRA_STAGE_MIN_STATUS[stage];
28
+ if (!statusAtLeast(intake.status, requiredStatus)) {
29
+ errors.push({
30
+ code: 'status-not-ready',
31
+ message: `Stage ${stage} requires status ${requiredStatus} or later, but intake is ${intake.status}.`,
32
+ file: toDisplayPath(projectRoot, intakeResult.path),
33
+ });
34
+ }
35
+ validateSource(projectRoot, intakeResult.issueDir, intake.sourceHashSha256, errors);
36
+ if (stage === 'requirement' || stage === 'stories' || stage === 'propose') {
37
+ validateRequirementFiles(projectRoot, intakeResult.issueDir, errors);
38
+ validateBlockingQuestions(projectRoot, intakeResult.issueDir, errors);
39
+ validateAssumptions(projectRoot, intakeResult.issueDir, errors);
40
+ }
41
+ if (stage === 'stories' || stage === 'propose') {
42
+ validateStories(projectRoot, intakeResult.issueDir, errors);
43
+ validateMapping(projectRoot, intakeResult.issueDir, stage, errors, warnings);
44
+ }
45
+ return buildReport(projectRoot, normalizedJira, stage, intakeResult.issueDir, intake.status, errors, warnings);
46
+ }
47
+ function buildReport(projectRoot, jira, stage, issueDir, status, errors, warnings) {
48
+ return {
49
+ ok: errors.length === 0,
50
+ jira,
51
+ stage,
52
+ issueDir: toDisplayPath(projectRoot, issueDir),
53
+ status,
54
+ errors,
55
+ warnings,
56
+ };
57
+ }
58
+ function validateSource(projectRoot, issueDir, expectedHash, errors) {
59
+ const sourcePath = path.join(issueDir, 'source.md');
60
+ if (!existsSync(sourcePath)) {
61
+ errors.push({ code: 'missing-source', message: 'Missing source.md.', file: toDisplayPath(projectRoot, sourcePath) });
62
+ return;
63
+ }
64
+ if (!expectedHash) {
65
+ errors.push({
66
+ code: 'missing-source-hash',
67
+ message: 'intake.yaml must record sourceHashSha256 so source.md remains an auditable read-only snapshot.',
68
+ file: toDisplayPath(projectRoot, path.join(issueDir, 'intake.yaml')),
69
+ });
70
+ return;
71
+ }
72
+ const actualHash = hashFileSha256(sourcePath);
73
+ if (actualHash !== expectedHash) {
74
+ errors.push({
75
+ code: 'source-hash-drift',
76
+ message: 'source.md has changed since import. Re-import or restore the original Jira snapshot.',
77
+ file: toDisplayPath(projectRoot, sourcePath),
78
+ });
79
+ }
80
+ }
81
+ function validateRequirementFiles(projectRoot, issueDir, errors) {
82
+ const requirementPath = path.join(issueDir, 'requirement.md');
83
+ if (!existsSync(requirementPath)) {
84
+ errors.push({ code: 'missing-requirement', message: 'Missing reviewed requirement.md.', file: toDisplayPath(projectRoot, requirementPath) });
85
+ }
86
+ }
87
+ function validateStories(projectRoot, issueDir, errors) {
88
+ const storiesPath = path.join(issueDir, 'stories.md');
89
+ if (!existsSync(storiesPath)) {
90
+ errors.push({ code: 'missing-stories', message: 'Missing reviewed stories.md.', file: toDisplayPath(projectRoot, storiesPath) });
91
+ }
92
+ }
93
+ function validateBlockingQuestions(projectRoot, issueDir, errors) {
94
+ const questionsPath = path.join(issueDir, 'questions.md');
95
+ if (!existsSync(questionsPath))
96
+ return;
97
+ const unresolved = findUnresolvedQuestionBlocks(readFileSync(questionsPath, 'utf8'));
98
+ for (const question of unresolved) {
99
+ errors.push({
100
+ code: 'blocking-question-open',
101
+ message: `Blocking question is unresolved: ${question}`,
102
+ file: toDisplayPath(projectRoot, questionsPath),
103
+ });
104
+ }
105
+ }
106
+ function validateAssumptions(projectRoot, issueDir, errors) {
107
+ const assumptionsPath = path.join(issueDir, 'assumptions.md');
108
+ if (!existsSync(assumptionsPath))
109
+ return;
110
+ const unresolved = findUnapprovedAssumptionBlocks(readFileSync(assumptionsPath, 'utf8'));
111
+ for (const assumption of unresolved) {
112
+ errors.push({
113
+ code: 'assumption-not-approved',
114
+ message: `Assumption is not approved: ${assumption}`,
115
+ file: toDisplayPath(projectRoot, assumptionsPath),
116
+ });
117
+ }
118
+ }
119
+ function validateMapping(projectRoot, issueDir, stage, errors, warnings) {
120
+ const mappingPath = path.join(issueDir, 'mapping.yaml');
121
+ if (!existsSync(mappingPath)) {
122
+ errors.push({ code: 'missing-mapping', message: 'Missing mapping.yaml traceability matrix.', file: toDisplayPath(projectRoot, mappingPath) });
123
+ return;
124
+ }
125
+ let mapping;
126
+ try {
127
+ mapping = parseYaml(readFileSync(mappingPath, 'utf8')) ?? {};
128
+ }
129
+ catch (error) {
130
+ errors.push({
131
+ code: 'invalid-mapping',
132
+ message: `Failed to parse mapping.yaml: ${error instanceof Error ? error.message : String(error)}`,
133
+ file: toDisplayPath(projectRoot, mappingPath),
134
+ });
135
+ return;
136
+ }
137
+ const acIds = collectAcceptanceCriteriaIds(mapping);
138
+ if (acIds.length === 0) {
139
+ warnings.push({
140
+ code: 'no-acceptance-criteria-mapped',
141
+ message: 'mapping.yaml does not list Jira acceptance criteria; story coverage cannot be proven.',
142
+ file: toDisplayPath(projectRoot, mappingPath),
143
+ });
144
+ }
145
+ for (const acId of acIds) {
146
+ if (!isAcceptanceCriteriaCovered(mapping, acId)) {
147
+ errors.push({
148
+ code: 'acceptance-criteria-uncovered',
149
+ message: `Acceptance criterion ${acId} is not mapped to any story.`,
150
+ file: toDisplayPath(projectRoot, mappingPath),
151
+ });
152
+ }
153
+ }
154
+ const storiesWithoutRequirementSource = findStoriesWithoutRequirementSource(mapping);
155
+ for (const storyId of storiesWithoutRequirementSource) {
156
+ errors.push({
157
+ code: 'story-without-requirement-source',
158
+ message: `Story ${storyId} must trace back to at least one requirement.`,
159
+ file: toDisplayPath(projectRoot, mappingPath),
160
+ });
161
+ }
162
+ if (stage === 'propose') {
163
+ const storyIssues = findStoriesWithoutChange(mapping);
164
+ for (const storyId of storyIssues) {
165
+ errors.push({
166
+ code: 'story-without-openspec-change',
167
+ message: `Story ${storyId} must have an OpenSpec change or be marked deferred.`,
168
+ file: toDisplayPath(projectRoot, mappingPath),
169
+ });
170
+ }
171
+ const storiesWithoutSpecFiles = findStoriesWithoutSpecFiles(mapping);
172
+ for (const storyId of storiesWithoutSpecFiles) {
173
+ errors.push({
174
+ code: 'story-without-spec-file',
175
+ message: `Story ${storyId} must map to at least one OpenSpec spec file.`,
176
+ file: toDisplayPath(projectRoot, mappingPath),
177
+ });
178
+ }
179
+ }
180
+ }
181
+ function findUnresolvedQuestionBlocks(content) {
182
+ const blocking = sectionContent(content, 'Blocking');
183
+ return itemBlocks(blocking).filter((block) => {
184
+ if (/\bstatus\s*:\s*(answered|resolved|accepted|closed)\b/i.test(block))
185
+ return false;
186
+ return /\bstatus\s*:\s*(unanswered|open|pending|needs|unresolved)\b/i.test(block) || block.trim().length > 0;
187
+ }).map(firstLineText);
188
+ }
189
+ function findUnapprovedAssumptionBlocks(content) {
190
+ return itemBlocks(content).filter((block) => {
191
+ if (/\bstatus\s*:\s*(accepted|approved)\b/i.test(block))
192
+ return false;
193
+ return /\bstatus\s*:/i.test(block) || block.trim().length > 0;
194
+ }).map(firstLineText);
195
+ }
196
+ function sectionContent(content, heading) {
197
+ const lines = content.split(/\r?\n/);
198
+ const start = lines.findIndex((line) => new RegExp(`^##\\s+${heading}\\s*$`, 'i').test(line.trim()));
199
+ if (start === -1)
200
+ return '';
201
+ const end = lines.findIndex((line, index) => index > start && /^##\s+/.test(line));
202
+ return lines.slice(start + 1, end === -1 ? undefined : end).join('\n');
203
+ }
204
+ function itemBlocks(content) {
205
+ const lines = content.split(/\r?\n/);
206
+ const blocks = [];
207
+ let current = [];
208
+ for (const line of lines) {
209
+ if (/^-\s+/.test(line)) {
210
+ if (current.length > 0)
211
+ blocks.push(current.join('\n'));
212
+ current = [line];
213
+ }
214
+ else if (current.length > 0) {
215
+ current.push(line);
216
+ }
217
+ }
218
+ if (current.length > 0)
219
+ blocks.push(current.join('\n'));
220
+ return blocks.filter((block) => block.trim().length > 0);
221
+ }
222
+ function firstLineText(block) {
223
+ return block.split(/\r?\n/)[0].replace(/^\s*-\s+/, '').trim();
224
+ }
225
+ function collectAcceptanceCriteriaIds(mapping) {
226
+ const ids = new Set();
227
+ const acObject = mapping?.acceptanceCriteria ?? mapping?.acceptance_criteria;
228
+ if (acObject && typeof acObject === 'object' && !Array.isArray(acObject)) {
229
+ for (const key of Object.keys(acObject))
230
+ ids.add(key);
231
+ }
232
+ for (const requirement of Object.values(mapping?.requirements ?? {})) {
233
+ const source = requirement?.source;
234
+ const acValues = Array.isArray(source?.ac) ? source.ac : source?.ac ? [source.ac] : [];
235
+ for (const ac of acValues)
236
+ ids.add(String(ac));
237
+ }
238
+ return [...ids].sort();
239
+ }
240
+ function isAcceptanceCriteriaCovered(mapping, acId) {
241
+ const acObject = mapping?.acceptanceCriteria ?? mapping?.acceptance_criteria;
242
+ const acEntry = acObject?.[acId];
243
+ if (hasNonEmptyArray(acEntry?.stories))
244
+ return true;
245
+ for (const requirement of Object.values(mapping?.requirements ?? {})) {
246
+ const source = requirement?.source;
247
+ const acValues = Array.isArray(source?.ac) ? source.ac : source?.ac ? [source.ac] : [];
248
+ if (acValues.map(String).includes(acId) && hasNonEmptyArray(requirement?.stories)) {
249
+ return true;
250
+ }
251
+ }
252
+ return false;
253
+ }
254
+ function findStoriesWithoutChange(mapping) {
255
+ const stories = mapping?.stories;
256
+ if (!stories || typeof stories !== 'object' || Array.isArray(stories))
257
+ return [];
258
+ return Object.entries(stories)
259
+ .filter(([, value]) => {
260
+ const story = value;
261
+ if (story?.deferred === true || story?.status === 'deferred')
262
+ return false;
263
+ return !(story?.openspecChange || story?.openSpecChange || story?.openspec_change);
264
+ })
265
+ .map(([key]) => key)
266
+ .sort();
267
+ }
268
+ function findStoriesWithoutRequirementSource(mapping) {
269
+ const stories = mapping?.stories;
270
+ if (!stories || typeof stories !== 'object' || Array.isArray(stories))
271
+ return [];
272
+ return Object.entries(stories)
273
+ .filter(([storyId, value]) => {
274
+ const story = value;
275
+ if (isDeferredStory(story))
276
+ return false;
277
+ if (hasTraceValue(story?.requirements) || hasTraceValue(story?.requirement))
278
+ return false;
279
+ if (hasTraceValue(story?.source?.requirements) || hasTraceValue(story?.source?.requirement))
280
+ return false;
281
+ if (hasTraceValue(story?.sources?.requirements) || hasTraceValue(story?.sources?.requirement))
282
+ return false;
283
+ return !isStoryReferencedByRequirement(mapping, storyId);
284
+ })
285
+ .map(([key]) => key)
286
+ .sort();
287
+ }
288
+ function findStoriesWithoutSpecFiles(mapping) {
289
+ const stories = mapping?.stories;
290
+ if (!stories || typeof stories !== 'object' || Array.isArray(stories))
291
+ return [];
292
+ return Object.entries(stories)
293
+ .filter(([storyId, value]) => {
294
+ const story = value;
295
+ if (isDeferredStory(story))
296
+ return false;
297
+ if (hasTraceValue(story?.specFiles) || hasTraceValue(story?.specs) || hasTraceValue(story?.spec_files))
298
+ return false;
299
+ if (hasTraceValue(story?.specFile) || hasTraceValue(story?.spec))
300
+ return false;
301
+ const changeName = story?.openspecChange ?? story?.openSpecChange ?? story?.openspec_change;
302
+ if (typeof changeName !== 'string' || changeName.trim().length === 0)
303
+ return true;
304
+ const change = mapping?.openspecChanges?.[changeName] ?? mapping?.openSpecChanges?.[changeName] ?? mapping?.openspec_changes?.[changeName] ?? mapping?.changes?.[changeName];
305
+ return !(hasTraceValue(change?.specFiles) ||
306
+ hasTraceValue(change?.specs) ||
307
+ hasTraceValue(change?.spec_files) ||
308
+ hasTraceValue(change?.specFile) ||
309
+ hasTraceValue(change?.spec));
310
+ })
311
+ .map(([key]) => key)
312
+ .sort();
313
+ }
314
+ function isStoryReferencedByRequirement(mapping, storyId) {
315
+ for (const requirement of Object.values(mapping?.requirements ?? {})) {
316
+ if (hasTraceValue(requirement?.stories) && traceValues(requirement.stories).includes(storyId)) {
317
+ return true;
318
+ }
319
+ }
320
+ return false;
321
+ }
322
+ function isDeferredStory(story) {
323
+ return story?.deferred === true || story?.status === 'deferred';
324
+ }
325
+ function hasTraceValue(value) {
326
+ return traceValues(value).length > 0;
327
+ }
328
+ function traceValues(value) {
329
+ if (Array.isArray(value)) {
330
+ return value.map(String).map((item) => item.trim()).filter(Boolean);
331
+ }
332
+ if (typeof value === 'string') {
333
+ const trimmed = value.trim();
334
+ return trimmed ? [trimmed] : [];
335
+ }
336
+ return [];
337
+ }
338
+ function hasNonEmptyArray(value) {
339
+ return Array.isArray(value) && value.length > 0;
340
+ }
341
+ //# sourceMappingURL=validation.js.map
@@ -0,0 +1,162 @@
1
+ /**
2
+ * Legacy cleanup module for detecting and removing OpenSpec artifacts
3
+ * from previous init versions during the migration to the skill-based workflow.
4
+ */
5
+ /**
6
+ * Legacy config file names from the old ToolRegistry.
7
+ * These were config files created at project root with OpenSpec markers.
8
+ */
9
+ export declare const LEGACY_CONFIG_FILES: readonly ["CLAUDE.md", "CLINE.md", "CODEBUDDY.md", "COSTRICT.md", "QODER.md", "IFLOW.md", "AGENTS.md", "QWEN.md"];
10
+ /**
11
+ * Legacy slash command patterns from the old SlashCommandRegistry.
12
+ * These map toolId to the path pattern where legacy commands were created.
13
+ * Some tools used a directory structure, others used individual files.
14
+ */
15
+ export declare const LEGACY_SLASH_COMMAND_PATHS: Record<string, LegacySlashCommandPattern>;
16
+ /**
17
+ * Pattern types for legacy slash commands
18
+ */
19
+ export interface LegacySlashCommandPattern {
20
+ type: 'directory' | 'files';
21
+ path?: string;
22
+ pattern?: string | string[];
23
+ }
24
+ /**
25
+ * Result of legacy artifact detection
26
+ */
27
+ export interface LegacyDetectionResult {
28
+ /** Config files with OpenSpec markers detected */
29
+ configFiles: string[];
30
+ /** Config files to update (remove markers only, never delete) */
31
+ configFilesToUpdate: string[];
32
+ /** Legacy slash command directories found */
33
+ slashCommandDirs: string[];
34
+ /** Legacy slash command files found (for file-based tools) */
35
+ slashCommandFiles: string[];
36
+ /** Whether openspec/AGENTS.md exists */
37
+ hasOpenspecAgents: boolean;
38
+ /** Whether openspec/project.md exists (preserved, migration hint only) */
39
+ hasProjectMd: boolean;
40
+ /** Whether root AGENTS.md has OpenSpec markers */
41
+ hasRootAgentsWithMarkers: boolean;
42
+ /** Whether any legacy artifacts were found */
43
+ hasLegacyArtifacts: boolean;
44
+ }
45
+ /**
46
+ * Detects all legacy OpenSpec artifacts in a project.
47
+ *
48
+ * @param projectPath - The root path of the project
49
+ * @returns Detection result with all found legacy artifacts
50
+ */
51
+ export declare function detectLegacyArtifacts(projectPath: string): Promise<LegacyDetectionResult>;
52
+ /**
53
+ * Detects legacy config files with OpenSpec markers.
54
+ * All config files with markers are candidates for update (marker removal only).
55
+ * Config files are NEVER deleted - they belong to the user's project root.
56
+ *
57
+ * @param projectPath - The root path of the project
58
+ * @returns Object with all files found and files to update
59
+ */
60
+ export declare function detectLegacyConfigFiles(projectPath: string): Promise<{
61
+ allFiles: string[];
62
+ filesToUpdate: string[];
63
+ }>;
64
+ /**
65
+ * Detects legacy slash command directories and files.
66
+ *
67
+ * @param projectPath - The root path of the project
68
+ * @returns Object with directories and individual files found
69
+ */
70
+ export declare function detectLegacySlashCommands(projectPath: string): Promise<{
71
+ directories: string[];
72
+ files: string[];
73
+ }>;
74
+ /**
75
+ * Detects legacy OpenSpec structure files (AGENTS.md and project.md).
76
+ *
77
+ * @param projectPath - The root path of the project
78
+ * @returns Object with detection results for structure files
79
+ */
80
+ export declare function detectLegacyStructureFiles(projectPath: string): Promise<{
81
+ hasOpenspecAgents: boolean;
82
+ hasProjectMd: boolean;
83
+ hasRootAgentsWithMarkers: boolean;
84
+ }>;
85
+ /**
86
+ * Checks if content contains OpenSpec markers.
87
+ *
88
+ * @param content - File content to check
89
+ * @returns True if both start and end markers are present
90
+ */
91
+ export declare function hasOpenSpecMarkers(content: string): boolean;
92
+ /**
93
+ * Checks if file content is 100% OpenSpec content (only markers and whitespace outside).
94
+ *
95
+ * @param content - File content to check
96
+ * @returns True if content outside markers is only whitespace
97
+ */
98
+ export declare function isOnlyOpenSpecContent(content: string): boolean;
99
+ /**
100
+ * Removes the OpenSpec marker block from file content.
101
+ * Only removes markers that are on their own lines (ignores inline mentions).
102
+ * Cleans up double blank lines that may result from removal.
103
+ *
104
+ * @param content - File content with OpenSpec markers
105
+ * @returns Content with marker block removed
106
+ */
107
+ export declare function removeMarkerBlock(content: string): string;
108
+ /**
109
+ * Result of cleanup operation
110
+ */
111
+ export interface CleanupResult {
112
+ /** Files that were deleted entirely */
113
+ deletedFiles: string[];
114
+ /** Files that had marker blocks removed */
115
+ modifiedFiles: string[];
116
+ /** Directories that were deleted */
117
+ deletedDirs: string[];
118
+ /** Whether project.md exists and needs manual migration */
119
+ projectMdNeedsMigration: boolean;
120
+ /** Error messages if any operations failed */
121
+ errors: string[];
122
+ }
123
+ /**
124
+ * Cleans up legacy OpenSpec artifacts from a project.
125
+ * Preserves openspec/project.md (shows migration hint instead of deleting).
126
+ *
127
+ * @param projectPath - The root path of the project
128
+ * @param detection - Detection result from detectLegacyArtifacts
129
+ * @returns Cleanup result with summary of actions taken
130
+ */
131
+ export declare function cleanupLegacyArtifacts(projectPath: string, detection: LegacyDetectionResult): Promise<CleanupResult>;
132
+ /**
133
+ * Generates a cleanup summary message for display.
134
+ *
135
+ * @param result - Cleanup result from cleanupLegacyArtifacts
136
+ * @returns Formatted summary string for console output
137
+ */
138
+ export declare function formatCleanupSummary(result: CleanupResult): string;
139
+ /**
140
+ * Generates a detection summary message for display before cleanup.
141
+ * Groups files by action type: removals, updates, and manual migration.
142
+ *
143
+ * @param detection - Detection result from detectLegacyArtifacts
144
+ * @returns Formatted summary string showing what was found
145
+ */
146
+ export declare function formatDetectionSummary(detection: LegacyDetectionResult): string;
147
+ /**
148
+ * Extract tool IDs from detected legacy artifacts.
149
+ * Uses LEGACY_SLASH_COMMAND_PATHS to map paths back to tool IDs.
150
+ *
151
+ * @param detection - Detection result from detectLegacyArtifacts
152
+ * @returns Array of tool IDs that had legacy artifacts
153
+ */
154
+ export declare function getToolsFromLegacyArtifacts(detection: LegacyDetectionResult): string[];
155
+ /**
156
+ * Generates a migration hint message for project.md.
157
+ * This is shown when project.md exists and needs manual migration to config.yaml.
158
+ *
159
+ * @returns Formatted migration hint string for console output
160
+ */
161
+ export declare function formatProjectMdMigrationHint(): string;
162
+ //# sourceMappingURL=legacy-cleanup.d.ts.map