@specsafe/cli 0.8.0 → 2.0.3

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 (242) hide show
  1. package/README.md +100 -279
  2. package/canonical/personas/bolt-zane.md +29 -0
  3. package/canonical/personas/forge-reva.md +29 -0
  4. package/canonical/personas/herald-cass.md +30 -0
  5. package/canonical/personas/mason-kai.md +30 -0
  6. package/canonical/personas/scout-elena.md +27 -0
  7. package/canonical/personas/warden-lyra.md +30 -0
  8. package/canonical/rules/.cursorrules.mdc +53 -0
  9. package/canonical/rules/.rules +48 -0
  10. package/canonical/rules/AGENTS.md +48 -0
  11. package/canonical/rules/CLAUDE.md +48 -0
  12. package/canonical/rules/CONVENTIONS.md +41 -0
  13. package/canonical/rules/GEMINI.md +50 -0
  14. package/canonical/rules/continue-config.yaml +5 -0
  15. package/canonical/skills/specsafe-archive/SKILL.md +63 -0
  16. package/canonical/skills/specsafe-code/SKILL.md +7 -0
  17. package/canonical/skills/specsafe-code/workflow.md +212 -0
  18. package/canonical/skills/specsafe-complete/SKILL.md +7 -0
  19. package/canonical/skills/specsafe-complete/workflow.md +130 -0
  20. package/canonical/skills/specsafe-doctor/SKILL.md +103 -0
  21. package/canonical/skills/specsafe-explore/SKILL.md +7 -0
  22. package/canonical/skills/specsafe-explore/workflow.md +100 -0
  23. package/canonical/skills/specsafe-init/SKILL.md +119 -0
  24. package/canonical/skills/specsafe-new/SKILL.md +7 -0
  25. package/canonical/skills/specsafe-new/workflow.md +156 -0
  26. package/canonical/skills/specsafe-qa/SKILL.md +7 -0
  27. package/canonical/skills/specsafe-qa/workflow.md +223 -0
  28. package/canonical/skills/specsafe-spec/SKILL.md +7 -0
  29. package/canonical/skills/specsafe-spec/workflow.md +158 -0
  30. package/canonical/skills/specsafe-status/SKILL.md +77 -0
  31. package/canonical/skills/specsafe-test/SKILL.md +7 -0
  32. package/canonical/skills/specsafe-test/workflow.md +210 -0
  33. package/canonical/skills/specsafe-verify/SKILL.md +7 -0
  34. package/canonical/skills/specsafe-verify/workflow.md +143 -0
  35. package/canonical/templates/project-state-template.md +33 -0
  36. package/canonical/templates/qa-report-template.md +55 -0
  37. package/canonical/templates/spec-template.md +52 -0
  38. package/canonical/templates/specsafe-config-template.json +10 -0
  39. package/generators/dist/adapters/aider.d.ts +2 -0
  40. package/generators/dist/adapters/aider.js +23 -0
  41. package/generators/dist/adapters/aider.js.map +1 -0
  42. package/generators/dist/adapters/antigravity.d.ts +2 -0
  43. package/generators/dist/adapters/antigravity.js +33 -0
  44. package/generators/dist/adapters/antigravity.js.map +1 -0
  45. package/generators/dist/adapters/claude-code.d.ts +2 -0
  46. package/generators/dist/adapters/claude-code.js +31 -0
  47. package/generators/dist/adapters/claude-code.js.map +1 -0
  48. package/generators/dist/adapters/continue.d.ts +2 -0
  49. package/generators/dist/adapters/continue.js +33 -0
  50. package/generators/dist/adapters/continue.js.map +1 -0
  51. package/generators/dist/adapters/cursor.d.ts +2 -0
  52. package/generators/dist/adapters/cursor.js +32 -0
  53. package/generators/dist/adapters/cursor.js.map +1 -0
  54. package/generators/dist/adapters/gemini.d.ts +2 -0
  55. package/generators/dist/adapters/gemini.js +36 -0
  56. package/generators/dist/adapters/gemini.js.map +1 -0
  57. package/generators/dist/adapters/index.d.ts +13 -0
  58. package/generators/dist/adapters/index.js +29 -0
  59. package/generators/dist/adapters/index.js.map +1 -0
  60. package/generators/dist/adapters/opencode.d.ts +2 -0
  61. package/generators/dist/adapters/opencode.js +32 -0
  62. package/generators/dist/adapters/opencode.js.map +1 -0
  63. package/generators/dist/adapters/types.d.ts +49 -0
  64. package/generators/dist/adapters/types.js +14 -0
  65. package/generators/dist/adapters/types.js.map +1 -0
  66. package/generators/dist/adapters/utils.d.ts +12 -0
  67. package/generators/dist/adapters/utils.js +68 -0
  68. package/generators/dist/adapters/utils.js.map +1 -0
  69. package/generators/dist/adapters/zed.d.ts +2 -0
  70. package/generators/dist/adapters/zed.js +31 -0
  71. package/generators/dist/adapters/zed.js.map +1 -0
  72. package/generators/dist/doctor.d.ts +10 -0
  73. package/generators/dist/doctor.js +123 -0
  74. package/generators/dist/doctor.js.map +1 -0
  75. package/generators/dist/index.d.ts +2 -0
  76. package/generators/dist/index.js +45 -0
  77. package/generators/dist/index.js.map +1 -0
  78. package/generators/dist/init.d.ts +9 -0
  79. package/generators/dist/init.js +167 -0
  80. package/generators/dist/init.js.map +1 -0
  81. package/generators/dist/install.d.ts +5 -0
  82. package/generators/dist/install.js +66 -0
  83. package/generators/dist/install.js.map +1 -0
  84. package/generators/dist/registry.d.ts +3 -0
  85. package/generators/dist/registry.js +8 -0
  86. package/generators/dist/registry.js.map +1 -0
  87. package/generators/dist/update.d.ts +5 -0
  88. package/generators/dist/update.js +40 -0
  89. package/generators/dist/update.js.map +1 -0
  90. package/package.json +31 -27
  91. package/dist/commands/apply.d.ts +0 -3
  92. package/dist/commands/apply.d.ts.map +0 -1
  93. package/dist/commands/apply.js +0 -182
  94. package/dist/commands/apply.js.map +0 -1
  95. package/dist/commands/archive.d.ts +0 -3
  96. package/dist/commands/archive.d.ts.map +0 -1
  97. package/dist/commands/archive.js +0 -99
  98. package/dist/commands/archive.js.map +0 -1
  99. package/dist/commands/capsule.d.ts +0 -8
  100. package/dist/commands/capsule.d.ts.map +0 -1
  101. package/dist/commands/capsule.js +0 -466
  102. package/dist/commands/capsule.js.map +0 -1
  103. package/dist/commands/complete.d.ts +0 -3
  104. package/dist/commands/complete.d.ts.map +0 -1
  105. package/dist/commands/complete.js +0 -140
  106. package/dist/commands/complete.js.map +0 -1
  107. package/dist/commands/constitution.d.ts +0 -3
  108. package/dist/commands/constitution.d.ts.map +0 -1
  109. package/dist/commands/constitution.js +0 -192
  110. package/dist/commands/constitution.js.map +0 -1
  111. package/dist/commands/create.d.ts +0 -10
  112. package/dist/commands/create.d.ts.map +0 -1
  113. package/dist/commands/create.js +0 -120
  114. package/dist/commands/create.js.map +0 -1
  115. package/dist/commands/delta.d.ts +0 -3
  116. package/dist/commands/delta.d.ts.map +0 -1
  117. package/dist/commands/delta.js +0 -82
  118. package/dist/commands/delta.js.map +0 -1
  119. package/dist/commands/diff.d.ts +0 -3
  120. package/dist/commands/diff.d.ts.map +0 -1
  121. package/dist/commands/diff.js +0 -102
  122. package/dist/commands/diff.js.map +0 -1
  123. package/dist/commands/doctor.d.ts +0 -3
  124. package/dist/commands/doctor.d.ts.map +0 -1
  125. package/dist/commands/doctor.js +0 -204
  126. package/dist/commands/doctor.js.map +0 -1
  127. package/dist/commands/done.d.ts +0 -3
  128. package/dist/commands/done.d.ts.map +0 -1
  129. package/dist/commands/done.js +0 -237
  130. package/dist/commands/done.js.map +0 -1
  131. package/dist/commands/explore.d.ts +0 -3
  132. package/dist/commands/explore.d.ts.map +0 -1
  133. package/dist/commands/explore.js +0 -236
  134. package/dist/commands/explore.js.map +0 -1
  135. package/dist/commands/export.d.ts +0 -7
  136. package/dist/commands/export.d.ts.map +0 -1
  137. package/dist/commands/export.js +0 -179
  138. package/dist/commands/export.js.map +0 -1
  139. package/dist/commands/extend.d.ts +0 -6
  140. package/dist/commands/extend.d.ts.map +0 -1
  141. package/dist/commands/extend.js +0 -167
  142. package/dist/commands/extend.js.map +0 -1
  143. package/dist/commands/init-old.d.ts +0 -3
  144. package/dist/commands/init-old.d.ts.map +0 -1
  145. package/dist/commands/init-old.js +0 -146
  146. package/dist/commands/init-old.js.map +0 -1
  147. package/dist/commands/init.d.ts +0 -3
  148. package/dist/commands/init.d.ts.map +0 -1
  149. package/dist/commands/init.js +0 -298
  150. package/dist/commands/init.js.map +0 -1
  151. package/dist/commands/list.d.ts +0 -3
  152. package/dist/commands/list.d.ts.map +0 -1
  153. package/dist/commands/list.js +0 -122
  154. package/dist/commands/list.js.map +0 -1
  155. package/dist/commands/memory.d.ts +0 -3
  156. package/dist/commands/memory.d.ts.map +0 -1
  157. package/dist/commands/memory.js +0 -166
  158. package/dist/commands/memory.js.map +0 -1
  159. package/dist/commands/new.d.ts +0 -3
  160. package/dist/commands/new.d.ts.map +0 -1
  161. package/dist/commands/new.js +0 -508
  162. package/dist/commands/new.js.map +0 -1
  163. package/dist/commands/qa.d.ts +0 -3
  164. package/dist/commands/qa.d.ts.map +0 -1
  165. package/dist/commands/qa.js +0 -179
  166. package/dist/commands/qa.js.map +0 -1
  167. package/dist/commands/rules.d.ts +0 -6
  168. package/dist/commands/rules.d.ts.map +0 -1
  169. package/dist/commands/rules.js +0 -232
  170. package/dist/commands/rules.js.map +0 -1
  171. package/dist/commands/shard.d.ts +0 -6
  172. package/dist/commands/shard.d.ts.map +0 -1
  173. package/dist/commands/shard.js +0 -199
  174. package/dist/commands/shard.js.map +0 -1
  175. package/dist/commands/spec.d.ts +0 -3
  176. package/dist/commands/spec.d.ts.map +0 -1
  177. package/dist/commands/spec.js +0 -302
  178. package/dist/commands/spec.js.map +0 -1
  179. package/dist/commands/status.d.ts +0 -3
  180. package/dist/commands/status.d.ts.map +0 -1
  181. package/dist/commands/status.js +0 -47
  182. package/dist/commands/status.js.map +0 -1
  183. package/dist/commands/test-apply.d.ts +0 -3
  184. package/dist/commands/test-apply.d.ts.map +0 -1
  185. package/dist/commands/test-apply.js +0 -228
  186. package/dist/commands/test-apply.js.map +0 -1
  187. package/dist/commands/test-create.d.ts +0 -3
  188. package/dist/commands/test-create.d.ts.map +0 -1
  189. package/dist/commands/test-create.js +0 -183
  190. package/dist/commands/test-create.js.map +0 -1
  191. package/dist/commands/test-guide.d.ts +0 -3
  192. package/dist/commands/test-guide.d.ts.map +0 -1
  193. package/dist/commands/test-guide.js +0 -190
  194. package/dist/commands/test-guide.js.map +0 -1
  195. package/dist/commands/test-report.d.ts +0 -3
  196. package/dist/commands/test-report.d.ts.map +0 -1
  197. package/dist/commands/test-report.js +0 -196
  198. package/dist/commands/test-report.js.map +0 -1
  199. package/dist/commands/test-submit.d.ts +0 -6
  200. package/dist/commands/test-submit.d.ts.map +0 -1
  201. package/dist/commands/test-submit.js +0 -236
  202. package/dist/commands/test-submit.js.map +0 -1
  203. package/dist/commands/verify.d.ts +0 -3
  204. package/dist/commands/verify.d.ts.map +0 -1
  205. package/dist/commands/verify.js +0 -288
  206. package/dist/commands/verify.js.map +0 -1
  207. package/dist/config.d.ts +0 -23
  208. package/dist/config.d.ts.map +0 -1
  209. package/dist/config.js +0 -44
  210. package/dist/config.js.map +0 -1
  211. package/dist/index.d.ts +0 -8
  212. package/dist/index.d.ts.map +0 -1
  213. package/dist/index.js +0 -129
  214. package/dist/index.js.map +0 -1
  215. package/dist/rules/downloader.d.ts +0 -40
  216. package/dist/rules/downloader.d.ts.map +0 -1
  217. package/dist/rules/downloader.js +0 -253
  218. package/dist/rules/downloader.js.map +0 -1
  219. package/dist/rules/index.d.ts +0 -8
  220. package/dist/rules/index.d.ts.map +0 -1
  221. package/dist/rules/index.js +0 -8
  222. package/dist/rules/index.js.map +0 -1
  223. package/dist/rules/registry.d.ts +0 -45
  224. package/dist/rules/registry.d.ts.map +0 -1
  225. package/dist/rules/registry.js +0 -158
  226. package/dist/rules/registry.js.map +0 -1
  227. package/dist/rules/types.d.ts +0 -86
  228. package/dist/rules/types.d.ts.map +0 -1
  229. package/dist/rules/types.js +0 -6
  230. package/dist/rules/types.js.map +0 -1
  231. package/dist/utils/detectTools.d.ts +0 -15
  232. package/dist/utils/detectTools.d.ts.map +0 -1
  233. package/dist/utils/detectTools.js +0 -54
  234. package/dist/utils/detectTools.js.map +0 -1
  235. package/dist/utils/generateToolConfig.d.ts +0 -12
  236. package/dist/utils/generateToolConfig.d.ts.map +0 -1
  237. package/dist/utils/generateToolConfig.js +0 -1179
  238. package/dist/utils/generateToolConfig.js.map +0 -1
  239. package/dist/utils/testRunner.d.ts +0 -39
  240. package/dist/utils/testRunner.d.ts.map +0 -1
  241. package/dist/utils/testRunner.js +0 -325
  242. package/dist/utils/testRunner.js.map +0 -1
