@wundr.io/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 (213) hide show
  1. package/README.md +551 -0
  2. package/bin/wundr.js +39 -0
  3. package/dist/ai/ai-service.d.ts +152 -0
  4. package/dist/ai/ai-service.d.ts.map +1 -0
  5. package/dist/ai/ai-service.js +430 -0
  6. package/dist/ai/ai-service.js.map +1 -0
  7. package/dist/ai/claude-client.d.ts +130 -0
  8. package/dist/ai/claude-client.d.ts.map +1 -0
  9. package/dist/ai/claude-client.js +339 -0
  10. package/dist/ai/claude-client.js.map +1 -0
  11. package/dist/ai/conversation-manager.d.ts +164 -0
  12. package/dist/ai/conversation-manager.d.ts.map +1 -0
  13. package/dist/ai/conversation-manager.js +612 -0
  14. package/dist/ai/conversation-manager.js.map +1 -0
  15. package/dist/ai/index.d.ts +5 -0
  16. package/dist/ai/index.d.ts.map +1 -0
  17. package/dist/ai/index.js +8 -0
  18. package/dist/ai/index.js.map +1 -0
  19. package/dist/cli.d.ts +36 -0
  20. package/dist/cli.d.ts.map +1 -0
  21. package/dist/cli.js +173 -0
  22. package/dist/cli.js.map +1 -0
  23. package/dist/commands/ai.d.ts +89 -0
  24. package/dist/commands/ai.d.ts.map +1 -0
  25. package/dist/commands/ai.js +735 -0
  26. package/dist/commands/ai.js.map +1 -0
  27. package/dist/commands/analyze-optimized.d.ts +14 -0
  28. package/dist/commands/analyze-optimized.d.ts.map +1 -0
  29. package/dist/commands/analyze-optimized.js +437 -0
  30. package/dist/commands/analyze-optimized.js.map +1 -0
  31. package/dist/commands/analyze.d.ts +65 -0
  32. package/dist/commands/analyze.d.ts.map +1 -0
  33. package/dist/commands/analyze.js +435 -0
  34. package/dist/commands/analyze.js.map +1 -0
  35. package/dist/commands/batch.d.ts +71 -0
  36. package/dist/commands/batch.d.ts.map +1 -0
  37. package/dist/commands/batch.js +738 -0
  38. package/dist/commands/batch.js.map +1 -0
  39. package/dist/commands/chat.d.ts +71 -0
  40. package/dist/commands/chat.d.ts.map +1 -0
  41. package/dist/commands/chat.js +674 -0
  42. package/dist/commands/chat.js.map +1 -0
  43. package/dist/commands/claude-init.d.ts +28 -0
  44. package/dist/commands/claude-init.d.ts.map +1 -0
  45. package/dist/commands/claude-init.js +587 -0
  46. package/dist/commands/claude-init.js.map +1 -0
  47. package/dist/commands/claude-setup.d.ts +32 -0
  48. package/dist/commands/claude-setup.d.ts.map +1 -0
  49. package/dist/commands/claude-setup.js +570 -0
  50. package/dist/commands/claude-setup.js.map +1 -0
  51. package/dist/commands/computer-setup-commands.d.ts +39 -0
  52. package/dist/commands/computer-setup-commands.d.ts.map +1 -0
  53. package/dist/commands/computer-setup-commands.js +563 -0
  54. package/dist/commands/computer-setup-commands.js.map +1 -0
  55. package/dist/commands/computer-setup.d.ts +7 -0
  56. package/dist/commands/computer-setup.d.ts.map +1 -0
  57. package/dist/commands/computer-setup.js +481 -0
  58. package/dist/commands/computer-setup.js.map +1 -0
  59. package/dist/commands/create-command.d.ts +7 -0
  60. package/dist/commands/create-command.d.ts.map +1 -0
  61. package/dist/commands/create-command.js +158 -0
  62. package/dist/commands/create-command.js.map +1 -0
  63. package/dist/commands/create.d.ts +74 -0
  64. package/dist/commands/create.d.ts.map +1 -0
  65. package/dist/commands/create.js +556 -0
  66. package/dist/commands/create.js.map +1 -0
  67. package/dist/commands/dashboard.d.ts +91 -0
  68. package/dist/commands/dashboard.d.ts.map +1 -0
  69. package/dist/commands/dashboard.js +537 -0
  70. package/dist/commands/dashboard.js.map +1 -0
  71. package/dist/commands/govern.d.ts +70 -0
  72. package/dist/commands/govern.d.ts.map +1 -0
  73. package/dist/commands/govern.js +480 -0
  74. package/dist/commands/govern.js.map +1 -0
  75. package/dist/commands/init.d.ts +55 -0
  76. package/dist/commands/init.d.ts.map +1 -0
  77. package/dist/commands/init.js +584 -0
  78. package/dist/commands/init.js.map +1 -0
  79. package/dist/commands/performance-optimizer.d.ts +30 -0
  80. package/dist/commands/performance-optimizer.d.ts.map +1 -0
  81. package/dist/commands/performance-optimizer.js +649 -0
  82. package/dist/commands/performance-optimizer.js.map +1 -0
  83. package/dist/commands/plugins.d.ts +87 -0
  84. package/dist/commands/plugins.d.ts.map +1 -0
  85. package/dist/commands/plugins.js +685 -0
  86. package/dist/commands/plugins.js.map +1 -0
  87. package/dist/commands/setup.d.ts +29 -0
  88. package/dist/commands/setup.d.ts.map +1 -0
  89. package/dist/commands/setup.js +399 -0
  90. package/dist/commands/setup.js.map +1 -0
  91. package/dist/commands/test-init.d.ts +9 -0
  92. package/dist/commands/test-init.d.ts.map +1 -0
  93. package/dist/commands/test-init.js +222 -0
  94. package/dist/commands/test-init.js.map +1 -0
  95. package/dist/commands/test.d.ts +25 -0
  96. package/dist/commands/test.d.ts.map +1 -0
  97. package/dist/commands/test.js +217 -0
  98. package/dist/commands/test.js.map +1 -0
  99. package/dist/commands/watch.d.ts +76 -0
  100. package/dist/commands/watch.d.ts.map +1 -0
  101. package/dist/commands/watch.js +610 -0
  102. package/dist/commands/watch.js.map +1 -0
  103. package/dist/context/context-manager.d.ts +155 -0
  104. package/dist/context/context-manager.d.ts.map +1 -0
  105. package/dist/context/context-manager.js +383 -0
  106. package/dist/context/context-manager.js.map +1 -0
  107. package/dist/context/index.d.ts +3 -0
  108. package/dist/context/index.d.ts.map +1 -0
  109. package/dist/context/index.js +6 -0
  110. package/dist/context/index.js.map +1 -0
  111. package/dist/context/session-manager.d.ts +207 -0
  112. package/dist/context/session-manager.d.ts.map +1 -0
  113. package/dist/context/session-manager.js +682 -0
  114. package/dist/context/session-manager.js.map +1 -0
  115. package/dist/index.d.ts +8 -0
  116. package/dist/index.d.ts.map +1 -0
  117. package/dist/index.js +51 -0
  118. package/dist/index.js.map +1 -0
  119. package/dist/interactive/interactive-mode.d.ts +76 -0
  120. package/dist/interactive/interactive-mode.d.ts.map +1 -0
  121. package/dist/interactive/interactive-mode.js +730 -0
  122. package/dist/interactive/interactive-mode.js.map +1 -0
  123. package/dist/nlp/command-mapper.d.ts +174 -0
  124. package/dist/nlp/command-mapper.d.ts.map +1 -0
  125. package/dist/nlp/command-mapper.js +623 -0
  126. package/dist/nlp/command-mapper.js.map +1 -0
  127. package/dist/nlp/command-parser.d.ts +106 -0
  128. package/dist/nlp/command-parser.d.ts.map +1 -0
  129. package/dist/nlp/command-parser.js +416 -0
  130. package/dist/nlp/command-parser.js.map +1 -0
  131. package/dist/nlp/index.d.ts +5 -0
  132. package/dist/nlp/index.d.ts.map +1 -0
  133. package/dist/nlp/index.js +8 -0
  134. package/dist/nlp/index.js.map +1 -0
  135. package/dist/nlp/intent-classifier.d.ts +59 -0
  136. package/dist/nlp/intent-classifier.d.ts.map +1 -0
  137. package/dist/nlp/intent-classifier.js +384 -0
  138. package/dist/nlp/intent-classifier.js.map +1 -0
  139. package/dist/nlp/intent-parser.d.ts +152 -0
  140. package/dist/nlp/intent-parser.d.ts.map +1 -0
  141. package/dist/nlp/intent-parser.js +739 -0
  142. package/dist/nlp/intent-parser.js.map +1 -0
  143. package/dist/plugins/plugin-manager.d.ts +120 -0
  144. package/dist/plugins/plugin-manager.d.ts.map +1 -0
  145. package/dist/plugins/plugin-manager.js +595 -0
  146. package/dist/plugins/plugin-manager.js.map +1 -0
  147. package/dist/types/index.d.ts +224 -0
  148. package/dist/types/index.d.ts.map +1 -0
  149. package/dist/types/index.js +3 -0
  150. package/dist/types/index.js.map +1 -0
  151. package/dist/utils/config-manager.d.ts +73 -0
  152. package/dist/utils/config-manager.d.ts.map +1 -0
  153. package/dist/utils/config-manager.js +339 -0
  154. package/dist/utils/config-manager.js.map +1 -0
  155. package/dist/utils/error-handler.d.ts +46 -0
  156. package/dist/utils/error-handler.d.ts.map +1 -0
  157. package/dist/utils/error-handler.js +169 -0
  158. package/dist/utils/error-handler.js.map +1 -0
  159. package/dist/utils/logger.d.ts +25 -0
  160. package/dist/utils/logger.d.ts.map +1 -0
  161. package/dist/utils/logger.js +94 -0
  162. package/dist/utils/logger.js.map +1 -0
  163. package/package.json +119 -0
  164. package/src/ai/ai-service.ts +595 -0
  165. package/src/ai/claude-client.ts +490 -0
  166. package/src/ai/conversation-manager.ts +907 -0
  167. package/src/ai/index.ts +8 -0
  168. package/src/cli.ts +202 -0
  169. package/src/commands/ai.ts +995 -0
  170. package/src/commands/analyze-optimized.ts +641 -0
  171. package/src/commands/analyze.ts +576 -0
  172. package/src/commands/batch.ts +935 -0
  173. package/src/commands/chat.ts +876 -0
  174. package/src/commands/claude-init.ts +715 -0
  175. package/src/commands/claude-setup.ts +697 -0
  176. package/src/commands/computer-setup-commands.ts +709 -0
  177. package/src/commands/computer-setup.ts +565 -0
  178. package/src/commands/create-command.ts +175 -0
  179. package/src/commands/create.ts +727 -0
  180. package/src/commands/dashboard.ts +691 -0
  181. package/src/commands/govern.ts +635 -0
  182. package/src/commands/init.ts +677 -0
  183. package/src/commands/performance-optimizer.ts +864 -0
  184. package/src/commands/plugins.ts +848 -0
  185. package/src/commands/setup.ts +508 -0
  186. package/src/commands/test-init.ts +242 -0
  187. package/src/commands/test.ts +264 -0
  188. package/src/commands/watch.ts +755 -0
  189. package/src/context/context-manager.ts +546 -0
  190. package/src/context/index.ts +9 -0
  191. package/src/context/session-manager.ts +1019 -0
  192. package/src/index.ts +64 -0
  193. package/src/interactive/interactive-mode.ts +830 -0
  194. package/src/nlp/command-mapper.ts +885 -0
  195. package/src/nlp/command-parser.ts +564 -0
  196. package/src/nlp/index.ts +4 -0
  197. package/src/nlp/intent-classifier.ts +458 -0
  198. package/src/nlp/intent-parser.ts +1101 -0
  199. package/src/plugins/plugin-manager.ts +744 -0
  200. package/src/types/index.ts +252 -0
  201. package/src/types/modules.d.ts +56 -0
  202. package/src/utils/config-manager.ts +391 -0
  203. package/src/utils/error-handler.ts +192 -0
  204. package/src/utils/logger.ts +104 -0
  205. package/templates/batch/ci-cd.yaml +62 -0
  206. package/templates/component/{{fileName}}.test.tsx +17 -0
  207. package/templates/component/{{fileName}}.tsx +21 -0
  208. package/templates/service/{{fileName}}.ts +98 -0
  209. package/templates/wundr-test.config.js +0 -0
  210. package/test-suites/api/health.spec.ts +134 -0
  211. package/test-suites/helpers/test-config.ts +84 -0
  212. package/test-suites/ui/accessibility.spec.ts +102 -0
  213. package/test-suites/ui/smoke.spec.ts +92 -0
