@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,252 @@
|
|
|
1
|
+
import { Command } from 'commander';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Core types for the Wundr CLI
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
export interface WundrConfig {
|
|
8
|
+
version: string;
|
|
9
|
+
defaultMode: 'cli' | 'interactive' | 'chat' | 'tui';
|
|
10
|
+
plugins: string[];
|
|
11
|
+
integrations: {
|
|
12
|
+
github?: GitHubIntegration;
|
|
13
|
+
slack?: SlackIntegration;
|
|
14
|
+
jira?: JiraIntegration;
|
|
15
|
+
};
|
|
16
|
+
ai: {
|
|
17
|
+
provider: string;
|
|
18
|
+
model: string;
|
|
19
|
+
apiKey?: string;
|
|
20
|
+
};
|
|
21
|
+
analysis: {
|
|
22
|
+
patterns: string[];
|
|
23
|
+
excludes: string[];
|
|
24
|
+
maxDepth: number;
|
|
25
|
+
};
|
|
26
|
+
governance: {
|
|
27
|
+
rules: string[];
|
|
28
|
+
severity: 'error' | 'warning' | 'info';
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export interface GitHubIntegration {
|
|
33
|
+
token: string;
|
|
34
|
+
owner: string;
|
|
35
|
+
repo: string;
|
|
36
|
+
webhooks?: boolean;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export interface SlackIntegration {
|
|
40
|
+
token: string;
|
|
41
|
+
channel: string;
|
|
42
|
+
webhooks?: boolean;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export interface JiraIntegration {
|
|
46
|
+
url: string;
|
|
47
|
+
email: string;
|
|
48
|
+
token: string;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
export interface CommandContext {
|
|
52
|
+
config: WundrConfig;
|
|
53
|
+
logger: Logger;
|
|
54
|
+
spinner: Spinner;
|
|
55
|
+
interactive: boolean;
|
|
56
|
+
dryRun: boolean;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
export interface Logger {
|
|
60
|
+
debug(message: string, ...args: any[]): void;
|
|
61
|
+
info(message: string, ...args: any[]): void;
|
|
62
|
+
warn(message: string, ...args: any[]): void;
|
|
63
|
+
error(message: string, ...args: any[]): void;
|
|
64
|
+
success(message: string, ...args: any[]): void;
|
|
65
|
+
setLevel(level: 'debug' | 'info' | 'warn' | 'error'): void;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
export interface Spinner {
|
|
69
|
+
start(text?: string): void;
|
|
70
|
+
succeed(text?: string): void;
|
|
71
|
+
fail(text?: string): void;
|
|
72
|
+
warn(text?: string): void;
|
|
73
|
+
info(text?: string): void;
|
|
74
|
+
stop(): void;
|
|
75
|
+
text: string;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
export interface Plugin {
|
|
79
|
+
name: string;
|
|
80
|
+
version: string;
|
|
81
|
+
description: string;
|
|
82
|
+
commands?: PluginCommand[];
|
|
83
|
+
hooks?: PluginHook[];
|
|
84
|
+
activate(context: PluginContext): Promise<void>;
|
|
85
|
+
deactivate(): Promise<void>;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
export interface PluginCommand {
|
|
89
|
+
name: string;
|
|
90
|
+
description: string;
|
|
91
|
+
options?: CommandOption[];
|
|
92
|
+
action: (args: any[], options: any, context: CommandContext) => Promise<void>;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
export interface PluginHook {
|
|
96
|
+
event: string;
|
|
97
|
+
handler: (data: any, context: CommandContext) => Promise<void>;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
export interface CommandOption {
|
|
101
|
+
flags: string;
|
|
102
|
+
description: string;
|
|
103
|
+
defaultValue?: any;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
export interface PluginContext {
|
|
107
|
+
config: WundrConfig;
|
|
108
|
+
logger: Logger;
|
|
109
|
+
registerCommand(command: PluginCommand): void;
|
|
110
|
+
registerHook(hook: PluginHook): void;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
export interface BatchJob {
|
|
114
|
+
name: string;
|
|
115
|
+
description?: string;
|
|
116
|
+
commands: BatchCommand[];
|
|
117
|
+
parallel?: boolean;
|
|
118
|
+
continueOnError?: boolean;
|
|
119
|
+
timeout?: number;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
export interface BatchCommand {
|
|
123
|
+
command: string;
|
|
124
|
+
args?: string[];
|
|
125
|
+
options?: Record<string, any>;
|
|
126
|
+
condition?: string;
|
|
127
|
+
retry?: number;
|
|
128
|
+
timeout?: number;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
export interface WatchConfig {
|
|
132
|
+
patterns: string[];
|
|
133
|
+
ignore?: string[];
|
|
134
|
+
commands: WatchCommand[];
|
|
135
|
+
debounce?: number;
|
|
136
|
+
recursive?: boolean;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
export interface WatchCommand {
|
|
140
|
+
trigger: 'change' | 'add' | 'delete' | 'rename';
|
|
141
|
+
command: string;
|
|
142
|
+
args?: string[];
|
|
143
|
+
condition?: string;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
export interface TUILayout {
|
|
147
|
+
name: string;
|
|
148
|
+
widgets: TUIWidget[];
|
|
149
|
+
keybindings?: Keybinding[];
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
export interface TUIWidget {
|
|
153
|
+
type: 'log' | 'chart' | 'table' | 'progress' | 'text';
|
|
154
|
+
position: {
|
|
155
|
+
top: string | number;
|
|
156
|
+
left: string | number;
|
|
157
|
+
width: string | number;
|
|
158
|
+
height: string | number;
|
|
159
|
+
};
|
|
160
|
+
options: Record<string, any>;
|
|
161
|
+
dataSource?: string;
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
export interface Keybinding {
|
|
165
|
+
key: string;
|
|
166
|
+
action: string;
|
|
167
|
+
description: string;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
export interface ChatSession {
|
|
171
|
+
id: string;
|
|
172
|
+
model: string;
|
|
173
|
+
context?: string;
|
|
174
|
+
history: ChatMessage[];
|
|
175
|
+
created: Date;
|
|
176
|
+
updated: Date;
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
export interface ChatMessage {
|
|
180
|
+
role: 'user' | 'assistant' | 'system';
|
|
181
|
+
content: string;
|
|
182
|
+
timestamp: Date;
|
|
183
|
+
metadata?: Record<string, any>;
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
export interface AnalysisResult {
|
|
187
|
+
type: 'dependency' | 'quality' | 'security' | 'performance';
|
|
188
|
+
findings: Finding[];
|
|
189
|
+
metrics: Record<string, number>;
|
|
190
|
+
recommendations: Recommendation[];
|
|
191
|
+
timestamp: Date;
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
export interface Finding {
|
|
195
|
+
id: string;
|
|
196
|
+
severity: 'critical' | 'high' | 'medium' | 'low' | 'info';
|
|
197
|
+
title: string;
|
|
198
|
+
description: string;
|
|
199
|
+
file: string;
|
|
200
|
+
line?: number;
|
|
201
|
+
column?: number;
|
|
202
|
+
rule: string;
|
|
203
|
+
fixable: boolean;
|
|
204
|
+
fix?: string;
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
export interface Recommendation {
|
|
208
|
+
id: string;
|
|
209
|
+
title: string;
|
|
210
|
+
description: string;
|
|
211
|
+
impact: 'high' | 'medium' | 'low';
|
|
212
|
+
effort: 'low' | 'medium' | 'high';
|
|
213
|
+
category: string;
|
|
214
|
+
actions: RecommendationAction[];
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
export interface RecommendationAction {
|
|
218
|
+
type: 'command' | 'file_change' | 'config_change';
|
|
219
|
+
description: string;
|
|
220
|
+
command?: string;
|
|
221
|
+
file?: string;
|
|
222
|
+
changes?: any;
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
/**
|
|
226
|
+
* Base command interface for all command categories
|
|
227
|
+
*/
|
|
228
|
+
export interface BaseCommand {
|
|
229
|
+
program: Command;
|
|
230
|
+
config: WundrConfig;
|
|
231
|
+
logger: Logger;
|
|
232
|
+
registerCommands(): void;
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
/**
|
|
236
|
+
* Interactive mode types
|
|
237
|
+
*/
|
|
238
|
+
export interface InteractiveSession {
|
|
239
|
+
mode: 'wizard' | 'chat' | 'tui' | 'watch';
|
|
240
|
+
config: any;
|
|
241
|
+
state: Record<string, any>;
|
|
242
|
+
active: boolean;
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
/**
|
|
246
|
+
* Error handling types
|
|
247
|
+
*/
|
|
248
|
+
export interface WundrError extends Error {
|
|
249
|
+
code?: string;
|
|
250
|
+
context?: Record<string, any>;
|
|
251
|
+
recoverable?: boolean;
|
|
252
|
+
}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
// Type declarations for external modules
|
|
2
|
+
declare module '@wundr/computer-setup' {
|
|
3
|
+
export class ComputerSetupManager {
|
|
4
|
+
static getInstance(): ComputerSetupManager;
|
|
5
|
+
initialize(): Promise<void>;
|
|
6
|
+
validateSetup(profile?: any): Promise<boolean>;
|
|
7
|
+
cleanup(): Promise<void>;
|
|
8
|
+
getProfile(name: string): Promise<any>;
|
|
9
|
+
getDefaultProfile(): Promise<any>;
|
|
10
|
+
getAvailableProfiles(): Promise<any[]>;
|
|
11
|
+
setup(profile: any): Promise<{
|
|
12
|
+
success: boolean;
|
|
13
|
+
completedSteps?: any[];
|
|
14
|
+
skippedSteps?: any[];
|
|
15
|
+
failedSteps?: any[];
|
|
16
|
+
warnings?: string[];
|
|
17
|
+
errors?: string[];
|
|
18
|
+
report?: any;
|
|
19
|
+
}>;
|
|
20
|
+
on(event: string, callback: Function): void;
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
declare module '@wundr/core' {
|
|
25
|
+
export interface CoreConfig {
|
|
26
|
+
[key: string]: any;
|
|
27
|
+
}
|
|
28
|
+
export const defaultConfig: CoreConfig;
|
|
29
|
+
export function getLogger(name: string): any;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
declare module '@wundr/project-templates' {
|
|
33
|
+
export interface TemplateConfig {
|
|
34
|
+
name: string;
|
|
35
|
+
description: string;
|
|
36
|
+
files: Array<{ path: string; content: string }>;
|
|
37
|
+
[key: string]: any;
|
|
38
|
+
}
|
|
39
|
+
export function getTemplate(name: string): TemplateConfig | null;
|
|
40
|
+
export function listTemplates(): string[];
|
|
41
|
+
export const projectTemplates: Record<string, any>;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
declare module 'open' {
|
|
45
|
+
interface Options {
|
|
46
|
+
app?: string | string[];
|
|
47
|
+
wait?: boolean;
|
|
48
|
+
background?: boolean;
|
|
49
|
+
url?: boolean;
|
|
50
|
+
}
|
|
51
|
+
function open(
|
|
52
|
+
target: string,
|
|
53
|
+
options?: Options
|
|
54
|
+
): Promise<import('child_process').ChildProcess>;
|
|
55
|
+
export = open;
|
|
56
|
+
}
|
|
@@ -0,0 +1,391 @@
|
|
|
1
|
+
import fs from 'fs-extra';
|
|
2
|
+
import path from 'path';
|
|
3
|
+
import os from 'os';
|
|
4
|
+
import { z } from 'zod';
|
|
5
|
+
import { WundrConfig } from '../types';
|
|
6
|
+
import { logger } from './logger';
|
|
7
|
+
import { errorHandler } from './error-handler';
|
|
8
|
+
|
|
9
|
+
// Zod schema for configuration validation
|
|
10
|
+
const WundrConfigSchema = z.object({
|
|
11
|
+
version: z.string(),
|
|
12
|
+
defaultMode: z.enum(['cli', 'interactive', 'chat', 'tui']).default('cli'),
|
|
13
|
+
plugins: z.array(z.string()).default([]),
|
|
14
|
+
integrations: z
|
|
15
|
+
.object({
|
|
16
|
+
github: z
|
|
17
|
+
.object({
|
|
18
|
+
token: z.string(),
|
|
19
|
+
owner: z.string(),
|
|
20
|
+
repo: z.string(),
|
|
21
|
+
webhooks: z.boolean().optional(),
|
|
22
|
+
})
|
|
23
|
+
.optional(),
|
|
24
|
+
slack: z
|
|
25
|
+
.object({
|
|
26
|
+
token: z.string(),
|
|
27
|
+
channel: z.string(),
|
|
28
|
+
webhooks: z.boolean().optional(),
|
|
29
|
+
})
|
|
30
|
+
.optional(),
|
|
31
|
+
jira: z
|
|
32
|
+
.object({
|
|
33
|
+
url: z.string(),
|
|
34
|
+
email: z.string(),
|
|
35
|
+
token: z.string(),
|
|
36
|
+
})
|
|
37
|
+
.optional(),
|
|
38
|
+
})
|
|
39
|
+
.default({}),
|
|
40
|
+
ai: z.object({
|
|
41
|
+
provider: z.string().default('claude'),
|
|
42
|
+
model: z.string().default('claude-3'),
|
|
43
|
+
apiKey: z.string().optional(),
|
|
44
|
+
}),
|
|
45
|
+
analysis: z.object({
|
|
46
|
+
patterns: z
|
|
47
|
+
.array(z.string())
|
|
48
|
+
.default(['**/*.ts', '**/*.js', '**/*.tsx', '**/*.jsx']),
|
|
49
|
+
excludes: z
|
|
50
|
+
.array(z.string())
|
|
51
|
+
.default(['**/node_modules/**', '**/dist/**', '**/build/**']),
|
|
52
|
+
maxDepth: z.number().default(10),
|
|
53
|
+
}),
|
|
54
|
+
governance: z.object({
|
|
55
|
+
rules: z.array(z.string()).default([]),
|
|
56
|
+
severity: z.enum(['error', 'warning', 'info']).default('warning'),
|
|
57
|
+
}),
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Configuration management system
|
|
62
|
+
*/
|
|
63
|
+
export class ConfigManager {
|
|
64
|
+
private config: WundrConfig | null = null;
|
|
65
|
+
private configPath: string;
|
|
66
|
+
private userConfigDir: string;
|
|
67
|
+
|
|
68
|
+
constructor() {
|
|
69
|
+
this.userConfigDir = path.join(os.homedir(), '.wundr');
|
|
70
|
+
this.configPath = path.join(this.userConfigDir, 'config.json');
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* Load configuration from file or create default
|
|
75
|
+
*/
|
|
76
|
+
async loadConfig(customPath?: string): Promise<WundrConfig> {
|
|
77
|
+
const configFile = customPath || this.configPath;
|
|
78
|
+
|
|
79
|
+
try {
|
|
80
|
+
// Ensure config directory exists
|
|
81
|
+
await fs.ensureDir(path.dirname(configFile));
|
|
82
|
+
|
|
83
|
+
// Load existing config or create default
|
|
84
|
+
if (await fs.pathExists(configFile)) {
|
|
85
|
+
const rawConfig = await fs.readJson(configFile);
|
|
86
|
+
this.config = WundrConfigSchema.parse(rawConfig);
|
|
87
|
+
logger.debug(`Loaded config from: ${configFile}`);
|
|
88
|
+
} else {
|
|
89
|
+
this.config = this.createDefaultConfig();
|
|
90
|
+
await this.saveConfig();
|
|
91
|
+
logger.info('Created default configuration');
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
// Merge with environment variables
|
|
95
|
+
this.config = this.mergeEnvironmentVariables(this.config);
|
|
96
|
+
|
|
97
|
+
return this.config;
|
|
98
|
+
} catch (error) {
|
|
99
|
+
logger.error('Failed to load configuration:', error);
|
|
100
|
+
throw errorHandler.createError(
|
|
101
|
+
'WUNDR_CONFIG_INVALID',
|
|
102
|
+
'Failed to load or parse configuration file',
|
|
103
|
+
{ configPath: configFile },
|
|
104
|
+
true
|
|
105
|
+
);
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* Save current configuration to file
|
|
111
|
+
*/
|
|
112
|
+
async saveConfig(customPath?: string): Promise<void> {
|
|
113
|
+
if (!this.config) {
|
|
114
|
+
throw new Error('No configuration to save');
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
const configFile = customPath || this.configPath;
|
|
118
|
+
|
|
119
|
+
try {
|
|
120
|
+
await fs.ensureDir(path.dirname(configFile));
|
|
121
|
+
await fs.writeJson(configFile, this.config, { spaces: 2 });
|
|
122
|
+
logger.debug(`Saved config to: ${configFile}`);
|
|
123
|
+
} catch (error) {
|
|
124
|
+
logger.error('Failed to save configuration:', error);
|
|
125
|
+
throw errorHandler.createError(
|
|
126
|
+
'WUNDR_CONFIG_INVALID',
|
|
127
|
+
'Failed to save configuration file',
|
|
128
|
+
{ configPath: configFile },
|
|
129
|
+
false
|
|
130
|
+
);
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
/**
|
|
135
|
+
* Get current configuration
|
|
136
|
+
*/
|
|
137
|
+
getConfig(): WundrConfig {
|
|
138
|
+
if (!this.config) {
|
|
139
|
+
throw new Error('Configuration not loaded. Call loadConfig() first.');
|
|
140
|
+
}
|
|
141
|
+
return this.config;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
/**
|
|
145
|
+
* Update configuration values
|
|
146
|
+
*/
|
|
147
|
+
updateConfig(updates: Partial<WundrConfig>): void {
|
|
148
|
+
if (!this.config) {
|
|
149
|
+
throw new Error('Configuration not loaded. Call loadConfig() first.');
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
this.config = { ...this.config, ...updates };
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
/**
|
|
156
|
+
* Validate configuration against schema
|
|
157
|
+
*/
|
|
158
|
+
validateConfig(config?: any): { valid: boolean; errors: string[] } {
|
|
159
|
+
const configToValidate = config || this.config;
|
|
160
|
+
|
|
161
|
+
try {
|
|
162
|
+
WundrConfigSchema.parse(configToValidate);
|
|
163
|
+
return { valid: true, errors: [] };
|
|
164
|
+
} catch (error) {
|
|
165
|
+
if (error instanceof z.ZodError) {
|
|
166
|
+
return {
|
|
167
|
+
valid: false,
|
|
168
|
+
errors: error.issues.map(
|
|
169
|
+
issue => `${issue.path.join('.')}: ${issue.message}`
|
|
170
|
+
),
|
|
171
|
+
};
|
|
172
|
+
}
|
|
173
|
+
return { valid: false, errors: [error.message] };
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
/**
|
|
178
|
+
* Get configuration value by path
|
|
179
|
+
*/
|
|
180
|
+
get<T>(path: string, defaultValue?: T): T | undefined {
|
|
181
|
+
if (!this.config) {
|
|
182
|
+
return defaultValue;
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
const keys = path.split('.');
|
|
186
|
+
let value: any = this.config;
|
|
187
|
+
|
|
188
|
+
for (const key of keys) {
|
|
189
|
+
if (value && typeof value === 'object' && key in value) {
|
|
190
|
+
value = value[key];
|
|
191
|
+
} else {
|
|
192
|
+
return defaultValue;
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
return value;
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
/**
|
|
200
|
+
* Set configuration value by path
|
|
201
|
+
*/
|
|
202
|
+
set(path: string, value: any): void {
|
|
203
|
+
if (!this.config) {
|
|
204
|
+
throw new Error('Configuration not loaded. Call loadConfig() first.');
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
const keys = path.split('.');
|
|
208
|
+
let current: any = this.config;
|
|
209
|
+
|
|
210
|
+
for (let i = 0; i < keys.length - 1; i++) {
|
|
211
|
+
const key = keys[i];
|
|
212
|
+
if (!key) {
|
|
213
|
+
throw new Error(`Invalid path: empty key at position ${i}`);
|
|
214
|
+
}
|
|
215
|
+
if (!current || typeof current !== 'object') {
|
|
216
|
+
throw new Error(`Invalid path: cannot set property on non-object`);
|
|
217
|
+
}
|
|
218
|
+
if (!current[key] || typeof current[key] !== 'object') {
|
|
219
|
+
current[key] = {};
|
|
220
|
+
}
|
|
221
|
+
current = current[key];
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
const finalKey = keys[keys.length - 1];
|
|
225
|
+
if (!finalKey) {
|
|
226
|
+
throw new Error('Invalid path: empty final key');
|
|
227
|
+
}
|
|
228
|
+
if (!finalKey || !current || typeof current !== 'object') {
|
|
229
|
+
throw new Error(`Invalid path: cannot set property`);
|
|
230
|
+
}
|
|
231
|
+
current[finalKey] = value;
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
/**
|
|
235
|
+
* Create default configuration
|
|
236
|
+
*/
|
|
237
|
+
private createDefaultConfig(): WundrConfig {
|
|
238
|
+
return {
|
|
239
|
+
version: '1.0.0',
|
|
240
|
+
defaultMode: 'cli',
|
|
241
|
+
plugins: [],
|
|
242
|
+
integrations: {},
|
|
243
|
+
ai: {
|
|
244
|
+
provider: 'claude',
|
|
245
|
+
model: 'claude-3-opus-20240229',
|
|
246
|
+
},
|
|
247
|
+
analysis: {
|
|
248
|
+
patterns: ['**/*.ts', '**/*.js', '**/*.tsx', '**/*.jsx'],
|
|
249
|
+
excludes: ['**/node_modules/**', '**/dist/**', '**/build/**'],
|
|
250
|
+
maxDepth: 10,
|
|
251
|
+
},
|
|
252
|
+
governance: {
|
|
253
|
+
rules: [],
|
|
254
|
+
severity: 'warning',
|
|
255
|
+
},
|
|
256
|
+
};
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
/**
|
|
260
|
+
* Merge environment variables into configuration
|
|
261
|
+
*/
|
|
262
|
+
private mergeEnvironmentVariables(config: WundrConfig): WundrConfig {
|
|
263
|
+
const envConfig = { ...config };
|
|
264
|
+
|
|
265
|
+
// AI API Key from environment
|
|
266
|
+
if (process.env['CLAUDE_API_KEY'] && !envConfig.ai.apiKey) {
|
|
267
|
+
envConfig.ai.apiKey = process.env['CLAUDE_API_KEY'];
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
if (
|
|
271
|
+
process.env['OPENAI_API_KEY'] &&
|
|
272
|
+
envConfig.ai.provider === 'openai' &&
|
|
273
|
+
!envConfig.ai.apiKey
|
|
274
|
+
) {
|
|
275
|
+
envConfig.ai.apiKey = process.env['OPENAI_API_KEY'];
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
// AI Provider and Model from environment
|
|
279
|
+
if (process.env['WUNDR_AI_PROVIDER']) {
|
|
280
|
+
envConfig.ai.provider = process.env['WUNDR_AI_PROVIDER'];
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
if (process.env['WUNDR_AI_MODEL']) {
|
|
284
|
+
envConfig.ai.model = process.env['WUNDR_AI_MODEL'];
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
// GitHub integration
|
|
288
|
+
if (process.env['GITHUB_TOKEN']) {
|
|
289
|
+
envConfig.integrations.github = envConfig.integrations.github || {
|
|
290
|
+
token: process.env['GITHUB_TOKEN'],
|
|
291
|
+
owner: process.env['GITHUB_OWNER'] || '',
|
|
292
|
+
repo: process.env['GITHUB_REPO'] || '',
|
|
293
|
+
};
|
|
294
|
+
if (!envConfig.integrations.github.token) {
|
|
295
|
+
envConfig.integrations.github.token = process.env['GITHUB_TOKEN'];
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
return envConfig;
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
/**
|
|
303
|
+
* Get API key for AI provider with fallback mechanisms
|
|
304
|
+
*/
|
|
305
|
+
getAIApiKey(provider?: string): string | undefined {
|
|
306
|
+
const currentProvider = provider || this.config?.ai?.provider || 'claude';
|
|
307
|
+
|
|
308
|
+
// First check config
|
|
309
|
+
if (this.config?.ai?.apiKey) {
|
|
310
|
+
return this.config.ai.apiKey;
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
// Then check environment variables based on provider
|
|
314
|
+
switch (currentProvider.toLowerCase()) {
|
|
315
|
+
case 'claude':
|
|
316
|
+
return process.env['CLAUDE_API_KEY'];
|
|
317
|
+
case 'openai':
|
|
318
|
+
return process.env['OPENAI_API_KEY'];
|
|
319
|
+
default:
|
|
320
|
+
return process.env['CLAUDE_API_KEY']; // Default fallback
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
/**
|
|
325
|
+
* Set API key securely in config
|
|
326
|
+
*/
|
|
327
|
+
async setAIApiKey(apiKey: string, provider?: string): Promise<void> {
|
|
328
|
+
if (!this.config) {
|
|
329
|
+
await this.loadConfig();
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
if (provider && provider !== this.config!.ai.provider) {
|
|
333
|
+
this.config!.ai.provider = provider;
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
this.config!.ai.apiKey = apiKey;
|
|
337
|
+
await this.saveConfig();
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
/**
|
|
341
|
+
* Check if AI is properly configured
|
|
342
|
+
*/
|
|
343
|
+
isAIConfigured(): boolean {
|
|
344
|
+
const apiKey = this.getAIApiKey();
|
|
345
|
+
const provider = this.config?.ai?.provider;
|
|
346
|
+
|
|
347
|
+
return !!(apiKey && provider);
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
/**
|
|
351
|
+
* Get config file paths
|
|
352
|
+
*/
|
|
353
|
+
getConfigPaths(): { user: string; project: string } {
|
|
354
|
+
return {
|
|
355
|
+
user: this.configPath,
|
|
356
|
+
project: path.join(process.cwd(), 'wundr.config.json'),
|
|
357
|
+
};
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
/**
|
|
361
|
+
* Merge project config with user config
|
|
362
|
+
*/
|
|
363
|
+
async loadProjectConfig(): Promise<WundrConfig> {
|
|
364
|
+
const projectConfigPath = path.join(process.cwd(), 'wundr.config.json');
|
|
365
|
+
|
|
366
|
+
// Load user config first
|
|
367
|
+
await this.loadConfig();
|
|
368
|
+
|
|
369
|
+
// Merge with project config if it exists
|
|
370
|
+
if (await fs.pathExists(projectConfigPath)) {
|
|
371
|
+
try {
|
|
372
|
+
const projectConfig = await fs.readJson(projectConfigPath);
|
|
373
|
+
const validatedProjectConfig =
|
|
374
|
+
WundrConfigSchema.partial().parse(projectConfig);
|
|
375
|
+
|
|
376
|
+
this.config = {
|
|
377
|
+
...this.config!,
|
|
378
|
+
...validatedProjectConfig,
|
|
379
|
+
};
|
|
380
|
+
|
|
381
|
+
logger.debug(`Merged project config from: ${projectConfigPath}`);
|
|
382
|
+
} catch (error) {
|
|
383
|
+
const message =
|
|
384
|
+
error instanceof Error ? error.message : 'Unknown error';
|
|
385
|
+
logger.warn(`Failed to load project config: ${message}`);
|
|
386
|
+
}
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
return this.config!;
|
|
390
|
+
}
|
|
391
|
+
}
|