anchorspec 1.3.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 (273) hide show
  1. package/LICENSE +22 -0
  2. package/README.md +230 -0
  3. package/bin/anchorspec.js +3 -0
  4. package/bin/openspec.js +3 -0
  5. package/dist/cli/index.d.ts +2 -0
  6. package/dist/cli/index.js +455 -0
  7. package/dist/commands/change.d.ts +35 -0
  8. package/dist/commands/change.js +277 -0
  9. package/dist/commands/completion.d.ts +72 -0
  10. package/dist/commands/completion.js +257 -0
  11. package/dist/commands/config.d.ts +36 -0
  12. package/dist/commands/config.js +552 -0
  13. package/dist/commands/feedback.d.ts +9 -0
  14. package/dist/commands/feedback.js +183 -0
  15. package/dist/commands/schema.d.ts +6 -0
  16. package/dist/commands/schema.js +869 -0
  17. package/dist/commands/show.d.ts +14 -0
  18. package/dist/commands/show.js +132 -0
  19. package/dist/commands/spec.d.ts +15 -0
  20. package/dist/commands/spec.js +225 -0
  21. package/dist/commands/validate.d.ts +24 -0
  22. package/dist/commands/validate.js +294 -0
  23. package/dist/commands/workflow/index.d.ts +17 -0
  24. package/dist/commands/workflow/index.js +12 -0
  25. package/dist/commands/workflow/instructions.d.ts +29 -0
  26. package/dist/commands/workflow/instructions.js +381 -0
  27. package/dist/commands/workflow/new-change.d.ts +11 -0
  28. package/dist/commands/workflow/new-change.js +44 -0
  29. package/dist/commands/workflow/schemas.d.ts +10 -0
  30. package/dist/commands/workflow/schemas.js +34 -0
  31. package/dist/commands/workflow/shared.d.ts +57 -0
  32. package/dist/commands/workflow/shared.js +116 -0
  33. package/dist/commands/workflow/status.d.ts +14 -0
  34. package/dist/commands/workflow/status.js +75 -0
  35. package/dist/commands/workflow/templates.d.ts +16 -0
  36. package/dist/commands/workflow/templates.js +68 -0
  37. package/dist/core/archive.d.ts +11 -0
  38. package/dist/core/archive.js +318 -0
  39. package/dist/core/artifact-graph/graph.d.ts +56 -0
  40. package/dist/core/artifact-graph/graph.js +141 -0
  41. package/dist/core/artifact-graph/index.d.ts +7 -0
  42. package/dist/core/artifact-graph/index.js +13 -0
  43. package/dist/core/artifact-graph/instruction-loader.d.ts +143 -0
  44. package/dist/core/artifact-graph/instruction-loader.js +214 -0
  45. package/dist/core/artifact-graph/resolver.d.ts +81 -0
  46. package/dist/core/artifact-graph/resolver.js +257 -0
  47. package/dist/core/artifact-graph/schema.d.ts +13 -0
  48. package/dist/core/artifact-graph/schema.js +108 -0
  49. package/dist/core/artifact-graph/state.d.ts +12 -0
  50. package/dist/core/artifact-graph/state.js +54 -0
  51. package/dist/core/artifact-graph/types.d.ts +45 -0
  52. package/dist/core/artifact-graph/types.js +43 -0
  53. package/dist/core/available-tools.d.ts +17 -0
  54. package/dist/core/available-tools.js +43 -0
  55. package/dist/core/command-generation/adapters/amazon-q.d.ts +13 -0
  56. package/dist/core/command-generation/adapters/amazon-q.js +26 -0
  57. package/dist/core/command-generation/adapters/antigravity.d.ts +13 -0
  58. package/dist/core/command-generation/adapters/antigravity.js +26 -0
  59. package/dist/core/command-generation/adapters/auggie.d.ts +13 -0
  60. package/dist/core/command-generation/adapters/auggie.js +27 -0
  61. package/dist/core/command-generation/adapters/bob.d.ts +14 -0
  62. package/dist/core/command-generation/adapters/bob.js +45 -0
  63. package/dist/core/command-generation/adapters/claude.d.ts +13 -0
  64. package/dist/core/command-generation/adapters/claude.js +50 -0
  65. package/dist/core/command-generation/adapters/cline.d.ts +14 -0
  66. package/dist/core/command-generation/adapters/cline.js +27 -0
  67. package/dist/core/command-generation/adapters/codebuddy.d.ts +13 -0
  68. package/dist/core/command-generation/adapters/codebuddy.js +28 -0
  69. package/dist/core/command-generation/adapters/codex.d.ts +16 -0
  70. package/dist/core/command-generation/adapters/codex.js +39 -0
  71. package/dist/core/command-generation/adapters/continue.d.ts +13 -0
  72. package/dist/core/command-generation/adapters/continue.js +28 -0
  73. package/dist/core/command-generation/adapters/costrict.d.ts +13 -0
  74. package/dist/core/command-generation/adapters/costrict.js +27 -0
  75. package/dist/core/command-generation/adapters/crush.d.ts +13 -0
  76. package/dist/core/command-generation/adapters/crush.js +30 -0
  77. package/dist/core/command-generation/adapters/cursor.d.ts +14 -0
  78. package/dist/core/command-generation/adapters/cursor.js +44 -0
  79. package/dist/core/command-generation/adapters/factory.d.ts +13 -0
  80. package/dist/core/command-generation/adapters/factory.js +27 -0
  81. package/dist/core/command-generation/adapters/gemini.d.ts +13 -0
  82. package/dist/core/command-generation/adapters/gemini.js +26 -0
  83. package/dist/core/command-generation/adapters/github-copilot.d.ts +13 -0
  84. package/dist/core/command-generation/adapters/github-copilot.js +26 -0
  85. package/dist/core/command-generation/adapters/iflow.d.ts +13 -0
  86. package/dist/core/command-generation/adapters/iflow.js +29 -0
  87. package/dist/core/command-generation/adapters/index.d.ts +32 -0
  88. package/dist/core/command-generation/adapters/index.js +32 -0
  89. package/dist/core/command-generation/adapters/junie.d.ts +13 -0
  90. package/dist/core/command-generation/adapters/junie.js +26 -0
  91. package/dist/core/command-generation/adapters/kilocode.d.ts +14 -0
  92. package/dist/core/command-generation/adapters/kilocode.js +23 -0
  93. package/dist/core/command-generation/adapters/kiro.d.ts +13 -0
  94. package/dist/core/command-generation/adapters/kiro.js +26 -0
  95. package/dist/core/command-generation/adapters/lingma.d.ts +13 -0
  96. package/dist/core/command-generation/adapters/lingma.js +30 -0
  97. package/dist/core/command-generation/adapters/opencode.d.ts +13 -0
  98. package/dist/core/command-generation/adapters/opencode.js +29 -0
  99. package/dist/core/command-generation/adapters/pi.d.ts +18 -0
  100. package/dist/core/command-generation/adapters/pi.js +55 -0
  101. package/dist/core/command-generation/adapters/qoder.d.ts +13 -0
  102. package/dist/core/command-generation/adapters/qoder.js +30 -0
  103. package/dist/core/command-generation/adapters/qwen.d.ts +13 -0
  104. package/dist/core/command-generation/adapters/qwen.js +26 -0
  105. package/dist/core/command-generation/adapters/roocode.d.ts +14 -0
  106. package/dist/core/command-generation/adapters/roocode.js +27 -0
  107. package/dist/core/command-generation/adapters/windsurf.d.ts +14 -0
  108. package/dist/core/command-generation/adapters/windsurf.js +51 -0
  109. package/dist/core/command-generation/generator.d.ts +21 -0
  110. package/dist/core/command-generation/generator.js +27 -0
  111. package/dist/core/command-generation/index.d.ts +22 -0
  112. package/dist/core/command-generation/index.js +24 -0
  113. package/dist/core/command-generation/registry.d.ts +36 -0
  114. package/dist/core/command-generation/registry.js +98 -0
  115. package/dist/core/command-generation/types.d.ts +56 -0
  116. package/dist/core/command-generation/types.js +8 -0
  117. package/dist/core/completions/command-registry.d.ts +7 -0
  118. package/dist/core/completions/command-registry.js +461 -0
  119. package/dist/core/completions/completion-provider.d.ts +60 -0
  120. package/dist/core/completions/completion-provider.js +102 -0
  121. package/dist/core/completions/factory.d.ts +64 -0
  122. package/dist/core/completions/factory.js +75 -0
  123. package/dist/core/completions/generators/bash-generator.d.ts +32 -0
  124. package/dist/core/completions/generators/bash-generator.js +174 -0
  125. package/dist/core/completions/generators/fish-generator.d.ts +32 -0
  126. package/dist/core/completions/generators/fish-generator.js +157 -0
  127. package/dist/core/completions/generators/powershell-generator.d.ts +33 -0
  128. package/dist/core/completions/generators/powershell-generator.js +207 -0
  129. package/dist/core/completions/generators/zsh-generator.d.ts +44 -0
  130. package/dist/core/completions/generators/zsh-generator.js +250 -0
  131. package/dist/core/completions/installers/bash-installer.d.ts +87 -0
  132. package/dist/core/completions/installers/bash-installer.js +318 -0
  133. package/dist/core/completions/installers/fish-installer.d.ts +43 -0
  134. package/dist/core/completions/installers/fish-installer.js +143 -0
  135. package/dist/core/completions/installers/powershell-installer.d.ts +102 -0
  136. package/dist/core/completions/installers/powershell-installer.js +387 -0
  137. package/dist/core/completions/installers/zsh-installer.d.ts +125 -0
  138. package/dist/core/completions/installers/zsh-installer.js +449 -0
  139. package/dist/core/completions/templates/bash-templates.d.ts +6 -0
  140. package/dist/core/completions/templates/bash-templates.js +24 -0
  141. package/dist/core/completions/templates/fish-templates.d.ts +7 -0
  142. package/dist/core/completions/templates/fish-templates.js +39 -0
  143. package/dist/core/completions/templates/powershell-templates.d.ts +6 -0
  144. package/dist/core/completions/templates/powershell-templates.js +25 -0
  145. package/dist/core/completions/templates/zsh-templates.d.ts +6 -0
  146. package/dist/core/completions/templates/zsh-templates.js +36 -0
  147. package/dist/core/completions/types.d.ts +79 -0
  148. package/dist/core/completions/types.js +2 -0
  149. package/dist/core/config-prompts.d.ts +9 -0
  150. package/dist/core/config-prompts.js +34 -0
  151. package/dist/core/config-schema.d.ts +86 -0
  152. package/dist/core/config-schema.js +213 -0
  153. package/dist/core/config.d.ts +18 -0
  154. package/dist/core/config.js +37 -0
  155. package/dist/core/converters/json-converter.d.ts +6 -0
  156. package/dist/core/converters/json-converter.js +51 -0
  157. package/dist/core/global-config.d.ts +44 -0
  158. package/dist/core/global-config.js +125 -0
  159. package/dist/core/index.d.ts +2 -0
  160. package/dist/core/index.js +3 -0
  161. package/dist/core/init.d.ts +37 -0
  162. package/dist/core/init.js +593 -0
  163. package/dist/core/legacy-cleanup.d.ts +162 -0
  164. package/dist/core/legacy-cleanup.js +514 -0
  165. package/dist/core/list.d.ts +9 -0
  166. package/dist/core/list.js +171 -0
  167. package/dist/core/migration.d.ts +23 -0
  168. package/dist/core/migration.js +108 -0
  169. package/dist/core/parsers/change-parser.d.ts +13 -0
  170. package/dist/core/parsers/change-parser.js +193 -0
  171. package/dist/core/parsers/markdown-parser.d.ts +22 -0
  172. package/dist/core/parsers/markdown-parser.js +187 -0
  173. package/dist/core/parsers/requirement-blocks.d.ts +37 -0
  174. package/dist/core/parsers/requirement-blocks.js +201 -0
  175. package/dist/core/profile-sync-drift.d.ts +38 -0
  176. package/dist/core/profile-sync-drift.js +200 -0
  177. package/dist/core/profiles.d.ts +26 -0
  178. package/dist/core/profiles.js +40 -0
  179. package/dist/core/project-config.d.ts +64 -0
  180. package/dist/core/project-config.js +223 -0
  181. package/dist/core/schemas/base.schema.d.ts +13 -0
  182. package/dist/core/schemas/base.schema.js +13 -0
  183. package/dist/core/schemas/change.schema.d.ts +73 -0
  184. package/dist/core/schemas/change.schema.js +31 -0
  185. package/dist/core/schemas/index.d.ts +4 -0
  186. package/dist/core/schemas/index.js +4 -0
  187. package/dist/core/schemas/spec.schema.d.ts +18 -0
  188. package/dist/core/schemas/spec.schema.js +15 -0
  189. package/dist/core/shared/index.d.ts +8 -0
  190. package/dist/core/shared/index.js +8 -0
  191. package/dist/core/shared/skill-generation.d.ts +49 -0
  192. package/dist/core/shared/skill-generation.js +96 -0
  193. package/dist/core/shared/tool-detection.d.ts +71 -0
  194. package/dist/core/shared/tool-detection.js +158 -0
  195. package/dist/core/specs-apply.d.ts +73 -0
  196. package/dist/core/specs-apply.js +384 -0
  197. package/dist/core/styles/palette.d.ts +7 -0
  198. package/dist/core/styles/palette.js +8 -0
  199. package/dist/core/templates/index.d.ts +8 -0
  200. package/dist/core/templates/index.js +9 -0
  201. package/dist/core/templates/skill-templates.d.ts +19 -0
  202. package/dist/core/templates/skill-templates.js +18 -0
  203. package/dist/core/templates/types.d.ts +19 -0
  204. package/dist/core/templates/types.js +5 -0
  205. package/dist/core/templates/workflows/apply-change.d.ts +10 -0
  206. package/dist/core/templates/workflows/apply-change.js +308 -0
  207. package/dist/core/templates/workflows/archive-change.d.ts +10 -0
  208. package/dist/core/templates/workflows/archive-change.js +271 -0
  209. package/dist/core/templates/workflows/bulk-archive-change.d.ts +10 -0
  210. package/dist/core/templates/workflows/bulk-archive-change.js +488 -0
  211. package/dist/core/templates/workflows/continue-change.d.ts +10 -0
  212. package/dist/core/templates/workflows/continue-change.js +232 -0
  213. package/dist/core/templates/workflows/explore.d.ts +10 -0
  214. package/dist/core/templates/workflows/explore.js +461 -0
  215. package/dist/core/templates/workflows/feedback.d.ts +9 -0
  216. package/dist/core/templates/workflows/feedback.js +108 -0
  217. package/dist/core/templates/workflows/ff-change.d.ts +10 -0
  218. package/dist/core/templates/workflows/ff-change.js +198 -0
  219. package/dist/core/templates/workflows/new-change.d.ts +10 -0
  220. package/dist/core/templates/workflows/new-change.js +143 -0
  221. package/dist/core/templates/workflows/onboard.d.ts +10 -0
  222. package/dist/core/templates/workflows/onboard.js +565 -0
  223. package/dist/core/templates/workflows/propose.d.ts +10 -0
  224. package/dist/core/templates/workflows/propose.js +216 -0
  225. package/dist/core/templates/workflows/sync-specs.d.ts +10 -0
  226. package/dist/core/templates/workflows/sync-specs.js +272 -0
  227. package/dist/core/templates/workflows/verify-change.d.ts +10 -0
  228. package/dist/core/templates/workflows/verify-change.js +332 -0
  229. package/dist/core/update.d.ts +77 -0
  230. package/dist/core/update.js +537 -0
  231. package/dist/core/validation/constants.d.ts +34 -0
  232. package/dist/core/validation/constants.js +40 -0
  233. package/dist/core/validation/types.d.ts +18 -0
  234. package/dist/core/validation/types.js +2 -0
  235. package/dist/core/validation/validator.d.ts +33 -0
  236. package/dist/core/validation/validator.js +409 -0
  237. package/dist/core/view.d.ts +8 -0
  238. package/dist/core/view.js +168 -0
  239. package/dist/index.d.ts +3 -0
  240. package/dist/index.js +3 -0
  241. package/dist/prompts/searchable-multi-select.d.ts +28 -0
  242. package/dist/prompts/searchable-multi-select.js +159 -0
  243. package/dist/ui/ascii-patterns.d.ts +16 -0
  244. package/dist/ui/ascii-patterns.js +133 -0
  245. package/dist/ui/welcome-screen.d.ts +10 -0
  246. package/dist/ui/welcome-screen.js +146 -0
  247. package/dist/utils/change-metadata.d.ts +51 -0
  248. package/dist/utils/change-metadata.js +147 -0
  249. package/dist/utils/change-utils.d.ts +62 -0
  250. package/dist/utils/change-utils.js +121 -0
  251. package/dist/utils/command-references.d.ts +18 -0
  252. package/dist/utils/command-references.js +20 -0
  253. package/dist/utils/file-system.d.ts +36 -0
  254. package/dist/utils/file-system.js +281 -0
  255. package/dist/utils/index.d.ts +6 -0
  256. package/dist/utils/index.js +9 -0
  257. package/dist/utils/interactive.d.ts +18 -0
  258. package/dist/utils/interactive.js +21 -0
  259. package/dist/utils/item-discovery.d.ts +4 -0
  260. package/dist/utils/item-discovery.js +72 -0
  261. package/dist/utils/match.d.ts +3 -0
  262. package/dist/utils/match.js +22 -0
  263. package/dist/utils/shell-detection.d.ts +20 -0
  264. package/dist/utils/shell-detection.js +41 -0
  265. package/dist/utils/task-progress.d.ts +8 -0
  266. package/dist/utils/task-progress.js +36 -0
  267. package/package.json +78 -0
  268. package/schemas/spec-driven/schema.yaml +153 -0
  269. package/schemas/spec-driven/templates/design.md +19 -0
  270. package/schemas/spec-driven/templates/proposal.md +23 -0
  271. package/schemas/spec-driven/templates/spec.md +8 -0
  272. package/schemas/spec-driven/templates/tasks.md +9 -0
  273. package/scripts/postinstall.js +83 -0
