@kbdavis07/openspec 1.5.0-nov.1

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 (352) hide show
  1. package/LICENSE +22 -0
  2. package/README.md +239 -0
  3. package/bin/openspec.js +5 -0
  4. package/dist/cli/index.d.ts +10 -0
  5. package/dist/cli/index.js +544 -0
  6. package/dist/commands/change.d.ts +38 -0
  7. package/dist/commands/change.js +245 -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 +552 -0
  12. package/dist/commands/context.d.ts +3 -0
  13. package/dist/commands/context.js +155 -0
  14. package/dist/commands/doctor.d.ts +8 -0
  15. package/dist/commands/doctor.js +163 -0
  16. package/dist/commands/feedback.d.ts +9 -0
  17. package/dist/commands/feedback.js +183 -0
  18. package/dist/commands/schema.d.ts +6 -0
  19. package/dist/commands/schema.js +869 -0
  20. package/dist/commands/shared-gather.d.ts +14 -0
  21. package/dist/commands/shared-gather.js +31 -0
  22. package/dist/commands/shared-output.d.ts +18 -0
  23. package/dist/commands/shared-output.js +61 -0
  24. package/dist/commands/show.d.ts +19 -0
  25. package/dist/commands/show.js +177 -0
  26. package/dist/commands/spec.d.ts +19 -0
  27. package/dist/commands/spec.js +236 -0
  28. package/dist/commands/store.d.ts +3 -0
  29. package/dist/commands/store.js +547 -0
  30. package/dist/commands/validate.d.ts +34 -0
  31. package/dist/commands/validate.js +342 -0
  32. package/dist/commands/workflow/index.d.ts +17 -0
  33. package/dist/commands/workflow/index.js +12 -0
  34. package/dist/commands/workflow/instructions.d.ts +39 -0
  35. package/dist/commands/workflow/instructions.js +393 -0
  36. package/dist/commands/workflow/new-change.d.ts +20 -0
  37. package/dist/commands/workflow/new-change.js +109 -0
  38. package/dist/commands/workflow/schemas.d.ts +10 -0
  39. package/dist/commands/workflow/schemas.js +34 -0
  40. package/dist/commands/workflow/shared.d.ts +74 -0
  41. package/dist/commands/workflow/shared.js +170 -0
  42. package/dist/commands/workflow/status.d.ts +16 -0
  43. package/dist/commands/workflow/status.js +92 -0
  44. package/dist/commands/workflow/templates.d.ts +16 -0
  45. package/dist/commands/workflow/templates.js +69 -0
  46. package/dist/commands/workset-input.d.ts +19 -0
  47. package/dist/commands/workset-input.js +112 -0
  48. package/dist/commands/workset-prompts.d.ts +12 -0
  49. package/dist/commands/workset-prompts.js +143 -0
  50. package/dist/commands/workset.d.ts +25 -0
  51. package/dist/commands/workset.js +446 -0
  52. package/dist/core/archive.d.ts +22 -0
  53. package/dist/core/archive.js +496 -0
  54. package/dist/core/artifact-graph/graph.d.ts +56 -0
  55. package/dist/core/artifact-graph/graph.js +141 -0
  56. package/dist/core/artifact-graph/index.d.ts +9 -0
  57. package/dist/core/artifact-graph/index.js +14 -0
  58. package/dist/core/artifact-graph/instruction-loader.d.ts +188 -0
  59. package/dist/core/artifact-graph/instruction-loader.js +233 -0
  60. package/dist/core/artifact-graph/outputs.d.ts +14 -0
  61. package/dist/core/artifact-graph/outputs.js +39 -0
  62. package/dist/core/artifact-graph/resolver.d.ts +81 -0
  63. package/dist/core/artifact-graph/resolver.js +257 -0
  64. package/dist/core/artifact-graph/schema.d.ts +13 -0
  65. package/dist/core/artifact-graph/schema.js +108 -0
  66. package/dist/core/artifact-graph/state.d.ts +12 -0
  67. package/dist/core/artifact-graph/state.js +31 -0
  68. package/dist/core/artifact-graph/types.d.ts +40 -0
  69. package/dist/core/artifact-graph/types.js +29 -0
  70. package/dist/core/available-tools.d.ts +17 -0
  71. package/dist/core/available-tools.js +43 -0
  72. package/dist/core/change-metadata/index.d.ts +2 -0
  73. package/dist/core/change-metadata/index.js +2 -0
  74. package/dist/core/change-metadata/schema.d.ts +19 -0
  75. package/dist/core/change-metadata/schema.js +30 -0
  76. package/dist/core/change-status-policy.d.ts +37 -0
  77. package/dist/core/change-status-policy.js +35 -0
  78. package/dist/core/command-generation/adapters/amazon-q.d.ts +13 -0
  79. package/dist/core/command-generation/adapters/amazon-q.js +26 -0
  80. package/dist/core/command-generation/adapters/antigravity.d.ts +13 -0
  81. package/dist/core/command-generation/adapters/antigravity.js +26 -0
  82. package/dist/core/command-generation/adapters/auggie.d.ts +13 -0
  83. package/dist/core/command-generation/adapters/auggie.js +27 -0
  84. package/dist/core/command-generation/adapters/bob.d.ts +14 -0
  85. package/dist/core/command-generation/adapters/bob.js +32 -0
  86. package/dist/core/command-generation/adapters/claude.d.ts +13 -0
  87. package/dist/core/command-generation/adapters/claude.js +39 -0
  88. package/dist/core/command-generation/adapters/cline.d.ts +14 -0
  89. package/dist/core/command-generation/adapters/cline.js +27 -0
  90. package/dist/core/command-generation/adapters/codebuddy.d.ts +13 -0
  91. package/dist/core/command-generation/adapters/codebuddy.js +28 -0
  92. package/dist/core/command-generation/adapters/codex.d.ts +16 -0
  93. package/dist/core/command-generation/adapters/codex.js +39 -0
  94. package/dist/core/command-generation/adapters/continue.d.ts +13 -0
  95. package/dist/core/command-generation/adapters/continue.js +28 -0
  96. package/dist/core/command-generation/adapters/costrict.d.ts +13 -0
  97. package/dist/core/command-generation/adapters/costrict.js +27 -0
  98. package/dist/core/command-generation/adapters/crush.d.ts +13 -0
  99. package/dist/core/command-generation/adapters/crush.js +30 -0
  100. package/dist/core/command-generation/adapters/cursor.d.ts +14 -0
  101. package/dist/core/command-generation/adapters/cursor.js +31 -0
  102. package/dist/core/command-generation/adapters/factory.d.ts +13 -0
  103. package/dist/core/command-generation/adapters/factory.js +27 -0
  104. package/dist/core/command-generation/adapters/gemini.d.ts +13 -0
  105. package/dist/core/command-generation/adapters/gemini.js +26 -0
  106. package/dist/core/command-generation/adapters/github-copilot.d.ts +13 -0
  107. package/dist/core/command-generation/adapters/github-copilot.js +26 -0
  108. package/dist/core/command-generation/adapters/iflow.d.ts +13 -0
  109. package/dist/core/command-generation/adapters/iflow.js +29 -0
  110. package/dist/core/command-generation/adapters/index.d.ts +34 -0
  111. package/dist/core/command-generation/adapters/index.js +34 -0
  112. package/dist/core/command-generation/adapters/junie.d.ts +13 -0
  113. package/dist/core/command-generation/adapters/junie.js +26 -0
  114. package/dist/core/command-generation/adapters/kilocode.d.ts +14 -0
  115. package/dist/core/command-generation/adapters/kilocode.js +23 -0
  116. package/dist/core/command-generation/adapters/kiro.d.ts +13 -0
  117. package/dist/core/command-generation/adapters/kiro.js +26 -0
  118. package/dist/core/command-generation/adapters/lingma.d.ts +13 -0
  119. package/dist/core/command-generation/adapters/lingma.js +30 -0
  120. package/dist/core/command-generation/adapters/oh-my-pi.d.ts +21 -0
  121. package/dist/core/command-generation/adapters/oh-my-pi.js +44 -0
  122. package/dist/core/command-generation/adapters/opencode.d.ts +13 -0
  123. package/dist/core/command-generation/adapters/opencode.js +29 -0
  124. package/dist/core/command-generation/adapters/pi.d.ts +18 -0
  125. package/dist/core/command-generation/adapters/pi.js +42 -0
  126. package/dist/core/command-generation/adapters/qoder.d.ts +13 -0
  127. package/dist/core/command-generation/adapters/qoder.js +30 -0
  128. package/dist/core/command-generation/adapters/qwen.d.ts +13 -0
  129. package/dist/core/command-generation/adapters/qwen.js +26 -0
  130. package/dist/core/command-generation/adapters/roocode.d.ts +14 -0
  131. package/dist/core/command-generation/adapters/roocode.js +27 -0
  132. package/dist/core/command-generation/adapters/trae.d.ts +13 -0
  133. package/dist/core/command-generation/adapters/trae.js +48 -0
  134. package/dist/core/command-generation/adapters/windsurf.d.ts +14 -0
  135. package/dist/core/command-generation/adapters/windsurf.js +38 -0
  136. package/dist/core/command-generation/generator.d.ts +21 -0
  137. package/dist/core/command-generation/generator.js +27 -0
  138. package/dist/core/command-generation/index.d.ts +22 -0
  139. package/dist/core/command-generation/index.js +24 -0
  140. package/dist/core/command-generation/registry.d.ts +36 -0
  141. package/dist/core/command-generation/registry.js +102 -0
  142. package/dist/core/command-generation/types.d.ts +56 -0
  143. package/dist/core/command-generation/types.js +8 -0
  144. package/dist/core/command-generation/yaml.d.ts +22 -0
  145. package/dist/core/command-generation/yaml.js +38 -0
  146. package/dist/core/completions/command-registry.d.ts +3 -0
  147. package/dist/core/completions/command-registry.js +759 -0
  148. package/dist/core/completions/completion-provider.d.ts +71 -0
  149. package/dist/core/completions/completion-provider.js +129 -0
  150. package/dist/core/completions/factory.d.ts +64 -0
  151. package/dist/core/completions/factory.js +75 -0
  152. package/dist/core/completions/generators/bash-generator.d.ts +35 -0
  153. package/dist/core/completions/generators/bash-generator.js +230 -0
  154. package/dist/core/completions/generators/fish-generator.d.ts +32 -0
  155. package/dist/core/completions/generators/fish-generator.js +160 -0
  156. package/dist/core/completions/generators/powershell-generator.d.ts +36 -0
  157. package/dist/core/completions/generators/powershell-generator.js +266 -0
  158. package/dist/core/completions/generators/zsh-generator.d.ts +47 -0
  159. package/dist/core/completions/generators/zsh-generator.js +276 -0
  160. package/dist/core/completions/installers/bash-installer.d.ts +87 -0
  161. package/dist/core/completions/installers/bash-installer.js +321 -0
  162. package/dist/core/completions/installers/fish-installer.d.ts +43 -0
  163. package/dist/core/completions/installers/fish-installer.js +151 -0
  164. package/dist/core/completions/installers/powershell-installer.d.ts +102 -0
  165. package/dist/core/completions/installers/powershell-installer.js +415 -0
  166. package/dist/core/completions/installers/zsh-installer.d.ts +117 -0
  167. package/dist/core/completions/installers/zsh-installer.js +424 -0
  168. package/dist/core/completions/shared-flags.d.ts +13 -0
  169. package/dist/core/completions/shared-flags.js +33 -0
  170. package/dist/core/completions/templates/bash-templates.d.ts +6 -0
  171. package/dist/core/completions/templates/bash-templates.js +30 -0
  172. package/dist/core/completions/templates/fish-templates.d.ts +7 -0
  173. package/dist/core/completions/templates/fish-templates.js +45 -0
  174. package/dist/core/completions/templates/powershell-templates.d.ts +6 -0
  175. package/dist/core/completions/templates/powershell-templates.js +34 -0
  176. package/dist/core/completions/templates/zsh-templates.d.ts +6 -0
  177. package/dist/core/completions/templates/zsh-templates.js +45 -0
  178. package/dist/core/completions/types.d.ts +101 -0
  179. package/dist/core/completions/types.js +2 -0
  180. package/dist/core/config-prompts.d.ts +9 -0
  181. package/dist/core/config-prompts.js +34 -0
  182. package/dist/core/config-schema.d.ts +87 -0
  183. package/dist/core/config-schema.js +239 -0
  184. package/dist/core/config.d.ts +18 -0
  185. package/dist/core/config.js +40 -0
  186. package/dist/core/converters/json-converter.d.ts +6 -0
  187. package/dist/core/converters/json-converter.js +51 -0
  188. package/dist/core/file-state.d.ts +36 -0
  189. package/dist/core/file-state.js +112 -0
  190. package/dist/core/global-config.d.ts +51 -0
  191. package/dist/core/global-config.js +124 -0
  192. package/dist/core/id.d.ts +17 -0
  193. package/dist/core/id.js +30 -0
  194. package/dist/core/index.d.ts +6 -0
  195. package/dist/core/index.js +7 -0
  196. package/dist/core/init.d.ts +37 -0
  197. package/dist/core/init.js +614 -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 +11 -0
  201. package/dist/core/list.js +214 -0
  202. package/dist/core/migration.d.ts +23 -0
  203. package/dist/core/migration.js +108 -0
  204. package/dist/core/openers.d.ts +77 -0
  205. package/dist/core/openers.js +251 -0
  206. package/dist/core/openspec-root.d.ts +45 -0
  207. package/dist/core/openspec-root.js +195 -0
  208. package/dist/core/parsers/change-parser.d.ts +13 -0
  209. package/dist/core/parsers/change-parser.js +198 -0
  210. package/dist/core/parsers/markdown-parser.d.ts +23 -0
  211. package/dist/core/parsers/markdown-parser.js +173 -0
  212. package/dist/core/parsers/requirement-blocks.d.ts +48 -0
  213. package/dist/core/parsers/requirement-blocks.js +235 -0
  214. package/dist/core/parsers/requirement-text.d.ts +55 -0
  215. package/dist/core/parsers/requirement-text.js +136 -0
  216. package/dist/core/parsers/spec-structure.d.ts +9 -0
  217. package/dist/core/parsers/spec-structure.js +88 -0
  218. package/dist/core/planning-home.d.ts +16 -0
  219. package/dist/core/planning-home.js +67 -0
  220. package/dist/core/profile-sync-drift.d.ts +38 -0
  221. package/dist/core/profile-sync-drift.js +201 -0
  222. package/dist/core/profiles.d.ts +26 -0
  223. package/dist/core/profiles.js +41 -0
  224. package/dist/core/project-config.d.ts +107 -0
  225. package/dist/core/project-config.js +373 -0
  226. package/dist/core/references.d.ts +63 -0
  227. package/dist/core/references.js +310 -0
  228. package/dist/core/relationship-health.d.ts +65 -0
  229. package/dist/core/relationship-health.js +64 -0
  230. package/dist/core/root-selection.d.ts +122 -0
  231. package/dist/core/root-selection.js +337 -0
  232. package/dist/core/schemas/base.schema.d.ts +13 -0
  233. package/dist/core/schemas/base.schema.js +18 -0
  234. package/dist/core/schemas/change.schema.d.ts +73 -0
  235. package/dist/core/schemas/change.schema.js +31 -0
  236. package/dist/core/schemas/index.d.ts +4 -0
  237. package/dist/core/schemas/index.js +4 -0
  238. package/dist/core/schemas/spec.schema.d.ts +18 -0
  239. package/dist/core/schemas/spec.schema.js +15 -0
  240. package/dist/core/shared/allowed-tools.d.ts +12 -0
  241. package/dist/core/shared/allowed-tools.js +12 -0
  242. package/dist/core/shared/index.d.ts +8 -0
  243. package/dist/core/shared/index.js +8 -0
  244. package/dist/core/shared/skill-generation.d.ts +49 -0
  245. package/dist/core/shared/skill-generation.js +100 -0
  246. package/dist/core/shared/tool-detection.d.ts +71 -0
  247. package/dist/core/shared/tool-detection.js +160 -0
  248. package/dist/core/specs-apply.d.ts +78 -0
  249. package/dist/core/specs-apply.js +428 -0
  250. package/dist/core/store/errors.d.ts +20 -0
  251. package/dist/core/store/errors.js +22 -0
  252. package/dist/core/store/foundation.d.ts +56 -0
  253. package/dist/core/store/foundation.js +251 -0
  254. package/dist/core/store/git.d.ts +23 -0
  255. package/dist/core/store/git.js +137 -0
  256. package/dist/core/store/index.d.ts +5 -0
  257. package/dist/core/store/index.js +5 -0
  258. package/dist/core/store/operations.d.ts +114 -0
  259. package/dist/core/store/operations.js +803 -0
  260. package/dist/core/store/registry.d.ts +58 -0
  261. package/dist/core/store/registry.js +275 -0
  262. package/dist/core/styles/palette.d.ts +7 -0
  263. package/dist/core/styles/palette.js +8 -0
  264. package/dist/core/templates/index.d.ts +8 -0
  265. package/dist/core/templates/index.js +9 -0
  266. package/dist/core/templates/skill-templates.d.ts +20 -0
  267. package/dist/core/templates/skill-templates.js +19 -0
  268. package/dist/core/templates/types.d.ts +19 -0
  269. package/dist/core/templates/types.js +5 -0
  270. package/dist/core/templates/workflows/apply-change.d.ts +10 -0
  271. package/dist/core/templates/workflows/apply-change.js +315 -0
  272. package/dist/core/templates/workflows/archive-change.d.ts +10 -0
  273. package/dist/core/templates/workflows/archive-change.js +278 -0
  274. package/dist/core/templates/workflows/bulk-archive-change.d.ts +10 -0
  275. package/dist/core/templates/workflows/bulk-archive-change.js +493 -0
  276. package/dist/core/templates/workflows/continue-change.d.ts +10 -0
  277. package/dist/core/templates/workflows/continue-change.js +239 -0
  278. package/dist/core/templates/workflows/explore.d.ts +10 -0
  279. package/dist/core/templates/workflows/explore.js +464 -0
  280. package/dist/core/templates/workflows/feedback.d.ts +9 -0
  281. package/dist/core/templates/workflows/feedback.js +108 -0
  282. package/dist/core/templates/workflows/ff-change.d.ts +10 -0
  283. package/dist/core/templates/workflows/ff-change.js +205 -0
  284. package/dist/core/templates/workflows/new-change.d.ts +10 -0
  285. package/dist/core/templates/workflows/new-change.js +148 -0
  286. package/dist/core/templates/workflows/onboard.d.ts +10 -0
  287. package/dist/core/templates/workflows/onboard.js +566 -0
  288. package/dist/core/templates/workflows/propose.d.ts +10 -0
  289. package/dist/core/templates/workflows/propose.js +223 -0
  290. package/dist/core/templates/workflows/store-selection.d.ts +8 -0
  291. package/dist/core/templates/workflows/store-selection.js +8 -0
  292. package/dist/core/templates/workflows/sync-specs.d.ts +10 -0
  293. package/dist/core/templates/workflows/sync-specs.js +291 -0
  294. package/dist/core/templates/workflows/update-change.d.ts +10 -0
  295. package/dist/core/templates/workflows/update-change.js +167 -0
  296. package/dist/core/templates/workflows/verify-change.d.ts +10 -0
  297. package/dist/core/templates/workflows/verify-change.js +339 -0
  298. package/dist/core/update.d.ts +82 -0
  299. package/dist/core/update.js +557 -0
  300. package/dist/core/validation/constants.d.ts +34 -0
  301. package/dist/core/validation/constants.js +40 -0
  302. package/dist/core/validation/types.d.ts +18 -0
  303. package/dist/core/validation/types.js +2 -0
  304. package/dist/core/validation/validator.d.ts +51 -0
  305. package/dist/core/validation/validator.js +498 -0
  306. package/dist/core/view.d.ts +8 -0
  307. package/dist/core/view.js +168 -0
  308. package/dist/core/working-set.d.ts +47 -0
  309. package/dist/core/working-set.js +43 -0
  310. package/dist/core/worksets.d.ts +75 -0
  311. package/dist/core/worksets.js +245 -0
  312. package/dist/core/zod-issues.d.ts +4 -0
  313. package/dist/core/zod-issues.js +10 -0
  314. package/dist/index.d.ts +3 -0
  315. package/dist/index.js +3 -0
  316. package/dist/prompts/searchable-multi-select.d.ts +28 -0
  317. package/dist/prompts/searchable-multi-select.js +159 -0
  318. package/dist/telemetry/config.d.ts +38 -0
  319. package/dist/telemetry/config.js +136 -0
  320. package/dist/telemetry/index.d.ts +31 -0
  321. package/dist/telemetry/index.js +164 -0
  322. package/dist/ui/ascii-patterns.d.ts +16 -0
  323. package/dist/ui/ascii-patterns.js +133 -0
  324. package/dist/ui/welcome-screen.d.ts +10 -0
  325. package/dist/ui/welcome-screen.js +146 -0
  326. package/dist/utils/change-metadata.d.ts +55 -0
  327. package/dist/utils/change-metadata.js +141 -0
  328. package/dist/utils/change-utils.d.ts +85 -0
  329. package/dist/utils/change-utils.js +173 -0
  330. package/dist/utils/command-references.d.ts +18 -0
  331. package/dist/utils/command-references.js +20 -0
  332. package/dist/utils/file-system.d.ts +41 -0
  333. package/dist/utils/file-system.js +320 -0
  334. package/dist/utils/index.d.ts +6 -0
  335. package/dist/utils/index.js +9 -0
  336. package/dist/utils/interactive.d.ts +18 -0
  337. package/dist/utils/interactive.js +21 -0
  338. package/dist/utils/item-discovery.d.ts +4 -0
  339. package/dist/utils/item-discovery.js +72 -0
  340. package/dist/utils/match.d.ts +3 -0
  341. package/dist/utils/match.js +22 -0
  342. package/dist/utils/shell-detection.d.ts +20 -0
  343. package/dist/utils/shell-detection.js +41 -0
  344. package/dist/utils/task-progress.d.ts +17 -0
  345. package/dist/utils/task-progress.js +100 -0
  346. package/package.json +85 -0
  347. package/schemas/spec-driven/schema.yaml +153 -0
  348. package/schemas/spec-driven/templates/design.md +19 -0
  349. package/schemas/spec-driven/templates/proposal.md +23 -0
  350. package/schemas/spec-driven/templates/spec.md +8 -0
  351. package/schemas/spec-driven/templates/tasks.md +9 -0
  352. package/scripts/postinstall.js +83 -0