@@ -1,228 +0,0 @@
1
- import { Command } from 'commander';
2
- import chalk from 'chalk';
3
- import ora from 'ora';
4
- import { Workflow, ProjectTracker, validateSpecId } from '@specsafe/core';
5
- import { readFile, writeFile, mkdir } from 'fs/promises';
6
- import { join } from 'path';
7
- import { input, confirm, select } from '@inquirer/prompts';
8
- export const testApplyCommand = new Command('test-apply')
9
- .description('Start implementation with development guidance (TEST → CODE)')
10
- .argument('<id>', 'Spec ID')
11
- .option('--skip-confirm', 'Skip confirmation prompts')
12
- .option('--quick', 'Quick mode - minimal guidance')
13
- .action(async (id, options) => {
14
- const spinner = ora(`Starting implementation for ${id}...`).start();
15
- try {
16
- // Validate spec ID format
17
- validateSpecId(id);
18
- const workflow = new Workflow();
19
- const tracker = new ProjectTracker(process.cwd());
20
- // Load existing specs from disk
21
- await tracker.loadSpecsIntoWorkflow(workflow);
22
- // Check if spec exists
23
- const spec = workflow.getSpec(id);
24
- if (!spec) {
25
- throw new Error(`Spec '${id}' not found. Run 'specsafe new <name>' to create it first.`);
26
- }
27
- // Read spec content for guidance
28
- const specPath = join('specs/active', `${id}.md`);
29
- let specContent;
30
- try {
31
- specContent = await readFile(specPath, 'utf-8');
32
- }
33
- catch {
34
- throw new Error(`Spec file not found: ${specPath}`);
35
- }
36
- spinner.stop();
37
- // Display development guidance
38
- console.log(chalk.blue('\n' + '━'.repeat(60)));
39
- console.log(chalk.bold(` Development Mode: ${id}`));
40
- console.log(chalk.blue('━'.repeat(60) + '\n'));
41
- // Show current status
42
- console.log(chalk.white(` Current Stage: ${spec.stage.toUpperCase()}`));
43
- console.log(chalk.white(` Requirements: ${spec.requirements.length}`));
44
- console.log(chalk.white(` Test Files: ${spec.testFiles.length}`));
45
- console.log();
46
- // Extract key information from spec
47
- const prdSection = extractSection(specContent, 'Product Requirements Document');
48
- const acceptanceCriteria = extractSection(specContent, 'Acceptance Criteria');
49
- const technicalApproach = extractSection(specContent, 'Technical Approach');
50
- // Show PRD highlights
51
- if (prdSection) {
52
- console.log(chalk.cyan(' šŸ“ Problem Statement:'));
53
- const problem = extractSection(prdSection, 'Problem Statement');
54
- if (problem) {
55
- const summary = problem.split('\n').find(line => line.trim() && !line.trim().startsWith('#'));
56
- if (summary) {
57
- console.log(chalk.gray(` ${summary.substring(0, 100)}${summary.length > 100 ? '...' : ''}`));
58
- }
59
- }
60
- console.log();
61
- }
62
- // Show acceptance criteria
63
- if (acceptanceCriteria) {
64
- console.log(chalk.cyan(' āœ… Acceptance Criteria:'));
65
- const criteria = acceptanceCriteria
66
- .split('\n')
67
- .filter(line => line.trim().startsWith('- [') || line.trim().startsWith('-'))
68
- .slice(0, 5);
69
- for (const criterion of criteria) {
70
- const clean = criterion.replace(/^- \[[ x]\]\s*/i, '').trim();
71
- console.log(chalk.gray(` • ${clean.substring(0, 60)}${clean.length > 60 ? '...' : ''}`));
72
- }
73
- console.log();
74
- }
75
- // Show technical approach hints
76
- if (technicalApproach) {
77
- console.log(chalk.cyan(' šŸ› ļø Technical Approach:'));
78
- const techStack = extractSection(technicalApproach, 'Tech Stack');
79
- if (techStack) {
80
- console.log(chalk.gray(` ${techStack.split('\n').find(l => l.trim() && !l.trim().startsWith('#')) || 'See spec for details'}`));
81
- }
82
- console.log();
83
- }
84
- // Development guidance
85
- if (!options.quick) {
86
- console.log(chalk.cyan(' šŸ“‹ Implementation Checklist:\n'));
87
- const checklist = [
88
- 'Review test files to understand expected behavior',
89
- 'Create minimal implementation to pass first test',
90
- 'Iterate: run tests, fix, repeat',
91
- 'Refactor once all tests pass'
92
- ];
93
- for (const item of checklist) {
94
- console.log(chalk.gray(` [ ] ${item}`));
95
- }
96
- console.log();
97
- }
98
- // Interactive guidance
99
- if (!options.skipConfirm && !options.quick) {
100
- const wantGuidance = await confirm({
101
- message: 'Would you like implementation guidance?',
102
- default: true
103
- });
104
- if (wantGuidance) {
105
- // Offer to create implementation file
106
- const createFile = await confirm({
107
- message: 'Create implementation file?',
108
- default: true
109
- });
110
- if (createFile) {
111
- const fileName = await input({
112
- message: 'Implementation file name:',
113
- default: `${id.toLowerCase().replace(/-/g, '_')}.ts`
114
- });
115
- const implPath = join('src', fileName);
116
- // Generate boilerplate
117
- const boilerplate = generateBoilerplate(spec, fileName);
118
- await mkdir('src', { recursive: true });
119
- await writeFile(implPath, boilerplate);
120
- console.log(chalk.green(`\n āœ… Created: ${implPath}`));
121
- // Add to spec
122
- spec.implementationFiles.push(implPath);
123
- }
124
- // Offer TDD approach guidance
125
- const tddApproach = await select({
126
- message: 'Choose your approach:',
127
- choices: [
128
- { name: 'šŸ“• Read tests first, then implement', value: 'read-first' },
129
- { name: '⚔ Start coding (I know what to do)', value: 'start-coding' },
130
- { name: 'šŸŽÆ One test at a time', value: 'one-test' }
131
- ]
132
- });
133
- switch (tddApproach) {
134
- case 'read-first':
135
- console.log(chalk.blue('\n šŸ“– Recommended: Read the test files first'));
136
- if (spec.testFiles.length > 0) {
137
- console.log(chalk.gray(` ${spec.testFiles.join(', ')}`));
138
- }
139
- console.log(chalk.gray(' Understand what the tests expect, then implement.'));
140
- break;
141
- case 'one-test':
142
- console.log(chalk.blue('\n šŸŽÆ Run tests with verbose output:'));
143
- console.log(chalk.gray(` npx vitest run --reporter=verbose`));
144
- console.log(chalk.gray(' Fix one failing test at a time.'));
145
- break;
146
- case 'start-coding':
147
- console.log(chalk.blue('\n ⚔ Go for it! Remember:'));
148
- console.log(chalk.gray(' - Run specsafe verify after changes'));
149
- console.log(chalk.gray(' - Keep tests passing as you go'));
150
- break;
151
- }
152
- }
153
- }
154
- // Move to code stage (validates tests exist)
155
- try {
156
- workflow.moveToCode(id);
157
- await tracker.addSpec(spec);
158
- console.log(chalk.green(`\n āœ… Moved ${id} to CODE stage`));
159
- }
160
- catch (moveError) {
161
- if (moveError.message.includes('Must be in TEST stage')) {
162
- // Already in code or beyond, that's fine
163
- console.log(chalk.gray(`\n Note: Spec already in ${spec.stage.toUpperCase()} stage`));
164
- }
165
- else if (moveError.message.includes('No test files generated')) {
166
- throw new Error(`No test files found. Run 'specsafe test ${id}' to generate tests first.`);
167
- }
168
- else {
169
- throw moveError;
170
- }
171
- }
172
- // Development commands reference
173
- console.log(chalk.blue('\n Development Commands:\n'));
174
- console.log(chalk.gray(` Run tests: npx vitest run`));
175
- console.log(chalk.gray(` Watch mode: npx vitest`));
176
- console.log(chalk.gray(` Verify: specsafe verify ${id}`));
177
- console.log(chalk.gray(` Check status: specsafe status`));
178
- console.log(chalk.blue('\n' + '━'.repeat(60)));
179
- console.log();
180
- }
181
- catch (error) {
182
- spinner.fail(chalk.red(error.message));
183
- if (error.message.includes('not in TEST stage') || error.message.includes('Run \'specsafe test\'')) {
184
- console.log(chalk.gray(`šŸ’” Tip: Run 'specsafe test ${id}' to generate tests first.`));
185
- }
186
- else if (error.message.includes('not found')) {
187
- console.log(chalk.gray(`šŸ’” Tip: Run 'specsafe new <name>' to create a spec first.`));
188
- }
189
- else if (error.message.includes('No test files')) {
190
- console.log(chalk.gray(`šŸ’” Tip: Run 'specsafe test ${id}' to generate tests first.`));
191
- }
192
- process.exit(1);
193
- }
194
- });
195
- function extractSection(content, sectionName) {
196
- const regex = new RegExp(`##+\s*${sectionName}[\\s\\S]*?(?=##+|$)`, 'i');
197
- const match = content.match(regex);
198
- return match ? match[0] : null;
199
- }
200
- function generateBoilerplate(spec, fileName) {
201
- const functionName = fileName
202
- .replace(/\.ts$/, '')
203
- .replace(/[_-](.)/g, (_, char) => char.toUpperCase())
204
- .replace(/^(.)/, (_, char) => char.toUpperCase());
205
- const requirements = spec.requirements.map((r) => `// - ${r.text}`).join('\n');
206
- return `/**
207
- * ${spec.name}
208
- * Spec: ${spec.id}
209
- *
210
- * Requirements:
211
- ${requirements || ' * (See spec for requirements)'}
212
- */
213
-
214
- // TODO: Implement functionality to pass tests
215
-
216
- export interface ${functionName}Options {
217
- // Define options here
218
- }
219
-
220
- export function ${functionName}(options?: ${functionName}Options): void {
221
- // TODO: Implement
222
- throw new Error('Not implemented');
223
- }
224
-
225
- // TODO: Add more exports as needed
226
- `;
227
- }
228
- //# sourceMappingURL=test-apply.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"test-apply.js","sourceRoot":"","sources":["../../src/commands/test-apply.ts"],"names":[],"mappings":"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"}
@@ -1,3 +0,0 @@
1
- import { Command } from 'commander';
2
- export declare const testCreateCommand: Command;
3
- //# sourceMappingURL=test-create.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"test-create.d.ts","sourceRoot":"","sources":["../../src/commands/test-create.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAUpC,eAAO,MAAM,iBAAiB,SAsM1B,CAAC"}
@@ -1,183 +0,0 @@
1
- import { Command } from 'commander';
2
- import chalk from 'chalk';
3
- import ora from 'ora';
4
- import { Workflow, ProjectTracker, validateSpecId } from '@specsafe/core';
5
- import { TypeScriptTestGenerator, ScenarioParser } from '@specsafe/test-gen';
6
- import { loadConfig } from '../config.js';
7
- import { mkdir, writeFile, readFile, access } from 'fs/promises';
8
- import { join } from 'path';
9
- import { confirm } from '@inquirer/prompts';
10
- export const testCreateCommand = new Command('test-create')
11
- .description('Generate tests from spec scenarios (SPEC → TEST)')
12
- .argument('<id>', 'Spec ID')
13
- .option('-n, --dry-run', 'Preview changes without writing files')
14
- .option('--scenarios-only', 'Only generate tests for specific scenarios')
15
- .option('--framework <framework>', 'Override test framework')
16
- .action(async (id, options) => {
17
- const spinner = ora(`Generating tests for ${id}...`).start();
18
- try {
19
- // Validate spec ID format
20
- validateSpecId(id);
21
- const config = await loadConfig();
22
- const workflow = new Workflow();
23
- const tracker = new ProjectTracker(process.cwd());
24
- // Use specified framework or fall back to config
25
- const framework = options.framework || config.testFramework;
26
- // Load existing specs from disk
27
- await tracker.loadSpecsIntoWorkflow(workflow);
28
- // Read spec file to extract scenarios
29
- const specPath = join('specs', 'active', `${id}.md`);
30
- let specContent;
31
- try {
32
- specContent = await readFile(specPath, 'utf-8');
33
- }
34
- catch {
35
- throw new Error(`Spec file not found: ${specPath}`);
36
- }
37
- spinner.stop();
38
- // Parse scenarios from spec
39
- const parser = new ScenarioParser();
40
- let scenarios = parser.parseScenarios(specContent);
41
- // Also parse requirements
42
- let requirements = parser.parseRequirements(specContent);
43
- // Fall back to basic table parsing if ScenarioParser finds nothing
44
- if (requirements.length === 0) {
45
- const reqMatch = specContent.match(/###\s+Functional\s+Requirements[\s\S]*?(?=###|$)/i);
46
- if (reqMatch) {
47
- const rows = reqMatch[0].match(/\|\s*FR-\d+\s*\|[^|]+\|/g);
48
- if (rows) {
49
- requirements = rows.map(row => ({
50
- id: row.match(/FR-\d+/)?.[0] || 'REQ-1',
51
- text: row.split('|')[2]?.trim() || 'Requirement',
52
- priority: 'P1',
53
- scenarios: []
54
- }));
55
- }
56
- }
57
- }
58
- // Parse manual scenarios from markdown
59
- if (scenarios.length === 0) {
60
- const scenarioMatches = specContent.matchAll(/###\s*Scenario\s*\d*:?\s*(.+?)\n[\s\S]*?\*\*Given\*\*\s*(.+?)\n[\s\S]*?\*\*When\*\*\s*(.+?)\n[\s\S]*?\*\*Then\*\*\s*(.+?)(?=\n###|$)/gi);
61
- for (const match of scenarioMatches) {
62
- scenarios.push({
63
- id: `SC-${scenarios.length + 1}`,
64
- given: match[2].trim(),
65
- when: match[3].trim(),
66
- thenOutcome: match[4].trim()
67
- });
68
- }
69
- }
70
- // Ensure spec exists in workflow
71
- let spec = workflow.getSpec(id);
72
- if (!spec) {
73
- throw new Error(`Spec '${id}' not found in project state. Run 'specsafe spec ${id}' first.`);
74
- }
75
- // Update spec with parsed requirements
76
- spec.requirements = requirements;
77
- // Add scenarios to requirements
78
- if (scenarios.length > 0 && spec.requirements.length > 0) {
79
- // Distribute scenarios across requirements
80
- scenarios.forEach((scenario, index) => {
81
- const reqIndex = index % spec.requirements.length;
82
- spec.requirements[reqIndex].scenarios.push(scenario);
83
- });
84
- }
85
- // Display what we found
86
- console.log(chalk.blue(`\nšŸ“‹ Found in spec:`));
87
- console.log(chalk.gray(` ${requirements.length} requirements`));
88
- console.log(chalk.gray(` ${scenarios.length} scenarios`));
89
- // Move to test stage (validates requirements exist)
90
- try {
91
- workflow.moveToTest(id);
92
- }
93
- catch (moveError) {
94
- if (moveError.message.includes('not found')) {
95
- throw new Error(`Spec '${id}' not found in project state. Run 'specsafe spec ${id}' first.`);
96
- }
97
- if (moveError.message.includes('Must be in SPEC stage')) {
98
- // Spec might already be in test stage or beyond, that's okay
99
- console.log(chalk.gray(` Note: Spec is already in ${spec.stage.toUpperCase()} stage`));
100
- }
101
- if (moveError.message.includes('No requirements defined')) {
102
- throw new Error(`Spec '${id}' has no requirements defined. Add requirements to the spec file first.`);
103
- }
104
- }
105
- // Generate test code using the actual spec object
106
- spinner.start('Generating test code...');
107
- const generator = new TypeScriptTestGenerator({
108
- framework: framework
109
- });
110
- const testCode = generator.generate(spec);
111
- // Determine test file path
112
- const testFileName = `${id.toLowerCase().replace(/-/g, '_')}.test.ts`;
113
- const testPath = join('tests', testFileName);
114
- // Check if test file already exists
115
- let shouldOverwrite = true;
116
- try {
117
- await access(testPath);
118
- spinner.stop();
119
- shouldOverwrite = await confirm({
120
- message: `Test file ${testPath} already exists. Overwrite?`,
121
- default: false
122
- });
123
- spinner.start();
124
- }
125
- catch {
126
- // File doesn't exist, proceed
127
- }
128
- // Handle dry-run mode
129
- if (options.dryRun) {
130
- spinner.stop();
131
- console.log(chalk.cyan('\n[DRY RUN] Would generate the following test file:\n'));
132
- console.log(chalk.cyan(` ${testPath}`));
133
- console.log(chalk.cyan(`\nTest code preview (first 30 lines):\n`));
134
- const previewLines = testCode.split('\n').slice(0, 30).join('\n');
135
- console.log(chalk.gray(previewLines));
136
- if (testCode.split('\n').length > 30) {
137
- console.log(chalk.gray(' ... (truncated)'));
138
- }
139
- console.log(chalk.cyan(`\nFramework: ${framework}`));
140
- console.log(chalk.cyan(`Requirements: ${requirements.length}`));
141
- console.log(chalk.cyan(`Scenarios: ${scenarios.length}`));
142
- console.log(chalk.cyan(`Would update PROJECT_STATE.md for spec: ${id}`));
143
- process.exit(0);
144
- }
145
- if (!shouldOverwrite) {
146
- console.log(chalk.yellow('\nSkipped: Test file not modified'));
147
- return;
148
- }
149
- // Write test file
150
- await mkdir('tests', { recursive: true });
151
- await writeFile(testPath, testCode);
152
- // Update spec with test file reference
153
- if (!spec.testFiles.includes(testPath)) {
154
- spec.testFiles.push(testPath);
155
- }
156
- // Persist state
157
- await tracker.addSpec(spec);
158
- spinner.succeed(chalk.green(`Generated tests for ${id}`));
159
- console.log(chalk.blue(`\n Test file: ${testPath}`));
160
- console.log(chalk.blue(` Framework: ${framework}`));
161
- console.log(chalk.blue(` Requirements: ${requirements.length}`));
162
- console.log(chalk.blue(` Scenarios: ${scenarios.length}`));
163
- console.log(chalk.gray('\n Next steps:'));
164
- console.log(chalk.gray(` 1. Review and customize tests in ${testPath}`));
165
- console.log(chalk.gray(` 2. Run: specsafe code ${id} → Start implementation`));
166
- console.log(chalk.gray(` 3. Run: specsafe verify ${id} → Verify against tests`));
167
- }
168
- catch (error) {
169
- spinner.fail(chalk.red(error.message));
170
- if (error.message.includes('not found in project state') || error.message.includes('Run \'specsafe spec\'')) {
171
- console.log(chalk.gray(`šŸ’” Tip: Run 'specsafe spec ${id}' to validate the spec first.`));
172
- }
173
- else if (error.message.includes('no requirements defined')) {
174
- console.log(chalk.gray(`šŸ’” Tip: Add requirements to specs/active/${id}.md before generating tests.`));
175
- }
176
- else if (error.message.includes('Spec file not found')) {
177
- console.log(chalk.gray(`šŸ’” Tip: Run 'specsafe new <name>' to create a spec first.`));
178
- console.log(chalk.gray(` Expected file: specs/active/${id}.md`));
179
- }
180
- process.exit(1);
181
- }
182
- });
183
- //# sourceMappingURL=test-create.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"test-create.js","sourceRoot":"","sources":["../../src/commands/test-create.ts"],"names":[],"mappings":"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"}
@@ -1,3 +0,0 @@
1
- import { Command } from 'commander';
2
- export declare const testGuideCommand: Command;
3
- //# sourceMappingURL=test-guide.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"test-guide.d.ts","sourceRoot":"","sources":["../../src/commands/test-guide.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAgCpC,eAAO,MAAM,gBAAgB,SAuHzB,CAAC"}
@@ -1,190 +0,0 @@
1
- import { Command } from 'commander';
2
- import chalk from 'chalk';
3
- import ora from 'ora';
4
- import { Workflow, ProjectTracker, generateGuide, generateGuideContent, convertToPlaywrightScenarios, generatePlaywrightScript, } from '@specsafe/core';
5
- import { readFile, writeFile, mkdir } from 'fs/promises';
6
- import { join, dirname, normalize, isAbsolute } from 'path';
7
- function validateSpecInput(specInput) {
8
- if (specInput.endsWith('.md'))
9
- return specInput;
10
- if (!/^[A-Za-z0-9_-]+$/.test(specInput)) {
11
- throw new Error('Invalid spec identifier. Use only letters, numbers, dash, and underscore.');
12
- }
13
- return specInput;
14
- }
15
- function sanitizeOutputPath(outputPath) {
16
- const normalized = normalize(outputPath);
17
- if (isAbsolute(normalized) || normalized.includes('..')) {
18
- throw new Error('Output path must be a safe relative path');
19
- }
20
- return normalized;
21
- }
22
- export const testGuideCommand = new Command('test-guide')
23
- .description('Generate E2E test guide from spec')
24
- .argument('<spec>', 'Spec ID or path to spec file')
25
- .option('-o, --output <file>', 'Output file path')
26
- .option('--format <format>', 'Output format (markdown|json)', 'markdown')
27
- .option('--mode <mode>', 'Automation mode (manual|playwright)', 'manual')
28
- .option('--auto', 'Generate Playwright script output')
29
- .option('--priority <priorities...>', 'Filter by priority (P0 P1 P2)', ['P0', 'P1', 'P2'])
30
- .action(async (specInput, options) => {
31
- const spinner = ora('Generating test guide...').start();
32
- try {
33
- specInput = validateSpecInput(specInput);
34
- const workflow = new Workflow();
35
- const tracker = new ProjectTracker(process.cwd());
36
- await tracker.loadSpecsIntoWorkflow(workflow);
37
- let specId;
38
- let specContent;
39
- let specPath;
40
- if (specInput.endsWith('.md')) {
41
- specPath = specInput;
42
- try {
43
- specContent = await readFile(specPath, 'utf-8');
44
- specId = specInput.split('/').pop().replace('.md', '');
45
- }
46
- catch {
47
- throw new Error(`Spec file not found: ${specPath}`);
48
- }
49
- }
50
- else {
51
- specId = specInput;
52
- specPath = join('specs/active', `${specId}.md`);
53
- try {
54
- specContent = await readFile(specPath, 'utf-8');
55
- }
56
- catch {
57
- throw new Error(`Spec file not found: ${specPath}`);
58
- }
59
- }
60
- let spec = workflow.getSpec(specId);
61
- if (!spec)
62
- spec = parseSpecFromContent(specId, specContent);
63
- spinner.text = 'Generating test content...';
64
- const priorityFilter = options.priority;
65
- const mode = options.auto ? 'playwright' : (options.mode ?? 'manual');
66
- const guide = generateGuide(spec, {
67
- priorityFilter,
68
- format: options.format,
69
- mode,
70
- });
71
- let output;
72
- let outputFormat;
73
- if (options.auto) {
74
- const scenarios = convertToPlaywrightScenarios(guide);
75
- output = generatePlaywrightScript(spec.id, scenarios);
76
- outputFormat = 'js';
77
- }
78
- else {
79
- const result = generateGuideContent(spec, {
80
- priorityFilter,
81
- format: options.format,
82
- mode,
83
- });
84
- output = result.content;
85
- outputFormat = result.format === 'markdown' ? 'md' : result.format;
86
- }
87
- spinner.stop();
88
- let outputPath;
89
- if (options.output) {
90
- outputPath = sanitizeOutputPath(options.output);
91
- }
92
- else {
93
- const guidesDir = join('.specsafe', 'e2e', 'guides');
94
- await mkdir(guidesDir, { recursive: true });
95
- const extension = outputFormat;
96
- outputPath = join(guidesDir, `test-guide-${specId}.${extension}`);
97
- }
98
- await mkdir(dirname(outputPath), { recursive: true });
99
- await writeFile(outputPath, output, 'utf-8');
100
- console.log(chalk.green(`\nāœ… Test guide generated: ${outputPath}`));
101
- console.log(chalk.blue('\nGuide Summary:'));
102
- console.log(` Mode: ${mode}`);
103
- console.log(` Scenarios: ${guide.scenarios.length}`);
104
- console.log(` Steps: ${guide.scenarios.reduce((sum, s) => sum + s.steps.length, 0)}`);
105
- console.log(` P0 (Critical): ${guide.scenarios.filter(s => s.priority === 'P0').length}`);
106
- console.log(` P1 (High): ${guide.scenarios.filter(s => s.priority === 'P1').length}`);
107
- console.log(` P2 (Normal): ${guide.scenarios.filter(s => s.priority === 'P2').length}`);
108
- console.log(chalk.blue('\nNext steps:'));
109
- if (mode === 'playwright') {
110
- console.log(chalk.gray(` 1. Run generated script with: npx playwright test ${outputPath}`));
111
- console.log(chalk.gray(' 2. Review screenshots captured at configured intervals'));
112
- console.log(chalk.gray(' 3. Validate assertions and adjust selectors as needed'));
113
- }
114
- else {
115
- console.log(chalk.gray(` 1. Review the test guide: ${outputPath}`));
116
- console.log(chalk.gray(' 2. Execute test scenarios manually'));
117
- console.log(chalk.gray(' 3. Take screenshots at key steps'));
118
- console.log(chalk.gray(` 4. Submit for analysis: specsafe test-submit ${specId} --screenshots ./my-screenshots/`));
119
- }
120
- }
121
- catch (error) {
122
- spinner.fail(chalk.red(error.message));
123
- if (error.message.includes('not found')) {
124
- console.log(chalk.gray(`\nšŸ’” Tip: Create a spec first with 'specsafe new <name>'`));
125
- }
126
- process.exit(1);
127
- }
128
- });
129
- function parseSpecFromContent(specId, content) {
130
- const safeContent = content.slice(0, 500_000);
131
- const nameMatch = safeContent.match(/^#\s+(.+?)(?:\s+Specification)?$/m);
132
- const name = nameMatch ? nameMatch[1] : specId;
133
- const descMatch = safeContent.match(/## Overview\n+([\s\S]*?)(?=##|$)/);
134
- const description = descMatch ? descMatch[1].trim() : '';
135
- const requirements = [];
136
- const tableMatch = safeContent.match(/\| ID \| Requirement \| Priority \|[^|]+\|\n\|[-\s|]+\|\n([\s\S]*?)(?=\n## |\n### |$)/);
137
- if (tableMatch) {
138
- const rows = tableMatch[1].trim().split('\n');
139
- for (const row of rows) {
140
- const cells = row.split('|').map(c => c.trim()).filter(Boolean);
141
- if (cells.length >= 3) {
142
- const [id, text, priority] = cells;
143
- requirements.push({ id, text, priority: priority || 'P1', scenarios: [] });
144
- }
145
- }
146
- }
147
- const scenariosMatch = safeContent.match(/## \d+\.\s*Scenarios\n+([\s\S]*?)(?=## \d+\.|$)/);
148
- if (scenariosMatch) {
149
- const scenarioBlocks = scenariosMatch[1].split(/### Scenario \d+:/);
150
- for (let i = 0; i < scenarioBlocks.length; i++) {
151
- const block = scenarioBlocks[i];
152
- const givenMatch = block.match(/[-*]\s*\*\*Given\*\*\s*(.+)/i);
153
- const whenMatch = block.match(/[-*]\s*\*\*When\*\*\s*(.+)/i);
154
- const thenMatch = block.match(/[-*]\s*\*\*Then\*\*\s*(.+)/i);
155
- if (givenMatch && whenMatch && thenMatch) {
156
- const scenario = {
157
- id: `SC-${i + 1}`,
158
- given: givenMatch[1].trim(),
159
- when: whenMatch[1].trim(),
160
- thenOutcome: thenMatch[1].trim(),
161
- };
162
- if (requirements.length > 0)
163
- requirements[0].scenarios.push(scenario);
164
- else
165
- requirements.push({ id: 'FR-1', text: 'Generated from scenarios', priority: 'P1', scenarios: [scenario] });
166
- }
167
- }
168
- }
169
- if (requirements.length === 0) {
170
- requirements.push({
171
- id: 'FR-1',
172
- text: 'Feature implementation matches spec',
173
- priority: 'P0',
174
- scenarios: [{ id: 'SC-1', given: 'user accesses the feature', when: 'user interacts with the feature', thenOutcome: 'feature behaves as specified' }],
175
- });
176
- }
177
- return {
178
- id: specId,
179
- name,
180
- description,
181
- stage: 'spec',
182
- createdAt: new Date(),
183
- updatedAt: new Date(),
184
- requirements,
185
- testFiles: [],
186
- implementationFiles: [],
187
- metadata: { author: 'unknown', project: 'unknown', tags: [] },
188
- };
189
- }
190
- //# sourceMappingURL=test-guide.js.map