@wundr.io/cli 1.0.0 → 1.0.2-dev.20260530174250.ef0ec927

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 (230) hide show
  1. package/README.md +696 -280
  2. package/bin/wundr.js +13 -5
  3. package/package.json +30 -9
  4. package/src/ai/ai-service.ts +6 -4
  5. package/src/ai/claude-client.ts +6 -2
  6. package/src/ai/conversation-manager.ts +12 -5
  7. package/src/cli.ts +42 -13
  8. package/src/commands/ai.ts +340 -64
  9. package/src/commands/alignment.ts +1212 -0
  10. package/src/commands/analyze-optimized.ts +371 -33
  11. package/src/commands/analyze.ts +8 -6
  12. package/src/commands/batch.ts +166 -26
  13. package/src/commands/chat.ts +20 -10
  14. package/src/commands/claude-init.ts +31 -27
  15. package/src/commands/claude-setup.ts +761 -81
  16. package/src/commands/computer-setup.ts +524 -12
  17. package/src/commands/create-command.ts +3 -3
  18. package/src/commands/create.ts +9 -6
  19. package/src/commands/dashboard.ts +11 -6
  20. package/src/commands/govern.ts +11 -6
  21. package/src/commands/governance.ts +1005 -0
  22. package/src/commands/guardian.ts +887 -0
  23. package/src/commands/init.ts +104 -11
  24. package/src/commands/orchestrator.ts +789 -0
  25. package/src/commands/performance-optimizer.ts +15 -10
  26. package/src/commands/plugins.ts +8 -5
  27. package/src/commands/project-update.ts +1156 -0
  28. package/src/commands/rag.ts +1011 -0
  29. package/src/commands/session.ts +631 -0
  30. package/src/commands/setup.ts +42 -344
  31. package/src/commands/test-init.ts +3 -2
  32. package/src/commands/test.ts +3 -2
  33. package/src/commands/watch.ts +21 -11
  34. package/src/commands/worktree.ts +1057 -0
  35. package/src/context/context-manager.ts +5 -2
  36. package/src/context/session-manager.ts +18 -7
  37. package/src/framework/command-interface.ts +520 -0
  38. package/src/framework/command-registry.ts +942 -0
  39. package/src/framework/completion-exporter.ts +383 -0
  40. package/src/framework/debug-logger.ts +519 -0
  41. package/src/framework/error-handler.ts +867 -0
  42. package/src/framework/help-generator.ts +540 -0
  43. package/src/framework/index.ts +169 -0
  44. package/src/framework/interactive-repl.ts +703 -0
  45. package/src/framework/output-formatter.ts +834 -0
  46. package/src/framework/progress-manager.ts +539 -0
  47. package/src/index.ts +3 -2
  48. package/src/interactive/interactive-mode.ts +14 -7
  49. package/src/lib/conflict-resolution.ts +818 -0
  50. package/src/lib/merge-strategy.ts +550 -0
  51. package/src/lib/safety-mechanisms.ts +451 -0
  52. package/src/lib/state-detection.ts +1030 -0
  53. package/src/nlp/command-mapper.ts +8 -3
  54. package/src/nlp/command-parser.ts +5 -2
  55. package/src/nlp/intent-parser.ts +23 -9
  56. package/src/plugins/plugin-manager.ts +50 -24
  57. package/src/tests/computer-setup-integration.test.ts +470 -0
  58. package/src/types/index.ts +1 -1
  59. package/src/types/modules.d.ts +425 -1
  60. package/src/utils/backup-rollback-manager.ts +366 -0
  61. package/src/utils/claude-config-installer.ts +823 -0
  62. package/src/utils/config-manager.ts +9 -6
  63. package/src/utils/error-handler.ts +3 -1
  64. package/src/utils/logger.ts +35 -12
  65. package/templates/batch/ci-cd.yaml +7 -7
  66. package/test-suites/api/health.spec.ts +20 -23
  67. package/test-suites/helpers/test-config.ts +14 -13
  68. package/test-suites/ui/accessibility.spec.ts +27 -22
  69. package/test-suites/ui/smoke.spec.ts +26 -21
  70. package/dist/ai/ai-service.d.ts +0 -152
  71. package/dist/ai/ai-service.d.ts.map +0 -1
  72. package/dist/ai/ai-service.js +0 -430
  73. package/dist/ai/ai-service.js.map +0 -1
  74. package/dist/ai/claude-client.d.ts +0 -130
  75. package/dist/ai/claude-client.d.ts.map +0 -1
  76. package/dist/ai/claude-client.js +0 -339
  77. package/dist/ai/claude-client.js.map +0 -1
  78. package/dist/ai/conversation-manager.d.ts +0 -164
  79. package/dist/ai/conversation-manager.d.ts.map +0 -1
  80. package/dist/ai/conversation-manager.js +0 -612
  81. package/dist/ai/conversation-manager.js.map +0 -1
  82. package/dist/ai/index.d.ts +0 -5
  83. package/dist/ai/index.d.ts.map +0 -1
  84. package/dist/ai/index.js +0 -8
  85. package/dist/ai/index.js.map +0 -1
  86. package/dist/cli.d.ts +0 -36
  87. package/dist/cli.d.ts.map +0 -1
  88. package/dist/cli.js +0 -173
  89. package/dist/cli.js.map +0 -1
  90. package/dist/commands/ai.d.ts +0 -89
  91. package/dist/commands/ai.d.ts.map +0 -1
  92. package/dist/commands/ai.js +0 -735
  93. package/dist/commands/ai.js.map +0 -1
  94. package/dist/commands/analyze-optimized.d.ts +0 -14
  95. package/dist/commands/analyze-optimized.d.ts.map +0 -1
  96. package/dist/commands/analyze-optimized.js +0 -437
  97. package/dist/commands/analyze-optimized.js.map +0 -1
  98. package/dist/commands/analyze.d.ts +0 -65
  99. package/dist/commands/analyze.d.ts.map +0 -1
  100. package/dist/commands/analyze.js +0 -435
  101. package/dist/commands/analyze.js.map +0 -1
  102. package/dist/commands/batch.d.ts +0 -71
  103. package/dist/commands/batch.d.ts.map +0 -1
  104. package/dist/commands/batch.js +0 -738
  105. package/dist/commands/batch.js.map +0 -1
  106. package/dist/commands/chat.d.ts +0 -71
  107. package/dist/commands/chat.d.ts.map +0 -1
  108. package/dist/commands/chat.js +0 -674
  109. package/dist/commands/chat.js.map +0 -1
  110. package/dist/commands/claude-init.d.ts +0 -28
  111. package/dist/commands/claude-init.d.ts.map +0 -1
  112. package/dist/commands/claude-init.js +0 -587
  113. package/dist/commands/claude-init.js.map +0 -1
  114. package/dist/commands/claude-setup.d.ts +0 -32
  115. package/dist/commands/claude-setup.d.ts.map +0 -1
  116. package/dist/commands/claude-setup.js +0 -570
  117. package/dist/commands/claude-setup.js.map +0 -1
  118. package/dist/commands/computer-setup-commands.d.ts +0 -39
  119. package/dist/commands/computer-setup-commands.d.ts.map +0 -1
  120. package/dist/commands/computer-setup-commands.js +0 -563
  121. package/dist/commands/computer-setup-commands.js.map +0 -1
  122. package/dist/commands/computer-setup.d.ts +0 -7
  123. package/dist/commands/computer-setup.d.ts.map +0 -1
  124. package/dist/commands/computer-setup.js +0 -481
  125. package/dist/commands/computer-setup.js.map +0 -1
  126. package/dist/commands/create-command.d.ts +0 -7
  127. package/dist/commands/create-command.d.ts.map +0 -1
  128. package/dist/commands/create-command.js +0 -158
  129. package/dist/commands/create-command.js.map +0 -1
  130. package/dist/commands/create.d.ts +0 -74
  131. package/dist/commands/create.d.ts.map +0 -1
  132. package/dist/commands/create.js +0 -556
  133. package/dist/commands/create.js.map +0 -1
  134. package/dist/commands/dashboard.d.ts +0 -91
  135. package/dist/commands/dashboard.d.ts.map +0 -1
  136. package/dist/commands/dashboard.js +0 -537
  137. package/dist/commands/dashboard.js.map +0 -1
  138. package/dist/commands/govern.d.ts +0 -70
  139. package/dist/commands/govern.d.ts.map +0 -1
  140. package/dist/commands/govern.js +0 -480
  141. package/dist/commands/govern.js.map +0 -1
  142. package/dist/commands/init.d.ts +0 -55
  143. package/dist/commands/init.d.ts.map +0 -1
  144. package/dist/commands/init.js +0 -584
  145. package/dist/commands/init.js.map +0 -1
  146. package/dist/commands/performance-optimizer.d.ts +0 -30
  147. package/dist/commands/performance-optimizer.d.ts.map +0 -1
  148. package/dist/commands/performance-optimizer.js +0 -649
  149. package/dist/commands/performance-optimizer.js.map +0 -1
  150. package/dist/commands/plugins.d.ts +0 -87
  151. package/dist/commands/plugins.d.ts.map +0 -1
  152. package/dist/commands/plugins.js +0 -685
  153. package/dist/commands/plugins.js.map +0 -1
  154. package/dist/commands/setup.d.ts +0 -29
  155. package/dist/commands/setup.d.ts.map +0 -1
  156. package/dist/commands/setup.js +0 -399
  157. package/dist/commands/setup.js.map +0 -1
  158. package/dist/commands/test-init.d.ts +0 -9
  159. package/dist/commands/test-init.d.ts.map +0 -1
  160. package/dist/commands/test-init.js +0 -222
  161. package/dist/commands/test-init.js.map +0 -1
  162. package/dist/commands/test.d.ts +0 -25
  163. package/dist/commands/test.d.ts.map +0 -1
  164. package/dist/commands/test.js +0 -217
  165. package/dist/commands/test.js.map +0 -1
  166. package/dist/commands/watch.d.ts +0 -76
  167. package/dist/commands/watch.d.ts.map +0 -1
  168. package/dist/commands/watch.js +0 -610
  169. package/dist/commands/watch.js.map +0 -1
  170. package/dist/context/context-manager.d.ts +0 -155
  171. package/dist/context/context-manager.d.ts.map +0 -1
  172. package/dist/context/context-manager.js +0 -383
  173. package/dist/context/context-manager.js.map +0 -1
  174. package/dist/context/index.d.ts +0 -3
  175. package/dist/context/index.d.ts.map +0 -1
  176. package/dist/context/index.js +0 -6
  177. package/dist/context/index.js.map +0 -1
  178. package/dist/context/session-manager.d.ts +0 -207
  179. package/dist/context/session-manager.d.ts.map +0 -1
  180. package/dist/context/session-manager.js +0 -682
  181. package/dist/context/session-manager.js.map +0 -1
  182. package/dist/index.d.ts +0 -8
  183. package/dist/index.d.ts.map +0 -1
  184. package/dist/index.js +0 -51
  185. package/dist/index.js.map +0 -1
  186. package/dist/interactive/interactive-mode.d.ts +0 -76
  187. package/dist/interactive/interactive-mode.d.ts.map +0 -1
  188. package/dist/interactive/interactive-mode.js +0 -730
  189. package/dist/interactive/interactive-mode.js.map +0 -1
  190. package/dist/nlp/command-mapper.d.ts +0 -174
  191. package/dist/nlp/command-mapper.d.ts.map +0 -1
  192. package/dist/nlp/command-mapper.js +0 -623
  193. package/dist/nlp/command-mapper.js.map +0 -1
  194. package/dist/nlp/command-parser.d.ts +0 -106
  195. package/dist/nlp/command-parser.d.ts.map +0 -1
  196. package/dist/nlp/command-parser.js +0 -416
  197. package/dist/nlp/command-parser.js.map +0 -1
  198. package/dist/nlp/index.d.ts +0 -5
  199. package/dist/nlp/index.d.ts.map +0 -1
  200. package/dist/nlp/index.js +0 -8
  201. package/dist/nlp/index.js.map +0 -1
  202. package/dist/nlp/intent-classifier.d.ts +0 -59
  203. package/dist/nlp/intent-classifier.d.ts.map +0 -1
  204. package/dist/nlp/intent-classifier.js +0 -384
  205. package/dist/nlp/intent-classifier.js.map +0 -1
  206. package/dist/nlp/intent-parser.d.ts +0 -152
  207. package/dist/nlp/intent-parser.d.ts.map +0 -1
  208. package/dist/nlp/intent-parser.js +0 -739
  209. package/dist/nlp/intent-parser.js.map +0 -1
  210. package/dist/plugins/plugin-manager.d.ts +0 -120
  211. package/dist/plugins/plugin-manager.d.ts.map +0 -1
  212. package/dist/plugins/plugin-manager.js +0 -595
  213. package/dist/plugins/plugin-manager.js.map +0 -1
  214. package/dist/types/index.d.ts +0 -224
  215. package/dist/types/index.d.ts.map +0 -1
  216. package/dist/types/index.js +0 -3
  217. package/dist/types/index.js.map +0 -1
  218. package/dist/utils/config-manager.d.ts +0 -73
  219. package/dist/utils/config-manager.d.ts.map +0 -1
  220. package/dist/utils/config-manager.js +0 -339
  221. package/dist/utils/config-manager.js.map +0 -1
  222. package/dist/utils/error-handler.d.ts +0 -46
  223. package/dist/utils/error-handler.d.ts.map +0 -1
  224. package/dist/utils/error-handler.js +0 -169
  225. package/dist/utils/error-handler.js.map +0 -1
  226. package/dist/utils/logger.d.ts +0 -25
  227. package/dist/utils/logger.d.ts.map +0 -1
  228. package/dist/utils/logger.js +0 -94
  229. package/dist/utils/logger.js.map +0 -1
  230. package/src/commands/computer-setup-commands.ts +0 -709
