spec-gen-cli 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (303) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +1078 -0
  3. package/dist/api/analyze.d.ts +17 -0
  4. package/dist/api/analyze.d.ts.map +1 -0
  5. package/dist/api/analyze.js +109 -0
  6. package/dist/api/analyze.js.map +1 -0
  7. package/dist/api/drift.d.ts +21 -0
  8. package/dist/api/drift.d.ts.map +1 -0
  9. package/dist/api/drift.js +145 -0
  10. package/dist/api/drift.js.map +1 -0
  11. package/dist/api/generate.d.ts +18 -0
  12. package/dist/api/generate.d.ts.map +1 -0
  13. package/dist/api/generate.js +251 -0
  14. package/dist/api/generate.js.map +1 -0
  15. package/dist/api/index.d.ts +39 -0
  16. package/dist/api/index.d.ts.map +1 -0
  17. package/dist/api/index.js +32 -0
  18. package/dist/api/index.js.map +1 -0
  19. package/dist/api/init.d.ts +18 -0
  20. package/dist/api/init.d.ts.map +1 -0
  21. package/dist/api/init.js +82 -0
  22. package/dist/api/init.js.map +1 -0
  23. package/dist/api/run.d.ts +19 -0
  24. package/dist/api/run.d.ts.map +1 -0
  25. package/dist/api/run.js +291 -0
  26. package/dist/api/run.js.map +1 -0
  27. package/dist/api/specs.d.ts +49 -0
  28. package/dist/api/specs.d.ts.map +1 -0
  29. package/dist/api/specs.js +136 -0
  30. package/dist/api/specs.js.map +1 -0
  31. package/dist/api/types.d.ts +176 -0
  32. package/dist/api/types.d.ts.map +1 -0
  33. package/dist/api/types.js +9 -0
  34. package/dist/api/types.js.map +1 -0
  35. package/dist/api/verify.d.ts +20 -0
  36. package/dist/api/verify.d.ts.map +1 -0
  37. package/dist/api/verify.js +117 -0
  38. package/dist/api/verify.js.map +1 -0
  39. package/dist/cli/commands/analyze.d.ts +27 -0
  40. package/dist/cli/commands/analyze.d.ts.map +1 -0
  41. package/dist/cli/commands/analyze.js +485 -0
  42. package/dist/cli/commands/analyze.js.map +1 -0
  43. package/dist/cli/commands/drift.d.ts +9 -0
  44. package/dist/cli/commands/drift.d.ts.map +1 -0
  45. package/dist/cli/commands/drift.js +540 -0
  46. package/dist/cli/commands/drift.js.map +1 -0
  47. package/dist/cli/commands/generate.d.ts +9 -0
  48. package/dist/cli/commands/generate.d.ts.map +1 -0
  49. package/dist/cli/commands/generate.js +633 -0
  50. package/dist/cli/commands/generate.js.map +1 -0
  51. package/dist/cli/commands/init.d.ts +9 -0
  52. package/dist/cli/commands/init.d.ts.map +1 -0
  53. package/dist/cli/commands/init.js +171 -0
  54. package/dist/cli/commands/init.js.map +1 -0
  55. package/dist/cli/commands/mcp.d.ts +638 -0
  56. package/dist/cli/commands/mcp.d.ts.map +1 -0
  57. package/dist/cli/commands/mcp.js +574 -0
  58. package/dist/cli/commands/mcp.js.map +1 -0
  59. package/dist/cli/commands/run.d.ts +24 -0
  60. package/dist/cli/commands/run.d.ts.map +1 -0
  61. package/dist/cli/commands/run.js +546 -0
  62. package/dist/cli/commands/run.js.map +1 -0
  63. package/dist/cli/commands/verify.d.ts +9 -0
  64. package/dist/cli/commands/verify.d.ts.map +1 -0
  65. package/dist/cli/commands/verify.js +417 -0
  66. package/dist/cli/commands/verify.js.map +1 -0
  67. package/dist/cli/commands/view.d.ts +9 -0
  68. package/dist/cli/commands/view.d.ts.map +1 -0
  69. package/dist/cli/commands/view.js +511 -0
  70. package/dist/cli/commands/view.js.map +1 -0
  71. package/dist/cli/index.d.ts +9 -0
  72. package/dist/cli/index.d.ts.map +1 -0
  73. package/dist/cli/index.js +83 -0
  74. package/dist/cli/index.js.map +1 -0
  75. package/dist/core/analyzer/architecture-writer.d.ts +67 -0
  76. package/dist/core/analyzer/architecture-writer.d.ts.map +1 -0
  77. package/dist/core/analyzer/architecture-writer.js +209 -0
  78. package/dist/core/analyzer/architecture-writer.js.map +1 -0
  79. package/dist/core/analyzer/artifact-generator.d.ts +222 -0
  80. package/dist/core/analyzer/artifact-generator.d.ts.map +1 -0
  81. package/dist/core/analyzer/artifact-generator.js +726 -0
  82. package/dist/core/analyzer/artifact-generator.js.map +1 -0
  83. package/dist/core/analyzer/call-graph.d.ts +83 -0
  84. package/dist/core/analyzer/call-graph.d.ts.map +1 -0
  85. package/dist/core/analyzer/call-graph.js +827 -0
  86. package/dist/core/analyzer/call-graph.js.map +1 -0
  87. package/dist/core/analyzer/code-shaper.d.ts +33 -0
  88. package/dist/core/analyzer/code-shaper.d.ts.map +1 -0
  89. package/dist/core/analyzer/code-shaper.js +149 -0
  90. package/dist/core/analyzer/code-shaper.js.map +1 -0
  91. package/dist/core/analyzer/dependency-graph.d.ts +179 -0
  92. package/dist/core/analyzer/dependency-graph.d.ts.map +1 -0
  93. package/dist/core/analyzer/dependency-graph.js +574 -0
  94. package/dist/core/analyzer/dependency-graph.js.map +1 -0
  95. package/dist/core/analyzer/duplicate-detector.d.ts +52 -0
  96. package/dist/core/analyzer/duplicate-detector.d.ts.map +1 -0
  97. package/dist/core/analyzer/duplicate-detector.js +279 -0
  98. package/dist/core/analyzer/duplicate-detector.js.map +1 -0
  99. package/dist/core/analyzer/embedding-service.d.ts +50 -0
  100. package/dist/core/analyzer/embedding-service.d.ts.map +1 -0
  101. package/dist/core/analyzer/embedding-service.js +104 -0
  102. package/dist/core/analyzer/embedding-service.js.map +1 -0
  103. package/dist/core/analyzer/file-walker.d.ts +78 -0
  104. package/dist/core/analyzer/file-walker.d.ts.map +1 -0
  105. package/dist/core/analyzer/file-walker.js +531 -0
  106. package/dist/core/analyzer/file-walker.js.map +1 -0
  107. package/dist/core/analyzer/import-parser.d.ts +91 -0
  108. package/dist/core/analyzer/import-parser.d.ts.map +1 -0
  109. package/dist/core/analyzer/import-parser.js +720 -0
  110. package/dist/core/analyzer/import-parser.js.map +1 -0
  111. package/dist/core/analyzer/index.d.ts +10 -0
  112. package/dist/core/analyzer/index.d.ts.map +1 -0
  113. package/dist/core/analyzer/index.js +10 -0
  114. package/dist/core/analyzer/index.js.map +1 -0
  115. package/dist/core/analyzer/refactor-analyzer.d.ts +80 -0
  116. package/dist/core/analyzer/refactor-analyzer.d.ts.map +1 -0
  117. package/dist/core/analyzer/refactor-analyzer.js +339 -0
  118. package/dist/core/analyzer/refactor-analyzer.js.map +1 -0
  119. package/dist/core/analyzer/repository-mapper.d.ts +150 -0
  120. package/dist/core/analyzer/repository-mapper.d.ts.map +1 -0
  121. package/dist/core/analyzer/repository-mapper.js +731 -0
  122. package/dist/core/analyzer/repository-mapper.js.map +1 -0
  123. package/dist/core/analyzer/signature-extractor.d.ts +31 -0
  124. package/dist/core/analyzer/signature-extractor.d.ts.map +1 -0
  125. package/dist/core/analyzer/signature-extractor.js +387 -0
  126. package/dist/core/analyzer/signature-extractor.js.map +1 -0
  127. package/dist/core/analyzer/significance-scorer.d.ts +79 -0
  128. package/dist/core/analyzer/significance-scorer.d.ts.map +1 -0
  129. package/dist/core/analyzer/significance-scorer.js +407 -0
  130. package/dist/core/analyzer/significance-scorer.js.map +1 -0
  131. package/dist/core/analyzer/subgraph-extractor.d.ts +43 -0
  132. package/dist/core/analyzer/subgraph-extractor.d.ts.map +1 -0
  133. package/dist/core/analyzer/subgraph-extractor.js +129 -0
  134. package/dist/core/analyzer/subgraph-extractor.js.map +1 -0
  135. package/dist/core/analyzer/vector-index.d.ts +63 -0
  136. package/dist/core/analyzer/vector-index.d.ts.map +1 -0
  137. package/dist/core/analyzer/vector-index.js +169 -0
  138. package/dist/core/analyzer/vector-index.js.map +1 -0
  139. package/dist/core/drift/drift-detector.d.ts +102 -0
  140. package/dist/core/drift/drift-detector.d.ts.map +1 -0
  141. package/dist/core/drift/drift-detector.js +597 -0
  142. package/dist/core/drift/drift-detector.js.map +1 -0
  143. package/dist/core/drift/git-diff.d.ts +55 -0
  144. package/dist/core/drift/git-diff.d.ts.map +1 -0
  145. package/dist/core/drift/git-diff.js +356 -0
  146. package/dist/core/drift/git-diff.js.map +1 -0
  147. package/dist/core/drift/index.d.ts +12 -0
  148. package/dist/core/drift/index.d.ts.map +1 -0
  149. package/dist/core/drift/index.js +9 -0
  150. package/dist/core/drift/index.js.map +1 -0
  151. package/dist/core/drift/spec-mapper.d.ts +73 -0
  152. package/dist/core/drift/spec-mapper.d.ts.map +1 -0
  153. package/dist/core/drift/spec-mapper.js +353 -0
  154. package/dist/core/drift/spec-mapper.js.map +1 -0
  155. package/dist/core/generator/adr-generator.d.ts +32 -0
  156. package/dist/core/generator/adr-generator.d.ts.map +1 -0
  157. package/dist/core/generator/adr-generator.js +192 -0
  158. package/dist/core/generator/adr-generator.js.map +1 -0
  159. package/dist/core/generator/index.d.ts +9 -0
  160. package/dist/core/generator/index.d.ts.map +1 -0
  161. package/dist/core/generator/index.js +12 -0
  162. package/dist/core/generator/index.js.map +1 -0
  163. package/dist/core/generator/mapping-generator.d.ts +54 -0
  164. package/dist/core/generator/mapping-generator.d.ts.map +1 -0
  165. package/dist/core/generator/mapping-generator.js +239 -0
  166. package/dist/core/generator/mapping-generator.js.map +1 -0
  167. package/dist/core/generator/openspec-compat.d.ts +160 -0
  168. package/dist/core/generator/openspec-compat.d.ts.map +1 -0
  169. package/dist/core/generator/openspec-compat.js +523 -0
  170. package/dist/core/generator/openspec-compat.js.map +1 -0
  171. package/dist/core/generator/openspec-format-generator.d.ts +111 -0
  172. package/dist/core/generator/openspec-format-generator.d.ts.map +1 -0
  173. package/dist/core/generator/openspec-format-generator.js +817 -0
  174. package/dist/core/generator/openspec-format-generator.js.map +1 -0
  175. package/dist/core/generator/openspec-writer.d.ts +131 -0
  176. package/dist/core/generator/openspec-writer.d.ts.map +1 -0
  177. package/dist/core/generator/openspec-writer.js +379 -0
  178. package/dist/core/generator/openspec-writer.js.map +1 -0
  179. package/dist/core/generator/prompts.d.ts +35 -0
  180. package/dist/core/generator/prompts.d.ts.map +1 -0
  181. package/dist/core/generator/prompts.js +212 -0
  182. package/dist/core/generator/prompts.js.map +1 -0
  183. package/dist/core/generator/spec-pipeline.d.ts +94 -0
  184. package/dist/core/generator/spec-pipeline.d.ts.map +1 -0
  185. package/dist/core/generator/spec-pipeline.js +474 -0
  186. package/dist/core/generator/spec-pipeline.js.map +1 -0
  187. package/dist/core/generator/stages/stage1-survey.d.ts +19 -0
  188. package/dist/core/generator/stages/stage1-survey.d.ts.map +1 -0
  189. package/dist/core/generator/stages/stage1-survey.js +105 -0
  190. package/dist/core/generator/stages/stage1-survey.js.map +1 -0
  191. package/dist/core/generator/stages/stage2-entities.d.ts +11 -0
  192. package/dist/core/generator/stages/stage2-entities.d.ts.map +1 -0
  193. package/dist/core/generator/stages/stage2-entities.js +67 -0
  194. package/dist/core/generator/stages/stage2-entities.js.map +1 -0
  195. package/dist/core/generator/stages/stage3-services.d.ts +11 -0
  196. package/dist/core/generator/stages/stage3-services.d.ts.map +1 -0
  197. package/dist/core/generator/stages/stage3-services.js +75 -0
  198. package/dist/core/generator/stages/stage3-services.js.map +1 -0
  199. package/dist/core/generator/stages/stage4-api.d.ts +11 -0
  200. package/dist/core/generator/stages/stage4-api.d.ts.map +1 -0
  201. package/dist/core/generator/stages/stage4-api.js +65 -0
  202. package/dist/core/generator/stages/stage4-api.js.map +1 -0
  203. package/dist/core/generator/stages/stage5-architecture.d.ts +10 -0
  204. package/dist/core/generator/stages/stage5-architecture.d.ts.map +1 -0
  205. package/dist/core/generator/stages/stage5-architecture.js +62 -0
  206. package/dist/core/generator/stages/stage5-architecture.js.map +1 -0
  207. package/dist/core/generator/stages/stage6-adr.d.ts +8 -0
  208. package/dist/core/generator/stages/stage6-adr.d.ts.map +1 -0
  209. package/dist/core/generator/stages/stage6-adr.js +41 -0
  210. package/dist/core/generator/stages/stage6-adr.js.map +1 -0
  211. package/dist/core/services/chat-agent.d.ts +45 -0
  212. package/dist/core/services/chat-agent.d.ts.map +1 -0
  213. package/dist/core/services/chat-agent.js +310 -0
  214. package/dist/core/services/chat-agent.js.map +1 -0
  215. package/dist/core/services/chat-tools.d.ts +32 -0
  216. package/dist/core/services/chat-tools.d.ts.map +1 -0
  217. package/dist/core/services/chat-tools.js +270 -0
  218. package/dist/core/services/chat-tools.js.map +1 -0
  219. package/dist/core/services/config-manager.d.ts +61 -0
  220. package/dist/core/services/config-manager.d.ts.map +1 -0
  221. package/dist/core/services/config-manager.js +143 -0
  222. package/dist/core/services/config-manager.js.map +1 -0
  223. package/dist/core/services/gitignore-manager.d.ts +29 -0
  224. package/dist/core/services/gitignore-manager.d.ts.map +1 -0
  225. package/dist/core/services/gitignore-manager.js +106 -0
  226. package/dist/core/services/gitignore-manager.js.map +1 -0
  227. package/dist/core/services/index.d.ts +8 -0
  228. package/dist/core/services/index.d.ts.map +1 -0
  229. package/dist/core/services/index.js +8 -0
  230. package/dist/core/services/index.js.map +1 -0
  231. package/dist/core/services/llm-service.d.ts +336 -0
  232. package/dist/core/services/llm-service.d.ts.map +1 -0
  233. package/dist/core/services/llm-service.js +1155 -0
  234. package/dist/core/services/llm-service.js.map +1 -0
  235. package/dist/core/services/mcp-handlers/analysis.d.ts +42 -0
  236. package/dist/core/services/mcp-handlers/analysis.d.ts.map +1 -0
  237. package/dist/core/services/mcp-handlers/analysis.js +300 -0
  238. package/dist/core/services/mcp-handlers/analysis.js.map +1 -0
  239. package/dist/core/services/mcp-handlers/graph.d.ts +65 -0
  240. package/dist/core/services/mcp-handlers/graph.d.ts.map +1 -0
  241. package/dist/core/services/mcp-handlers/graph.js +509 -0
  242. package/dist/core/services/mcp-handlers/graph.js.map +1 -0
  243. package/dist/core/services/mcp-handlers/semantic.d.ts +38 -0
  244. package/dist/core/services/mcp-handlers/semantic.d.ts.map +1 -0
  245. package/dist/core/services/mcp-handlers/semantic.js +172 -0
  246. package/dist/core/services/mcp-handlers/semantic.js.map +1 -0
  247. package/dist/core/services/mcp-handlers/utils.d.ts +21 -0
  248. package/dist/core/services/mcp-handlers/utils.d.ts.map +1 -0
  249. package/dist/core/services/mcp-handlers/utils.js +62 -0
  250. package/dist/core/services/mcp-handlers/utils.js.map +1 -0
  251. package/dist/core/services/project-detector.d.ts +32 -0
  252. package/dist/core/services/project-detector.d.ts.map +1 -0
  253. package/dist/core/services/project-detector.js +111 -0
  254. package/dist/core/services/project-detector.js.map +1 -0
  255. package/dist/core/verifier/index.d.ts +5 -0
  256. package/dist/core/verifier/index.d.ts.map +1 -0
  257. package/dist/core/verifier/index.js +5 -0
  258. package/dist/core/verifier/index.js.map +1 -0
  259. package/dist/core/verifier/verification-engine.d.ts +226 -0
  260. package/dist/core/verifier/verification-engine.d.ts.map +1 -0
  261. package/dist/core/verifier/verification-engine.js +681 -0
  262. package/dist/core/verifier/verification-engine.js.map +1 -0
  263. package/dist/types/index.d.ts +252 -0
  264. package/dist/types/index.d.ts.map +1 -0
  265. package/dist/types/index.js +5 -0
  266. package/dist/types/index.js.map +1 -0
  267. package/dist/types/pipeline.d.ts +148 -0
  268. package/dist/types/pipeline.d.ts.map +1 -0
  269. package/dist/types/pipeline.js +5 -0
  270. package/dist/types/pipeline.js.map +1 -0
  271. package/dist/utils/errors.d.ts +51 -0
  272. package/dist/utils/errors.d.ts.map +1 -0
  273. package/dist/utils/errors.js +128 -0
  274. package/dist/utils/errors.js.map +1 -0
  275. package/dist/utils/logger.d.ts +149 -0
  276. package/dist/utils/logger.d.ts.map +1 -0
  277. package/dist/utils/logger.js +331 -0
  278. package/dist/utils/logger.js.map +1 -0
  279. package/dist/utils/progress.d.ts +142 -0
  280. package/dist/utils/progress.d.ts.map +1 -0
  281. package/dist/utils/progress.js +280 -0
  282. package/dist/utils/progress.js.map +1 -0
  283. package/dist/utils/prompts.d.ts +53 -0
  284. package/dist/utils/prompts.d.ts.map +1 -0
  285. package/dist/utils/prompts.js +199 -0
  286. package/dist/utils/prompts.js.map +1 -0
  287. package/dist/utils/shutdown.d.ts +89 -0
  288. package/dist/utils/shutdown.d.ts.map +1 -0
  289. package/dist/utils/shutdown.js +237 -0
  290. package/dist/utils/shutdown.js.map +1 -0
  291. package/package.json +114 -0
  292. package/src/viewer/InteractiveGraphViewer.jsx +1486 -0
  293. package/src/viewer/app/index.html +17 -0
  294. package/src/viewer/app/main.jsx +13 -0
  295. package/src/viewer/components/ArchitectureView.jsx +177 -0
  296. package/src/viewer/components/ChatPanel.jsx +448 -0
  297. package/src/viewer/components/ClusterGraph.jsx +441 -0
  298. package/src/viewer/components/FilterBar.jsx +179 -0
  299. package/src/viewer/components/FlatGraph.jsx +275 -0
  300. package/src/viewer/components/MicroComponents.jsx +83 -0
  301. package/src/viewer/hooks/usePanZoom.js +79 -0
  302. package/src/viewer/utils/constants.js +47 -0
  303. package/src/viewer/utils/graph-helpers.js +291 -0
