@dedesfr/prompter 0.9.0 → 1.1.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 (225) hide show
  1. package/CHANGELOG.md +35 -0
  2. package/README.md +105 -77
  3. package/dist/cli/index.js +25 -1
  4. package/dist/cli/index.js.map +1 -1
  5. package/dist/commands/init.d.ts.map +1 -1
  6. package/dist/commands/init.js +35 -9
  7. package/dist/commands/init.js.map +1 -1
  8. package/dist/commands/login.d.ts +4 -0
  9. package/dist/commands/login.d.ts.map +1 -0
  10. package/dist/commands/login.js +56 -0
  11. package/dist/commands/login.js.map +1 -0
  12. package/dist/commands/logout.d.ts +4 -0
  13. package/dist/commands/logout.d.ts.map +1 -0
  14. package/dist/commands/logout.js +14 -0
  15. package/dist/commands/logout.js.map +1 -0
  16. package/dist/commands/update.d.ts +0 -2
  17. package/dist/commands/update.d.ts.map +1 -1
  18. package/dist/commands/update.js +19 -48
  19. package/dist/commands/update.js.map +1 -1
  20. package/dist/commands/whoami.d.ts +4 -0
  21. package/dist/commands/whoami.d.ts.map +1 -0
  22. package/dist/commands/whoami.js +42 -0
  23. package/dist/commands/whoami.js.map +1 -0
  24. package/dist/core/auth-store.d.ts +10 -0
  25. package/dist/core/auth-store.d.ts.map +1 -0
  26. package/dist/core/auth-store.js +39 -0
  27. package/dist/core/auth-store.js.map +1 -0
  28. package/dist/core/config.d.ts +0 -7
  29. package/dist/core/config.d.ts.map +1 -1
  30. package/dist/core/config.js +0 -128
  31. package/dist/core/config.js.map +1 -1
  32. package/dist/core/registry.d.ts +18 -0
  33. package/dist/core/registry.d.ts.map +1 -0
  34. package/dist/core/registry.js +94 -0
  35. package/dist/core/registry.js.map +1 -0
  36. package/package.json +7 -1
  37. package/AGENTS.md +0 -123
  38. package/CLAUDE.md +0 -17
  39. package/build.js +0 -20
  40. package/convex-setup.md +0 -403
  41. package/dist/core/prompt-templates.d.ts +0 -23
  42. package/dist/core/prompt-templates.d.ts.map +0 -1
  43. package/dist/core/prompt-templates.js +0 -3485
  44. package/dist/core/prompt-templates.js.map +0 -1
  45. package/prompt/ai-humanizer.md +0 -45
  46. package/prompt/api-contract-generator.md +0 -234
  47. package/prompt/apply.md +0 -17
  48. package/prompt/archive.md +0 -21
  49. package/prompt/design-system.md +0 -210
  50. package/prompt/document-explainer.md +0 -149
  51. package/prompt/epic-generator.md +0 -198
  52. package/prompt/epic-single.md +0 -47
  53. package/prompt/erd-generator.md +0 -130
  54. package/prompt/fsd-generator.md +0 -157
  55. package/prompt/prd-agent-generator.md +0 -147
  56. package/prompt/prd-generator.md +0 -195
  57. package/prompt/product-brief.md +0 -289
  58. package/prompt/proposal.md +0 -22
  59. package/prompt/qa-test-scenario.md +0 -133
  60. package/prompt/skill-creator.md +0 -350
  61. package/prompt/story-generator.md +0 -278
  62. package/prompt/story-single.md +0 -70
  63. package/prompt/tdd-generator.md +0 -294
  64. package/prompt/tdd-lite-generator.md +0 -224
  65. package/prompt/wireframe-generator.md +0 -219
  66. package/skills/ai-context-generator/SKILL.md +0 -54
  67. package/skills/ai-context-generator/references/AGENTS.template.md +0 -83
  68. package/skills/ai-context-generator/references/CLAUDE.template.md +0 -39
  69. package/skills/ai-context-generator/references/behavioral-guidelines.md +0 -71
  70. package/skills/ai-context-generator/references/discovery-checklist.md +0 -40
  71. package/skills/ai-context-generator/references/examples/AGENTS.good.md +0 -103
  72. package/skills/ai-context-generator/references/extraction-checklist.md +0 -23
  73. package/skills/ai-context-generator/references/overlays/laravel.md +0 -44
  74. package/skills/ai-humanizer/SKILL.md +0 -50
  75. package/skills/api-contract-generator/SKILL.md +0 -243
  76. package/skills/apply/SKILL.md +0 -23
  77. package/skills/archive/SKILL.md +0 -27
  78. package/skills/cerebro/SKILL.md +0 -187
  79. package/skills/cerebro/references/agents.md +0 -213
  80. package/skills/code-review/SKILL.md +0 -373
  81. package/skills/code-review/assets/report-template-agent.md +0 -212
  82. package/skills/code-review/assets/report-template-compact.md +0 -81
  83. package/skills/code-review/assets/report-template-full.md +0 -264
  84. package/skills/code-review/assets/report-template-human.md +0 -168
  85. package/skills/code-review/references/universal-patterns.md +0 -495
  86. package/skills/design-md/README.md +0 -34
  87. package/skills/design-md/SKILL.md +0 -172
  88. package/skills/design-md/examples/DESIGN.md +0 -154
  89. package/skills/design-system/SKILL.md +0 -216
  90. package/skills/design-system-generator/SKILL.md +0 -324
  91. package/skills/design-system-generator/assets/design-system-template.md +0 -348
  92. package/skills/design-system-generator/references/extraction-patterns.md +0 -321
  93. package/skills/doc-builder/SKILL.md +0 -115
  94. package/skills/doc-builder/references/ui-patterns.md +0 -394
  95. package/skills/document-explainer/SKILL.md +0 -155
  96. package/skills/document-translator/SKILL.md +0 -58
  97. package/skills/enhance/SKILL.md +0 -47
  98. package/skills/enhance-prompt/README.md +0 -34
  99. package/skills/enhance-prompt/SKILL.md +0 -204
  100. package/skills/enhance-prompt/references/KEYWORDS.md +0 -114
  101. package/skills/epic-generator/SKILL.md +0 -204
  102. package/skills/epic-single/SKILL.md +0 -63
  103. package/skills/erd-generator/SKILL.md +0 -138
  104. package/skills/feature-planner/SKILL.md +0 -305
  105. package/skills/feature-planner/assets/implementation-plan-template.md +0 -85
  106. package/skills/frontend-design/LICENSE.txt +0 -177
  107. package/skills/frontend-design/SKILL.md +0 -42
  108. package/skills/fsd-generator/SKILL.md +0 -163
  109. package/skills/gamma-builder/SKILL.md +0 -134
  110. package/skills/laravel-code-review/SKILL.md +0 -383
  111. package/skills/laravel-code-review/assets/report-template-agent.md +0 -195
  112. package/skills/laravel-code-review/assets/report-template-compact.md +0 -79
  113. package/skills/laravel-code-review/assets/report-template-full.md +0 -253
  114. package/skills/laravel-code-review/assets/report-template-human.md +0 -159
  115. package/skills/laravel-code-review/references/laravel-patterns.md +0 -571
  116. package/skills/laravel-code-review/references/php84-features.md +0 -442
  117. package/skills/mcp-builder/LICENSE.txt +0 -202
  118. package/skills/mcp-builder/SKILL.md +0 -236
  119. package/skills/mcp-builder/reference/evaluation.md +0 -602
  120. package/skills/mcp-builder/reference/mcp_best_practices.md +0 -249
  121. package/skills/mcp-builder/reference/node_mcp_server.md +0 -970
  122. package/skills/mcp-builder/reference/python_mcp_server.md +0 -719
  123. package/skills/mcp-builder/scripts/connections.py +0 -151
  124. package/skills/mcp-builder/scripts/evaluation.py +0 -373
  125. package/skills/mcp-builder/scripts/example_evaluation.xml +0 -22
  126. package/skills/mcp-builder/scripts/requirements.txt +0 -2
  127. package/skills/meeting-notes/SKILL.md +0 -159
  128. package/skills/meeting-notes/evals/evals.json +0 -23
  129. package/skills/prd-agent-generator/SKILL.md +0 -132
  130. package/skills/prd-generator/SKILL.md +0 -211
  131. package/skills/product-brief/SKILL.md +0 -141
  132. package/skills/project-orchestrator/SKILL.md +0 -487
  133. package/skills/project-orchestrator/assets/caddy-vps-setup.md +0 -180
  134. package/skills/project-orchestrator/assets/plan-summary-template.md +0 -159
  135. package/skills/prompter-specs/SKILL.md +0 -115
  136. package/skills/prompter-workflow/SKILL.md +0 -166
  137. package/skills/prompter-workflow/evals/evals.json +0 -89
  138. package/skills/proposal/SKILL.md +0 -28
  139. package/skills/qa-test-scenario/SKILL.md +0 -149
  140. package/skills/skill-creator/SKILL.md +0 -173
  141. package/skills/sph-generator/SKILL.md +0 -488
  142. package/skills/story-generator/SKILL.md +0 -285
  143. package/skills/story-single/SKILL.md +0 -86
  144. package/skills/tdd-generator/SKILL.md +0 -300
  145. package/skills/tdd-lite-generator/SKILL.md +0 -230
  146. package/skills/ui-ux-pro/SKILL.md +0 -199
  147. package/skills/ui-ux-pro/assets/design-spec-template.md +0 -173
  148. package/skills/ui-ux-pro/references/component-patterns.md +0 -255
  149. package/skills/ui-ux-pro/references/design-principles.md +0 -167
  150. package/skills/wireframe-generator/SKILL.md +0 -227
  151. package/src/cli/index.ts +0 -223
  152. package/src/commands/archive.ts +0 -302
  153. package/src/commands/change.ts +0 -292
  154. package/src/commands/config.ts +0 -233
  155. package/src/commands/guide.ts +0 -50
  156. package/src/commands/init.ts +0 -597
  157. package/src/commands/list.ts +0 -194
  158. package/src/commands/show.ts +0 -138
  159. package/src/commands/spec.ts +0 -251
  160. package/src/commands/update.ts +0 -129
  161. package/src/commands/upgrade.ts +0 -30
  162. package/src/commands/validate.ts +0 -326
  163. package/src/core/artifact-graph/graph.ts +0 -167
  164. package/src/core/artifact-graph/index.ts +0 -44
  165. package/src/core/artifact-graph/instruction-loader.ts +0 -302
  166. package/src/core/artifact-graph/resolver.ts +0 -226
  167. package/src/core/artifact-graph/schema.ts +0 -124
  168. package/src/core/artifact-graph/state.ts +0 -64
  169. package/src/core/artifact-graph/types.ts +0 -65
  170. package/src/core/completions/command-registry.ts +0 -382
  171. package/src/core/completions/completion-provider.ts +0 -128
  172. package/src/core/completions/generators/bash-generator.ts +0 -191
  173. package/src/core/completions/generators/fish-generator.ts +0 -188
  174. package/src/core/completions/generators/powershell-generator.ts +0 -223
  175. package/src/core/completions/generators/zsh-generator.ts +0 -281
  176. package/src/core/completions/templates/bash-templates.ts +0 -24
  177. package/src/core/completions/templates/fish-templates.ts +0 -40
  178. package/src/core/completions/templates/powershell-templates.ts +0 -25
  179. package/src/core/completions/templates/zsh-templates.ts +0 -36
  180. package/src/core/completions/types.ts +0 -90
  181. package/src/core/config-schema.ts +0 -230
  182. package/src/core/config.ts +0 -181
  183. package/src/core/configurators/slash/antigravity.ts +0 -10
  184. package/src/core/configurators/slash/base.ts +0 -109
  185. package/src/core/configurators/slash/claude.ts +0 -10
  186. package/src/core/configurators/slash/codex.ts +0 -10
  187. package/src/core/configurators/slash/droid.ts +0 -10
  188. package/src/core/configurators/slash/forge.ts +0 -10
  189. package/src/core/configurators/slash/github-copilot.ts +0 -10
  190. package/src/core/configurators/slash/index.ts +0 -10
  191. package/src/core/configurators/slash/kilocode.ts +0 -10
  192. package/src/core/configurators/slash/opencode.ts +0 -10
  193. package/src/core/configurators/slash/registry.ts +0 -51
  194. package/src/core/converters/json-converter.ts +0 -62
  195. package/src/core/global-config.ts +0 -136
  196. package/src/core/parsers/change-parser.ts +0 -234
  197. package/src/core/parsers/markdown-parser.ts +0 -237
  198. package/src/core/parsers/requirement-blocks.ts +0 -234
  199. package/src/core/prompt-templates.ts +0 -3504
  200. package/src/core/schemas/base.schema.ts +0 -20
  201. package/src/core/schemas/change.schema.ts +0 -42
  202. package/src/core/schemas/index.ts +0 -20
  203. package/src/core/schemas/spec.schema.ts +0 -17
  204. package/src/core/skill-discovery.ts +0 -68
  205. package/src/core/specs-apply.ts +0 -483
  206. package/src/core/styles/palette.ts +0 -8
  207. package/src/core/templates/agents-template.ts +0 -459
  208. package/src/core/templates/claude-template.ts +0 -2
  209. package/src/core/templates/index.ts +0 -3
  210. package/src/core/templates/project-template.ts +0 -32
  211. package/src/core/validation/constants.ts +0 -48
  212. package/src/core/validation/types.ts +0 -19
  213. package/src/core/validation/validator.ts +0 -449
  214. package/src/core/view.ts +0 -219
  215. package/src/index.ts +0 -1
  216. package/src/utils/change-metadata.ts +0 -171
  217. package/src/utils/change-utils.ts +0 -131
  218. package/src/utils/file-system.ts +0 -252
  219. package/src/utils/index.ts +0 -12
  220. package/src/utils/interactive.ts +0 -29
  221. package/src/utils/item-discovery.ts +0 -66
  222. package/src/utils/match.ts +0 -26
  223. package/src/utils/shell-detection.ts +0 -62
  224. package/src/utils/task-progress.ts +0 -43
  225. package/tsconfig.json +0 -28