@@ -0,0 +1,727 @@
1
+ import { Command } from 'commander';
2
+ import inquirer from 'inquirer';
3
+ import fs from 'fs-extra';
4
+ import path from 'path';
5
+ import chalk from 'chalk';
6
+ import { ConfigManager } from '../utils/config-manager';
7
+ import { PluginManager } from '../plugins/plugin-manager';
8
+ import { logger } from '../utils/logger';
9
+ import { errorHandler } from '../utils/error-handler';
10
+ // import { projectTemplates } from '@wundr/project-templates';
11
+ // TODO: Fix this import - project-templates package needs to be created
12
+ const projectTemplates = {
13
+ createProject: async (options: any) => {
14
+ console.log('Creating project with options:', options);
15
+ // TODO: Implement actual project creation logic
16
+ console.log('Project creation not yet implemented');
17
+ },
18
+ createInteractive: async () => {
19
+ console.log('Interactive project creation not yet implemented');
20
+ // TODO: Implement interactive project creation
21
+ },
22
+ };
23
+
24
+ /**
25
+ * Create commands for generating components, services, and templates
26
+ */
27
+ export class CreateCommands {
28
+ constructor(
29
+ private program: Command,
30
+ private configManager: ConfigManager,
31
+ private pluginManager: PluginManager
32
+ ) {
33
+ this.registerCommands();
34
+ }
35
+
36
+ private registerCommands(): void {
37
+ const createCmd = this.program
38
+ .command('create')
39
+ .description(
40
+ 'create new wundr-compliant projects, components, services, and templates'
41
+ );
42
+
43
+ // Create new project (full wundr-compliant project)
44
+ createCmd
45
+ .command('project <type> [name]')
46
+ .alias('p')
47
+ .description('create a new wundr-compliant project')
48
+ .option('-f, --framework <framework>', 'framework to use')
49
+ .option('-d, --description <description>', 'project description')
50
+ .option('-a, --author <author>', 'project author')
51
+ .option('--no-git', 'skip git initialization')
52
+ .option('--no-install', 'skip dependency installation')
53
+ .option('--typescript', 'use TypeScript', true)
54
+ .option('--testing', 'include testing setup', true)
55
+ .option('--ci', 'include CI/CD workflows', true)
56
+ .option('--docker', 'include Docker configuration')
57
+ .option('-p, --path <path>', 'path to create project in')
58
+ .action(async (type: string, name: string | undefined, options: any) => {
59
+ await this.createProject(type, name, options);
60
+ });
61
+
62
+ // Quick project creation commands
63
+ createCmd
64
+ .command('frontend <name>')
65
+ .description('create a frontend application')
66
+ .option(
67
+ '-f, --framework <framework>',
68
+ 'framework (next|react|vue)',
69
+ 'next'
70
+ )
71
+ .action(async (name: string, options: any) => {
72
+ await projectTemplates.createProject({
73
+ name,
74
+ type: 'frontend',
75
+ framework: options.framework,
76
+ install: true,
77
+ git: true,
78
+ });
79
+ });
80
+
81
+ createCmd
82
+ .command('backend <name>')
83
+ .description('create a backend API')
84
+ .option(
85
+ '-f, --framework <framework>',
86
+ 'framework (fastify|express|nestjs)',
87
+ 'fastify'
88
+ )
89
+ .action(async (name: string, options: any) => {
90
+ await projectTemplates.createProject({
91
+ name,
92
+ type: 'backend',
93
+ framework: options.framework,
94
+ install: true,
95
+ git: true,
96
+ });
97
+ });
98
+
99
+ createCmd
100
+ .command('monorepo <name>')
101
+ .description('create a monorepo platform')
102
+ .action(async (name: string) => {
103
+ await projectTemplates.createProject({
104
+ name,
105
+ type: 'monorepo',
106
+ framework: 'turborepo',
107
+ install: true,
108
+ git: true,
109
+ });
110
+ });
111
+
112
+ createCmd
113
+ .command('fullstack <name>')
114
+ .description('create a full-stack application')
115
+ .action(async (name: string) => {
116
+ await projectTemplates.createProject({
117
+ name,
118
+ type: 'monorepo',
119
+ framework: 'turborepo',
120
+ install: true,
121
+ git: true,
122
+ description: 'Full-stack wundr-compliant application',
123
+ });
124
+ });
125
+
126
+ // Create component
127
+ createCmd
128
+ .command('component <name>')
129
+ .description('create a new component')
130
+ .option('--type <type>', 'component type (react, vue, angular)', 'react')
131
+ .option('--template <template>', 'component template')
132
+ .option('--with-tests', 'generate test files')
133
+ .option('--with-stories', 'generate storybook stories')
134
+ .action(async (name, options) => {
135
+ await this.createComponent(name, options);
136
+ });
137
+
138
+ // Create service
139
+ createCmd
140
+ .command('service <name>')
141
+ .description('create a new service')
142
+ .option(
143
+ '--type <type>',
144
+ 'service type (api, worker, microservice)',
145
+ 'api'
146
+ )
147
+ .option(
148
+ '--framework <framework>',
149
+ 'framework (express, fastify, nest)',
150
+ 'express'
151
+ )
152
+ .option('--with-tests', 'generate test files')
153
+ .option('--with-docs', 'generate API documentation')
154
+ .action(async (name, options) => {
155
+ await this.createService(name, options);
156
+ });
157
+
158
+ // Create package
159
+ createCmd
160
+ .command('package <name>')
161
+ .description('create a new package in monorepo')
162
+ .option('--type <type>', 'package type (library, app, tool)', 'library')
163
+ .option('--template <template>', 'package template')
164
+ .option('--public', 'make package public')
165
+ .action(async (name, options) => {
166
+ await this.createPackage(name, options);
167
+ });
168
+
169
+ // Create template
170
+ createCmd
171
+ .command('template <name>')
172
+ .description('create a new template')
173
+ .option('--from <source>', 'create template from existing code')
174
+ .option('--interactive', 'use interactive template creation')
175
+ .action(async (name, options) => {
176
+ await this.createTemplate(name, options);
177
+ });
178
+
179
+ // Create workflow
180
+ createCmd
181
+ .command('workflow <name>')
182
+ .description('create a new workflow or automation')
183
+ .option('--type <type>', 'workflow type (ci, deployment, analysis)', 'ci')
184
+ .option(
185
+ '--platform <platform>',
186
+ 'platform (github, gitlab, jenkins)',
187
+ 'github'
188
+ )
189
+ .action(async (name, options) => {
190
+ await this.createWorkflow(name, options);
191
+ });
192
+
193
+ // Create config
194
+ createCmd
195
+ .command('config <name>')
196
+ .description('create configuration files')
197
+ .option(
198
+ '--type <type>',
199
+ 'config type (eslint, prettier, jest, typescript)'
200
+ )
201
+ .option('--preset <preset>', 'configuration preset')
202
+ .action(async (name, options) => {
203
+ await this.createConfig(name, options);
204
+ });
205
+ }
206
+
207
+ /**
208
+ * Create a new wundr-compliant project
209
+ */
210
+ private async createProject(
211
+ type: string,
212
+ name: string | undefined,
213
+ options: any
214
+ ): Promise<void> {
215
+ try {
216
+ // If no name provided, launch interactive mode
217
+ if (!name) {
218
+ await projectTemplates.createInteractive();
219
+ return;
220
+ }
221
+
222
+ // Validate project type
223
+ const validTypes = [
224
+ 'frontend',
225
+ 'backend',
226
+ 'fullstack',
227
+ 'monorepo',
228
+ 'library',
229
+ 'cli',
230
+ ];
231
+ if (!validTypes.includes(type)) {
232
+ logger.error(`Invalid project type: ${type}`);
233
+ logger.info(`Valid types: ${validTypes.join(', ')}`);
234
+ process.exit(1);
235
+ }
236
+
237
+ logger.info(`Creating ${type} project: ${chalk.cyan(name)}`);
238
+
239
+ // Create project with options
240
+ await projectTemplates.createProject({
241
+ name,
242
+ type: type as any,
243
+ framework: options.framework,
244
+ description: options.description,
245
+ author: options.author,
246
+ git: options.git,
247
+ install: options.install,
248
+ typescript: options.typescript,
249
+ testing: options.testing,
250
+ ci: options.ci,
251
+ docker: options.docker,
252
+ path: options.path,
253
+ });
254
+ } catch (error) {
255
+ throw errorHandler.createError(
256
+ 'WUNDR_CREATE_PROJECT_FAILED',
257
+ 'Failed to create project',
258
+ { type, name, options },
259
+ true
260
+ );
261
+ }
262
+ }
263
+
264
+ /**
265
+ * Create a new component
266
+ */
267
+ private async createComponent(name: string, options: any): Promise<void> {
268
+ try {
269
+ logger.info(`Creating component: ${chalk.cyan(name)}`);
270
+
271
+ const componentData = await this.gatherComponentData(name, options);
272
+ const outputPath = await this.determineOutputPath('components', name);
273
+
274
+ await this.generateFromTemplate('component', componentData, outputPath);
275
+
276
+ if (options.withTests) {
277
+ await this.generateFromTemplate(
278
+ 'component-test',
279
+ componentData,
280
+ outputPath
281
+ );
282
+ }
283
+
284
+ if (options.withStories) {
285
+ await this.generateFromTemplate(
286
+ 'component-stories',
287
+ componentData,
288
+ outputPath
289
+ );
290
+ }
291
+
292
+ logger.success(`Component ${name} created successfully at ${outputPath}`);
293
+ } catch (error) {
294
+ throw errorHandler.createError(
295
+ 'WUNDR_CREATE_COMPONENT_FAILED',
296
+ 'Failed to create component',
297
+ { name, options },
298
+ true
299
+ );
300
+ }
301
+ }
302
+
303
+ /**
304
+ * Create a new service
305
+ */
306
+ private async createService(name: string, options: any): Promise<void> {
307
+ try {
308
+ logger.info(`Creating service: ${chalk.cyan(name)}`);
309
+
310
+ const serviceData = await this.gatherServiceData(name, options);
311
+ const outputPath = await this.determineOutputPath('services', name);
312
+
313
+ await this.generateFromTemplate('service', serviceData, outputPath);
314
+
315
+ if (options.withTests) {
316
+ await this.generateFromTemplate(
317
+ 'service-test',
318
+ serviceData,
319
+ outputPath
320
+ );
321
+ }
322
+
323
+ if (options.withDocs) {
324
+ await this.generateApiDocs(serviceData, outputPath);
325
+ }
326
+
327
+ logger.success(`Service ${name} created successfully at ${outputPath}`);
328
+ } catch (error) {
329
+ throw errorHandler.createError(
330
+ 'WUNDR_CREATE_SERVICE_FAILED',
331
+ 'Failed to create service',
332
+ { name, options },
333
+ true
334
+ );
335
+ }
336
+ }
337
+
338
+ /**
339
+ * Create a new package in monorepo
340
+ */
341
+ private async createPackage(name: string, options: any): Promise<void> {
342
+ try {
343
+ logger.info(`Creating package: ${chalk.cyan(name)}`);
344
+
345
+ const packageData = await this.gatherPackageData(name, options);
346
+ const outputPath = await this.determinePackagePath(name, options.type);
347
+
348
+ await this.generateFromTemplate('package', packageData, outputPath);
349
+ await this.updateWorkspaceConfig(name, options.type);
350
+
351
+ logger.success(`Package ${name} created successfully at ${outputPath}`);
352
+ } catch (error) {
353
+ throw errorHandler.createError(
354
+ 'WUNDR_CREATE_PACKAGE_FAILED',
355
+ 'Failed to create package',
356
+ { name, options },
357
+ true
358
+ );
359
+ }
360
+ }
361
+
362
+ /**
363
+ * Create a new template
364
+ */
365
+ private async createTemplate(name: string, options: any): Promise<void> {
366
+ try {
367
+ logger.info(`Creating template: ${chalk.cyan(name)}`);
368
+
369
+ if (options.interactive) {
370
+ await this.interactiveTemplateCreation(name);
371
+ } else if (options.from) {
372
+ await this.createTemplateFromSource(name, options.from);
373
+ } else {
374
+ await this.createBlankTemplate(name);
375
+ }
376
+
377
+ logger.success(`Template ${name} created successfully`);
378
+ } catch (error) {
379
+ throw errorHandler.createError(
380
+ 'WUNDR_CREATE_TEMPLATE_FAILED',
381
+ 'Failed to create template',
382
+ { name, options },
383
+ true
384
+ );
385
+ }
386
+ }
387
+
388
+ /**
389
+ * Create a new workflow
390
+ */
391
+ private async createWorkflow(name: string, options: any): Promise<void> {
392
+ try {
393
+ logger.info(`Creating workflow: ${chalk.cyan(name)}`);
394
+
395
+ const workflowData = await this.gatherWorkflowData(name, options);
396
+ const outputPath = this.getWorkflowPath(options.platform);
397
+
398
+ await this.generateFromTemplate('workflow', workflowData, outputPath);
399
+
400
+ logger.success(`Workflow ${name} created successfully at ${outputPath}`);
401
+ } catch (error) {
402
+ throw errorHandler.createError(
403
+ 'WUNDR_CREATE_WORKFLOW_FAILED',
404
+ 'Failed to create workflow',
405
+ { name, options },
406
+ true
407
+ );
408
+ }
409
+ }
410
+
411
+ /**
412
+ * Create configuration files
413
+ */
414
+ private async createConfig(name: string, options: any): Promise<void> {
415
+ try {
416
+ logger.info(`Creating config: ${chalk.cyan(name)}`);
417
+
418
+ const configData = await this.gatherConfigData(name, options);
419
+ const outputPath = process.cwd();
420
+
421
+ await this.generateFromTemplate('config', configData, outputPath);
422
+
423
+ logger.success(`Configuration ${name} created successfully`);
424
+ } catch (error) {
425
+ throw errorHandler.createError(
426
+ 'WUNDR_CREATE_CONFIG_FAILED',
427
+ 'Failed to create configuration',
428
+ { name, options },
429
+ true
430
+ );
431
+ }
432
+ }
433
+
434
+ /**
435
+ * Data gathering methods
436
+ */
437
+ private async gatherComponentData(name: string, options: any): Promise<any> {
438
+ return {
439
+ name,
440
+ type: options.type,
441
+ template: options.template,
442
+ className: this.toPascalCase(name),
443
+ fileName: this.toKebabCase(name),
444
+ withTests: options.withTests,
445
+ withStories: options.withStories,
446
+ timestamp: new Date().toISOString(),
447
+ };
448
+ }
449
+
450
+ private async gatherServiceData(name: string, options: any): Promise<any> {
451
+ return {
452
+ name,
453
+ type: options.type,
454
+ framework: options.framework,
455
+ className: this.toPascalCase(name),
456
+ fileName: this.toKebabCase(name),
457
+ withTests: options.withTests,
458
+ withDocs: options.withDocs,
459
+ timestamp: new Date().toISOString(),
460
+ };
461
+ }
462
+
463
+ private async gatherPackageData(name: string, options: any): Promise<any> {
464
+ const packageName = name.startsWith('@') ? name : `@wundr/${name}`;
465
+
466
+ return {
467
+ name: packageName,
468
+ shortName: name,
469
+ type: options.type,
470
+ template: options.template,
471
+ public: options.public,
472
+ className: this.toPascalCase(name),
473
+ fileName: this.toKebabCase(name),
474
+ timestamp: new Date().toISOString(),
475
+ };
476
+ }
477
+
478
+ private async gatherWorkflowData(name: string, options: any): Promise<any> {
479
+ return {
480
+ name,
481
+ type: options.type,
482
+ platform: options.platform,
483
+ fileName: this.toKebabCase(name),
484
+ timestamp: new Date().toISOString(),
485
+ };
486
+ }
487
+
488
+ private async gatherConfigData(name: string, options: any): Promise<any> {
489
+ return {
490
+ name,
491
+ type: options.type,
492
+ preset: options.preset,
493
+ fileName: this.getConfigFileName(name, options.type),
494
+ timestamp: new Date().toISOString(),
495
+ };
496
+ }
497
+
498
+ /**
499
+ * Template generation methods
500
+ */
501
+ private async generateFromTemplate(
502
+ templateType: string,
503
+ data: any,
504
+ outputPath: string
505
+ ): Promise<void> {
506
+ const templatePath = this.getTemplatePath(templateType);
507
+
508
+ if (!(await fs.pathExists(templatePath))) {
509
+ throw new Error(`Template ${templateType} not found`);
510
+ }
511
+
512
+ await fs.ensureDir(outputPath);
513
+
514
+ // Copy template files and replace placeholders
515
+ await this.copyTemplateWithReplacements(templatePath, outputPath, data);
516
+ }
517
+
518
+ private async copyTemplateWithReplacements(
519
+ srcPath: string,
520
+ destPath: string,
521
+ data: any
522
+ ): Promise<void> {
523
+ const files = await fs.readdir(srcPath);
524
+
525
+ for (const file of files) {
526
+ const srcFile = path.join(srcPath, file);
527
+ const destFile = path.join(
528
+ destPath,
529
+ this.replacePlaceholders(file, data)
530
+ );
531
+
532
+ const stat = await fs.stat(srcFile);
533
+
534
+ if (stat.isDirectory()) {
535
+ await fs.ensureDir(destFile);
536
+ await this.copyTemplateWithReplacements(srcFile, destFile, data);
537
+ } else {
538
+ const content = await fs.readFile(srcFile, 'utf8');
539
+ const processedContent = this.replacePlaceholders(content, data);
540
+ await fs.writeFile(destFile, processedContent);
541
+ }
542
+ }
543
+ }
544
+
545
+ private replacePlaceholders(content: string, data: any): string {
546
+ let result = content;
547
+
548
+ Object.entries(data).forEach(([key, value]) => {
549
+ const placeholder = new RegExp(`{{${key}}}`, 'g');
550
+ result = result.replace(placeholder, String(value));
551
+ });
552
+
553
+ return result;
554
+ }
555
+
556
+ /**
557
+ * Path determination methods
558
+ */
559
+ private async determineOutputPath(
560
+ category: string,
561
+ name: string
562
+ ): Promise<string> {
563
+ const projectRoot = process.cwd();
564
+ const srcPath = path.join(projectRoot, 'src');
565
+
566
+ if (await fs.pathExists(srcPath)) {
567
+ return path.join(srcPath, category, this.toKebabCase(name));
568
+ }
569
+
570
+ return path.join(projectRoot, category, this.toKebabCase(name));
571
+ }
572
+
573
+ private async determinePackagePath(
574
+ name: string,
575
+ type: string
576
+ ): Promise<string> {
577
+ const projectRoot = process.cwd();
578
+ const packagesPath = path.join(projectRoot, 'packages');
579
+ const appsPath = path.join(projectRoot, 'apps');
580
+
581
+ if (type === 'app' && (await fs.pathExists(appsPath))) {
582
+ return path.join(appsPath, this.toKebabCase(name));
583
+ }
584
+
585
+ return path.join(packagesPath, this.toKebabCase(name));
586
+ }
587
+
588
+ private getWorkflowPath(platform: string): string {
589
+ const paths = {
590
+ github: '.github/workflows',
591
+ gitlab: '.gitlab-ci',
592
+ jenkins: 'jenkins',
593
+ };
594
+
595
+ return paths[platform as keyof typeof paths] || '.github/workflows';
596
+ }
597
+
598
+ private getTemplatePath(templateType: string): string {
599
+ return path.join(__dirname, '../../templates', templateType);
600
+ }
601
+
602
+ private getConfigFileName(name: string, type: string): string {
603
+ const fileNames = {
604
+ eslint: '.eslintrc.js',
605
+ prettier: '.prettierrc.js',
606
+ jest: 'jest.config.js',
607
+ typescript: 'tsconfig.json',
608
+ };
609
+
610
+ return fileNames[type as keyof typeof fileNames] || `${name}.config.js`;
611
+ }
612
+
613
+ /**
614
+ * Utility methods
615
+ */
616
+ private toPascalCase(str: string): string {
617
+ return str
618
+ .split(/[-_\s]/)
619
+ .map(word => word.charAt(0).toUpperCase() + word.slice(1).toLowerCase())
620
+ .join('');
621
+ }
622
+
623
+ private toKebabCase(str: string): string {
624
+ return str
625
+ .replace(/([a-z])([A-Z])/g, '$1-$2')
626
+ .replace(/[\s_]+/g, '-')
627
+ .toLowerCase();
628
+ }
629
+
630
+ private async updateWorkspaceConfig(
631
+ name: string,
632
+ type: string
633
+ ): Promise<void> {
634
+ const packageJsonPath = path.join(process.cwd(), 'package.json');
635
+
636
+ if (await fs.pathExists(packageJsonPath)) {
637
+ const packageJson = await fs.readJson(packageJsonPath);
638
+
639
+ if (packageJson.workspaces) {
640
+ const workspace = type === 'app' ? 'apps/*' : 'packages/*';
641
+ if (!packageJson.workspaces.includes(workspace)) {
642
+ packageJson.workspaces.push(workspace);
643
+ await fs.writeJson(packageJsonPath, packageJson, { spaces: 2 });
644
+ }
645
+ }
646
+ }
647
+ }
648
+
649
+ private async generateApiDocs(
650
+ serviceData: any,
651
+ outputPath: string
652
+ ): Promise<void> {
653
+ // Generate API documentation based on service type and framework
654
+ const docsPath = path.join(outputPath, 'docs');
655
+ await fs.ensureDir(docsPath);
656
+
657
+ const apiDoc = `# ${serviceData.name} API Documentation
658
+
659
+ ## Overview
660
+
661
+ Service: ${serviceData.name}
662
+ Type: ${serviceData.type}
663
+ Framework: ${serviceData.framework}
664
+
665
+ ## Endpoints
666
+
667
+ ### GET /health
668
+ Health check endpoint
669
+
670
+ ### GET /api/${serviceData.fileName}
671
+ Get ${serviceData.name} data
672
+
673
+ ### POST /api/${serviceData.fileName}
674
+ Create new ${serviceData.name}
675
+
676
+ ## Authentication
677
+
678
+ [Add authentication details here]
679
+
680
+ ## Error Handling
681
+
682
+ [Add error handling information here]
683
+ `;
684
+
685
+ await fs.writeFile(path.join(docsPath, 'api.md'), apiDoc);
686
+ }
687
+
688
+ private async interactiveTemplateCreation(name: string): Promise<void> {
689
+ const answers = await inquirer.prompt([
690
+ {
691
+ type: 'input',
692
+ name: 'description',
693
+ message: 'Template description:',
694
+ },
695
+ {
696
+ type: 'checkbox',
697
+ name: 'features',
698
+ message: 'Template features:',
699
+ choices: [
700
+ 'TypeScript',
701
+ 'React',
702
+ 'Vue',
703
+ 'Node.js',
704
+ 'Testing',
705
+ 'Storybook',
706
+ 'Documentation',
707
+ ],
708
+ },
709
+ ]);
710
+
711
+ // Create template based on answers
712
+ logger.debug('Creating interactive template with:', answers);
713
+ }
714
+
715
+ private async createTemplateFromSource(
716
+ name: string,
717
+ sourcePath: string
718
+ ): Promise<void> {
719
+ logger.debug(`Creating template ${name} from source: ${sourcePath}`);
720
+ // Implementation for creating template from existing source
721
+ }
722
+
723
+ private async createBlankTemplate(name: string): Promise<void> {
724
+ logger.debug(`Creating blank template: ${name}`);
725
+ // Implementation for creating blank template structure
726
+ }
727
+ }