@@ -0,0 +1,159 @@
1
+ import chalk from 'chalk';
2
+ /**
3
+ * Create the searchable multi-select prompt.
4
+ * Uses dynamic import to prevent pre-commit hook hangs (see #367).
5
+ */
6
+ async function createSearchableMultiSelect() {
7
+ const { createPrompt, useState, useKeypress, useMemo, usePrefix, isEnterKey, isBackspaceKey, isUpKey, isDownKey, } = await import('@inquirer/core');
8
+ return createPrompt((config, done) => {
9
+ const { message, choices, pageSize = 15, validate } = config;
10
+ const [searchText, setSearchText] = useState('');
11
+ const [selectedValues, setSelectedValues] = useState(() => choices.filter(c => c.preSelected).map(c => c.value));
12
+ const [cursor, setCursor] = useState(0);
13
+ const [status, setStatus] = useState('idle');
14
+ const [error, setError] = useState(null);
15
+ const prefix = usePrefix({ status });
16
+ // Filter choices by search
17
+ const filteredChoices = useMemo(() => {
18
+ if (!searchText.trim())
19
+ return choices;
20
+ const term = searchText.toLowerCase();
21
+ return choices.filter((c) => c.name.toLowerCase().includes(term) ||
22
+ c.value.toLowerCase().includes(term));
23
+ }, [searchText, choices]);
24
+ const selectedSet = useMemo(() => new Set(selectedValues), [selectedValues]);
25
+ const choiceMap = useMemo(() => new Map(choices.map((c) => [c.value, c])), [choices]);
26
+ useKeypress((key) => {
27
+ if (status === 'done')
28
+ return;
29
+ // Enter to confirm/submit
30
+ if (isEnterKey(key)) {
31
+ if (validate) {
32
+ const result = validate(selectedValues);
33
+ if (result !== true) {
34
+ setError(typeof result === 'string' ? result : 'Invalid');
35
+ return;
36
+ }
37
+ }
38
+ setStatus('done');
39
+ done(selectedValues);
40
+ return;
41
+ }
42
+ // Space to toggle selection
43
+ if (key.name === 'space') {
44
+ const choice = filteredChoices[cursor];
45
+ if (choice) {
46
+ if (selectedSet.has(choice.value)) {
47
+ setSelectedValues(selectedValues.filter(v => v !== choice.value));
48
+ }
49
+ else {
50
+ setSelectedValues([...selectedValues, choice.value]);
51
+ }
52
+ }
53
+ return;
54
+ }
55
+ // Backspace to remove or delete search char
56
+ if (isBackspaceKey(key)) {
57
+ if (searchText === '' && selectedValues.length > 0) {
58
+ setSelectedValues(selectedValues.slice(0, -1));
59
+ }
60
+ else {
61
+ setSearchText(searchText.slice(0, -1));
62
+ setCursor(0);
63
+ }
64
+ return;
65
+ }
66
+ // Navigation
67
+ if (isUpKey(key)) {
68
+ setCursor(Math.max(0, cursor - 1));
69
+ return;
70
+ }
71
+ if (isDownKey(key)) {
72
+ setCursor(Math.min(filteredChoices.length - 1, cursor + 1));
73
+ return;
74
+ }
75
+ // Character input - handle printable characters
76
+ if (key.name && key.name.length === 1 && !key.ctrl) {
77
+ setSearchText(searchText + key.name);
78
+ setCursor(0);
79
+ }
80
+ });
81
+ // Render done state
82
+ if (status === 'done') {
83
+ const names = selectedValues
84
+ .map((v) => choiceMap.get(v)?.name ?? v)
85
+ .join(', ');
86
+ return `${prefix} ${chalk.bold(message)} ${chalk.cyan(names || '(none)')}`;
87
+ }
88
+ // Render active state
89
+ const lines = [];
90
+ lines.push(`${prefix} ${chalk.bold(message)}`);
91
+ // Selected chips
92
+ const chips = selectedValues.length > 0
93
+ ? selectedValues
94
+ .map((v) => chalk.bgCyan.black(` ${choiceMap.get(v)?.name} `))
95
+ .join(' ')
96
+ : chalk.dim('(none selected)');
97
+ lines.push(` Selected: ${chips}`);
98
+ // Search box
99
+ lines.push(` Search: ${chalk.yellow('[')}${searchText || chalk.dim('type to filter')}${chalk.yellow(']')}`);
100
+ // Instructions
101
+ lines.push(` ${chalk.cyan('↑↓')} navigate • ${chalk.cyan('Space')} toggle • ${chalk.cyan('Backspace')} remove • ${chalk.cyan('Enter')} confirm`);
102
+ // List
103
+ if (filteredChoices.length === 0) {
104
+ lines.push(chalk.yellow(' No matches'));
105
+ }
106
+ else {
107
+ // Calculate pagination
108
+ const startIndex = Math.max(0, Math.min(cursor - Math.floor(pageSize / 2), filteredChoices.length - pageSize));
109
+ const endIndex = Math.min(startIndex + pageSize, filteredChoices.length);
110
+ const visibleChoices = filteredChoices.slice(startIndex, endIndex);
111
+ for (let i = 0; i < visibleChoices.length; i++) {
112
+ const item = visibleChoices[i];
113
+ const actualIndex = startIndex + i;
114
+ const isActive = actualIndex === cursor;
115
+ const selected = selectedSet.has(item.value);
116
+ const icon = selected ? chalk.green('◉') : chalk.dim('○');
117
+ const arrow = isActive ? chalk.cyan('›') : ' ';
118
+ const name = isActive ? chalk.cyan(item.name) : item.name;
119
+ const isRefresh = selected && item.configured;
120
+ const statusLabel = !selected
121
+ ? item.configured
122
+ ? ' (configured)'
123
+ : item.detected
124
+ ? ' (detected)'
125
+ : ''
126
+ : '';
127
+ const suffix = selected
128
+ ? chalk.dim(isRefresh ? ' (refresh)' : ' (selected)')
129
+ : chalk.dim(statusLabel);
130
+ lines.push(` ${arrow} ${icon} ${name}${suffix}`);
131
+ }
132
+ // Show pagination indicator if needed
133
+ if (filteredChoices.length > pageSize) {
134
+ const currentPage = Math.floor(cursor / pageSize) + 1;
135
+ const totalPages = Math.ceil(filteredChoices.length / pageSize);
136
+ lines.push(chalk.dim(` (${currentPage}/${totalPages})`));
137
+ }
138
+ }
139
+ if (error)
140
+ lines.push(chalk.red(` ${error}`));
141
+ return lines.join('\n');
142
+ });
143
+ }
144
+ /**
145
+ * A searchable multi-select prompt with visible search box,
146
+ * selected items display, and intuitive keyboard navigation.
147
+ *
148
+ * - Type to filter choices
149
+ * - ↑↓ to navigate
150
+ * - Space to toggle highlighted item selection
151
+ * - Backspace to remove last selected item (or delete search char)
152
+ * - Enter to confirm selections
153
+ */
154
+ export async function searchableMultiSelect(config) {
155
+ const prompt = await createSearchableMultiSelect();
156
+ return prompt(config);
157
+ }
158
+ export default searchableMultiSelect;
159
+ //# sourceMappingURL=searchable-multi-select.js.map
@@ -0,0 +1,16 @@
1
+ /**
2
+ * ASCII art animation patterns for the welcome screen.
3
+ * OpenSpec logo animation - diamond/rhombus shape with hollow center "O".
4
+ */
5
+ /**
6
+ * Welcome animation frames - OpenSpec logo building from center
7
+ * 7 rows × 6 columns diamond with hollow center "O"
8
+ * Center bar is 2 cols × 3 rows (rows 3,4,5 cols 3,4)
9
+ * Each frame is an array of strings (lines of ASCII art)
10
+ * Grid: 6 cols × 2 chars = 12 chars wide
11
+ */
12
+ export declare const WELCOME_ANIMATION: {
13
+ interval: number;
14
+ frames: string[][];
15
+ };
16
+ //# sourceMappingURL=ascii-patterns.d.ts.map
@@ -0,0 +1,133 @@
1
+ /**
2
+ * ASCII art animation patterns for the welcome screen.
3
+ * AnchorSpec logo animation - diamond/rhombus shape with hollow center "O".
4
+ */
5
+ // Detect if full Unicode is supported
6
+ const supportsUnicode = process.platform !== 'win32' ||
7
+ !!process.env.WT_SESSION || // Windows Terminal
8
+ !!process.env.TERM_PROGRAM; // Modern terminal
9
+ // Character set based on Unicode support
10
+ // Block characters for pixel-art aesthetic
11
+ const CHARS = supportsUnicode
12
+ ? { full: '██', dim: '░░', empty: ' ' }
13
+ : { full: '##', dim: '++', empty: ' ' };
14
+ const _ = CHARS.empty;
15
+ const F = CHARS.full;
16
+ const D = CHARS.dim;
17
+ /**
18
+ * Welcome animation frames - AnchorSpec logo building from center
19
+ * 7 rows × 6 columns diamond with hollow center "O"
20
+ * Center bar is 2 cols × 3 rows (rows 3,4,5 cols 3,4)
21
+ * Each frame is an array of strings (lines of ASCII art)
22
+ * Grid: 6 cols × 2 chars = 12 chars wide
23
+ */
24
+ export const WELCOME_ANIMATION = {
25
+ interval: 120,
26
+ frames: [
27
+ // Frame 1: Empty
28
+ [
29
+ `${_}${_}${_}${_}${_}${_}${_}${_}`, // padding row 1
30
+ `${_}${_}${_}${_}${_}${_}${_}${_}`, // padding row 2
31
+ `${_}${_}${_}${_}${_}${_}${_}${_}`, // padding row 3
32
+ `${_}${_}${_}${_}${_}${_}${_}${_}`,
33
+ `${_}${_}${_}${_}${_}${_}${_}${_}`,
34
+ `${_}${_}${_}${_}${_}${_}${_}${_}`,
35
+ `${_}${_}${_}${_}${_}${_}${_}${_}`,
36
+ `${_}${_}${_}${_}${_}${_}${_}${_}`,
37
+ `${_}${_}${_}${_}${_}${_}${_}${_}`,
38
+ `${_}${_}${_}${_}${_}${_}${_}${_}`,
39
+ ],
40
+ // Frame 2: Center blocks appear (dim) - 2x3 center bar
41
+ [
42
+ `${_}${_}${_}${_}${_}${_}${_}${_}`, // padding row 1
43
+ `${_}${_}${_}${_}${_}${_}${_}${_}`, // padding row 2
44
+ `${_}${_}${_}${_}${_}${_}${_}${_}`, // padding row 3
45
+ `${_}${_}${_}${_}${_}${_}${_}${_}`,
46
+ `${_}${_}${_}${_}${_}${_}${_}${_}`,
47
+ `${_}${_}${_}${_}${D}${D}${_}${_}`,
48
+ `${_}${_}${_}${_}${D}${D}${_}${_}`,
49
+ `${_}${_}${_}${_}${D}${D}${_}${_}`,
50
+ `${_}${_}${_}${_}${_}${_}${_}${_}`,
51
+ `${_}${_}${_}${_}${_}${_}${_}${_}`,
52
+ ],
53
+ // Frame 3: Center blocks solidify
54
+ [
55
+ `${_}${_}${_}${_}${_}${_}${_}${_}`, // padding row 1
56
+ `${_}${_}${_}${_}${_}${_}${_}${_}`, // padding row 2
57
+ `${_}${_}${_}${_}${_}${_}${_}${_}`, // padding row 3
58
+ `${_}${_}${_}${_}${_}${_}${_}${_}`,
59
+ `${_}${_}${_}${_}${_}${_}${_}${_}`,
60
+ `${_}${_}${_}${_}${F}${F}${_}${_}`,
61
+ `${_}${_}${_}${_}${F}${F}${_}${_}`,
62
+ `${_}${_}${_}${_}${F}${F}${_}${_}`,
63
+ `${_}${_}${_}${_}${_}${_}${_}${_}`,
64
+ `${_}${_}${_}${_}${_}${_}${_}${_}`,
65
+ ],
66
+ // Frame 4: Top and bottom points appear
67
+ [
68
+ `${_}${_}${_}${_}${_}${_}${_}${_}`, // padding row 1
69
+ `${_}${_}${_}${_}${_}${_}${_}${_}`, // padding row 2
70
+ `${_}${_}${_}${_}${_}${_}${_}${_}`, // padding row 3
71
+ `${_}${_}${_}${_}${D}${D}${_}${_}`,
72
+ `${_}${_}${_}${_}${_}${_}${_}${_}`,
73
+ `${_}${_}${_}${_}${F}${F}${_}${_}`,
74
+ `${_}${_}${_}${_}${F}${F}${_}${_}`,
75
+ `${_}${_}${_}${_}${F}${F}${_}${_}`,
76
+ `${_}${_}${_}${_}${_}${_}${_}${_}`,
77
+ `${_}${_}${_}${_}${D}${D}${_}${_}`,
78
+ ],
79
+ // Frame 5: Inner ring forming
80
+ [
81
+ `${_}${_}${_}${_}${_}${_}${_}${_}`, // padding row 1
82
+ `${_}${_}${_}${_}${_}${_}${_}${_}`, // padding row 2
83
+ `${_}${_}${_}${_}${_}${_}${_}${_}`, // padding row 3
84
+ `${_}${_}${_}${_}${F}${F}${_}${_}`,
85
+ `${_}${_}${_}${D}${_}${_}${D}${_}`,
86
+ `${_}${_}${_}${_}${F}${F}${_}${_}`,
87
+ `${_}${_}${_}${_}${F}${F}${_}${_}`,
88
+ `${_}${_}${_}${_}${F}${F}${_}${_}`,
89
+ `${_}${_}${_}${D}${_}${_}${D}${_}`,
90
+ `${_}${_}${_}${_}${F}${F}${_}${_}`,
91
+ ],
92
+ // Frame 6: Outer ring appearing
93
+ [
94
+ `${_}${_}${_}${_}${_}${_}${_}${_}`, // padding row 1
95
+ `${_}${_}${_}${_}${_}${_}${_}${_}`, // padding row 2
96
+ `${_}${_}${_}${_}${_}${_}${_}${_}`, // padding row 3
97
+ `${_}${_}${_}${_}${F}${F}${_}${_}`,
98
+ `${_}${_}${_}${F}${_}${_}${F}${_}`,
99
+ `${_}${_}${D}${_}${F}${F}${_}${D}`,
100
+ `${_}${_}${D}${_}${F}${F}${_}${D}`,
101
+ `${_}${_}${D}${_}${F}${F}${_}${D}`,
102
+ `${_}${_}${_}${F}${_}${_}${F}${_}`,
103
+ `${_}${_}${_}${_}${F}${F}${_}${_}`,
104
+ ],
105
+ // Frame 7: Full logo
106
+ [
107
+ `${_}${_}${_}${_}${_}${_}${_}${_}`, // padding row 1
108
+ `${_}${_}${_}${_}${_}${_}${_}${_}`, // padding row 2
109
+ `${_}${_}${_}${_}${_}${_}${_}${_}`, // padding row 3
110
+ `${_}${_}${_}${_}${F}${F}${_}${_}`,
111
+ `${_}${_}${_}${F}${_}${_}${F}${_}`,
112
+ `${_}${_}${F}${_}${F}${F}${_}${F}`,
113
+ `${_}${_}${F}${_}${F}${F}${_}${F}`,
114
+ `${_}${_}${F}${_}${F}${F}${_}${F}`,
115
+ `${_}${_}${_}${F}${_}${_}${F}${_}`,
116
+ `${_}${_}${_}${_}${F}${F}${_}${_}`,
117
+ ],
118
+ // Frame 8: Hold complete logo
119
+ [
120
+ `${_}${_}${_}${_}${_}${_}${_}${_}`, // padding row 1
121
+ `${_}${_}${_}${_}${_}${_}${_}${_}`, // padding row 2
122
+ `${_}${_}${_}${_}${_}${_}${_}${_}`, // padding row 3
123
+ `${_}${_}${_}${_}${F}${F}${_}${_}`,
124
+ `${_}${_}${_}${F}${_}${_}${F}${_}`,
125
+ `${_}${_}${F}${_}${F}${F}${_}${F}`,
126
+ `${_}${_}${F}${_}${F}${F}${_}${F}`,
127
+ `${_}${_}${F}${_}${F}${F}${_}${F}`,
128
+ `${_}${_}${_}${F}${_}${_}${F}${_}`,
129
+ `${_}${_}${_}${_}${F}${F}${_}${_}`,
130
+ ],
131
+ ],
132
+ };
133
+ //# sourceMappingURL=ascii-patterns.js.map
@@ -0,0 +1,10 @@
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
+ /**
6
+ * Shows the animated welcome screen.
7
+ * Returns when user presses Enter.
8
+ */
9
+ export declare function showWelcomeScreen(): Promise<void>;
10
+ //# sourceMappingURL=welcome-screen.d.ts.map
@@ -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 AnchorSpec'),
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(' • /ansx:* slash commands'),
22
+ '',
23
+ chalk.white('Quick start after setup:'),
24
+ ` ${chalk.yellow('/ansx:new')} ${chalk.dim('Create a change')}`,
25
+ ` ${chalk.yellow('/ansx:continue')} ${chalk.dim('Next artifact')}`,
26
+ ` ${chalk.yellow('/ansx: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,51 @@
1
+ import { type ChangeMetadata } from '../core/artifact-graph/types.js';
2
+ /**
3
+ * Error thrown when change metadata validation fails.
4
+ */
5
+ export declare class ChangeMetadataError extends Error {
6
+ readonly metadataPath: string;
7
+ readonly cause?: Error | undefined;
8
+ constructor(message: string, metadataPath: string, cause?: Error | undefined);
9
+ }
10
+ /**
11
+ * Validates that a schema name is valid (exists in available schemas).
12
+ *
13
+ * @param schemaName - The schema name to validate
14
+ * @param projectRoot - Optional project root for project-local schema resolution
15
+ * @returns The validated schema name
16
+ * @throws Error if schema is not found
17
+ */
18
+ export declare function validateSchemaName(schemaName: string, projectRoot?: string): string;
19
+ /**
20
+ * Writes change metadata to .openspec.yaml in the change directory.
21
+ *
22
+ * @param changeDir - The path to the change directory
23
+ * @param metadata - The metadata to write
24
+ * @param projectRoot - Optional project root for project-local schema resolution
25
+ * @throws ChangeMetadataError if validation fails or write fails
26
+ */
27
+ export declare function writeChangeMetadata(changeDir: string, metadata: ChangeMetadata, projectRoot?: string): void;
28
+ /**
29
+ * Reads change metadata from .openspec.yaml in the change directory.
30
+ *
31
+ * @param changeDir - The path to the change directory
32
+ * @param projectRoot - Optional project root for project-local schema resolution
33
+ * @returns The validated metadata, or null if no metadata file exists
34
+ * @throws ChangeMetadataError if the file exists but is invalid
35
+ */
36
+ export declare function readChangeMetadata(changeDir: string, projectRoot?: string): ChangeMetadata | null;
37
+ /**
38
+ * Resolves the schema for a change, with explicit override taking precedence.
39
+ *
40
+ * Resolution order:
41
+ * 1. Explicit schema (if provided)
42
+ * 2. Schema from .openspec.yaml metadata (if exists)
43
+ * 3. Schema from openspec/config.yaml (if exists)
44
+ * 4. Default 'spec-driven'
45
+ *
46
+ * @param changeDir - The path to the change directory
47
+ * @param explicitSchema - Optional explicit schema override
48
+ * @returns The resolved schema name
49
+ */
50
+ export declare function resolveSchemaForChange(changeDir: string, explicitSchema?: string): string;
51
+ //# sourceMappingURL=change-metadata.d.ts.map
@@ -0,0 +1,147 @@
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/artifact-graph/types.js';
5
+ import { listSchemas } from '../core/artifact-graph/resolver.js';
6
+ import { readProjectConfig } from '../core/project-config.js';
7
+ const METADATA_FILENAME = '.anchorspec.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 .anchorspec.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 .anchorspec.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 .anchorspec.yaml metadata (if exists)
110
+ * 3. Schema from anchorspec/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) {
118
+ // Derive project root from changeDir (changeDir is typically projectRoot/anchorspec/changes/change-name)
119
+ const projectRoot = path.resolve(changeDir, '../../..');
120
+ // 1. Explicit override wins
121
+ if (explicitSchema) {
122
+ return explicitSchema;
123
+ }
124
+ // 2. Try reading from metadata
125
+ try {
126
+ const metadata = readChangeMetadata(changeDir, projectRoot);
127
+ if (metadata?.schema) {
128
+ return metadata.schema;
129
+ }
130
+ }
131
+ catch {
132
+ // If metadata read fails, continue to next option
133
+ }
134
+ // 3. Try reading from project config
135
+ try {
136
+ const config = readProjectConfig(projectRoot);
137
+ if (config?.schema) {
138
+ return config.schema;
139
+ }
140
+ }
141
+ catch {
142
+ // If config read fails, fall back to default
143
+ }
144
+ // 4. Default
145
+ return 'spec-driven';
146
+ }
147
+ //# sourceMappingURL=change-metadata.js.map