@@ -0,0 +1,146 @@
1
+ /**
2
+ * Animated welcome screen for the experimental artifact workflow setup.
3
+ * Shows side-by-side layout with animated ASCII art on left and welcome text on right.
4
+ */
5
+ import chalk from 'chalk';
6
+ import { WELCOME_ANIMATION } from './ascii-patterns.js';
7
+ // Minimum terminal width for side-by-side layout
8
+ const MIN_WIDTH = 60;
9
+ // Width of the ASCII art column (with padding)
10
+ const ART_COLUMN_WIDTH = 24;
11
+ /**
12
+ * Welcome text content (right column)
13
+ */
14
+ function getWelcomeText() {
15
+ return [
16
+ chalk.white.bold('Welcome to OpenSpec'),
17
+ chalk.dim('A lightweight spec-driven framework'),
18
+ '',
19
+ chalk.white('This setup will configure:'),
20
+ chalk.dim(' • Agent Skills for AI tools'),
21
+ chalk.dim(' • /opsx:* slash commands'),
22
+ '',
23
+ chalk.white('Quick start after setup:'),
24
+ ` ${chalk.yellow('/opsx:new')} ${chalk.dim('Create a change')}`,
25
+ ` ${chalk.yellow('/opsx:continue')} ${chalk.dim('Next artifact')}`,
26
+ ` ${chalk.yellow('/opsx:apply')} ${chalk.dim('Implement tasks')}`,
27
+ '',
28
+ chalk.cyan('Press Enter to select tools...'),
29
+ ];
30
+ }
31
+ /**
32
+ * Renders a single frame with side-by-side layout
33
+ */
34
+ function renderFrame(artLines, textLines) {
35
+ const maxLines = Math.max(artLines.length, textLines.length);
36
+ const lines = [];
37
+ for (let i = 0; i < maxLines; i++) {
38
+ const artLine = artLines[i] || '';
39
+ const textLine = textLines[i] || '';
40
+ // Pad the art column to fixed width
41
+ const paddedArt = artLine.padEnd(ART_COLUMN_WIDTH);
42
+ // Color the ASCII art with cyan for visual appeal
43
+ const coloredArt = chalk.cyan(paddedArt);
44
+ // Clear line before writing to prevent residual characters
45
+ lines.push(`\x1b[2K${coloredArt}${textLine}`);
46
+ }
47
+ return lines.join('\n');
48
+ }
49
+ /**
50
+ * Checks if the terminal supports animation
51
+ */
52
+ function canAnimate() {
53
+ // Must be TTY
54
+ if (!process.stdout.isTTY)
55
+ return false;
56
+ // Respect NO_COLOR
57
+ if (process.env.NO_COLOR)
58
+ return false;
59
+ // Check terminal width
60
+ const columns = process.stdout.columns || 80;
61
+ if (columns < MIN_WIDTH)
62
+ return false;
63
+ return true;
64
+ }
65
+ /**
66
+ * Wait for Enter key press
67
+ */
68
+ function waitForEnter() {
69
+ return new Promise((resolve) => {
70
+ const { stdin } = process;
71
+ // Handle non-TTY gracefully
72
+ if (!stdin.isTTY) {
73
+ resolve();
74
+ return;
75
+ }
76
+ const wasRaw = stdin.isRaw;
77
+ stdin.setRawMode(true);
78
+ stdin.resume();
79
+ const onData = (data) => {
80
+ const char = data.toString();
81
+ // Enter key or Ctrl+C
82
+ if (char === '\r' || char === '\n' || char === '\u0003') {
83
+ stdin.removeListener('data', onData);
84
+ stdin.setRawMode(wasRaw);
85
+ stdin.pause();
86
+ // Handle Ctrl+C
87
+ if (char === '\u0003') {
88
+ process.stdout.write('\n');
89
+ process.exit(0);
90
+ }
91
+ resolve();
92
+ }
93
+ };
94
+ stdin.on('data', onData);
95
+ });
96
+ }
97
+ /**
98
+ * Shows the animated welcome screen.
99
+ * Returns when user presses Enter.
100
+ */
101
+ export async function showWelcomeScreen() {
102
+ const textLines = getWelcomeText();
103
+ if (!canAnimate()) {
104
+ // Fallback: show static welcome
105
+ const frame = WELCOME_ANIMATION.frames[3]; // Peak frame
106
+ process.stdout.write('\n' + renderFrame(frame, textLines) + '\n\n');
107
+ return;
108
+ }
109
+ let frameIndex = 0;
110
+ let running = true;
111
+ let isFirstRender = true;
112
+ // Content height for cursor movement between frames
113
+ const numContentLines = Math.max(WELCOME_ANIMATION.frames[0].length, textLines.length);
114
+ const frameHeight = numContentLines + 1; // internal newlines (11) + trailing newlines (2) = 13
115
+ // Total height including initial newline (for cleanup)
116
+ const totalHeight = frameHeight + 1; // 14
117
+ // Initial render
118
+ process.stdout.write('\n');
119
+ // Animation loop
120
+ const interval = setInterval(() => {
121
+ if (!running)
122
+ return;
123
+ const frame = WELCOME_ANIMATION.frames[frameIndex];
124
+ // Move cursor up to overwrite previous frame (always after first render)
125
+ if (!isFirstRender) {
126
+ process.stdout.write(`\x1b[${frameHeight}A`);
127
+ }
128
+ isFirstRender = false;
129
+ // Render current frame
130
+ process.stdout.write(renderFrame(frame, textLines) + '\n\n');
131
+ // Advance to next frame
132
+ frameIndex = (frameIndex + 1) % WELCOME_ANIMATION.frames.length;
133
+ }, WELCOME_ANIMATION.interval);
134
+ // Wait for Enter
135
+ await waitForEnter();
136
+ // Stop animation
137
+ running = false;
138
+ clearInterval(interval);
139
+ // Clear the welcome screen and move on
140
+ process.stdout.write(`\x1b[${totalHeight}A`);
141
+ for (let i = 0; i < totalHeight; i++) {
142
+ process.stdout.write('\x1b[2K\n'); // Clear line
143
+ }
144
+ process.stdout.write(`\x1b[${totalHeight}A`); // Move back up
145
+ }
146
+ //# sourceMappingURL=welcome-screen.js.map
@@ -0,0 +1,55 @@
1
+ import { type ChangeMetadata } from '../core/change-metadata/index.js';
2
+ export declare const METADATA_FILENAME = ".openspec.yaml";
3
+ /**
4
+ * Error thrown when change metadata validation fails.
5
+ */
6
+ export declare class ChangeMetadataError extends Error {
7
+ readonly metadataPath: string;
8
+ readonly cause?: Error | undefined;
9
+ constructor(message: string, metadataPath: string, cause?: Error | undefined);
10
+ }
11
+ /**
12
+ * Validates that a schema name is valid (exists in available schemas).
13
+ *
14
+ * @param schemaName - The schema name to validate
15
+ * @param projectRoot - Optional project root for project-local schema resolution
16
+ * @returns The validated schema name
17
+ * @throws Error if schema is not found
18
+ */
19
+ export declare function validateSchemaName(schemaName: string, projectRoot?: string): string;
20
+ /**
21
+ * Writes change metadata to .openspec.yaml in the change directory.
22
+ *
23
+ * @param changeDir - The path to the change directory
24
+ * @param metadata - The metadata to write
25
+ * @param projectRoot - Optional project root for project-local schema resolution
26
+ * @throws ChangeMetadataError if validation fails or write fails
27
+ */
28
+ export declare function writeChangeMetadata(changeDir: string, metadata: ChangeMetadata, projectRoot?: string): void;
29
+ /**
30
+ * Reads change metadata from .openspec.yaml in the change directory.
31
+ *
32
+ * @param changeDir - The path to the change directory
33
+ * @param projectRoot - Optional project root for project-local schema resolution
34
+ * @returns The validated metadata, or null if no metadata file exists
35
+ * @throws ChangeMetadataError if the file exists but is invalid
36
+ */
37
+ export declare function readChangeMetadata(changeDir: string, projectRoot?: string): ChangeMetadata | null;
38
+ export interface ResolveSchemaForChangeOptions {
39
+ metadata?: ChangeMetadata | null;
40
+ }
41
+ /**
42
+ * Resolves the schema for a change, with explicit override taking precedence.
43
+ *
44
+ * Resolution order:
45
+ * 1. Explicit schema (if provided)
46
+ * 2. Schema from .openspec.yaml metadata (if exists)
47
+ * 3. Schema from openspec/config.yaml (if exists)
48
+ * 4. Default 'spec-driven'
49
+ *
50
+ * @param changeDir - The path to the change directory
51
+ * @param explicitSchema - Optional explicit schema override
52
+ * @returns The resolved schema name
53
+ */
54
+ export declare function resolveSchemaForChange(changeDir: string, explicitSchema?: string, projectRootOverride?: string, options?: ResolveSchemaForChangeOptions): string;
55
+ //# sourceMappingURL=change-metadata.d.ts.map
@@ -0,0 +1,141 @@
1
+ import * as fs from 'node:fs';
2
+ import * as path from 'node:path';
3
+ import * as yaml from 'yaml';
4
+ import { ChangeMetadataSchema } from '../core/change-metadata/index.js';
5
+ import { listSchemas } from '../core/artifact-graph/resolver.js';
6
+ import { readProjectConfig } from '../core/project-config.js';
7
+ export const METADATA_FILENAME = '.openspec.yaml';
8
+ /**
9
+ * Error thrown when change metadata validation fails.
10
+ */
11
+ export class ChangeMetadataError extends Error {
12
+ metadataPath;
13
+ cause;
14
+ constructor(message, metadataPath, cause) {
15
+ super(message);
16
+ this.metadataPath = metadataPath;
17
+ this.cause = cause;
18
+ this.name = 'ChangeMetadataError';
19
+ }
20
+ }
21
+ /**
22
+ * Validates that a schema name is valid (exists in available schemas).
23
+ *
24
+ * @param schemaName - The schema name to validate
25
+ * @param projectRoot - Optional project root for project-local schema resolution
26
+ * @returns The validated schema name
27
+ * @throws Error if schema is not found
28
+ */
29
+ export function validateSchemaName(schemaName, projectRoot) {
30
+ const availableSchemas = listSchemas(projectRoot);
31
+ if (!availableSchemas.includes(schemaName)) {
32
+ throw new Error(`Unknown schema '${schemaName}'. Available: ${availableSchemas.join(', ')}`);
33
+ }
34
+ return schemaName;
35
+ }
36
+ /**
37
+ * Writes change metadata to .openspec.yaml in the change directory.
38
+ *
39
+ * @param changeDir - The path to the change directory
40
+ * @param metadata - The metadata to write
41
+ * @param projectRoot - Optional project root for project-local schema resolution
42
+ * @throws ChangeMetadataError if validation fails or write fails
43
+ */
44
+ export function writeChangeMetadata(changeDir, metadata, projectRoot) {
45
+ const metaPath = path.join(changeDir, METADATA_FILENAME);
46
+ // Validate schema exists
47
+ validateSchemaName(metadata.schema, projectRoot);
48
+ // Validate with Zod
49
+ const parseResult = ChangeMetadataSchema.safeParse(metadata);
50
+ if (!parseResult.success) {
51
+ throw new ChangeMetadataError(`Invalid metadata: ${parseResult.error.message}`, metaPath);
52
+ }
53
+ // Write YAML file
54
+ const content = yaml.stringify(parseResult.data);
55
+ try {
56
+ fs.writeFileSync(metaPath, content, 'utf-8');
57
+ }
58
+ catch (err) {
59
+ const ioError = err instanceof Error ? err : new Error(String(err));
60
+ throw new ChangeMetadataError(`Failed to write metadata: ${ioError.message}`, metaPath, ioError);
61
+ }
62
+ }
63
+ /**
64
+ * Reads change metadata from .openspec.yaml in the change directory.
65
+ *
66
+ * @param changeDir - The path to the change directory
67
+ * @param projectRoot - Optional project root for project-local schema resolution
68
+ * @returns The validated metadata, or null if no metadata file exists
69
+ * @throws ChangeMetadataError if the file exists but is invalid
70
+ */
71
+ export function readChangeMetadata(changeDir, projectRoot) {
72
+ const metaPath = path.join(changeDir, METADATA_FILENAME);
73
+ if (!fs.existsSync(metaPath)) {
74
+ return null;
75
+ }
76
+ let content;
77
+ try {
78
+ content = fs.readFileSync(metaPath, 'utf-8');
79
+ }
80
+ catch (err) {
81
+ const ioError = err instanceof Error ? err : new Error(String(err));
82
+ throw new ChangeMetadataError(`Failed to read metadata: ${ioError.message}`, metaPath, ioError);
83
+ }
84
+ let parsed;
85
+ try {
86
+ parsed = yaml.parse(content);
87
+ }
88
+ catch (err) {
89
+ const parseError = err instanceof Error ? err : new Error(String(err));
90
+ throw new ChangeMetadataError(`Invalid YAML in metadata file: ${parseError.message}`, metaPath, parseError);
91
+ }
92
+ // Validate with Zod
93
+ const parseResult = ChangeMetadataSchema.safeParse(parsed);
94
+ if (!parseResult.success) {
95
+ throw new ChangeMetadataError(`Invalid metadata: ${parseResult.error.message}`, metaPath);
96
+ }
97
+ // Validate that the schema exists
98
+ const availableSchemas = listSchemas(projectRoot);
99
+ if (!availableSchemas.includes(parseResult.data.schema)) {
100
+ throw new ChangeMetadataError(`Unknown schema '${parseResult.data.schema}'. Available: ${availableSchemas.join(', ')}`, metaPath);
101
+ }
102
+ return parseResult.data;
103
+ }
104
+ /**
105
+ * Resolves the schema for a change, with explicit override taking precedence.
106
+ *
107
+ * Resolution order:
108
+ * 1. Explicit schema (if provided)
109
+ * 2. Schema from .openspec.yaml metadata (if exists)
110
+ * 3. Schema from openspec/config.yaml (if exists)
111
+ * 4. Default 'spec-driven'
112
+ *
113
+ * @param changeDir - The path to the change directory
114
+ * @param explicitSchema - Optional explicit schema override
115
+ * @returns The resolved schema name
116
+ */
117
+ export function resolveSchemaForChange(changeDir, explicitSchema, projectRootOverride, options = {}) {
118
+ // Derive project root from changeDir (changeDir is typically projectRoot/openspec/changes/change-name)
119
+ const projectRoot = projectRootOverride ?? path.resolve(changeDir, '../../..');
120
+ // 1. Explicit override wins
121
+ if (explicitSchema) {
122
+ return explicitSchema;
123
+ }
124
+ const metadata = options.metadata !== undefined ? options.metadata : readChangeMetadata(changeDir, projectRoot);
125
+ if (metadata?.schema) {
126
+ return metadata.schema;
127
+ }
128
+ // 3. Try reading from project config when metadata is absent.
129
+ try {
130
+ const config = readProjectConfig(projectRoot);
131
+ if (config?.schema) {
132
+ return config.schema;
133
+ }
134
+ }
135
+ catch {
136
+ // If config read fails, fall back to default
137
+ }
138
+ // 4. Default
139
+ return 'spec-driven';
140
+ }
141
+ //# sourceMappingURL=change-metadata.js.map
@@ -0,0 +1,85 @@
1
+ import type { ChangeMetadata } from '../core/change-metadata/index.js';
2
+ /**
3
+ * Options for creating a change.
4
+ */
5
+ export interface CreateChangeOptions {
6
+ /** The workflow schema to use (default: 'spec-driven') */
7
+ schema?: string;
8
+ /** Default schema to use when no explicit schema or project config is present */
9
+ defaultSchema?: string;
10
+ /** Directory that should contain the change directories */
11
+ changesDir?: string;
12
+ /** Additional metadata to persist in the change's .openspec.yaml */
13
+ metadata?: Partial<Pick<ChangeMetadata, 'goal' | 'affected_areas' | 'initiative'>>;
14
+ }
15
+ /**
16
+ * Result of creating a change.
17
+ */
18
+ export interface CreateChangeResult {
19
+ /** The schema that was actually used (resolved from options, config, or default) */
20
+ schema: string;
21
+ /** Absolute path to the created change directory */
22
+ changeDir: string;
23
+ }
24
+ /**
25
+ * Result of validating a change name.
26
+ */
27
+ export interface ValidationResult {
28
+ valid: boolean;
29
+ error?: string;
30
+ }
31
+ /**
32
+ * Validates an existing change path for safe filesystem lookup.
33
+ *
34
+ * Accepts paths that include a single feature-group prefix, e.g.
35
+ * "02-Session/10-session-token-rotation". Enforces only security rules
36
+ * (no path traversal, no absolute paths, max one separator level).
37
+ * Does NOT enforce kebab-case, so numbered or mixed-case group/change
38
+ * folder names used in this project are all accepted.
39
+ *
40
+ * @param name - The change name or group/change path to validate
41
+ * @returns Validation result
42
+ */
43
+ export declare function validateChangeExistingPath(name: string): ValidationResult;
44
+ /**
45
+ * Validates that a change name follows kebab-case conventions.
46
+ *
47
+ * Valid names:
48
+ * - Start with a lowercase letter OR digit (numeric prefixes like 10- are allowed)
49
+ * - Contain only lowercase letters, numbers, and hyphens
50
+ * - Do not start or end with a hyphen
51
+ * - Do not contain consecutive hyphens
52
+ *
53
+ * @param name - The change name to validate
54
+ * @returns Validation result with `valid: true` or `valid: false` with an error message
55
+ *
56
+ * @example
57
+ * validateChangeName('add-auth') // { valid: true }
58
+ * validateChangeName('10-session-flow') // { valid: true }
59
+ * validateChangeName('Add-Auth') // { valid: false, error: '...' }
60
+ */
61
+ export declare function validateChangeName(name: string): ValidationResult;
62
+ /**
63
+ * Creates a new change directory with metadata file.
64
+ *
65
+ * @param projectRoot - The root directory of the project (where `openspec/` lives)
66
+ * @param name - The change name (must be valid kebab-case)
67
+ * @param options - Optional settings for the change
68
+ * @throws Error if the change name is invalid
69
+ * @throws Error if the schema name is invalid
70
+ * @throws Error if the change directory already exists
71
+ *
72
+ * @returns Result containing the resolved schema name
73
+ *
74
+ * @example
75
+ * // Creates openspec/changes/add-auth/ with default schema
76
+ * const result = await createChange('/path/to/project', 'add-auth')
77
+ * console.log(result.schema) // 'spec-driven' or value from config
78
+ *
79
+ * @example
80
+ * // Creates openspec/changes/add-auth/ with custom schema
81
+ * const result = await createChange('/path/to/project', 'add-auth', { schema: 'my-workflow' })
82
+ * console.log(result.schema) // 'my-workflow'
83
+ */
84
+ export declare function createChange(projectRoot: string, name: string, options?: CreateChangeOptions): Promise<CreateChangeResult>;
85
+ //# sourceMappingURL=change-utils.d.ts.map
@@ -0,0 +1,173 @@
1
+ import path from 'path';
2
+ import { FileSystemUtils } from './file-system.js';
3
+ import { writeChangeMetadata, validateSchemaName } from './change-metadata.js';
4
+ import { readProjectConfig } from '../core/project-config.js';
5
+ const DEFAULT_SCHEMA = 'spec-driven';
6
+ /**
7
+ * Validates an existing change path for safe filesystem lookup.
8
+ *
9
+ * Accepts paths that include a single feature-group prefix, e.g.
10
+ * "02-Session/10-session-token-rotation". Enforces only security rules
11
+ * (no path traversal, no absolute paths, max one separator level).
12
+ * Does NOT enforce kebab-case, so numbered or mixed-case group/change
13
+ * folder names used in this project are all accepted.
14
+ *
15
+ * @param name - The change name or group/change path to validate
16
+ * @returns Validation result
17
+ */
18
+ export function validateChangeExistingPath(name) {
19
+ if (!name) {
20
+ return { valid: false, error: 'Change name cannot be empty' };
21
+ }
22
+ if (name.includes('\0')) {
23
+ return { valid: false, error: 'Change name cannot contain null bytes' };
24
+ }
25
+ if (path.isAbsolute(name)) {
26
+ return { valid: false, error: 'Change name cannot be an absolute path' };
27
+ }
28
+ // Normalise to forward slashes for consistent traversal check
29
+ const normalised = name.replace(/\\/g, '/');
30
+ if (normalised.split('/').some((seg) => seg === '..')) {
31
+ return { valid: false, error: 'Change name cannot contain path traversal ("..")' };
32
+ }
33
+ const parts = normalised.split('/');
34
+ if (parts.length > 2) {
35
+ return { valid: false, error: 'Change path may contain at most one group prefix ("group/change-name")' };
36
+ }
37
+ return { valid: true };
38
+ }
39
+ /**
40
+ * Validates that a change name follows kebab-case conventions.
41
+ *
42
+ * Valid names:
43
+ * - Start with a lowercase letter OR digit (numeric prefixes like 10- are allowed)
44
+ * - Contain only lowercase letters, numbers, and hyphens
45
+ * - Do not start or end with a hyphen
46
+ * - Do not contain consecutive hyphens
47
+ *
48
+ * @param name - The change name to validate
49
+ * @returns Validation result with `valid: true` or `valid: false` with an error message
50
+ *
51
+ * @example
52
+ * validateChangeName('add-auth') // { valid: true }
53
+ * validateChangeName('10-session-flow') // { valid: true }
54
+ * validateChangeName('Add-Auth') // { valid: false, error: '...' }
55
+ */
56
+ export function validateChangeName(name) {
57
+ // Pattern: starts with a lowercase letter or digit, followed by lowercase letters/numbers,
58
+ // optionally followed by hyphen + lowercase letters/numbers (repeatable)
59
+ const kebabCasePattern = /^[a-z0-9][a-z0-9]*(-[a-z0-9]+)*$/;
60
+ if (!name) {
61
+ return { valid: false, error: 'Change name cannot be empty' };
62
+ }
63
+ if (!kebabCasePattern.test(name)) {
64
+ // Provide specific error messages for common mistakes
65
+ if (/[A-Z]/.test(name)) {
66
+ return { valid: false, error: 'Change name must be lowercase (use kebab-case)' };
67
+ }
68
+ if (/\s/.test(name)) {
69
+ return { valid: false, error: 'Change name cannot contain spaces (use hyphens instead)' };
70
+ }
71
+ if (/_/.test(name)) {
72
+ return { valid: false, error: 'Change name cannot contain underscores (use hyphens instead)' };
73
+ }
74
+ if (name.startsWith('-')) {
75
+ return { valid: false, error: 'Change name cannot start with a hyphen' };
76
+ }
77
+ if (name.endsWith('-')) {
78
+ return { valid: false, error: 'Change name cannot end with a hyphen' };
79
+ }
80
+ if (/--/.test(name)) {
81
+ return { valid: false, error: 'Change name cannot contain consecutive hyphens' };
82
+ }
83
+ if (/[^a-z0-9-]/.test(name)) {
84
+ return { valid: false, error: 'Change name can only contain lowercase letters, numbers, and hyphens' };
85
+ }
86
+ return { valid: false, error: 'Change name must follow kebab-case convention (e.g., add-auth, 10-session-flow)' };
87
+ }
88
+ return { valid: true };
89
+ }
90
+ /**
91
+ * Creates a new change directory with metadata file.
92
+ *
93
+ * @param projectRoot - The root directory of the project (where `openspec/` lives)
94
+ * @param name - The change name (must be valid kebab-case)
95
+ * @param options - Optional settings for the change
96
+ * @throws Error if the change name is invalid
97
+ * @throws Error if the schema name is invalid
98
+ * @throws Error if the change directory already exists
99
+ *
100
+ * @returns Result containing the resolved schema name
101
+ *
102
+ * @example
103
+ * // Creates openspec/changes/add-auth/ with default schema
104
+ * const result = await createChange('/path/to/project', 'add-auth')
105
+ * console.log(result.schema) // 'spec-driven' or value from config
106
+ *
107
+ * @example
108
+ * // Creates openspec/changes/add-auth/ with custom schema
109
+ * const result = await createChange('/path/to/project', 'add-auth', { schema: 'my-workflow' })
110
+ * console.log(result.schema) // 'my-workflow'
111
+ */
112
+ export async function createChange(projectRoot, name, options = {}) {
113
+ // For paths with a group prefix (e.g. "02-Session/10-my-change") use the
114
+ // security-only validator; for plain names use the full kebab-case validator.
115
+ const hasGroupPrefix = name.replace(/\\/g, '/').includes('/');
116
+ const validation = hasGroupPrefix
117
+ ? validateChangeExistingPath(name)
118
+ : validateChangeName(name);
119
+ if (!validation.valid) {
120
+ throw new Error(validation.error);
121
+ }
122
+ const defaultSchema = options.defaultSchema ?? DEFAULT_SCHEMA;
123
+ // Determine schema: explicit option → project config → supplied default
124
+ let schemaName;
125
+ if (options.schema) {
126
+ schemaName = options.schema;
127
+ }
128
+ else {
129
+ // Try to read from project config
130
+ try {
131
+ const config = readProjectConfig(projectRoot);
132
+ schemaName = config?.schema ?? defaultSchema;
133
+ }
134
+ catch {
135
+ // If config read fails, use default
136
+ schemaName = defaultSchema;
137
+ }
138
+ }
139
+ // Validate the resolved schema
140
+ validateSchemaName(schemaName, projectRoot);
141
+ // Build the change directory path
142
+ const changeDir = path.join(options.changesDir ?? path.join(projectRoot, 'openspec', 'changes'), name);
143
+ // Check if change already exists
144
+ if (await FileSystemUtils.directoryExists(changeDir)) {
145
+ throw new Error(`Change '${name}' already exists at ${changeDir}`);
146
+ }
147
+ // Creating a change may scaffold or complete the root itself (an
148
+ // implicit root, or a config-only/incomplete clone). Never leave a
149
+ // half-root behind that doctor immediately calls unhealthy: ensure
150
+ // specs/ and changes/archive/ exist, and write a config only when
151
+ // none exists. The config records the PROJECT default schema, never
152
+ // a one-change --schema override.
153
+ const openspecDir = path.join(projectRoot, 'openspec');
154
+ // Create the directory (including parent directories if needed)
155
+ await FileSystemUtils.createDirectory(changeDir);
156
+ await FileSystemUtils.createDirectory(path.join(openspecDir, 'specs'));
157
+ await FileSystemUtils.createDirectory(path.join(openspecDir, 'changes', 'archive'));
158
+ const configPath = path.join(openspecDir, 'config.yaml');
159
+ const configYmlPath = path.join(openspecDir, 'config.yml');
160
+ if (!(await FileSystemUtils.fileExists(configPath)) &&
161
+ !(await FileSystemUtils.fileExists(configYmlPath))) {
162
+ await FileSystemUtils.writeFile(configPath, `schema: ${defaultSchema}\n`);
163
+ }
164
+ // Write metadata file with schema and creation date
165
+ const today = new Date().toISOString().split('T')[0];
166
+ writeChangeMetadata(changeDir, {
167
+ schema: schemaName,
168
+ created: today,
169
+ ...options.metadata,
170
+ }, projectRoot);
171
+ return { schema: schemaName, changeDir };
172
+ }
173
+ //# sourceMappingURL=change-utils.js.map
@@ -0,0 +1,18 @@
1
+ /**
2
+ * Command Reference Utilities
3
+ *
4
+ * Utilities for transforming command references to tool-specific formats.
5
+ */
6
+ /**
7
+ * Transforms colon-based command references to hyphen-based format.
8
+ * Converts `/opsx:` patterns to `/opsx-` for tools that use hyphen syntax.
9
+ *
10
+ * @param text - The text containing command references
11
+ * @returns Text with command references transformed to hyphen format
12
+ *
13
+ * @example
14
+ * transformToHyphenCommands('/opsx:new') // returns '/opsx-new'
15
+ * transformToHyphenCommands('Use /opsx:apply to implement') // returns 'Use /opsx-apply to implement'
16
+ */
17
+ export declare function transformToHyphenCommands(text: string): string;
18
+ //# sourceMappingURL=command-references.d.ts.map
@@ -0,0 +1,20 @@
1
+ /**
2
+ * Command Reference Utilities
3
+ *
4
+ * Utilities for transforming command references to tool-specific formats.
5
+ */
6
+ /**
7
+ * Transforms colon-based command references to hyphen-based format.
8
+ * Converts `/opsx:` patterns to `/opsx-` for tools that use hyphen syntax.
9
+ *
10
+ * @param text - The text containing command references
11
+ * @returns Text with command references transformed to hyphen format
12
+ *
13
+ * @example
14
+ * transformToHyphenCommands('/opsx:new') // returns '/opsx-new'
15
+ * transformToHyphenCommands('Use /opsx:apply to implement') // returns 'Use /opsx-apply to implement'
16
+ */
17
+ export function transformToHyphenCommands(text) {
18
+ return text.replace(/\/opsx:/g, '/opsx-');
19
+ }
20
+ //# sourceMappingURL=command-references.js.map
@@ -0,0 +1,41 @@
1
+ export declare class FileSystemUtils {
2
+ /**
3
+ * Converts a path to use forward slashes (POSIX style).
4
+ * Essential for cross-platform compatibility with glob libraries like fast-glob.
5
+ */
6
+ static toPosixPath(p: string): string;
7
+ /**
8
+ * Returns a canonical absolute path when the target exists.
9
+ * Falls back to path.resolve() so callers can still produce a stable absolute path.
10
+ */
11
+ static canonicalizeExistingPath(targetPath: string): string;
12
+ private static isWindowsBasePath;
13
+ private static normalizeSegments;
14
+ static joinPath(basePath: string, ...segments: string[]): string;
15
+ static createDirectory(dirPath: string): Promise<void>;
16
+ static fileExists(filePath: string): Promise<boolean>;
17
+ /**
18
+ * Finds the first existing parent directory by walking up the directory tree.
19
+ * @param dirPath Starting directory path
20
+ * @returns The first existing directory path, or null if root is reached without finding one
21
+ */
22
+ private static findFirstExistingDirectory;
23
+ static canWriteFile(filePath: string): Promise<boolean>;
24
+ static directoryExists(dirPath: string): Promise<boolean>;
25
+ static writeFile(filePath: string, content: string): Promise<void>;
26
+ static readFile(filePath: string): Promise<string>;
27
+ static updateFileWithMarkers(filePath: string, content: string, startMarker: string, endMarker: string): Promise<void>;
28
+ static ensureWritePermissions(dirPath: string): Promise<boolean>;
29
+ }
30
+ /**
31
+ * Removes a marker block from file content.
32
+ * Only removes markers that are on their own lines (ignores inline mentions).
33
+ * Cleans up double blank lines that may result from removal.
34
+ *
35
+ * @param content - File content with markers
36
+ * @param startMarker - The start marker string
37
+ * @param endMarker - The end marker string
38
+ * @returns Content with marker block removed, or original content if markers not found/invalid
39
+ */
40
+ export declare function removeMarkerBlock(content: string, startMarker: string, endMarker: string): string;
41
+ //# sourceMappingURL=file-system.d.ts.map