@@ -0,0 +1,199 @@
1
+ /**
2
+ * Interactive prompts for spec-gen CLI
3
+ * Uses @inquirer/prompts (same as OpenSpec)
4
+ */
5
+ import { select, confirm, input } from '@inquirer/prompts';
6
+ /**
7
+ * Prompt for handling existing spec files
8
+ */
9
+ export async function promptOverwrite(filePath) {
10
+ return select({
11
+ message: `${filePath} already exists. What would you like to do?`,
12
+ choices: [
13
+ {
14
+ value: 'backup-replace',
15
+ name: 'Backup and replace (recommended)',
16
+ description: 'Backup existing file and write new content',
17
+ },
18
+ {
19
+ value: 'merge',
20
+ name: 'Merge (append generated content)',
21
+ description: 'Add generated content to end of existing file',
22
+ },
23
+ {
24
+ value: 'skip',
25
+ name: 'Skip this file',
26
+ description: 'Keep existing file unchanged',
27
+ },
28
+ {
29
+ value: 'skip-all',
30
+ name: 'Skip all existing files',
31
+ description: 'Keep all existing files unchanged',
32
+ },
33
+ ],
34
+ });
35
+ }
36
+ /**
37
+ * Confirm before overwriting multiple files
38
+ */
39
+ export async function confirmOverwriteAll(count) {
40
+ return confirm({
41
+ message: `This will overwrite ${count} existing spec files. Continue?`,
42
+ default: false,
43
+ });
44
+ }
45
+ /**
46
+ * Confirm before running analysis that will take a while
47
+ */
48
+ export async function confirmLongAnalysis(fileCount) {
49
+ return confirm({
50
+ message: `About to analyze ${fileCount} files. This may take a while. Continue?`,
51
+ default: true,
52
+ });
53
+ }
54
+ /**
55
+ * Confirm before making API calls
56
+ */
57
+ export async function confirmGeneration(options) {
58
+ let message = `Ready to generate specs using ${options.model}.`;
59
+ if (options.estimatedTokens) {
60
+ message += ` Estimated ${options.estimatedTokens.toLocaleString()} tokens.`;
61
+ }
62
+ message += ' Continue?';
63
+ return confirm({
64
+ message,
65
+ default: true,
66
+ });
67
+ }
68
+ /**
69
+ * Prompt for API key when not found in environment
70
+ */
71
+ export async function promptApiKey(provider) {
72
+ const envVar = provider === 'anthropic' ? 'ANTHROPIC_API_KEY' : 'OPENAI_API_KEY';
73
+ const url = provider === 'anthropic'
74
+ ? 'https://console.anthropic.com/'
75
+ : 'https://platform.openai.com/api-keys';
76
+ console.log(`\nNo ${envVar} found in environment.`);
77
+ console.log(`Get an API key at: ${url}\n`);
78
+ return input({
79
+ message: `Enter your ${provider} API key:`,
80
+ validate: (value) => {
81
+ if (!value.trim()) {
82
+ return 'API key is required';
83
+ }
84
+ if (provider === 'anthropic' && !value.startsWith('sk-ant-')) {
85
+ return 'Anthropic API keys should start with sk-ant-';
86
+ }
87
+ if (provider === 'openai' && !value.startsWith('sk-')) {
88
+ return 'OpenAI API keys should start with sk-';
89
+ }
90
+ return true;
91
+ },
92
+ });
93
+ }
94
+ /**
95
+ * Select LLM provider when multiple are available
96
+ */
97
+ export async function selectProvider() {
98
+ return select({
99
+ message: 'Multiple API keys found. Which provider would you like to use?',
100
+ choices: [
101
+ {
102
+ value: 'anthropic',
103
+ name: 'Anthropic (Claude)',
104
+ description: 'Recommended for best results',
105
+ },
106
+ {
107
+ value: 'openai',
108
+ name: 'OpenAI (GPT-4)',
109
+ description: 'Alternative provider',
110
+ },
111
+ ],
112
+ });
113
+ }
114
+ /**
115
+ * Select verification sample count
116
+ */
117
+ export async function selectSampleCount() {
118
+ const answer = await select({
119
+ message: 'How many files would you like to verify?',
120
+ choices: [
121
+ { value: '3', name: '3 files (quick check)' },
122
+ { value: '5', name: '5 files (recommended)' },
123
+ { value: '10', name: '10 files (thorough)' },
124
+ { value: 'custom', name: 'Custom number' },
125
+ ],
126
+ });
127
+ if (answer === 'custom') {
128
+ const customAnswer = await input({
129
+ message: 'Enter number of files to verify:',
130
+ validate: (value) => {
131
+ const num = parseInt(value, 10);
132
+ if (isNaN(num) || num < 1) {
133
+ return 'Please enter a positive number';
134
+ }
135
+ if (num > 50) {
136
+ return 'Maximum is 50 files';
137
+ }
138
+ return true;
139
+ },
140
+ });
141
+ return parseInt(customAnswer, 10);
142
+ }
143
+ return parseInt(answer, 10);
144
+ }
145
+ /**
146
+ * Prompt to continue after partial failure
147
+ */
148
+ export async function promptContinueAfterError(stage, error) {
149
+ console.log(`\n⚠️ ${stage} encountered an error: ${error}\n`);
150
+ return confirm({
151
+ message: 'Would you like to continue with partial results?',
152
+ default: true,
153
+ });
154
+ }
155
+ /**
156
+ * Select domains to generate
157
+ */
158
+ export async function selectDomains(availableDomains) {
159
+ // Use a simple confirm + input approach since inquirer checkbox is complex
160
+ const selectAll = await confirm({
161
+ message: `Found ${availableDomains.length} domains. Generate specs for all?`,
162
+ default: true,
163
+ });
164
+ if (selectAll) {
165
+ return availableDomains;
166
+ }
167
+ const selected = await input({
168
+ message: `Enter domains to include (comma-separated):\nAvailable: ${availableDomains.join(', ')}\n`,
169
+ validate: (value) => {
170
+ if (!value.trim()) {
171
+ return 'Please enter at least one domain';
172
+ }
173
+ const domains = value.split(',').map((d) => d.trim());
174
+ const invalid = domains.filter((d) => !availableDomains.includes(d));
175
+ if (invalid.length > 0) {
176
+ return `Unknown domains: ${invalid.join(', ')}`;
177
+ }
178
+ return true;
179
+ },
180
+ });
181
+ return selected.split(',').map((d) => d.trim());
182
+ }
183
+ /**
184
+ * Interactive mode flag - can be disabled for CI/non-interactive environments
185
+ */
186
+ let interactiveMode = process.stdin.isTTY ?? false;
187
+ /**
188
+ * Check if we're in interactive mode
189
+ */
190
+ export function isInteractive() {
191
+ return interactiveMode;
192
+ }
193
+ /**
194
+ * Enable/disable interactive mode
195
+ */
196
+ export function setInteractiveMode(enabled) {
197
+ interactiveMode = enabled;
198
+ }
199
+ //# sourceMappingURL=prompts.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"prompts.js","sourceRoot":"","sources":["../../src/utils/prompts.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,89 @@
1
+ /**
2
+ * Graceful shutdown handling for spec-gen CLI
3
+ */
4
+ export interface ShutdownState {
5
+ /** Current phase when interrupted */
6
+ phase: 'init' | 'analyze' | 'generate' | 'verify';
7
+ /** Files that were being processed */
8
+ currentFiles?: string[];
9
+ /** Partial results that were saved */
10
+ savedResults?: string;
11
+ /** Timestamp of interruption */
12
+ timestamp: number;
13
+ }
14
+ type CleanupCallback = () => void | Promise<void>;
15
+ /**
16
+ * Manages graceful shutdown with cleanup callbacks
17
+ */
18
+ export declare class ShutdownManager {
19
+ private callbacks;
20
+ private isShuttingDown;
21
+ private state;
22
+ private stateFile;
23
+ private handlers;
24
+ private handlersAttached;
25
+ constructor(projectPath?: string, options?: {
26
+ skipHandlers?: boolean;
27
+ });
28
+ private setupHandlers;
29
+ /**
30
+ * Remove all registered signal handlers (for testing)
31
+ */
32
+ removeHandlers(): void;
33
+ private handleShutdown;
34
+ /**
35
+ * Register a cleanup callback to run on shutdown
36
+ */
37
+ onCleanup(callback: CleanupCallback): void;
38
+ /**
39
+ * Remove a cleanup callback
40
+ */
41
+ removeCleanup(callback: CleanupCallback): void;
42
+ /**
43
+ * Set the current state for potential resume
44
+ */
45
+ setState(state: Partial<ShutdownState>): void;
46
+ /**
47
+ * Clear state (call on successful completion)
48
+ */
49
+ clearState(): void;
50
+ /**
51
+ * Save state to file for potential resume
52
+ */
53
+ private saveState;
54
+ /**
55
+ * Load previous shutdown state
56
+ */
57
+ loadState(): ShutdownState | null;
58
+ /**
59
+ * Check if there's a previous interrupted session
60
+ */
61
+ hasPreviousState(): boolean;
62
+ private showResumeSuggestion;
63
+ /**
64
+ * Check if shutdown is in progress
65
+ */
66
+ isInProgress(): boolean;
67
+ }
68
+ /**
69
+ * Get or create the global shutdown manager
70
+ */
71
+ export declare function getShutdownManager(projectPath?: string): ShutdownManager;
72
+ /**
73
+ * Register a cleanup callback with the global manager
74
+ */
75
+ export declare function onShutdown(callback: CleanupCallback): void;
76
+ /**
77
+ * Set current state for potential resume
78
+ */
79
+ export declare function setShutdownState(state: Partial<ShutdownState>): void;
80
+ /**
81
+ * Clear shutdown state (call on successful completion)
82
+ */
83
+ export declare function clearShutdownState(): void;
84
+ /**
85
+ * Create a scope that sets/clears state automatically
86
+ */
87
+ export declare function withShutdownState<T>(state: Partial<ShutdownState>, fn: () => Promise<T>): Promise<T>;
88
+ export {};
89
+ //# sourceMappingURL=shutdown.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"shutdown.d.ts","sourceRoot":"","sources":["../../src/utils/shutdown.ts"],"names":[],"mappings":"AAAA;;GAEG;AAKH,MAAM,WAAW,aAAa;IAC5B,qCAAqC;IACrC,KAAK,EAAE,MAAM,GAAG,SAAS,GAAG,UAAU,GAAG,QAAQ,CAAC;IAClD,sCAAsC;IACtC,YAAY,CAAC,EAAE,MAAM,EAAE,CAAC;IACxB,sCAAsC;IACtC,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,gCAAgC;IAChC,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,KAAK,eAAe,GAAG,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;AAElD;;GAEG;AACH,qBAAa,eAAe;IAC1B,OAAO,CAAC,SAAS,CAAyB;IAC1C,OAAO,CAAC,cAAc,CAAS;IAC/B,OAAO,CAAC,KAAK,CAA8B;IAC3C,OAAO,CAAC,SAAS,CAAS;IAC1B,OAAO,CAAC,QAAQ,CAAwD;IACxE,OAAO,CAAC,gBAAgB,CAAS;gBAErB,WAAW,GAAE,MAAsB,EAAE,OAAO,CAAC,EAAE;QAAE,YAAY,CAAC,EAAE,OAAO,CAAA;KAAE;IAQrF,OAAO,CAAC,aAAa;IAkCrB;;OAEG;IACH,cAAc,IAAI,IAAI;YAQR,cAAc;IA6B5B;;OAEG;IACH,SAAS,CAAC,QAAQ,EAAE,eAAe,GAAG,IAAI;IAI1C;;OAEG;IACH,aAAa,CAAC,QAAQ,EAAE,eAAe,GAAG,IAAI;IAO9C;;OAEG;IACH,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAC,aAAa,CAAC,GAAG,IAAI;IAS7C;;OAEG;IACH,UAAU,IAAI,IAAI;IAYlB;;OAEG;YACW,SAAS;IAevB;;OAEG;IACH,SAAS,IAAI,aAAa,GAAG,IAAI;IAYjC;;OAEG;IACH,gBAAgB,IAAI,OAAO;IAI3B,OAAO,CAAC,oBAAoB;IA6B5B;;OAEG;IACH,YAAY,IAAI,OAAO;CAGxB;AAKD;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,WAAW,CAAC,EAAE,MAAM,GAAG,eAAe,CAKxE;AAED;;GAEG;AACH,wBAAgB,UAAU,CAAC,QAAQ,EAAE,eAAe,GAAG,IAAI,CAE1D;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,OAAO,CAAC,aAAa,CAAC,GAAG,IAAI,CAEpE;AAED;;GAEG;AACH,wBAAgB,kBAAkB,IAAI,IAAI,CAEzC;AAED;;GAEG;AACH,wBAAsB,iBAAiB,CAAC,CAAC,EACvC,KAAK,EAAE,OAAO,CAAC,aAAa,CAAC,EAC7B,EAAE,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,GACnB,OAAO,CAAC,CAAC,CAAC,CAOZ"}
@@ -0,0 +1,237 @@
1
+ /**
2
+ * Graceful shutdown handling for spec-gen CLI
3
+ */
4
+ import * as fs from 'fs';
5
+ import * as path from 'path';
6
+ /**
7
+ * Manages graceful shutdown with cleanup callbacks
8
+ */
9
+ export class ShutdownManager {
10
+ callbacks = [];
11
+ isShuttingDown = false;
12
+ state = null;
13
+ stateFile;
14
+ handlers = new Map();
15
+ handlersAttached = false;
16
+ constructor(projectPath = process.cwd(), options) {
17
+ this.stateFile = path.join(projectPath, '.spec-gen', 'shutdown-state.json');
18
+ // Skip handlers in test environment or when explicitly disabled
19
+ if (!options?.skipHandlers && process.env.NODE_ENV !== 'test') {
20
+ this.setupHandlers();
21
+ }
22
+ }
23
+ setupHandlers() {
24
+ if (this.handlersAttached)
25
+ return;
26
+ this.handlersAttached = true;
27
+ const sigintHandler = () => this.handleShutdown('SIGINT');
28
+ const sigtermHandler = () => this.handleShutdown('SIGTERM');
29
+ const exceptionHandler = (error) => {
30
+ console.error('\n❌ Uncaught exception:', error.message);
31
+ this.handleShutdown('uncaughtException');
32
+ };
33
+ const rejectionHandler = (reason) => {
34
+ console.error('\n❌ Unhandled rejection:', reason);
35
+ this.handleShutdown('unhandledRejection');
36
+ };
37
+ // Store handlers for potential cleanup
38
+ this.handlers.set('SIGINT', sigintHandler);
39
+ this.handlers.set('SIGTERM', sigtermHandler);
40
+ this.handlers.set('uncaughtException', exceptionHandler);
41
+ this.handlers.set('unhandledRejection', rejectionHandler);
42
+ // Handle Ctrl+C
43
+ process.on('SIGINT', sigintHandler);
44
+ // Handle termination signal
45
+ process.on('SIGTERM', sigtermHandler);
46
+ // Handle uncaught exceptions
47
+ process.on('uncaughtException', exceptionHandler);
48
+ // Handle unhandled promise rejections
49
+ process.on('unhandledRejection', rejectionHandler);
50
+ }
51
+ /**
52
+ * Remove all registered signal handlers (for testing)
53
+ */
54
+ removeHandlers() {
55
+ for (const [event, handler] of this.handlers) {
56
+ process.removeListener(event, handler);
57
+ }
58
+ this.handlers.clear();
59
+ this.handlersAttached = false;
60
+ }
61
+ async handleShutdown(signal) {
62
+ if (this.isShuttingDown) {
63
+ console.log('\n⚠️ Force quitting...');
64
+ process.exit(1);
65
+ }
66
+ this.isShuttingDown = true;
67
+ console.log('\n\n🛑 Interrupted! Cleaning up...');
68
+ // Save state if we have one
69
+ if (this.state) {
70
+ await this.saveState();
71
+ }
72
+ // Run cleanup callbacks in reverse order
73
+ for (const callback of this.callbacks.reverse()) {
74
+ try {
75
+ await callback();
76
+ }
77
+ catch (error) {
78
+ console.error('Cleanup error:', error);
79
+ }
80
+ }
81
+ // Show resume suggestion
82
+ this.showResumeSuggestion();
83
+ process.exit(signal === 'SIGINT' ? 130 : 1);
84
+ }
85
+ /**
86
+ * Register a cleanup callback to run on shutdown
87
+ */
88
+ onCleanup(callback) {
89
+ this.callbacks.push(callback);
90
+ }
91
+ /**
92
+ * Remove a cleanup callback
93
+ */
94
+ removeCleanup(callback) {
95
+ const index = this.callbacks.indexOf(callback);
96
+ if (index !== -1) {
97
+ this.callbacks.splice(index, 1);
98
+ }
99
+ }
100
+ /**
101
+ * Set the current state for potential resume
102
+ */
103
+ setState(state) {
104
+ this.state = {
105
+ phase: state.phase ?? 'init',
106
+ currentFiles: state.currentFiles,
107
+ savedResults: state.savedResults,
108
+ timestamp: Date.now(),
109
+ };
110
+ }
111
+ /**
112
+ * Clear state (call on successful completion)
113
+ */
114
+ clearState() {
115
+ this.state = null;
116
+ // Remove state file if it exists
117
+ try {
118
+ if (fs.existsSync(this.stateFile)) {
119
+ fs.unlinkSync(this.stateFile);
120
+ }
121
+ }
122
+ catch {
123
+ // Ignore errors
124
+ }
125
+ }
126
+ /**
127
+ * Save state to file for potential resume
128
+ */
129
+ async saveState() {
130
+ if (!this.state)
131
+ return;
132
+ try {
133
+ const dir = path.dirname(this.stateFile);
134
+ if (!fs.existsSync(dir)) {
135
+ fs.mkdirSync(dir, { recursive: true });
136
+ }
137
+ fs.writeFileSync(this.stateFile, JSON.stringify(this.state, null, 2));
138
+ console.log(`📝 State saved to ${this.stateFile}`);
139
+ }
140
+ catch (error) {
141
+ console.error('Failed to save state:', error);
142
+ }
143
+ }
144
+ /**
145
+ * Load previous shutdown state
146
+ */
147
+ loadState() {
148
+ try {
149
+ if (fs.existsSync(this.stateFile)) {
150
+ const content = fs.readFileSync(this.stateFile, 'utf-8');
151
+ return JSON.parse(content);
152
+ }
153
+ }
154
+ catch {
155
+ // Ignore errors
156
+ }
157
+ return null;
158
+ }
159
+ /**
160
+ * Check if there's a previous interrupted session
161
+ */
162
+ hasPreviousState() {
163
+ return this.loadState() !== null;
164
+ }
165
+ showResumeSuggestion() {
166
+ if (!this.state)
167
+ return;
168
+ console.log('\n📋 To resume from where you left off:');
169
+ switch (this.state.phase) {
170
+ case 'init':
171
+ console.log(' Run: spec-gen init');
172
+ break;
173
+ case 'analyze':
174
+ console.log(' Run: spec-gen analyze');
175
+ if (this.state.savedResults) {
176
+ console.log(` Partial analysis saved to: ${this.state.savedResults}`);
177
+ }
178
+ break;
179
+ case 'generate':
180
+ console.log(' Run: spec-gen generate');
181
+ if (this.state.savedResults) {
182
+ console.log(` Partial specs saved to: ${this.state.savedResults}`);
183
+ }
184
+ break;
185
+ case 'verify':
186
+ console.log(' Run: spec-gen verify');
187
+ break;
188
+ }
189
+ console.log('');
190
+ }
191
+ /**
192
+ * Check if shutdown is in progress
193
+ */
194
+ isInProgress() {
195
+ return this.isShuttingDown;
196
+ }
197
+ }
198
+ // Global shutdown manager instance
199
+ let globalManager = null;
200
+ /**
201
+ * Get or create the global shutdown manager
202
+ */
203
+ export function getShutdownManager(projectPath) {
204
+ if (!globalManager) {
205
+ globalManager = new ShutdownManager(projectPath);
206
+ }
207
+ return globalManager;
208
+ }
209
+ /**
210
+ * Register a cleanup callback with the global manager
211
+ */
212
+ export function onShutdown(callback) {
213
+ getShutdownManager().onCleanup(callback);
214
+ }
215
+ /**
216
+ * Set current state for potential resume
217
+ */
218
+ export function setShutdownState(state) {
219
+ getShutdownManager().setState(state);
220
+ }
221
+ /**
222
+ * Clear shutdown state (call on successful completion)
223
+ */
224
+ export function clearShutdownState() {
225
+ getShutdownManager().clearState();
226
+ }
227
+ /**
228
+ * Create a scope that sets/clears state automatically
229
+ */
230
+ export async function withShutdownState(state, fn) {
231
+ const manager = getShutdownManager();
232
+ manager.setState(state);
233
+ const result = await fn();
234
+ manager.clearState();
235
+ return result;
236
+ }
237
+ //# sourceMappingURL=shutdown.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"shutdown.js","sourceRoot":"","sources":["../../src/utils/shutdown.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,MAAM,IAAI,CAAC;AACzB,OAAO,KAAK,IAAI,MAAM,MAAM,CAAC;AAe7B;;GAEG;AACH,MAAM,OAAO,eAAe;IAClB,SAAS,GAAsB,EAAE,CAAC;IAClC,cAAc,GAAG,KAAK,CAAC;IACvB,KAAK,GAAyB,IAAI,CAAC;IACnC,SAAS,CAAS;IAClB,QAAQ,GAA8C,IAAI,GAAG,EAAE,CAAC;IAChE,gBAAgB,GAAG,KAAK,CAAC;IAEjC,YAAY,cAAsB,OAAO,CAAC,GAAG,EAAE,EAAE,OAAoC;QACnF,IAAI,CAAC,SAAS,GAAG,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,WAAW,EAAE,qBAAqB,CAAC,CAAC;QAC5E,gEAAgE;QAChE,IAAI,CAAC,OAAO,EAAE,YAAY,IAAI,OAAO,CAAC,GAAG,CAAC,QAAQ,KAAK,MAAM,EAAE,CAAC;YAC9D,IAAI,CAAC,aAAa,EAAE,CAAC;QACvB,CAAC;IACH,CAAC;IAEO,aAAa;QACnB,IAAI,IAAI,CAAC,gBAAgB;YAAE,OAAO;QAClC,IAAI,CAAC,gBAAgB,GAAG,IAAI,CAAC;QAE7B,MAAM,aAAa,GAAG,GAAG,EAAE,CAAC,IAAI,CAAC,cAAc,CAAC,QAAQ,CAAC,CAAC;QAC1D,MAAM,cAAc,GAAG,GAAG,EAAE,CAAC,IAAI,CAAC,cAAc,CAAC,SAAS,CAAC,CAAC;QAC5D,MAAM,gBAAgB,GAAG,CAAC,KAAY,EAAE,EAAE;YACxC,OAAO,CAAC,KAAK,CAAC,yBAAyB,EAAE,KAAK,CAAC,OAAO,CAAC,CAAC;YACxD,IAAI,CAAC,cAAc,CAAC,mBAAmB,CAAC,CAAC;QAC3C,CAAC,CAAC;QACF,MAAM,gBAAgB,GAAG,CAAC,MAAe,EAAE,EAAE;YAC3C,OAAO,CAAC,KAAK,CAAC,0BAA0B,EAAE,MAAM,CAAC,CAAC;YAClD,IAAI,CAAC,cAAc,CAAC,oBAAoB,CAAC,CAAC;QAC5C,CAAC,CAAC;QAEF,uCAAuC;QACvC,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,QAAQ,EAAE,aAAa,CAAC,CAAC;QAC3C,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,SAAS,EAAE,cAAc,CAAC,CAAC;QAC7C,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,mBAAmB,EAAE,gBAAgD,CAAC,CAAC;QACzF,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,oBAAoB,EAAE,gBAAgD,CAAC,CAAC;QAE1F,gBAAgB;QAChB,OAAO,CAAC,EAAE,CAAC,QAAQ,EAAE,aAAa,CAAC,CAAC;QAEpC,4BAA4B;QAC5B,OAAO,CAAC,EAAE,CAAC,SAAS,EAAE,cAAc,CAAC,CAAC;QAEtC,6BAA6B;QAC7B,OAAO,CAAC,EAAE,CAAC,mBAAmB,EAAE,gBAAgB,CAAC,CAAC;QAElD,sCAAsC;QACtC,OAAO,CAAC,EAAE,CAAC,oBAAoB,EAAE,gBAAgB,CAAC,CAAC;IACrD,CAAC;IAED;;OAEG;IACH,cAAc;QACZ,KAAK,MAAM,CAAC,KAAK,EAAE,OAAO,CAAC,IAAI,IAAI,CAAC,QAAQ,EAAE,CAAC;YAC7C,OAAO,CAAC,cAAc,CAAC,KAAK,EAAE,OAAO,CAAC,CAAC;QACzC,CAAC;QACD,IAAI,CAAC,QAAQ,CAAC,KAAK,EAAE,CAAC;QACtB,IAAI,CAAC,gBAAgB,GAAG,KAAK,CAAC;IAChC,CAAC;IAEO,KAAK,CAAC,cAAc,CAAC,MAAc;QACzC,IAAI,IAAI,CAAC,cAAc,EAAE,CAAC;YACxB,OAAO,CAAC,GAAG,CAAC,yBAAyB,CAAC,CAAC;YACvC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC;QAED,IAAI,CAAC,cAAc,GAAG,IAAI,CAAC;QAC3B,OAAO,CAAC,GAAG,CAAC,oCAAoC,CAAC,CAAC;QAElD,4BAA4B;QAC5B,IAAI,IAAI,CAAC,KAAK,EAAE,CAAC;YACf,MAAM,IAAI,CAAC,SAAS,EAAE,CAAC;QACzB,CAAC;QAED,yCAAyC;QACzC,KAAK,MAAM,QAAQ,IAAI,IAAI,CAAC,SAAS,CAAC,OAAO,EAAE,EAAE,CAAC;YAChD,IAAI,CAAC;gBACH,MAAM,QAAQ,EAAE,CAAC;YACnB,CAAC;YAAC,OAAO,KAAK,EAAE,CAAC;gBACf,OAAO,CAAC,KAAK,CAAC,gBAAgB,EAAE,KAAK,CAAC,CAAC;YACzC,CAAC;QACH,CAAC;QAED,yBAAyB;QACzB,IAAI,CAAC,oBAAoB,EAAE,CAAC;QAE5B,OAAO,CAAC,IAAI,CAAC,MAAM,KAAK,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IAC9C,CAAC;IAED;;OAEG;IACH,SAAS,CAAC,QAAyB;QACjC,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;IAChC,CAAC;IAED;;OAEG;IACH,aAAa,CAAC,QAAyB;QACrC,MAAM,KAAK,GAAG,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;QAC/C,IAAI,KAAK,KAAK,CAAC,CAAC,EAAE,CAAC;YACjB,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC;QAClC,CAAC;IACH,CAAC;IAED;;OAEG;IACH,QAAQ,CAAC,KAA6B;QACpC,IAAI,CAAC,KAAK,GAAG;YACX,KAAK,EAAE,KAAK,CAAC,KAAK,IAAI,MAAM;YAC5B,YAAY,EAAE,KAAK,CAAC,YAAY;YAChC,YAAY,EAAE,KAAK,CAAC,YAAY;YAChC,SAAS,EAAE,IAAI,CAAC,GAAG,EAAE;SACtB,CAAC;IACJ,CAAC;IAED;;OAEG;IACH,UAAU;QACR,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC;QAClB,iCAAiC;QACjC,IAAI,CAAC;YACH,IAAI,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,CAAC;gBAClC,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;YAChC,CAAC;QACH,CAAC;QAAC,MAAM,CAAC;YACP,gBAAgB;QAClB,CAAC;IACH,CAAC;IAED;;OAEG;IACK,KAAK,CAAC,SAAS;QACrB,IAAI,CAAC,IAAI,CAAC,KAAK;YAAE,OAAO;QAExB,IAAI,CAAC;YACH,MAAM,GAAG,GAAG,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;YACzC,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;gBACxB,EAAE,CAAC,SAAS,CAAC,GAAG,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;YACzC,CAAC;YACD,EAAE,CAAC,aAAa,CAAC,IAAI,CAAC,SAAS,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;YACtE,OAAO,CAAC,GAAG,CAAC,qBAAqB,IAAI,CAAC,SAAS,EAAE,CAAC,CAAC;QACrD,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,OAAO,CAAC,KAAK,CAAC,uBAAuB,EAAE,KAAK,CAAC,CAAC;QAChD,CAAC;IACH,CAAC;IAED;;OAEG;IACH,SAAS;QACP,IAAI,CAAC;YACH,IAAI,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,CAAC;gBAClC,MAAM,OAAO,GAAG,EAAE,CAAC,YAAY,CAAC,IAAI,CAAC,SAAS,EAAE,OAAO,CAAC,CAAC;gBACzD,OAAO,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;YAC7B,CAAC;QACH,CAAC;QAAC,MAAM,CAAC;YACP,gBAAgB;QAClB,CAAC;QACD,OAAO,IAAI,CAAC;IACd,CAAC;IAED;;OAEG;IACH,gBAAgB;QACd,OAAO,IAAI,CAAC,SAAS,EAAE,KAAK,IAAI,CAAC;IACnC,CAAC;IAEO,oBAAoB;QAC1B,IAAI,CAAC,IAAI,CAAC,KAAK;YAAE,OAAO;QAExB,OAAO,CAAC,GAAG,CAAC,yCAAyC,CAAC,CAAC;QAEvD,QAAQ,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE,CAAC;YACzB,KAAK,MAAM;gBACT,OAAO,CAAC,GAAG,CAAC,uBAAuB,CAAC,CAAC;gBACrC,MAAM;YACR,KAAK,SAAS;gBACZ,OAAO,CAAC,GAAG,CAAC,0BAA0B,CAAC,CAAC;gBACxC,IAAI,IAAI,CAAC,KAAK,CAAC,YAAY,EAAE,CAAC;oBAC5B,OAAO,CAAC,GAAG,CAAC,iCAAiC,IAAI,CAAC,KAAK,CAAC,YAAY,EAAE,CAAC,CAAC;gBAC1E,CAAC;gBACD,MAAM;YACR,KAAK,UAAU;gBACb,OAAO,CAAC,GAAG,CAAC,2BAA2B,CAAC,CAAC;gBACzC,IAAI,IAAI,CAAC,KAAK,CAAC,YAAY,EAAE,CAAC;oBAC5B,OAAO,CAAC,GAAG,CAAC,8BAA8B,IAAI,CAAC,KAAK,CAAC,YAAY,EAAE,CAAC,CAAC;gBACvE,CAAC;gBACD,MAAM;YACR,KAAK,QAAQ;gBACX,OAAO,CAAC,GAAG,CAAC,yBAAyB,CAAC,CAAC;gBACvC,MAAM;QACV,CAAC;QAED,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;IAClB,CAAC;IAED;;OAEG;IACH,YAAY;QACV,OAAO,IAAI,CAAC,cAAc,CAAC;IAC7B,CAAC;CACF;AAED,mCAAmC;AACnC,IAAI,aAAa,GAA2B,IAAI,CAAC;AAEjD;;GAEG;AACH,MAAM,UAAU,kBAAkB,CAAC,WAAoB;IACrD,IAAI,CAAC,aAAa,EAAE,CAAC;QACnB,aAAa,GAAG,IAAI,eAAe,CAAC,WAAW,CAAC,CAAC;IACnD,CAAC;IACD,OAAO,aAAa,CAAC;AACvB,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,UAAU,CAAC,QAAyB;IAClD,kBAAkB,EAAE,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC;AAC3C,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,gBAAgB,CAAC,KAA6B;IAC5D,kBAAkB,EAAE,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;AACvC,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,kBAAkB;IAChC,kBAAkB,EAAE,CAAC,UAAU,EAAE,CAAC;AACpC,CAAC;AAED;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,iBAAiB,CACrC,KAA6B,EAC7B,EAAoB;IAEpB,MAAM,OAAO,GAAG,kBAAkB,EAAE,CAAC;IACrC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;IAExB,MAAM,MAAM,GAAG,MAAM,EAAE,EAAE,CAAC;IAC1B,OAAO,CAAC,UAAU,EAAE,CAAC;IACrB,OAAO,MAAM,CAAC;AAChB,CAAC"}
package/package.json ADDED
@@ -0,0 +1,114 @@
1
+ {
2
+ "name": "spec-gen-cli",
3
+ "version": "1.0.0",
4
+ "description": "Reverse-engineer OpenSpec specifications from existing codebases",
5
+ "type": "module",
6
+ "main": "dist/api/index.js",
7
+ "types": "dist/api/index.d.ts",
8
+ "exports": {
9
+ ".": {
10
+ "import": "./dist/api/index.js",
11
+ "types": "./dist/api/index.d.ts"
12
+ },
13
+ "./cli": {
14
+ "import": "./dist/cli/index.js"
15
+ }
16
+ },
17
+ "bin": {
18
+ "spec-gen": "dist/cli/index.js"
19
+ },
20
+ "engines": {
21
+ "node": ">=20.0.0"
22
+ },
23
+ "scripts": {
24
+ "dev": "tsx watch src/cli/index.ts",
25
+ "build": "tsc",
26
+ "start": "node dist/cli/index.js",
27
+ "view": "tsx src/cli/index.ts view",
28
+ "test": "vitest",
29
+ "test:run": "vitest run",
30
+ "test:coverage": "vitest run --coverage",
31
+ "test:openspec-compat": "vitest run --grep 'openspec' || echo 'No OpenSpec compat tests yet'",
32
+ "test:e2e": "vitest run --grep 'e2e' || echo 'No E2E tests yet'",
33
+ "test:integration": "vitest run --config vitest.integration.config.ts",
34
+ "lint": "eslint src",
35
+ "typecheck": "tsc --noEmit",
36
+ "prepublishOnly": "npm run build && npm run test:run"
37
+ },
38
+ "keywords": [
39
+ "openspec",
40
+ "spec-driven",
41
+ "code-analysis",
42
+ "documentation",
43
+ "reverse-engineering",
44
+ "specification",
45
+ "cli"
46
+ ],
47
+ "author": "Clay Good",
48
+ "license": "MIT",
49
+ "repository": {
50
+ "type": "git",
51
+ "url": "https://github.com/clay-good/spec-gen"
52
+ },
53
+ "bugs": {
54
+ "url": "https://github.com/clay-good/spec-gen/issues"
55
+ },
56
+ "homepage": "https://github.com/clay-good/spec-gen#readme",
57
+ "publishConfig": {
58
+ "access": "public"
59
+ },
60
+ "files": [
61
+ "dist",
62
+ "!dist/**/*.test.*",
63
+ "src/viewer",
64
+ "README.md",
65
+ "LICENSE"
66
+ ],
67
+ "peerDependencies": {
68
+ "@fission-ai/openspec": ">=0.1.0"
69
+ },
70
+ "peerDependenciesMeta": {
71
+ "@fission-ai/openspec": {
72
+ "optional": true
73
+ }
74
+ },
75
+ "dependencies": {
76
+ "@inquirer/prompts": "^7.2.1",
77
+ "@lancedb/lancedb": "^0.26.2",
78
+ "@modelcontextprotocol/sdk": "^1.27.1",
79
+ "apache-arrow": "^21.1.0",
80
+ "chalk": "^5.3.0",
81
+ "commander": "^12.1.0",
82
+ "glob": "^11.0.0",
83
+ "ignore": "^6.0.2",
84
+ "ora": "^8.1.1",
85
+ "react": "^19.1.1",
86
+ "react-dom": "^19.1.1",
87
+ "react-force-graph-2d": "^1.27.0",
88
+ "tree-sitter": "^0.22.4",
89
+ "tree-sitter-go": "^0.23.4",
90
+ "tree-sitter-java": "^0.23.5",
91
+ "tree-sitter-python": "^0.23.6",
92
+ "tree-sitter-ruby": "^0.23.1",
93
+ "tree-sitter-rust": "^0.24.0",
94
+ "tree-sitter-typescript": "^0.23.2",
95
+ "vite": "^7.1.3",
96
+ "yaml": "^2.6.1"
97
+ },
98
+ "optionalDependencies": {
99
+ "@lancedb/lancedb-darwin-x64": "^0.22.3",
100
+ "@lancedb/lancedb-linux-x64-gnu": "^0.22.3"
101
+ },
102
+ "devDependencies": {
103
+ "@eslint/js": "^9.17.0",
104
+ "@types/node": "^22.10.5",
105
+ "@vitejs/plugin-react": "^5.0.2",
106
+ "@vitest/coverage-v8": "^4.0.18",
107
+ "eslint": "^9.17.0",
108
+ "memfs": "^4.15.0",
109
+ "tsx": "^4.19.2",
110
+ "typescript": "^5.7.2",
111
+ "typescript-eslint": "^8.19.1",
112
+ "vitest": "^4.0.18"
113
+ }
114
+ }