@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.
- package/README.md +551 -0
- package/bin/wundr.js +39 -0
- package/dist/ai/ai-service.d.ts +152 -0
- package/dist/ai/ai-service.d.ts.map +1 -0
- package/dist/ai/ai-service.js +430 -0
- package/dist/ai/ai-service.js.map +1 -0
- package/dist/ai/claude-client.d.ts +130 -0
- package/dist/ai/claude-client.d.ts.map +1 -0
- package/dist/ai/claude-client.js +339 -0
- package/dist/ai/claude-client.js.map +1 -0
- package/dist/ai/conversation-manager.d.ts +164 -0
- package/dist/ai/conversation-manager.d.ts.map +1 -0
- package/dist/ai/conversation-manager.js +612 -0
- package/dist/ai/conversation-manager.js.map +1 -0
- package/dist/ai/index.d.ts +5 -0
- package/dist/ai/index.d.ts.map +1 -0
- package/dist/ai/index.js +8 -0
- package/dist/ai/index.js.map +1 -0
- package/dist/cli.d.ts +36 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +173 -0
- package/dist/cli.js.map +1 -0
- package/dist/commands/ai.d.ts +89 -0
- package/dist/commands/ai.d.ts.map +1 -0
- package/dist/commands/ai.js +735 -0
- package/dist/commands/ai.js.map +1 -0
- package/dist/commands/analyze-optimized.d.ts +14 -0
- package/dist/commands/analyze-optimized.d.ts.map +1 -0
- package/dist/commands/analyze-optimized.js +437 -0
- package/dist/commands/analyze-optimized.js.map +1 -0
- package/dist/commands/analyze.d.ts +65 -0
- package/dist/commands/analyze.d.ts.map +1 -0
- package/dist/commands/analyze.js +435 -0
- package/dist/commands/analyze.js.map +1 -0
- package/dist/commands/batch.d.ts +71 -0
- package/dist/commands/batch.d.ts.map +1 -0
- package/dist/commands/batch.js +738 -0
- package/dist/commands/batch.js.map +1 -0
- package/dist/commands/chat.d.ts +71 -0
- package/dist/commands/chat.d.ts.map +1 -0
- package/dist/commands/chat.js +674 -0
- package/dist/commands/chat.js.map +1 -0
- package/dist/commands/claude-init.d.ts +28 -0
- package/dist/commands/claude-init.d.ts.map +1 -0
- package/dist/commands/claude-init.js +587 -0
- package/dist/commands/claude-init.js.map +1 -0
- package/dist/commands/claude-setup.d.ts +32 -0
- package/dist/commands/claude-setup.d.ts.map +1 -0
- package/dist/commands/claude-setup.js +570 -0
- package/dist/commands/claude-setup.js.map +1 -0
- package/dist/commands/computer-setup-commands.d.ts +39 -0
- package/dist/commands/computer-setup-commands.d.ts.map +1 -0
- package/dist/commands/computer-setup-commands.js +563 -0
- package/dist/commands/computer-setup-commands.js.map +1 -0
- package/dist/commands/computer-setup.d.ts +7 -0
- package/dist/commands/computer-setup.d.ts.map +1 -0
- package/dist/commands/computer-setup.js +481 -0
- package/dist/commands/computer-setup.js.map +1 -0
- package/dist/commands/create-command.d.ts +7 -0
- package/dist/commands/create-command.d.ts.map +1 -0
- package/dist/commands/create-command.js +158 -0
- package/dist/commands/create-command.js.map +1 -0
- package/dist/commands/create.d.ts +74 -0
- package/dist/commands/create.d.ts.map +1 -0
- package/dist/commands/create.js +556 -0
- package/dist/commands/create.js.map +1 -0
- package/dist/commands/dashboard.d.ts +91 -0
- package/dist/commands/dashboard.d.ts.map +1 -0
- package/dist/commands/dashboard.js +537 -0
- package/dist/commands/dashboard.js.map +1 -0
- package/dist/commands/govern.d.ts +70 -0
- package/dist/commands/govern.d.ts.map +1 -0
- package/dist/commands/govern.js +480 -0
- package/dist/commands/govern.js.map +1 -0
- package/dist/commands/init.d.ts +55 -0
- package/dist/commands/init.d.ts.map +1 -0
- package/dist/commands/init.js +584 -0
- package/dist/commands/init.js.map +1 -0
- package/dist/commands/performance-optimizer.d.ts +30 -0
- package/dist/commands/performance-optimizer.d.ts.map +1 -0
- package/dist/commands/performance-optimizer.js +649 -0
- package/dist/commands/performance-optimizer.js.map +1 -0
- package/dist/commands/plugins.d.ts +87 -0
- package/dist/commands/plugins.d.ts.map +1 -0
- package/dist/commands/plugins.js +685 -0
- package/dist/commands/plugins.js.map +1 -0
- package/dist/commands/setup.d.ts +29 -0
- package/dist/commands/setup.d.ts.map +1 -0
- package/dist/commands/setup.js +399 -0
- package/dist/commands/setup.js.map +1 -0
- package/dist/commands/test-init.d.ts +9 -0
- package/dist/commands/test-init.d.ts.map +1 -0
- package/dist/commands/test-init.js +222 -0
- package/dist/commands/test-init.js.map +1 -0
- package/dist/commands/test.d.ts +25 -0
- package/dist/commands/test.d.ts.map +1 -0
- package/dist/commands/test.js +217 -0
- package/dist/commands/test.js.map +1 -0
- package/dist/commands/watch.d.ts +76 -0
- package/dist/commands/watch.d.ts.map +1 -0
- package/dist/commands/watch.js +610 -0
- package/dist/commands/watch.js.map +1 -0
- package/dist/context/context-manager.d.ts +155 -0
- package/dist/context/context-manager.d.ts.map +1 -0
- package/dist/context/context-manager.js +383 -0
- package/dist/context/context-manager.js.map +1 -0
- package/dist/context/index.d.ts +3 -0
- package/dist/context/index.d.ts.map +1 -0
- package/dist/context/index.js +6 -0
- package/dist/context/index.js.map +1 -0
- package/dist/context/session-manager.d.ts +207 -0
- package/dist/context/session-manager.d.ts.map +1 -0
- package/dist/context/session-manager.js +682 -0
- package/dist/context/session-manager.js.map +1 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +51 -0
- package/dist/index.js.map +1 -0
- package/dist/interactive/interactive-mode.d.ts +76 -0
- package/dist/interactive/interactive-mode.d.ts.map +1 -0
- package/dist/interactive/interactive-mode.js +730 -0
- package/dist/interactive/interactive-mode.js.map +1 -0
- package/dist/nlp/command-mapper.d.ts +174 -0
- package/dist/nlp/command-mapper.d.ts.map +1 -0
- package/dist/nlp/command-mapper.js +623 -0
- package/dist/nlp/command-mapper.js.map +1 -0
- package/dist/nlp/command-parser.d.ts +106 -0
- package/dist/nlp/command-parser.d.ts.map +1 -0
- package/dist/nlp/command-parser.js +416 -0
- package/dist/nlp/command-parser.js.map +1 -0
- package/dist/nlp/index.d.ts +5 -0
- package/dist/nlp/index.d.ts.map +1 -0
- package/dist/nlp/index.js +8 -0
- package/dist/nlp/index.js.map +1 -0
- package/dist/nlp/intent-classifier.d.ts +59 -0
- package/dist/nlp/intent-classifier.d.ts.map +1 -0
- package/dist/nlp/intent-classifier.js +384 -0
- package/dist/nlp/intent-classifier.js.map +1 -0
- package/dist/nlp/intent-parser.d.ts +152 -0
- package/dist/nlp/intent-parser.d.ts.map +1 -0
- package/dist/nlp/intent-parser.js +739 -0
- package/dist/nlp/intent-parser.js.map +1 -0
- package/dist/plugins/plugin-manager.d.ts +120 -0
- package/dist/plugins/plugin-manager.d.ts.map +1 -0
- package/dist/plugins/plugin-manager.js +595 -0
- package/dist/plugins/plugin-manager.js.map +1 -0
- package/dist/types/index.d.ts +224 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +3 -0
- package/dist/types/index.js.map +1 -0
- package/dist/utils/config-manager.d.ts +73 -0
- package/dist/utils/config-manager.d.ts.map +1 -0
- package/dist/utils/config-manager.js +339 -0
- package/dist/utils/config-manager.js.map +1 -0
- package/dist/utils/error-handler.d.ts +46 -0
- package/dist/utils/error-handler.d.ts.map +1 -0
- package/dist/utils/error-handler.js +169 -0
- package/dist/utils/error-handler.js.map +1 -0
- package/dist/utils/logger.d.ts +25 -0
- package/dist/utils/logger.d.ts.map +1 -0
- package/dist/utils/logger.js +94 -0
- package/dist/utils/logger.js.map +1 -0
- package/package.json +119 -0
- package/src/ai/ai-service.ts +595 -0
- package/src/ai/claude-client.ts +490 -0
- package/src/ai/conversation-manager.ts +907 -0
- package/src/ai/index.ts +8 -0
- package/src/cli.ts +202 -0
- package/src/commands/ai.ts +995 -0
- package/src/commands/analyze-optimized.ts +641 -0
- package/src/commands/analyze.ts +576 -0
- package/src/commands/batch.ts +935 -0
- package/src/commands/chat.ts +876 -0
- package/src/commands/claude-init.ts +715 -0
- package/src/commands/claude-setup.ts +697 -0
- package/src/commands/computer-setup-commands.ts +709 -0
- package/src/commands/computer-setup.ts +565 -0
- package/src/commands/create-command.ts +175 -0
- package/src/commands/create.ts +727 -0
- package/src/commands/dashboard.ts +691 -0
- package/src/commands/govern.ts +635 -0
- package/src/commands/init.ts +677 -0
- package/src/commands/performance-optimizer.ts +864 -0
- package/src/commands/plugins.ts +848 -0
- package/src/commands/setup.ts +508 -0
- package/src/commands/test-init.ts +242 -0
- package/src/commands/test.ts +264 -0
- package/src/commands/watch.ts +755 -0
- package/src/context/context-manager.ts +546 -0
- package/src/context/index.ts +9 -0
- package/src/context/session-manager.ts +1019 -0
- package/src/index.ts +64 -0
- package/src/interactive/interactive-mode.ts +830 -0
- package/src/nlp/command-mapper.ts +885 -0
- package/src/nlp/command-parser.ts +564 -0
- package/src/nlp/index.ts +4 -0
- package/src/nlp/intent-classifier.ts +458 -0
- package/src/nlp/intent-parser.ts +1101 -0
- package/src/plugins/plugin-manager.ts +744 -0
- package/src/types/index.ts +252 -0
- package/src/types/modules.d.ts +56 -0
- package/src/utils/config-manager.ts +391 -0
- package/src/utils/error-handler.ts +192 -0
- package/src/utils/logger.ts +104 -0
- package/templates/batch/ci-cd.yaml +62 -0
- package/templates/component/{{fileName}}.test.tsx +17 -0
- package/templates/component/{{fileName}}.tsx +21 -0
- package/templates/service/{{fileName}}.ts +98 -0
- package/templates/wundr-test.config.js +0 -0
- package/test-suites/api/health.spec.ts +134 -0
- package/test-suites/helpers/test-config.ts +84 -0
- package/test-suites/ui/accessibility.spec.ts +102 -0
- package/test-suites/ui/smoke.spec.ts +92 -0
|
@@ -0,0 +1,691 @@
|
|
|
1
|
+
import { Command } from 'commander';
|
|
2
|
+
import { spawn } from 'child_process';
|
|
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
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Dashboard commands for web interface and visualization
|
|
13
|
+
*/
|
|
14
|
+
export class DashboardCommands {
|
|
15
|
+
constructor(
|
|
16
|
+
private program: Command,
|
|
17
|
+
private configManager: ConfigManager,
|
|
18
|
+
private pluginManager: PluginManager
|
|
19
|
+
) {
|
|
20
|
+
this.registerCommands();
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
private registerCommands(): void {
|
|
24
|
+
const dashboardCmd = this.program
|
|
25
|
+
.command('dashboard')
|
|
26
|
+
.alias('dash')
|
|
27
|
+
.description('dashboard and visualization tools');
|
|
28
|
+
|
|
29
|
+
// Start dashboard
|
|
30
|
+
dashboardCmd
|
|
31
|
+
.command('start')
|
|
32
|
+
.description('start the web dashboard')
|
|
33
|
+
.option('--port <port>', 'dashboard port', '3000')
|
|
34
|
+
.option('--host <host>', 'dashboard host', 'localhost')
|
|
35
|
+
.option('--open', 'open browser automatically')
|
|
36
|
+
.option('--dev', 'start in development mode')
|
|
37
|
+
.action(async options => {
|
|
38
|
+
await this.startDashboard(options);
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
// Stop dashboard
|
|
42
|
+
dashboardCmd
|
|
43
|
+
.command('stop')
|
|
44
|
+
.description('stop the web dashboard')
|
|
45
|
+
.action(async () => {
|
|
46
|
+
await this.stopDashboard();
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
// Dashboard status
|
|
50
|
+
dashboardCmd
|
|
51
|
+
.command('status')
|
|
52
|
+
.description('check dashboard status')
|
|
53
|
+
.action(async () => {
|
|
54
|
+
await this.checkDashboardStatus();
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
// Generate reports
|
|
58
|
+
dashboardCmd
|
|
59
|
+
.command('report <type>')
|
|
60
|
+
.description('generate dashboard reports')
|
|
61
|
+
.option('--output <path>', 'output directory')
|
|
62
|
+
.option('--format <format>', 'report format (html, pdf, json)', 'html')
|
|
63
|
+
.option(
|
|
64
|
+
'--period <period>',
|
|
65
|
+
'report period (daily, weekly, monthly)',
|
|
66
|
+
'weekly'
|
|
67
|
+
)
|
|
68
|
+
.action(async (type, options) => {
|
|
69
|
+
await this.generateReport(type, options);
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
// Export data
|
|
73
|
+
dashboardCmd
|
|
74
|
+
.command('export <type>')
|
|
75
|
+
.description('export dashboard data')
|
|
76
|
+
.option('--output <path>', 'output file path')
|
|
77
|
+
.option('--format <format>', 'export format (json, csv, xlsx)', 'json')
|
|
78
|
+
.option('--filter <filter>', 'data filter')
|
|
79
|
+
.action(async (type, options) => {
|
|
80
|
+
await this.exportData(type, options);
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
// Import data
|
|
84
|
+
dashboardCmd
|
|
85
|
+
.command('import <file>')
|
|
86
|
+
.description('import data into dashboard')
|
|
87
|
+
.option('--type <type>', 'data type to import')
|
|
88
|
+
.option('--merge', 'merge with existing data')
|
|
89
|
+
.action(async (file, options) => {
|
|
90
|
+
await this.importData(file, options);
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
// Configure dashboard
|
|
94
|
+
dashboardCmd.command('config').description('configure dashboard settings');
|
|
95
|
+
|
|
96
|
+
dashboardCmd
|
|
97
|
+
.command('config set <key> <value>')
|
|
98
|
+
.description('set dashboard configuration')
|
|
99
|
+
.action(async (key, value) => {
|
|
100
|
+
await this.setDashboardConfig(key, value);
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
dashboardCmd
|
|
104
|
+
.command('config get [key]')
|
|
105
|
+
.description('get dashboard configuration')
|
|
106
|
+
.action(async key => {
|
|
107
|
+
await this.getDashboardConfig(key);
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
// Manage widgets
|
|
111
|
+
dashboardCmd.command('widget').description('manage dashboard widgets');
|
|
112
|
+
|
|
113
|
+
dashboardCmd
|
|
114
|
+
.command('widget add <type>')
|
|
115
|
+
.description('add a new widget')
|
|
116
|
+
.option('--config <config>', 'widget configuration')
|
|
117
|
+
.option('--position <position>', 'widget position')
|
|
118
|
+
.action(async (type, options) => {
|
|
119
|
+
await this.addWidget(type, options);
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
dashboardCmd
|
|
123
|
+
.command('widget remove <id>')
|
|
124
|
+
.description('remove a widget')
|
|
125
|
+
.action(async id => {
|
|
126
|
+
await this.removeWidget(id);
|
|
127
|
+
});
|
|
128
|
+
|
|
129
|
+
dashboardCmd
|
|
130
|
+
.command('widget list')
|
|
131
|
+
.description('list all widgets')
|
|
132
|
+
.action(async () => {
|
|
133
|
+
await this.listWidgets();
|
|
134
|
+
});
|
|
135
|
+
|
|
136
|
+
// Manage themes
|
|
137
|
+
dashboardCmd
|
|
138
|
+
.command('theme <action>')
|
|
139
|
+
.description('manage dashboard themes')
|
|
140
|
+
.option('--name <name>', 'theme name')
|
|
141
|
+
.option('--config <config>', 'theme configuration')
|
|
142
|
+
.action(async (action, options) => {
|
|
143
|
+
await this.manageTheme(action, options);
|
|
144
|
+
});
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
/**
|
|
148
|
+
* Start the web dashboard
|
|
149
|
+
*/
|
|
150
|
+
private async startDashboard(options: any): Promise<void> {
|
|
151
|
+
try {
|
|
152
|
+
logger.info('Starting Wundr dashboard...');
|
|
153
|
+
|
|
154
|
+
// Check if dashboard is already running
|
|
155
|
+
const isRunning = await this.isDashboardRunning();
|
|
156
|
+
if (isRunning) {
|
|
157
|
+
logger.warn('Dashboard is already running');
|
|
158
|
+
if (options.open) {
|
|
159
|
+
await this.openBrowser(`http://${options.host}:${options.port}`);
|
|
160
|
+
}
|
|
161
|
+
return;
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
// Ensure dashboard assets are available
|
|
165
|
+
await this.ensureDashboardAssets();
|
|
166
|
+
|
|
167
|
+
// Start the dashboard server
|
|
168
|
+
const dashboardProcess = await this.startDashboardServer(options);
|
|
169
|
+
|
|
170
|
+
// Save process info
|
|
171
|
+
await this.saveDashboardProcess(dashboardProcess, options);
|
|
172
|
+
|
|
173
|
+
logger.success(
|
|
174
|
+
`Dashboard started at http://${options.host}:${options.port}`
|
|
175
|
+
);
|
|
176
|
+
|
|
177
|
+
if (options.open) {
|
|
178
|
+
await this.openBrowser(`http://${options.host}:${options.port}`);
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
// Keep the process alive if not in dev mode
|
|
182
|
+
if (!options.dev) {
|
|
183
|
+
logger.info(
|
|
184
|
+
'Dashboard is running in the background. Use "wundr dashboard stop" to stop it.'
|
|
185
|
+
);
|
|
186
|
+
}
|
|
187
|
+
} catch (error) {
|
|
188
|
+
throw errorHandler.createError(
|
|
189
|
+
'WUNDR_DASHBOARD_START_FAILED',
|
|
190
|
+
'Failed to start dashboard',
|
|
191
|
+
{ options },
|
|
192
|
+
true
|
|
193
|
+
);
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
/**
|
|
198
|
+
* Stop the web dashboard
|
|
199
|
+
*/
|
|
200
|
+
private async stopDashboard(): Promise<void> {
|
|
201
|
+
try {
|
|
202
|
+
logger.info('Stopping dashboard...');
|
|
203
|
+
|
|
204
|
+
const processInfo = await this.loadDashboardProcess();
|
|
205
|
+
if (!processInfo) {
|
|
206
|
+
logger.warn('No running dashboard found');
|
|
207
|
+
return;
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
// Kill the dashboard process
|
|
211
|
+
process.kill(processInfo.pid, 'SIGTERM');
|
|
212
|
+
|
|
213
|
+
// Clean up process info
|
|
214
|
+
await this.cleanupDashboardProcess();
|
|
215
|
+
|
|
216
|
+
logger.success('Dashboard stopped successfully');
|
|
217
|
+
} catch (error) {
|
|
218
|
+
throw errorHandler.createError(
|
|
219
|
+
'WUNDR_DASHBOARD_STOP_FAILED',
|
|
220
|
+
'Failed to stop dashboard',
|
|
221
|
+
{},
|
|
222
|
+
true
|
|
223
|
+
);
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
/**
|
|
228
|
+
* Check dashboard status
|
|
229
|
+
*/
|
|
230
|
+
private async checkDashboardStatus(): Promise<void> {
|
|
231
|
+
try {
|
|
232
|
+
const isRunning = await this.isDashboardRunning();
|
|
233
|
+
const processInfo = await this.loadDashboardProcess();
|
|
234
|
+
|
|
235
|
+
if (isRunning && processInfo) {
|
|
236
|
+
logger.success(
|
|
237
|
+
`Dashboard is running on http://${processInfo.host}:${processInfo.port}`
|
|
238
|
+
);
|
|
239
|
+
logger.info(`Process ID: ${processInfo.pid}`);
|
|
240
|
+
logger.info(
|
|
241
|
+
`Started: ${new Date(processInfo.started).toLocaleString()}`
|
|
242
|
+
);
|
|
243
|
+
} else {
|
|
244
|
+
logger.info('Dashboard is not running');
|
|
245
|
+
}
|
|
246
|
+
} catch (error) {
|
|
247
|
+
throw errorHandler.createError(
|
|
248
|
+
'WUNDR_DASHBOARD_STATUS_FAILED',
|
|
249
|
+
'Failed to check dashboard status',
|
|
250
|
+
{},
|
|
251
|
+
true
|
|
252
|
+
);
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
/**
|
|
257
|
+
* Generate dashboard reports
|
|
258
|
+
*/
|
|
259
|
+
private async generateReport(type: string, options: any): Promise<void> {
|
|
260
|
+
try {
|
|
261
|
+
logger.info(`Generating ${type} report...`);
|
|
262
|
+
|
|
263
|
+
const reportData = await this.collectReportData(type, options.period);
|
|
264
|
+
const report = await this.formatReport(reportData, options.format);
|
|
265
|
+
|
|
266
|
+
const outputPath =
|
|
267
|
+
options.output || this.getDefaultReportPath(type, options.format);
|
|
268
|
+
await this.saveReport(report, outputPath);
|
|
269
|
+
|
|
270
|
+
logger.success(`Report generated: ${outputPath}`);
|
|
271
|
+
} catch (error) {
|
|
272
|
+
throw errorHandler.createError(
|
|
273
|
+
'WUNDR_DASHBOARD_REPORT_FAILED',
|
|
274
|
+
'Failed to generate report',
|
|
275
|
+
{ type, options },
|
|
276
|
+
true
|
|
277
|
+
);
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
/**
|
|
282
|
+
* Export dashboard data
|
|
283
|
+
*/
|
|
284
|
+
private async exportData(type: string, options: any): Promise<void> {
|
|
285
|
+
try {
|
|
286
|
+
logger.info(`Exporting ${type} data...`);
|
|
287
|
+
|
|
288
|
+
const data = await this.collectExportData(type, options.filter);
|
|
289
|
+
const exportedData = await this.formatExportData(data, options.format);
|
|
290
|
+
|
|
291
|
+
const outputPath =
|
|
292
|
+
options.output || this.getDefaultExportPath(type, options.format);
|
|
293
|
+
await this.saveExportData(exportedData, outputPath);
|
|
294
|
+
|
|
295
|
+
logger.success(`Data exported: ${outputPath}`);
|
|
296
|
+
} catch (error) {
|
|
297
|
+
throw errorHandler.createError(
|
|
298
|
+
'WUNDR_DASHBOARD_EXPORT_FAILED',
|
|
299
|
+
'Failed to export data',
|
|
300
|
+
{ type, options },
|
|
301
|
+
true
|
|
302
|
+
);
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
/**
|
|
307
|
+
* Import data into dashboard
|
|
308
|
+
*/
|
|
309
|
+
private async importData(file: string, options: any): Promise<void> {
|
|
310
|
+
try {
|
|
311
|
+
logger.info(`Importing data from ${chalk.cyan(file)}...`);
|
|
312
|
+
|
|
313
|
+
if (!(await fs.pathExists(file))) {
|
|
314
|
+
throw new Error(`File not found: ${file}`);
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
const data = await this.loadImportData(file);
|
|
318
|
+
const validatedData = await this.validateImportData(data, options.type);
|
|
319
|
+
|
|
320
|
+
if (options.merge) {
|
|
321
|
+
await this.mergeImportData(validatedData, options.type);
|
|
322
|
+
} else {
|
|
323
|
+
await this.replaceImportData(validatedData, options.type);
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
logger.success(`Data imported successfully from ${file}`);
|
|
327
|
+
} catch (error) {
|
|
328
|
+
throw errorHandler.createError(
|
|
329
|
+
'WUNDR_DASHBOARD_IMPORT_FAILED',
|
|
330
|
+
'Failed to import data',
|
|
331
|
+
{ file, options },
|
|
332
|
+
true
|
|
333
|
+
);
|
|
334
|
+
}
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
/**
|
|
338
|
+
* Set dashboard configuration
|
|
339
|
+
*/
|
|
340
|
+
private async setDashboardConfig(key: string, value: string): Promise<void> {
|
|
341
|
+
try {
|
|
342
|
+
this.configManager.set(`dashboard.${key}`, value);
|
|
343
|
+
await this.configManager.saveConfig();
|
|
344
|
+
logger.success(`Dashboard configuration updated: ${key} = ${value}`);
|
|
345
|
+
} catch (error) {
|
|
346
|
+
throw errorHandler.createError(
|
|
347
|
+
'WUNDR_DASHBOARD_CONFIG_SET_FAILED',
|
|
348
|
+
'Failed to set dashboard configuration',
|
|
349
|
+
{ key, value },
|
|
350
|
+
true
|
|
351
|
+
);
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
/**
|
|
356
|
+
* Get dashboard configuration
|
|
357
|
+
*/
|
|
358
|
+
private async getDashboardConfig(key?: string): Promise<void> {
|
|
359
|
+
try {
|
|
360
|
+
if (key) {
|
|
361
|
+
const value = this.configManager.get(`dashboard.${key}`);
|
|
362
|
+
console.log(`${key}: ${value}`);
|
|
363
|
+
} else {
|
|
364
|
+
const dashboardConfig = this.configManager.get('dashboard');
|
|
365
|
+
console.log(JSON.stringify(dashboardConfig, null, 2));
|
|
366
|
+
}
|
|
367
|
+
} catch (error) {
|
|
368
|
+
throw errorHandler.createError(
|
|
369
|
+
'WUNDR_DASHBOARD_CONFIG_GET_FAILED',
|
|
370
|
+
'Failed to get dashboard configuration',
|
|
371
|
+
{ key },
|
|
372
|
+
true
|
|
373
|
+
);
|
|
374
|
+
}
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
/**
|
|
378
|
+
* Add a new widget
|
|
379
|
+
*/
|
|
380
|
+
private async addWidget(type: string, options: any): Promise<void> {
|
|
381
|
+
try {
|
|
382
|
+
logger.info(`Adding ${type} widget...`);
|
|
383
|
+
|
|
384
|
+
const widget = {
|
|
385
|
+
id: `widget-${Date.now()}`,
|
|
386
|
+
type,
|
|
387
|
+
config: options.config ? JSON.parse(options.config) : {},
|
|
388
|
+
position: options.position
|
|
389
|
+
? JSON.parse(options.position)
|
|
390
|
+
: { x: 0, y: 0 },
|
|
391
|
+
created: new Date().toISOString(),
|
|
392
|
+
};
|
|
393
|
+
|
|
394
|
+
await this.saveWidget(widget);
|
|
395
|
+
logger.success(`Widget added: ${widget.id}`);
|
|
396
|
+
} catch (error) {
|
|
397
|
+
throw errorHandler.createError(
|
|
398
|
+
'WUNDR_DASHBOARD_ADD_WIDGET_FAILED',
|
|
399
|
+
'Failed to add widget',
|
|
400
|
+
{ type, options },
|
|
401
|
+
true
|
|
402
|
+
);
|
|
403
|
+
}
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
/**
|
|
407
|
+
* Remove a widget
|
|
408
|
+
*/
|
|
409
|
+
private async removeWidget(id: string): Promise<void> {
|
|
410
|
+
try {
|
|
411
|
+
logger.info(`Removing widget: ${chalk.cyan(id)}`);
|
|
412
|
+
|
|
413
|
+
await this.deleteWidget(id);
|
|
414
|
+
logger.success(`Widget removed: ${id}`);
|
|
415
|
+
} catch (error) {
|
|
416
|
+
throw errorHandler.createError(
|
|
417
|
+
'WUNDR_DASHBOARD_REMOVE_WIDGET_FAILED',
|
|
418
|
+
'Failed to remove widget',
|
|
419
|
+
{ id },
|
|
420
|
+
true
|
|
421
|
+
);
|
|
422
|
+
}
|
|
423
|
+
}
|
|
424
|
+
|
|
425
|
+
/**
|
|
426
|
+
* List all widgets
|
|
427
|
+
*/
|
|
428
|
+
private async listWidgets(): Promise<void> {
|
|
429
|
+
try {
|
|
430
|
+
const widgets = await this.getAllWidgets();
|
|
431
|
+
|
|
432
|
+
if (widgets.length === 0) {
|
|
433
|
+
logger.info('No widgets configured');
|
|
434
|
+
return;
|
|
435
|
+
}
|
|
436
|
+
|
|
437
|
+
logger.info(`Dashboard widgets (${widgets.length}):`);
|
|
438
|
+
console.table(
|
|
439
|
+
widgets.map(widget => ({
|
|
440
|
+
ID: widget.id,
|
|
441
|
+
Type: widget.type,
|
|
442
|
+
Position: `(${widget.position.x}, ${widget.position.y})`,
|
|
443
|
+
Created: new Date(widget.created).toLocaleDateString(),
|
|
444
|
+
}))
|
|
445
|
+
);
|
|
446
|
+
} catch (error) {
|
|
447
|
+
throw errorHandler.createError(
|
|
448
|
+
'WUNDR_DASHBOARD_LIST_WIDGETS_FAILED',
|
|
449
|
+
'Failed to list widgets',
|
|
450
|
+
{},
|
|
451
|
+
true
|
|
452
|
+
);
|
|
453
|
+
}
|
|
454
|
+
}
|
|
455
|
+
|
|
456
|
+
/**
|
|
457
|
+
* Manage dashboard themes
|
|
458
|
+
*/
|
|
459
|
+
private async manageTheme(action: string, options: any): Promise<void> {
|
|
460
|
+
try {
|
|
461
|
+
switch (action) {
|
|
462
|
+
case 'list':
|
|
463
|
+
await this.listThemes();
|
|
464
|
+
break;
|
|
465
|
+
case 'set':
|
|
466
|
+
await this.setTheme(options.name);
|
|
467
|
+
break;
|
|
468
|
+
case 'create':
|
|
469
|
+
await this.createTheme(options.name, options.config);
|
|
470
|
+
break;
|
|
471
|
+
case 'delete':
|
|
472
|
+
await this.deleteTheme(options.name);
|
|
473
|
+
break;
|
|
474
|
+
default:
|
|
475
|
+
throw new Error(`Unknown theme action: ${action}`);
|
|
476
|
+
}
|
|
477
|
+
} catch (error) {
|
|
478
|
+
throw errorHandler.createError(
|
|
479
|
+
'WUNDR_DASHBOARD_THEME_FAILED',
|
|
480
|
+
'Failed to manage theme',
|
|
481
|
+
{ action, options },
|
|
482
|
+
true
|
|
483
|
+
);
|
|
484
|
+
}
|
|
485
|
+
}
|
|
486
|
+
|
|
487
|
+
/**
|
|
488
|
+
* Helper methods for dashboard operations
|
|
489
|
+
*/
|
|
490
|
+
private async isDashboardRunning(): Promise<boolean> {
|
|
491
|
+
const processInfo = await this.loadDashboardProcess();
|
|
492
|
+
if (!processInfo) return false;
|
|
493
|
+
|
|
494
|
+
try {
|
|
495
|
+
process.kill(processInfo.pid, 0);
|
|
496
|
+
return true;
|
|
497
|
+
} catch {
|
|
498
|
+
return false;
|
|
499
|
+
}
|
|
500
|
+
}
|
|
501
|
+
|
|
502
|
+
private async ensureDashboardAssets(): Promise<void> {
|
|
503
|
+
// Ensure dashboard assets are available
|
|
504
|
+
const assetsPath = path.join(__dirname, '../../dashboard-assets');
|
|
505
|
+
if (!(await fs.pathExists(assetsPath))) {
|
|
506
|
+
logger.info('Dashboard assets not found, downloading...');
|
|
507
|
+
// Download or copy dashboard assets
|
|
508
|
+
}
|
|
509
|
+
}
|
|
510
|
+
|
|
511
|
+
private async startDashboardServer(options: any): Promise<any> {
|
|
512
|
+
// Start the actual dashboard server process
|
|
513
|
+
const serverPath = path.join(__dirname, '../../dashboard-server');
|
|
514
|
+
|
|
515
|
+
const child = spawn('node', [serverPath], {
|
|
516
|
+
env: {
|
|
517
|
+
...process.env,
|
|
518
|
+
PORT: options.port,
|
|
519
|
+
HOST: options.host,
|
|
520
|
+
NODE_ENV: options.dev ? 'development' : 'production',
|
|
521
|
+
},
|
|
522
|
+
detached: !options.dev,
|
|
523
|
+
stdio: options.dev ? 'inherit' : 'ignore',
|
|
524
|
+
});
|
|
525
|
+
|
|
526
|
+
if (!options.dev) {
|
|
527
|
+
child.unref();
|
|
528
|
+
}
|
|
529
|
+
|
|
530
|
+
return {
|
|
531
|
+
pid: child.pid,
|
|
532
|
+
host: options.host,
|
|
533
|
+
port: options.port,
|
|
534
|
+
started: Date.now(),
|
|
535
|
+
};
|
|
536
|
+
}
|
|
537
|
+
|
|
538
|
+
private async saveDashboardProcess(
|
|
539
|
+
processInfo: any,
|
|
540
|
+
options: any
|
|
541
|
+
): Promise<void> {
|
|
542
|
+
const processFile = path.join(process.cwd(), '.wundr', 'dashboard.pid');
|
|
543
|
+
await fs.ensureDir(path.dirname(processFile));
|
|
544
|
+
await fs.writeJson(processFile, { ...processInfo, ...options });
|
|
545
|
+
}
|
|
546
|
+
|
|
547
|
+
private async loadDashboardProcess(): Promise<any> {
|
|
548
|
+
const processFile = path.join(process.cwd(), '.wundr', 'dashboard.pid');
|
|
549
|
+
if (await fs.pathExists(processFile)) {
|
|
550
|
+
return await fs.readJson(processFile);
|
|
551
|
+
}
|
|
552
|
+
return null;
|
|
553
|
+
}
|
|
554
|
+
|
|
555
|
+
private async cleanupDashboardProcess(): Promise<void> {
|
|
556
|
+
const processFile = path.join(process.cwd(), '.wundr', 'dashboard.pid');
|
|
557
|
+
if (await fs.pathExists(processFile)) {
|
|
558
|
+
await fs.remove(processFile);
|
|
559
|
+
}
|
|
560
|
+
}
|
|
561
|
+
|
|
562
|
+
private async openBrowser(url: string): Promise<void> {
|
|
563
|
+
const { default: open } = await import('open');
|
|
564
|
+
await open(url);
|
|
565
|
+
}
|
|
566
|
+
|
|
567
|
+
// Report generation methods
|
|
568
|
+
private async collectReportData(type: string, period: string): Promise<any> {
|
|
569
|
+
// Collect data for report generation
|
|
570
|
+
return { type, period, data: [] };
|
|
571
|
+
}
|
|
572
|
+
|
|
573
|
+
private async formatReport(data: any, format: string): Promise<any> {
|
|
574
|
+
// Format report based on requested format
|
|
575
|
+
return data;
|
|
576
|
+
}
|
|
577
|
+
|
|
578
|
+
private getDefaultReportPath(type: string, format: string): string {
|
|
579
|
+
return `reports/wundr-${type}-report.${format}`;
|
|
580
|
+
}
|
|
581
|
+
|
|
582
|
+
private async saveReport(report: any, outputPath: string): Promise<void> {
|
|
583
|
+
await fs.ensureDir(path.dirname(outputPath));
|
|
584
|
+
if (typeof report === 'string') {
|
|
585
|
+
await fs.writeFile(outputPath, report);
|
|
586
|
+
} else {
|
|
587
|
+
await fs.writeJson(outputPath, report, { spaces: 2 });
|
|
588
|
+
}
|
|
589
|
+
}
|
|
590
|
+
|
|
591
|
+
// Data export/import methods
|
|
592
|
+
private async collectExportData(type: string, filter?: string): Promise<any> {
|
|
593
|
+
return { type, filter, data: [] };
|
|
594
|
+
}
|
|
595
|
+
|
|
596
|
+
private async formatExportData(data: any, format: string): Promise<any> {
|
|
597
|
+
return data;
|
|
598
|
+
}
|
|
599
|
+
|
|
600
|
+
private getDefaultExportPath(type: string, format: string): string {
|
|
601
|
+
return `exports/wundr-${type}-export.${format}`;
|
|
602
|
+
}
|
|
603
|
+
|
|
604
|
+
private async saveExportData(data: any, outputPath: string): Promise<void> {
|
|
605
|
+
await fs.ensureDir(path.dirname(outputPath));
|
|
606
|
+
await fs.writeFile(outputPath, JSON.stringify(data, null, 2));
|
|
607
|
+
}
|
|
608
|
+
|
|
609
|
+
private async loadImportData(file: string): Promise<any> {
|
|
610
|
+
return await fs.readJson(file);
|
|
611
|
+
}
|
|
612
|
+
|
|
613
|
+
private async validateImportData(data: any, type?: string): Promise<any> {
|
|
614
|
+
// Validate imported data
|
|
615
|
+
return data;
|
|
616
|
+
}
|
|
617
|
+
|
|
618
|
+
private async mergeImportData(data: any, type?: string): Promise<void> {
|
|
619
|
+
// Merge imported data with existing data
|
|
620
|
+
logger.debug('Merging import data');
|
|
621
|
+
}
|
|
622
|
+
|
|
623
|
+
private async replaceImportData(data: any, type?: string): Promise<void> {
|
|
624
|
+
// Replace existing data with imported data
|
|
625
|
+
logger.debug('Replacing with import data');
|
|
626
|
+
}
|
|
627
|
+
|
|
628
|
+
// Widget management methods
|
|
629
|
+
private async saveWidget(widget: any): Promise<void> {
|
|
630
|
+
const widgetFile = path.join(
|
|
631
|
+
process.cwd(),
|
|
632
|
+
'.wundr',
|
|
633
|
+
'widgets',
|
|
634
|
+
`${widget.id}.json`
|
|
635
|
+
);
|
|
636
|
+
await fs.ensureDir(path.dirname(widgetFile));
|
|
637
|
+
await fs.writeJson(widgetFile, widget, { spaces: 2 });
|
|
638
|
+
}
|
|
639
|
+
|
|
640
|
+
private async deleteWidget(id: string): Promise<void> {
|
|
641
|
+
const widgetFile = path.join(
|
|
642
|
+
process.cwd(),
|
|
643
|
+
'.wundr',
|
|
644
|
+
'widgets',
|
|
645
|
+
`${id}.json`
|
|
646
|
+
);
|
|
647
|
+
if (await fs.pathExists(widgetFile)) {
|
|
648
|
+
await fs.remove(widgetFile);
|
|
649
|
+
}
|
|
650
|
+
}
|
|
651
|
+
|
|
652
|
+
private async getAllWidgets(): Promise<any[]> {
|
|
653
|
+
const widgetsDir = path.join(process.cwd(), '.wundr', 'widgets');
|
|
654
|
+
if (!(await fs.pathExists(widgetsDir))) {
|
|
655
|
+
return [];
|
|
656
|
+
}
|
|
657
|
+
|
|
658
|
+
const files = await fs.readdir(widgetsDir);
|
|
659
|
+
const widgets: any[] = [];
|
|
660
|
+
|
|
661
|
+
for (const file of files.filter(f => f.endsWith('.json'))) {
|
|
662
|
+
const widget = await fs.readJson(path.join(widgetsDir, file));
|
|
663
|
+
widgets.push(widget);
|
|
664
|
+
}
|
|
665
|
+
|
|
666
|
+
return widgets;
|
|
667
|
+
}
|
|
668
|
+
|
|
669
|
+
// Theme management methods
|
|
670
|
+
private async listThemes(): Promise<void> {
|
|
671
|
+
const themes = ['default', 'dark', 'light'];
|
|
672
|
+
console.log('Available themes:');
|
|
673
|
+
themes.forEach(theme => console.log(` - ${theme}`));
|
|
674
|
+
}
|
|
675
|
+
|
|
676
|
+
private async setTheme(name: string): Promise<void> {
|
|
677
|
+
this.configManager.set('dashboard.theme', name);
|
|
678
|
+
await this.configManager.saveConfig();
|
|
679
|
+
logger.success(`Theme set to: ${name}`);
|
|
680
|
+
}
|
|
681
|
+
|
|
682
|
+
private async createTheme(name: string, config: string): Promise<void> {
|
|
683
|
+
logger.info(`Creating theme: ${name}`);
|
|
684
|
+
// Implementation for creating custom themes
|
|
685
|
+
}
|
|
686
|
+
|
|
687
|
+
private async deleteTheme(name: string): Promise<void> {
|
|
688
|
+
logger.info(`Deleting theme: ${name}`);
|
|
689
|
+
// Implementation for deleting custom themes
|
|
690
|
+
}
|
|
691
|
+
}
|