@@ -1,738 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.BatchCommands = void 0;
4
- const tslib_1 = require("tslib");
5
- const fs_extra_1 = tslib_1.__importDefault(require("fs-extra"));
6
- const path_1 = tslib_1.__importDefault(require("path"));
7
- const chalk_1 = tslib_1.__importDefault(require("chalk"));
8
- const yaml_1 = tslib_1.__importDefault(require("yaml"));
9
- const listr2_1 = require("listr2");
10
- const logger_1 = require("../utils/logger");
11
- const error_handler_1 = require("../utils/error-handler");
12
- /**
13
- * Batch commands for YAML automation and batch processing
14
- */
15
- class BatchCommands {
16
- program;
17
- configManager;
18
- pluginManager;
19
- runningJobs = new Map();
20
- constructor(program, configManager, pluginManager) {
21
- this.program = program;
22
- this.configManager = configManager;
23
- this.pluginManager = pluginManager;
24
- this.registerCommands();
25
- }
26
- registerCommands() {
27
- const batchCmd = this.program
28
- .command('batch')
29
- .description('batch processing and automation with YAML');
30
- // Run batch job
31
- batchCmd
32
- .command('run <file>')
33
- .description('run batch job from YAML file')
34
- .option('--dry-run', 'show what would be executed without running')
35
- .option('--parallel', 'run commands in parallel where possible')
36
- .option('--continue-on-error', 'continue execution on command failures')
37
- .option('--vars <vars>', 'variables to pass to batch job (JSON or key=value)')
38
- .option('--timeout <ms>', 'global timeout for batch job')
39
- .action(async (file, options) => {
40
- await this.runBatchJob(file, options);
41
- });
42
- // Create batch job
43
- batchCmd
44
- .command('create <name>')
45
- .description('create a new batch job')
46
- .option('--template <template>', 'batch job template')
47
- .option('--commands <commands>', 'commands to include (comma-separated)')
48
- .option('--interactive', 'create job interactively')
49
- .action(async (name, options) => {
50
- await this.createBatchJob(name, options);
51
- });
52
- // List batch jobs
53
- batchCmd
54
- .command('list')
55
- .alias('ls')
56
- .description('list available batch jobs')
57
- .option('--path <path>', 'custom batch jobs directory')
58
- .action(async (options) => {
59
- await this.listBatchJobs(options);
60
- });
61
- // Validate batch job
62
- batchCmd
63
- .command('validate <file>')
64
- .description('validate batch job YAML file')
65
- .action(async (file) => {
66
- await this.validateBatchJob(file);
67
- });
68
- // Stop running job
69
- batchCmd
70
- .command('stop <jobId>')
71
- .description('stop a running batch job')
72
- .action(async (jobId) => {
73
- await this.stopBatchJob(jobId);
74
- });
75
- // Show job status
76
- batchCmd
77
- .command('status [jobId]')
78
- .description('show batch job status')
79
- .action(async (jobId) => {
80
- await this.showJobStatus(jobId);
81
- });
82
- // Schedule batch job
83
- batchCmd
84
- .command('schedule <file>')
85
- .description('schedule batch job execution')
86
- .option('--cron <expression>', 'cron expression for scheduling')
87
- .option('--interval <ms>', 'interval in milliseconds')
88
- .option('--once', 'run once after delay')
89
- .action(async (file, options) => {
90
- await this.scheduleBatchJob(file, options);
91
- });
92
- // Export batch job
93
- batchCmd
94
- .command('export <file>')
95
- .description('export batch job to different formats')
96
- .option('--format <format>', 'export format (json, shell, dockerfile)', 'json')
97
- .option('--output <path>', 'output file path')
98
- .action(async (file, options) => {
99
- await this.exportBatchJob(file, options);
100
- });
101
- // Import batch job
102
- batchCmd
103
- .command('import <file>')
104
- .description('import batch job from different formats')
105
- .option('--format <format>', 'source format (json, shell, package-scripts)')
106
- .option('--name <name>', 'batch job name')
107
- .action(async (file, options) => {
108
- await this.importBatchJob(file, options);
109
- });
110
- // Template management
111
- batchCmd.command('template').description('manage batch job templates');
112
- batchCmd
113
- .command('template list')
114
- .description('list available templates')
115
- .action(async () => {
116
- await this.listTemplates();
117
- });
118
- batchCmd
119
- .command('template create <name>')
120
- .description('create a new template')
121
- .option('--from <file>', 'create template from existing batch job')
122
- .action(async (name, options) => {
123
- await this.createTemplate(name, options);
124
- });
125
- }
126
- /**
127
- * Run batch job from YAML file
128
- */
129
- async runBatchJob(file, options) {
130
- try {
131
- logger_1.logger.info(`Running batch job: ${chalk_1.default.cyan(file)}`);
132
- // Load and validate batch job
133
- const job = await this.loadBatchJob(file);
134
- await this.validateJobStructure(job);
135
- // Process variables
136
- const processedJob = await this.processJobVariables(job, options.vars);
137
- if (options.dryRun) {
138
- await this.showDryRun(processedJob);
139
- return;
140
- }
141
- // Create job ID and track execution
142
- const jobId = `job-${Date.now()}`;
143
- this.runningJobs.set(jobId, {
144
- file,
145
- job: processedJob,
146
- startTime: Date.now(),
147
- status: 'running',
148
- });
149
- try {
150
- await this.executeBatchJob(processedJob, jobId, options);
151
- logger_1.logger.success(`Batch job completed: ${file}`);
152
- }
153
- finally {
154
- this.runningJobs.delete(jobId);
155
- }
156
- }
157
- catch (error) {
158
- throw error_handler_1.errorHandler.createError('WUNDR_BATCH_RUN_FAILED', 'Failed to run batch job', { file, options }, true);
159
- }
160
- }
161
- /**
162
- * Create a new batch job
163
- */
164
- async createBatchJob(name, options) {
165
- try {
166
- logger_1.logger.info(`Creating batch job: ${chalk_1.default.cyan(name)}`);
167
- let job;
168
- if (options.interactive) {
169
- job = await this.createInteractiveBatchJob(name);
170
- }
171
- else if (options.template) {
172
- job = await this.createJobFromTemplate(name, options.template);
173
- }
174
- else {
175
- job = this.createBasicBatchJob(name, options);
176
- }
177
- const jobPath = path_1.default.join(process.cwd(), '.wundr', 'batch', `${name}.yaml`);
178
- await fs_extra_1.default.ensureDir(path_1.default.dirname(jobPath));
179
- await fs_extra_1.default.writeFile(jobPath, yaml_1.default.stringify(job));
180
- logger_1.logger.success(`Batch job created: ${jobPath}`);
181
- }
182
- catch (error) {
183
- throw error_handler_1.errorHandler.createError('WUNDR_BATCH_CREATE_FAILED', 'Failed to create batch job', { name, options }, true);
184
- }
185
- }
186
- /**
187
- * List available batch jobs
188
- */
189
- async listBatchJobs(options) {
190
- try {
191
- const batchDir = options.path || path_1.default.join(process.cwd(), '.wundr', 'batch');
192
- if (!(await fs_extra_1.default.pathExists(batchDir))) {
193
- logger_1.logger.info('No batch jobs directory found');
194
- return;
195
- }
196
- const files = await fs_extra_1.default.readdir(batchDir);
197
- const yamlFiles = files.filter(f => f.endsWith('.yaml') || f.endsWith('.yml'));
198
- if (yamlFiles.length === 0) {
199
- logger_1.logger.info('No batch jobs found');
200
- return;
201
- }
202
- logger_1.logger.info(`Batch jobs (${yamlFiles.length}):`);
203
- const jobs = [];
204
- for (const file of yamlFiles) {
205
- const filePath = path_1.default.join(batchDir, file);
206
- try {
207
- const job = await this.loadBatchJob(filePath);
208
- jobs.push({
209
- Name: path_1.default.basename(file, path_1.default.extname(file)),
210
- Description: job.description || 'No description',
211
- Commands: job.commands.length,
212
- Parallel: job.parallel ? '✓' : '✗',
213
- });
214
- }
215
- catch (error) {
216
- jobs.push({
217
- Name: path_1.default.basename(file, path_1.default.extname(file)),
218
- Description: 'Invalid YAML',
219
- Commands: 'N/A',
220
- Parallel: 'N/A',
221
- });
222
- }
223
- }
224
- console.table(jobs);
225
- }
226
- catch (error) {
227
- throw error_handler_1.errorHandler.createError('WUNDR_BATCH_LIST_FAILED', 'Failed to list batch jobs', { options }, true);
228
- }
229
- }
230
- /**
231
- * Validate batch job YAML file
232
- */
233
- async validateBatchJob(file) {
234
- try {
235
- logger_1.logger.info(`Validating batch job: ${chalk_1.default.cyan(file)}`);
236
- const job = await this.loadBatchJob(file);
237
- const validation = await this.validateJobStructure(job);
238
- if (validation.valid) {
239
- logger_1.logger.success('Batch job is valid ✓');
240
- // Show job summary
241
- console.log(chalk_1.default.blue('\nJob Summary:'));
242
- console.log(`Name: ${job.name}`);
243
- console.log(`Description: ${job.description || 'None'}`);
244
- console.log(`Commands: ${job.commands.length}`);
245
- console.log(`Parallel execution: ${job.parallel ? 'Yes' : 'No'}`);
246
- console.log(`Continue on error: ${job.continueOnError ? 'Yes' : 'No'}`);
247
- }
248
- else {
249
- logger_1.logger.error('Batch job validation failed:');
250
- validation.errors.forEach(error => {
251
- logger_1.logger.error(` - ${error}`);
252
- });
253
- process.exit(1);
254
- }
255
- }
256
- catch (error) {
257
- throw error_handler_1.errorHandler.createError('WUNDR_BATCH_VALIDATE_FAILED', 'Failed to validate batch job', { file }, true);
258
- }
259
- }
260
- /**
261
- * Stop a running batch job
262
- */
263
- async stopBatchJob(jobId) {
264
- try {
265
- const job = this.runningJobs.get(jobId);
266
- if (!job) {
267
- logger_1.logger.warn(`Job not found: ${jobId}`);
268
- return;
269
- }
270
- // Stop the job (implementation would depend on how jobs are executed)
271
- job.status = 'stopped';
272
- this.runningJobs.delete(jobId);
273
- logger_1.logger.success(`Batch job stopped: ${jobId}`);
274
- }
275
- catch (error) {
276
- throw error_handler_1.errorHandler.createError('WUNDR_BATCH_STOP_FAILED', 'Failed to stop batch job', { jobId }, true);
277
- }
278
- }
279
- /**
280
- * Show job status
281
- */
282
- async showJobStatus(jobId) {
283
- try {
284
- if (jobId) {
285
- const job = this.runningJobs.get(jobId);
286
- if (!job) {
287
- logger_1.logger.warn(`Job not found: ${jobId}`);
288
- return;
289
- }
290
- console.log(chalk_1.default.blue(`\nJob Status: ${jobId}`));
291
- console.log(`File: ${job.file}`);
292
- console.log(`Status: ${job.status}`);
293
- console.log(`Started: ${new Date(job.startTime).toLocaleString()}`);
294
- console.log(`Duration: ${Date.now() - job.startTime}ms`);
295
- }
296
- else {
297
- if (this.runningJobs.size === 0) {
298
- logger_1.logger.info('No running batch jobs');
299
- return;
300
- }
301
- console.log(chalk_1.default.blue(`\nRunning Jobs (${this.runningJobs.size}):`));
302
- const jobData = Array.from(this.runningJobs.entries()).map(([id, job]) => ({
303
- ID: id,
304
- File: path_1.default.basename(job.file),
305
- Status: job.status,
306
- Duration: `${Date.now() - job.startTime}ms`,
307
- }));
308
- console.table(jobData);
309
- }
310
- }
311
- catch (error) {
312
- throw error_handler_1.errorHandler.createError('WUNDR_BATCH_STATUS_FAILED', 'Failed to show job status', { jobId }, true);
313
- }
314
- }
315
- /**
316
- * Schedule batch job execution
317
- */
318
- async scheduleBatchJob(file, options) {
319
- try {
320
- logger_1.logger.info(`Scheduling batch job: ${chalk_1.default.cyan(file)}`);
321
- // Validate the job first
322
- await this.loadBatchJob(file);
323
- if (options.cron) {
324
- logger_1.logger.info(`Scheduled with cron: ${options.cron}`);
325
- // Implementation would use a cron library
326
- }
327
- else if (options.interval) {
328
- logger_1.logger.info(`Scheduled with interval: ${options.interval}ms`);
329
- // Implementation would use setInterval
330
- }
331
- else if (options.once) {
332
- logger_1.logger.info('Scheduled to run once');
333
- // Implementation would use setTimeout
334
- }
335
- else {
336
- throw new Error('No scheduling option provided');
337
- }
338
- logger_1.logger.success('Batch job scheduled successfully');
339
- }
340
- catch (error) {
341
- throw error_handler_1.errorHandler.createError('WUNDR_BATCH_SCHEDULE_FAILED', 'Failed to schedule batch job', { file, options }, true);
342
- }
343
- }
344
- /**
345
- * Export batch job to different formats
346
- */
347
- async exportBatchJob(file, options) {
348
- try {
349
- logger_1.logger.info(`Exporting batch job: ${chalk_1.default.cyan(file)}`);
350
- const job = await this.loadBatchJob(file);
351
- let exportedContent;
352
- switch (options.format) {
353
- case 'json':
354
- exportedContent = JSON.stringify(job, null, 2);
355
- break;
356
- case 'shell':
357
- exportedContent = this.convertToShellScript(job);
358
- break;
359
- case 'dockerfile':
360
- exportedContent = this.convertToDockerfile(job);
361
- break;
362
- default:
363
- throw new Error(`Unsupported export format: ${options.format}`);
364
- }
365
- const outputPath = options.output ||
366
- `${path_1.default.basename(file, path_1.default.extname(file))}.${options.format}`;
367
- await fs_extra_1.default.writeFile(outputPath, exportedContent);
368
- logger_1.logger.success(`Batch job exported: ${outputPath}`);
369
- }
370
- catch (error) {
371
- throw error_handler_1.errorHandler.createError('WUNDR_BATCH_EXPORT_FAILED', 'Failed to export batch job', { file, options }, true);
372
- }
373
- }
374
- /**
375
- * Import batch job from different formats
376
- */
377
- async importBatchJob(file, options) {
378
- try {
379
- logger_1.logger.info(`Importing batch job: ${chalk_1.default.cyan(file)}`);
380
- let job;
381
- switch (options.format) {
382
- case 'json':
383
- job = await this.importFromJSON(file, options.name);
384
- break;
385
- case 'shell':
386
- job = await this.importFromShell(file, options.name);
387
- break;
388
- case 'package-scripts':
389
- job = await this.importFromPackageScripts(file, options.name);
390
- break;
391
- default:
392
- throw new Error(`Unsupported import format: ${options.format}`);
393
- }
394
- const jobName = options.name || path_1.default.basename(file, path_1.default.extname(file));
395
- const jobPath = path_1.default.join(process.cwd(), '.wundr', 'batch', `${jobName}.yaml`);
396
- await fs_extra_1.default.ensureDir(path_1.default.dirname(jobPath));
397
- await fs_extra_1.default.writeFile(jobPath, yaml_1.default.stringify(job));
398
- logger_1.logger.success(`Batch job imported: ${jobPath}`);
399
- }
400
- catch (error) {
401
- throw error_handler_1.errorHandler.createError('WUNDR_BATCH_IMPORT_FAILED', 'Failed to import batch job', { file, options }, true);
402
- }
403
- }
404
- /**
405
- * Helper methods for batch job operations
406
- */
407
- async loadBatchJob(file) {
408
- if (!(await fs_extra_1.default.pathExists(file))) {
409
- throw new Error(`Batch job file not found: ${file}`);
410
- }
411
- const content = await fs_extra_1.default.readFile(file, 'utf8');
412
- const ext = path_1.default.extname(file).toLowerCase();
413
- if (ext === '.yaml' || ext === '.yml') {
414
- return yaml_1.default.parse(content);
415
- }
416
- else if (ext === '.json') {
417
- return JSON.parse(content);
418
- }
419
- else {
420
- throw new Error(`Unsupported file format: ${ext}`);
421
- }
422
- }
423
- async validateJobStructure(job) {
424
- const errors = [];
425
- if (!job.name) {
426
- errors.push('Job name is required');
427
- }
428
- if (!job.commands || job.commands.length === 0) {
429
- errors.push('At least one command is required');
430
- }
431
- else {
432
- job.commands.forEach((cmd, index) => {
433
- if (!cmd.command) {
434
- errors.push(`Command ${index + 1} is missing command property`);
435
- }
436
- });
437
- }
438
- return { valid: errors.length === 0, errors };
439
- }
440
- async processJobVariables(job, vars) {
441
- let variables = {};
442
- if (vars) {
443
- try {
444
- // Try parsing as JSON first
445
- variables = JSON.parse(vars);
446
- }
447
- catch {
448
- // Parse as key=value pairs
449
- vars.split(',').forEach(pair => {
450
- const [key, value] = pair.split('=');
451
- if (key && value) {
452
- variables[key.trim()] = value.trim();
453
- }
454
- });
455
- }
456
- }
457
- // Replace variables in job
458
- const processedJob = JSON.parse(JSON.stringify(job));
459
- const jobString = JSON.stringify(processedJob);
460
- let processedString = jobString;
461
- Object.entries(variables).forEach(([key, value]) => {
462
- const placeholder = new RegExp(`\\{\\{${key}\\}\\}`, 'g');
463
- processedString = processedString.replace(placeholder, String(value));
464
- });
465
- return JSON.parse(processedString);
466
- }
467
- async showDryRun(job) {
468
- console.log(chalk_1.default.blue('\nDry Run - Commands to be executed:'));
469
- console.log(chalk_1.default.gray('='.repeat(50)));
470
- job.commands.forEach((cmd, index) => {
471
- console.log(`${index + 1}. ${chalk_1.default.cyan(cmd.command)}`);
472
- if (cmd.args) {
473
- console.log(` Args: ${cmd.args.join(' ')}`);
474
- }
475
- if (cmd.condition) {
476
- console.log(` Condition: ${cmd.condition}`);
477
- }
478
- if (cmd.retry) {
479
- console.log(` Retry: ${cmd.retry} times`);
480
- }
481
- if (cmd.timeout) {
482
- console.log(` Timeout: ${cmd.timeout}ms`);
483
- }
484
- console.log();
485
- });
486
- console.log(chalk_1.default.gray('='.repeat(50)));
487
- console.log(`Total commands: ${job.commands.length}`);
488
- console.log(`Parallel execution: ${job.parallel ? 'Yes' : 'No'}`);
489
- console.log(`Continue on error: ${job.continueOnError ? 'Yes' : 'No'}`);
490
- }
491
- async executeBatchJob(job, _jobId, _options) {
492
- const tasks = job.commands.map((cmd, _index) => ({
493
- title: cmd.command,
494
- task: async () => {
495
- await this.executeCommand(cmd, _options);
496
- },
497
- retry: cmd.retry || 0,
498
- timeout: cmd.timeout,
499
- }));
500
- const listr = new listr2_1.Listr(tasks, {
501
- concurrent: job.parallel || _options.parallel,
502
- exitOnError: !(job.continueOnError || _options.continueOnError),
503
- rendererOptions: {
504
- showSubtasks: true,
505
- },
506
- });
507
- await listr.run();
508
- }
509
- async executeCommand(cmd, _options) {
510
- // Check condition if specified
511
- if (cmd.condition && !(await this.evaluateCondition(cmd.condition))) {
512
- logger_1.logger.debug(`Skipping command due to condition: ${cmd.condition}`);
513
- return;
514
- }
515
- const { spawn } = await Promise.resolve().then(() => tslib_1.__importStar(require('child_process')));
516
- const [command, ...args] = cmd.command.split(' ');
517
- const finalArgs = cmd.args ? [...args, ...cmd.args] : args;
518
- return new Promise((resolve, reject) => {
519
- const child = spawn(command ?? 'echo', finalArgs, {
520
- stdio: ['ignore', 'pipe', 'pipe'],
521
- shell: true,
522
- });
523
- let output = '';
524
- let error = '';
525
- child.stdout?.on('data', (data) => {
526
- output += data.toString();
527
- });
528
- child.stderr?.on('data', (data) => {
529
- error += data.toString();
530
- });
531
- child.on('exit', (code) => {
532
- if (code === 0) {
533
- resolve();
534
- }
535
- else {
536
- reject(new Error(`Command failed with exit code ${code}: ${error}`));
537
- }
538
- });
539
- // Handle timeout
540
- if (cmd.timeout) {
541
- setTimeout(() => {
542
- child.kill();
543
- reject(new Error(`Command timed out after ${cmd.timeout}ms`));
544
- }, cmd.timeout);
545
- }
546
- });
547
- }
548
- async evaluateCondition(condition) {
549
- // Simple condition evaluation
550
- // In a real implementation, this would be more sophisticated
551
- switch (condition) {
552
- case 'always':
553
- return true;
554
- case 'never':
555
- return false;
556
- default:
557
- // Could evaluate file existence, environment variables, etc.
558
- return true;
559
- }
560
- }
561
- async createInteractiveBatchJob(name) {
562
- const inquirer = await Promise.resolve().then(() => tslib_1.__importStar(require('inquirer')));
563
- const answers = await inquirer.default.prompt([
564
- {
565
- type: 'input',
566
- name: 'description',
567
- message: 'Job description:',
568
- },
569
- {
570
- type: 'confirm',
571
- name: 'parallel',
572
- message: 'Run commands in parallel?',
573
- default: false,
574
- },
575
- {
576
- type: 'confirm',
577
- name: 'continueOnError',
578
- message: 'Continue on command failure?',
579
- default: false,
580
- },
581
- ]);
582
- const commands = [];
583
- let addMore = true;
584
- while (addMore) {
585
- const cmdAnswers = await inquirer.default.prompt([
586
- {
587
- type: 'input',
588
- name: 'command',
589
- message: 'Command:',
590
- validate: input => input.length > 0 || 'Command is required',
591
- },
592
- {
593
- type: 'input',
594
- name: 'condition',
595
- message: 'Condition (optional):',
596
- },
597
- {
598
- type: 'number',
599
- name: 'retry',
600
- message: 'Retry count:',
601
- default: 0,
602
- },
603
- {
604
- type: 'confirm',
605
- name: 'addMore',
606
- message: 'Add another command?',
607
- default: true,
608
- },
609
- ]);
610
- commands.push({
611
- command: cmdAnswers.command,
612
- condition: cmdAnswers.condition || undefined,
613
- retry: cmdAnswers.retry || undefined,
614
- });
615
- addMore = cmdAnswers.addMore;
616
- }
617
- return {
618
- name,
619
- description: answers.description,
620
- commands,
621
- parallel: answers.parallel,
622
- continueOnError: answers.continueOnError,
623
- };
624
- }
625
- createBasicBatchJob(name, options) {
626
- const commands = options.commands
627
- ? options.commands
628
- .split(',')
629
- .map((cmd) => ({ command: cmd.trim() }))
630
- : [];
631
- return {
632
- name,
633
- description: `Batch job: ${name}`,
634
- commands,
635
- parallel: false,
636
- continueOnError: false,
637
- };
638
- }
639
- async createJobFromTemplate(name, template) {
640
- // Load template and create job
641
- const templatePath = path_1.default.join(__dirname, '../../templates/batch', `${template}.yaml`);
642
- if (await fs_extra_1.default.pathExists(templatePath)) {
643
- const templateJob = await this.loadBatchJob(templatePath);
644
- return { ...templateJob, name };
645
- }
646
- throw new Error(`Template not found: ${template}`);
647
- }
648
- // Format conversion methods
649
- convertToShellScript(job) {
650
- let script = `#!/bin/bash\n# Generated from batch job: ${job.name}\n\n`;
651
- if (job.description) {
652
- script += `# ${job.description}\n\n`;
653
- }
654
- script += 'set -e\n\n'; // Exit on error unless continueOnError is true
655
- job.commands.forEach(cmd => {
656
- script += `echo "Executing: ${cmd.command}"\n`;
657
- script += `${cmd.command}\n\n`;
658
- });
659
- return script;
660
- }
661
- convertToDockerfile(job) {
662
- let dockerfile = `# Generated from batch job: ${job.name}\n`;
663
- dockerfile += `FROM node:18-alpine\n\n`;
664
- if (job.description) {
665
- dockerfile += `# ${job.description}\n`;
666
- }
667
- dockerfile += `WORKDIR /app\n`;
668
- dockerfile += `COPY . .\n\n`;
669
- job.commands.forEach(cmd => {
670
- dockerfile += `RUN ${cmd.command}\n`;
671
- });
672
- return dockerfile;
673
- }
674
- async importFromJSON(file, name) {
675
- const content = await fs_extra_1.default.readJson(file);
676
- return { ...content, name: name || content.name };
677
- }
678
- async importFromShell(file, name) {
679
- const content = await fs_extra_1.default.readFile(file, 'utf8');
680
- const commands = content
681
- .split('\n')
682
- .filter(line => line.trim() && !line.startsWith('#'))
683
- .map(line => ({ command: line.trim() }));
684
- return {
685
- name: name || path_1.default.basename(file, path_1.default.extname(file)),
686
- description: `Imported from shell script: ${file}`,
687
- commands,
688
- };
689
- }
690
- async importFromPackageScripts(file, name) {
691
- const packageJson = await fs_extra_1.default.readJson(file);
692
- const scripts = packageJson.scripts || {};
693
- const commands = Object.entries(scripts).map(([script, command]) => ({
694
- command: `npm run ${script}`,
695
- args: [],
696
- condition: undefined,
697
- }));
698
- return {
699
- name: name || 'package-scripts',
700
- description: `Imported from package.json scripts`,
701
- commands,
702
- };
703
- }
704
- async listTemplates() {
705
- const templatesDir = path_1.default.join(__dirname, '../../templates/batch');
706
- if (await fs_extra_1.default.pathExists(templatesDir)) {
707
- const templates = await fs_extra_1.default.readdir(templatesDir);
708
- const yamlTemplates = templates.filter(t => t.endsWith('.yaml') || t.endsWith('.yml'));
709
- if (yamlTemplates.length > 0) {
710
- logger_1.logger.info('Available templates:');
711
- yamlTemplates.forEach(template => {
712
- console.log(` - ${path_1.default.basename(template, path_1.default.extname(template))}`);
713
- });
714
- }
715
- else {
716
- logger_1.logger.info('No templates available');
717
- }
718
- }
719
- else {
720
- logger_1.logger.info('No templates directory found');
721
- }
722
- }
723
- async createTemplate(name, options) {
724
- logger_1.logger.info(`Creating template: ${name}`);
725
- if (options.from) {
726
- const job = await this.loadBatchJob(options.from);
727
- const templatePath = path_1.default.join(__dirname, '../../templates/batch', `${name}.yaml`);
728
- await fs_extra_1.default.ensureDir(path_1.default.dirname(templatePath));
729
- await fs_extra_1.default.writeFile(templatePath, yaml_1.default.stringify(job));
730
- logger_1.logger.success(`Template created: ${templatePath}`);
731
- }
732
- else {
733
- logger_1.logger.info('Template creation from scratch not yet implemented');
734
- }
735
- }
736
- }
737
- exports.BatchCommands = BatchCommands;
738
- //# sourceMappingURL=batch.js.map