package/src/cli/index.ts DELETED
@@ -1,223 +0,0 @@
1
- import ora from 'ora';
2
- import { Command } from 'commander';
3
- import { InitCommand } from '../commands/init.js';
4
- import { UpdateCommand } from '../commands/update.js';
5
- import { ListCommand } from '../commands/list.js';
6
- import { GuideCommand } from '../commands/guide.js';
7
- import { UpgradeCommand } from '../commands/upgrade.js';
8
- import { ViewCommand } from '../core/view.js';
9
- import { ChangeCommand } from '../commands/change.js';
10
- import { registerSpecCommand } from '../commands/spec.js';
11
- import { registerConfigCommand } from '../commands/config.js';
12
- import { ValidateCommand } from '../commands/validate.js';
13
- import { ShowCommand } from '../commands/show.js';
14
- import { ArchiveCommand } from '../commands/archive.js';
15
-
16
- const program = new Command();
17
-
18
- program
19
- .name('prompter')
20
- .description('Enhance prompts directly in your AI coding workflow')
21
- .version('0.9.0');
22
-
23
- program
24
- .command('init')
25
- .description('Initialize Prompter in your project')
26
- .option('--tools <tools...>', 'Specify AI tools to configure (antigravity, claude, codex, github-copilot, opencode, kilocode)')
27
- .option('--prompts <prompts...>', 'Specify prompts to install (ai-humanizer, api-contract-generator, apply, archive, design-system, document-explainer, epic-single, epic-generator, erd-generator, fsd-generator, prd-agent-generator, prd-generator, product-brief, proposal, qa-test-scenario, skill-creator, story-single, story-generator, tdd-generator, tdd-lite-generator, wireframe-generator)')
28
- .option('--skills <skills...>', 'Specify skills to install by name (e.g. laravel-code-review design-system-generator)')
29
- .option('--no-interactive', 'Run without interactive prompts')
30
- .action(async (options) => {
31
- const initCommand = new InitCommand();
32
- await initCommand.execute(options);
33
- });
34
-
35
- program
36
- .command('update')
37
- .description('Update Prompter workflow files to latest version')
38
- .action(async () => {
39
- const updateCommand = new UpdateCommand();
40
- await updateCommand.execute();
41
- });
42
-
43
- program
44
- .command('list')
45
- .description('List items (changes by default). Use --specs to list specs.')
46
- .option('--specs', 'List specs instead of changes')
47
- .option('--changes', 'List changes explicitly (default)')
48
- .option('--sort <order>', 'Sort order: "recent" (default) or "name"', 'recent')
49
- .option('--json', 'Output as JSON (for programmatic use)')
50
- .action(async (options?: { specs?: boolean; changes?: boolean; sort?: string; json?: boolean }) => {
51
- try {
52
- const listCommand = new ListCommand();
53
- const mode: 'changes' | 'specs' = options?.specs ? 'specs' : 'changes';
54
- const sort = options?.sort === 'name' ? 'name' : 'recent';
55
- await listCommand.execute('.', mode, { sort, json: options?.json });
56
- } catch (error) {
57
- console.log(); // Empty line for spacing
58
- process.exit(1);
59
- }
60
- });
61
-
62
- program
63
- .command('view')
64
- .description('Display an interactive dashboard of specs and changes')
65
- .action(async () => {
66
- try {
67
- const viewCommand = new ViewCommand();
68
- await viewCommand.execute('.');
69
- } catch (error) {
70
- console.log(); // Empty line for spacing
71
- process.exit(1);
72
- }
73
- });
74
-
75
- program
76
- .command('guide')
77
- .description('Show setup guide for Prompter')
78
- .action(async () => {
79
- const guideCommand = new GuideCommand();
80
- await guideCommand.execute();
81
- });
82
-
83
- program
84
- .command('upgrade')
85
- .description('Upgrade Prompter to the latest version')
86
- .action(async () => {
87
- const upgradeCommand = new UpgradeCommand();
88
- await upgradeCommand.execute();
89
- });
90
-
91
- // Change command with subcommands
92
- const changeCmd = program
93
- .command('change')
94
- .description('Manage Prompter change proposals');
95
-
96
- // Deprecation notice for noun-based commands
97
- changeCmd.hook('preAction', () => {
98
- console.error('Warning: The "prompter change ..." commands are deprecated. Prefer verb-first commands (e.g., "prompter list", "prompter validate --changes").');
99
- });
100
-
101
- changeCmd
102
- .command('show [change-name]')
103
- .description('Show a change proposal in JSON or markdown format')
104
- .option('--json', 'Output as JSON')
105
- .option('--deltas-only', 'Show only deltas (JSON only)')
106
- .option('--requirements-only', 'Alias for --deltas-only (deprecated)')
107
- .option('--no-interactive', 'Disable interactive prompts')
108
- .action(async (changeName?: string, options?: { json?: boolean; requirementsOnly?: boolean; deltasOnly?: boolean; noInteractive?: boolean }) => {
109
- try {
110
- const changeCommand = new ChangeCommand();
111
- await changeCommand.show(changeName, options);
112
- } catch (error) {
113
- console.error(`Error: ${(error as Error).message}`);
114
- process.exitCode = 1;
115
- }
116
- });
117
-
118
- changeCmd
119
- .command('list')
120
- .description('List all active changes (DEPRECATED: use "prompter list" instead)')
121
- .option('--json', 'Output as JSON')
122
- .option('--long', 'Show id and title with counts')
123
- .action(async (options?: { json?: boolean; long?: boolean }) => {
124
- try {
125
- console.error('Warning: "prompter change list" is deprecated. Use "prompter list".');
126
- const changeCommand = new ChangeCommand();
127
- await changeCommand.list(options);
128
- } catch (error) {
129
- console.error(`Error: ${(error as Error).message}`);
130
- process.exitCode = 1;
131
- }
132
- });
133
-
134
- changeCmd
135
- .command('validate [change-name]')
136
- .description('Validate a change proposal')
137
- .option('--strict', 'Enable strict validation mode')
138
- .option('--json', 'Output validation report as JSON')
139
- .option('--no-interactive', 'Disable interactive prompts')
140
- .action(async (changeName?: string, options?: { strict?: boolean; json?: boolean; noInteractive?: boolean }) => {
141
- try {
142
- const changeCommand = new ChangeCommand();
143
- await changeCommand.validate(changeName, options);
144
- if (typeof process.exitCode === 'number' && process.exitCode !== 0) {
145
- process.exit(process.exitCode);
146
- }
147
- } catch (error) {
148
- console.error(`Error: ${(error as Error).message}`);
149
- process.exitCode = 1;
150
- }
151
- });
152
-
153
- program
154
- .command('archive [change-name]')
155
- .description('Archive a completed change and update main specs')
156
- .option('-y, --yes', 'Skip confirmation prompts')
157
- .option('--skip-specs', 'Skip spec update operations (useful for infrastructure, tooling, or doc-only changes)')
158
- .option('--no-validate', 'Skip validation (not recommended, requires confirmation)')
159
- .action(async (changeName?: string, options?: { yes?: boolean; skipSpecs?: boolean; noValidate?: boolean; validate?: boolean }) => {
160
- try {
161
- const archiveCommand = new ArchiveCommand();
162
- await archiveCommand.execute(changeName, options);
163
- } catch (error) {
164
- console.log(); // Empty line for spacing
165
- ora().fail(`Error: ${(error as Error).message}`);
166
- process.exit(1);
167
- }
168
- });
169
-
170
- registerSpecCommand(program);
171
- registerConfigCommand(program);
172
-
173
- // Top-level validate command
174
- program
175
- .command('validate [item-name]')
176
- .description('Validate changes and specs')
177
- .option('--all', 'Validate all changes and specs')
178
- .option('--changes', 'Validate all changes')
179
- .option('--specs', 'Validate all specs')
180
- .option('--type <type>', 'Specify item type when ambiguous: change|spec')
181
- .option('--strict', 'Enable strict validation mode')
182
- .option('--json', 'Output validation results as JSON')
183
- .option('--concurrency <n>', 'Max concurrent validations (defaults to env PROMPTER_CONCURRENCY or 6)')
184
- .option('--no-interactive', 'Disable interactive prompts')
185
- .action(async (itemName?: string, options?: { all?: boolean; changes?: boolean; specs?: boolean; type?: string; strict?: boolean; json?: boolean; noInteractive?: boolean; concurrency?: string }) => {
186
- try {
187
- const validateCommand = new ValidateCommand();
188
- await validateCommand.execute(itemName, options);
189
- } catch (error) {
190
- console.log();
191
- process.exit(1);
192
- }
193
- });
194
-
195
- // Top-level show command
196
- program
197
- .command('show [item-name]')
198
- .description('Show a change or spec')
199
- .option('--json', 'Output as JSON')
200
- .option('--type <type>', 'Specify item type when ambiguous: change|spec')
201
- .option('--no-interactive', 'Disable interactive prompts')
202
- // change-only flags
203
- .option('--deltas-only', 'Show only deltas (JSON only, change)')
204
- .option('--requirements-only', 'Alias for --deltas-only (deprecated, change)')
205
- // spec-only flags
206
- .option('--requirements', 'JSON only: Show only requirements (exclude scenarios)')
207
- .option('--no-scenarios', 'JSON only: Exclude scenario content')
208
- .option('-r, --requirement <id>', 'JSON only: Show specific requirement by ID (1-based)')
209
- // allow unknown options to pass-through to underlying command implementation
210
- .allowUnknownOption(true)
211
- .action(async (itemName?: string, options?: { json?: boolean; type?: string; noInteractive?: boolean;[k: string]: any }) => {
212
- try {
213
- const showCommand = new ShowCommand();
214
- await showCommand.execute(itemName, options ?? {});
215
- } catch (error) {
216
- console.log();
217
- process.exit(1);
218
- }
219
- });
220
-
221
-
222
-
223
- program.parse();
@@ -1,302 +0,0 @@
1
- import { promises as fs } from 'fs';
2
- import path from 'path';
3
- import { getTaskProgressForChange, formatTaskStatus } from '../utils/task-progress.js';
4
- import { Validator } from '../core/validation/validator.js';
5
- import chalk from 'chalk';
6
- import {
7
- findSpecUpdates,
8
- buildUpdatedSpec,
9
- writeUpdatedSpec,
10
- type SpecUpdate,
11
- } from '../core/specs-apply.js';
12
-
13
- export class ArchiveCommand {
14
- async execute(
15
- changeName?: string,
16
- options: { yes?: boolean; skipSpecs?: boolean; noValidate?: boolean; validate?: boolean } = {}
17
- ): Promise<void> {
18
- const targetPath = '.';
19
- const changesDir = path.join(targetPath, 'prompter', 'changes');
20
- const archiveDir = path.join(changesDir, 'archive');
21
- const mainSpecsDir = path.join(targetPath, 'prompter', 'specs');
22
-
23
- // Check if changes directory exists
24
- try {
25
- await fs.access(changesDir);
26
- } catch {
27
- throw new Error("No Prompter changes directory found. Run 'prompter init' first.");
28
- }
29
-
30
- // Get change name interactively if not provided
31
- if (!changeName) {
32
- const selectedChange = await this.selectChange(changesDir);
33
- if (!selectedChange) {
34
- console.log('No change selected. Aborting.');
35
- return;
36
- }
37
- changeName = selectedChange;
38
- }
39
-
40
- const changeDir = path.join(changesDir, changeName);
41
-
42
- // Verify change exists
43
- try {
44
- const stat = await fs.stat(changeDir);
45
- if (!stat.isDirectory()) {
46
- throw new Error(`Change '${changeName}' not found.`);
47
- }
48
- } catch {
49
- throw new Error(`Change '${changeName}' not found.`);
50
- }
51
-
52
- const skipValidation = options.validate === false || options.noValidate === true;
53
-
54
- // Validate specs and change before archiving
55
- if (!skipValidation) {
56
- const validator = new Validator();
57
- let hasValidationErrors = false;
58
-
59
- // Validate proposal.md (non-blocking unless strict mode desired in future)
60
- const changeFile = path.join(changeDir, 'proposal.md');
61
- try {
62
- await fs.access(changeFile);
63
- const changeReport = await validator.validateChange(changeFile);
64
- // Proposal validation is informative only (do not block archive)
65
- if (!changeReport.valid) {
66
- console.log(chalk.yellow(`\nProposal warnings in proposal.md (non-blocking):`));
67
- for (const issue of changeReport.issues) {
68
- const symbol = issue.level === 'ERROR' ? '⚠' : (issue.level === 'WARNING' ? '⚠' : 'ℹ');
69
- console.log(chalk.yellow(` ${symbol} ${issue.message}`));
70
- }
71
- }
72
- } catch {
73
- // Change file doesn't exist, skip validation
74
- }
75
-
76
- // Validate delta-formatted spec files under the change directory if present
77
- const changeSpecsDir = path.join(changeDir, 'specs');
78
- let hasDeltaSpecs = false;
79
- try {
80
- const candidates = await fs.readdir(changeSpecsDir, { withFileTypes: true });
81
- for (const c of candidates) {
82
- if (c.isDirectory()) {
83
- try {
84
- const candidatePath = path.join(changeSpecsDir, c.name, 'spec.md');
85
- await fs.access(candidatePath);
86
- const content = await fs.readFile(candidatePath, 'utf-8');
87
- if (/^##\s+(ADDED|MODIFIED|REMOVED|RENAMED)\s+Requirements/m.test(content)) {
88
- hasDeltaSpecs = true;
89
- break;
90
- }
91
- } catch {}
92
- }
93
- }
94
- } catch {}
95
- if (hasDeltaSpecs) {
96
- const deltaReport = await validator.validateChangeDeltaSpecs(changeDir);
97
- if (!deltaReport.valid) {
98
- hasValidationErrors = true;
99
- console.log(chalk.red(`\nValidation errors in change delta specs:`));
100
- for (const issue of deltaReport.issues) {
101
- if (issue.level === 'ERROR') {
102
- console.log(chalk.red(` ✗ ${issue.message}`));
103
- } else if (issue.level === 'WARNING') {
104
- console.log(chalk.yellow(` ⚠ ${issue.message}`));
105
- }
106
- }
107
- }
108
- }
109
-
110
- if (hasValidationErrors) {
111
- console.log(chalk.red('\nValidation failed. Please fix the errors before archiving.'));
112
- console.log(chalk.yellow('To skip validation (not recommended), use --no-validate flag.'));
113
- return;
114
- }
115
- } else {
116
- // Log warning when validation is skipped
117
- const timestamp = new Date().toISOString();
118
-
119
- if (!options.yes) {
120
- const { confirm } = await import('@inquirer/prompts');
121
- const proceed = await confirm({
122
- message: chalk.yellow('⚠️ WARNING: Skipping validation may archive invalid specs. Continue? (y/N)'),
123
- default: false
124
- });
125
- if (!proceed) {
126
- console.log('Archive cancelled.');
127
- return;
128
- }
129
- } else {
130
- console.log(chalk.yellow(`\n⚠️ WARNING: Skipping validation may archive invalid specs.`));
131
- }
132
-
133
- console.log(chalk.yellow(`[${timestamp}] Validation skipped for change: ${changeName}`));
134
- console.log(chalk.yellow(`Affected files: ${changeDir}`));
135
- }
136
-
137
- // Show progress and check for incomplete tasks
138
- const progress = await getTaskProgressForChange(changesDir, changeName);
139
- const status = formatTaskStatus(progress);
140
- console.log(`Task status: ${status}`);
141
-
142
- const incompleteTasks = Math.max(progress.total - progress.completed, 0);
143
- if (incompleteTasks > 0) {
144
- if (!options.yes) {
145
- const { confirm } = await import('@inquirer/prompts');
146
- const proceed = await confirm({
147
- message: `Warning: ${incompleteTasks} incomplete task(s) found. Continue?`,
148
- default: false
149
- });
150
- if (!proceed) {
151
- console.log('Archive cancelled.');
152
- return;
153
- }
154
- } else {
155
- console.log(`Warning: ${incompleteTasks} incomplete task(s) found. Continuing due to --yes flag.`);
156
- }
157
- }
158
-
159
- // Handle spec updates unless skipSpecs flag is set
160
- if (options.skipSpecs) {
161
- console.log('Skipping spec updates (--skip-specs flag provided).');
162
- } else {
163
- // Find specs to update
164
- const specUpdates = await findSpecUpdates(changeDir, mainSpecsDir);
165
-
166
- if (specUpdates.length > 0) {
167
- console.log('\nSpecs to update:');
168
- for (const update of specUpdates) {
169
- const status = update.exists ? 'update' : 'create';
170
- const capability = path.basename(path.dirname(update.target));
171
- console.log(` ${capability}: ${status}`);
172
- }
173
-
174
- let shouldUpdateSpecs = true;
175
- if (!options.yes) {
176
- const { confirm } = await import('@inquirer/prompts');
177
- shouldUpdateSpecs = await confirm({
178
- message: 'Proceed with spec updates?',
179
- default: true
180
- });
181
- if (!shouldUpdateSpecs) {
182
- console.log('Skipping spec updates. Proceeding with archive.');
183
- }
184
- }
185
-
186
- if (shouldUpdateSpecs) {
187
- // Prepare all updates first (validation pass, no writes)
188
- const prepared: Array<{ update: SpecUpdate; rebuilt: string; counts: { added: number; modified: number; removed: number; renamed: number } }> = [];
189
- try {
190
- for (const update of specUpdates) {
191
- const built = await buildUpdatedSpec(update, changeName!);
192
- prepared.push({ update, rebuilt: built.rebuilt, counts: built.counts });
193
- }
194
- } catch (err: any) {
195
- console.log(String(err.message || err));
196
- console.log('Aborted. No files were changed.');
197
- return;
198
- }
199
-
200
- // All validations passed; pre-validate rebuilt full spec and then write files and display counts
201
- let totals = { added: 0, modified: 0, removed: 0, renamed: 0 };
202
- for (const p of prepared) {
203
- const specName = path.basename(path.dirname(p.update.target));
204
- if (!skipValidation) {
205
- const report = await new Validator().validateSpecContent(specName, p.rebuilt);
206
- if (!report.valid) {
207
- console.log(chalk.red(`\nValidation errors in rebuilt spec for ${specName} (will not write changes):`));
208
- for (const issue of report.issues) {
209
- if (issue.level === 'ERROR') console.log(chalk.red(` ✗ ${issue.message}`));
210
- else if (issue.level === 'WARNING') console.log(chalk.yellow(` ⚠ ${issue.message}`));
211
- }
212
- console.log('Aborted. No files were changed.');
213
- return;
214
- }
215
- }
216
- await writeUpdatedSpec(p.update, p.rebuilt, p.counts);
217
- totals.added += p.counts.added;
218
- totals.modified += p.counts.modified;
219
- totals.removed += p.counts.removed;
220
- totals.renamed += p.counts.renamed;
221
- }
222
- console.log(
223
- `Totals: + ${totals.added}, ~ ${totals.modified}, - ${totals.removed}, → ${totals.renamed}`
224
- );
225
- console.log('Specs updated successfully.');
226
- }
227
- }
228
- }
229
-
230
- // Create archive directory with date prefix
231
- const archiveName = `${this.getArchiveDate()}-${changeName}`;
232
- const archivePath = path.join(archiveDir, archiveName);
233
-
234
- // Check if archive already exists
235
- try {
236
- await fs.access(archivePath);
237
- throw new Error(`Archive '${archiveName}' already exists.`);
238
- } catch (error: any) {
239
- if (error.code !== 'ENOENT') {
240
- throw error;
241
- }
242
- }
243
-
244
- // Create archive directory if needed
245
- await fs.mkdir(archiveDir, { recursive: true });
246
-
247
- // Move change to archive
248
- await fs.rename(changeDir, archivePath);
249
-
250
- console.log(`Change '${changeName}' archived as '${archiveName}'.`);
251
- }
252
-
253
- private async selectChange(changesDir: string): Promise<string | null> {
254
- const { select } = await import('@inquirer/prompts');
255
- // Get all directories in changes (excluding archive)
256
- const entries = await fs.readdir(changesDir, { withFileTypes: true });
257
- const changeDirs = entries
258
- .filter(entry => entry.isDirectory() && entry.name !== 'archive')
259
- .map(entry => entry.name)
260
- .sort();
261
-
262
- if (changeDirs.length === 0) {
263
- console.log('No active changes found.');
264
- return null;
265
- }
266
-
267
- // Build choices with progress inline to avoid duplicate lists
268
- let choices: Array<{ name: string; value: string }> = changeDirs.map(name => ({ name, value: name }));
269
- try {
270
- const progressList: Array<{ id: string; status: string }> = [];
271
- for (const id of changeDirs) {
272
- const progress = await getTaskProgressForChange(changesDir, id);
273
- const status = formatTaskStatus(progress);
274
- progressList.push({ id, status });
275
- }
276
- const nameWidth = Math.max(...progressList.map(p => p.id.length));
277
- choices = progressList.map(p => ({
278
- name: `${p.id.padEnd(nameWidth)} ${p.status}`,
279
- value: p.id
280
- }));
281
- } catch {
282
- // If anything fails, fall back to simple names
283
- choices = changeDirs.map(name => ({ name, value: name }));
284
- }
285
-
286
- try {
287
- const answer = await select({
288
- message: 'Select a change to archive',
289
- choices
290
- });
291
- return answer;
292
- } catch (error) {
293
- // User cancelled (Ctrl+C)
294
- return null;
295
- }
296
- }
297
-
298
- private getArchiveDate(): string {
299
- // Returns date in YYYY-MM-DD format
300
- return new Date().toISOString().split('T')[0];
301
- }
302
- }