@wundr.io/cli 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (213) hide show
  1. package/README.md +551 -0
  2. package/bin/wundr.js +39 -0
  3. package/dist/ai/ai-service.d.ts +152 -0
  4. package/dist/ai/ai-service.d.ts.map +1 -0
  5. package/dist/ai/ai-service.js +430 -0
  6. package/dist/ai/ai-service.js.map +1 -0
  7. package/dist/ai/claude-client.d.ts +130 -0
  8. package/dist/ai/claude-client.d.ts.map +1 -0
  9. package/dist/ai/claude-client.js +339 -0
  10. package/dist/ai/claude-client.js.map +1 -0
  11. package/dist/ai/conversation-manager.d.ts +164 -0
  12. package/dist/ai/conversation-manager.d.ts.map +1 -0
  13. package/dist/ai/conversation-manager.js +612 -0
  14. package/dist/ai/conversation-manager.js.map +1 -0
  15. package/dist/ai/index.d.ts +5 -0
  16. package/dist/ai/index.d.ts.map +1 -0
  17. package/dist/ai/index.js +8 -0
  18. package/dist/ai/index.js.map +1 -0
  19. package/dist/cli.d.ts +36 -0
  20. package/dist/cli.d.ts.map +1 -0
  21. package/dist/cli.js +173 -0
  22. package/dist/cli.js.map +1 -0
  23. package/dist/commands/ai.d.ts +89 -0
  24. package/dist/commands/ai.d.ts.map +1 -0
  25. package/dist/commands/ai.js +735 -0
  26. package/dist/commands/ai.js.map +1 -0
  27. package/dist/commands/analyze-optimized.d.ts +14 -0
  28. package/dist/commands/analyze-optimized.d.ts.map +1 -0
  29. package/dist/commands/analyze-optimized.js +437 -0
  30. package/dist/commands/analyze-optimized.js.map +1 -0
  31. package/dist/commands/analyze.d.ts +65 -0
  32. package/dist/commands/analyze.d.ts.map +1 -0
  33. package/dist/commands/analyze.js +435 -0
  34. package/dist/commands/analyze.js.map +1 -0
  35. package/dist/commands/batch.d.ts +71 -0
  36. package/dist/commands/batch.d.ts.map +1 -0
  37. package/dist/commands/batch.js +738 -0
  38. package/dist/commands/batch.js.map +1 -0
  39. package/dist/commands/chat.d.ts +71 -0
  40. package/dist/commands/chat.d.ts.map +1 -0
  41. package/dist/commands/chat.js +674 -0
  42. package/dist/commands/chat.js.map +1 -0
  43. package/dist/commands/claude-init.d.ts +28 -0
  44. package/dist/commands/claude-init.d.ts.map +1 -0
  45. package/dist/commands/claude-init.js +587 -0
  46. package/dist/commands/claude-init.js.map +1 -0
  47. package/dist/commands/claude-setup.d.ts +32 -0
  48. package/dist/commands/claude-setup.d.ts.map +1 -0
  49. package/dist/commands/claude-setup.js +570 -0
  50. package/dist/commands/claude-setup.js.map +1 -0
  51. package/dist/commands/computer-setup-commands.d.ts +39 -0
  52. package/dist/commands/computer-setup-commands.d.ts.map +1 -0
  53. package/dist/commands/computer-setup-commands.js +563 -0
  54. package/dist/commands/computer-setup-commands.js.map +1 -0
  55. package/dist/commands/computer-setup.d.ts +7 -0
  56. package/dist/commands/computer-setup.d.ts.map +1 -0
  57. package/dist/commands/computer-setup.js +481 -0
  58. package/dist/commands/computer-setup.js.map +1 -0
  59. package/dist/commands/create-command.d.ts +7 -0
  60. package/dist/commands/create-command.d.ts.map +1 -0
  61. package/dist/commands/create-command.js +158 -0
  62. package/dist/commands/create-command.js.map +1 -0
  63. package/dist/commands/create.d.ts +74 -0
  64. package/dist/commands/create.d.ts.map +1 -0
  65. package/dist/commands/create.js +556 -0
  66. package/dist/commands/create.js.map +1 -0
  67. package/dist/commands/dashboard.d.ts +91 -0
  68. package/dist/commands/dashboard.d.ts.map +1 -0
  69. package/dist/commands/dashboard.js +537 -0
  70. package/dist/commands/dashboard.js.map +1 -0
  71. package/dist/commands/govern.d.ts +70 -0
  72. package/dist/commands/govern.d.ts.map +1 -0
  73. package/dist/commands/govern.js +480 -0
  74. package/dist/commands/govern.js.map +1 -0
  75. package/dist/commands/init.d.ts +55 -0
  76. package/dist/commands/init.d.ts.map +1 -0
  77. package/dist/commands/init.js +584 -0
  78. package/dist/commands/init.js.map +1 -0
  79. package/dist/commands/performance-optimizer.d.ts +30 -0
  80. package/dist/commands/performance-optimizer.d.ts.map +1 -0
  81. package/dist/commands/performance-optimizer.js +649 -0
  82. package/dist/commands/performance-optimizer.js.map +1 -0
  83. package/dist/commands/plugins.d.ts +87 -0
  84. package/dist/commands/plugins.d.ts.map +1 -0
  85. package/dist/commands/plugins.js +685 -0
  86. package/dist/commands/plugins.js.map +1 -0
  87. package/dist/commands/setup.d.ts +29 -0
  88. package/dist/commands/setup.d.ts.map +1 -0
  89. package/dist/commands/setup.js +399 -0
  90. package/dist/commands/setup.js.map +1 -0
  91. package/dist/commands/test-init.d.ts +9 -0
  92. package/dist/commands/test-init.d.ts.map +1 -0
  93. package/dist/commands/test-init.js +222 -0
  94. package/dist/commands/test-init.js.map +1 -0
  95. package/dist/commands/test.d.ts +25 -0
  96. package/dist/commands/test.d.ts.map +1 -0
  97. package/dist/commands/test.js +217 -0
  98. package/dist/commands/test.js.map +1 -0
  99. package/dist/commands/watch.d.ts +76 -0
  100. package/dist/commands/watch.d.ts.map +1 -0
  101. package/dist/commands/watch.js +610 -0
  102. package/dist/commands/watch.js.map +1 -0
  103. package/dist/context/context-manager.d.ts +155 -0
  104. package/dist/context/context-manager.d.ts.map +1 -0
  105. package/dist/context/context-manager.js +383 -0
  106. package/dist/context/context-manager.js.map +1 -0
  107. package/dist/context/index.d.ts +3 -0
  108. package/dist/context/index.d.ts.map +1 -0
  109. package/dist/context/index.js +6 -0
  110. package/dist/context/index.js.map +1 -0
  111. package/dist/context/session-manager.d.ts +207 -0
  112. package/dist/context/session-manager.d.ts.map +1 -0
  113. package/dist/context/session-manager.js +682 -0
  114. package/dist/context/session-manager.js.map +1 -0
  115. package/dist/index.d.ts +8 -0
  116. package/dist/index.d.ts.map +1 -0
  117. package/dist/index.js +51 -0
  118. package/dist/index.js.map +1 -0
  119. package/dist/interactive/interactive-mode.d.ts +76 -0
  120. package/dist/interactive/interactive-mode.d.ts.map +1 -0
  121. package/dist/interactive/interactive-mode.js +730 -0
  122. package/dist/interactive/interactive-mode.js.map +1 -0
  123. package/dist/nlp/command-mapper.d.ts +174 -0
  124. package/dist/nlp/command-mapper.d.ts.map +1 -0
  125. package/dist/nlp/command-mapper.js +623 -0
  126. package/dist/nlp/command-mapper.js.map +1 -0
  127. package/dist/nlp/command-parser.d.ts +106 -0
  128. package/dist/nlp/command-parser.d.ts.map +1 -0
  129. package/dist/nlp/command-parser.js +416 -0
  130. package/dist/nlp/command-parser.js.map +1 -0
  131. package/dist/nlp/index.d.ts +5 -0
  132. package/dist/nlp/index.d.ts.map +1 -0
  133. package/dist/nlp/index.js +8 -0
  134. package/dist/nlp/index.js.map +1 -0
  135. package/dist/nlp/intent-classifier.d.ts +59 -0
  136. package/dist/nlp/intent-classifier.d.ts.map +1 -0
  137. package/dist/nlp/intent-classifier.js +384 -0
  138. package/dist/nlp/intent-classifier.js.map +1 -0
  139. package/dist/nlp/intent-parser.d.ts +152 -0
  140. package/dist/nlp/intent-parser.d.ts.map +1 -0
  141. package/dist/nlp/intent-parser.js +739 -0
  142. package/dist/nlp/intent-parser.js.map +1 -0
  143. package/dist/plugins/plugin-manager.d.ts +120 -0
  144. package/dist/plugins/plugin-manager.d.ts.map +1 -0
  145. package/dist/plugins/plugin-manager.js +595 -0
  146. package/dist/plugins/plugin-manager.js.map +1 -0
  147. package/dist/types/index.d.ts +224 -0
  148. package/dist/types/index.d.ts.map +1 -0
  149. package/dist/types/index.js +3 -0
  150. package/dist/types/index.js.map +1 -0
  151. package/dist/utils/config-manager.d.ts +73 -0
  152. package/dist/utils/config-manager.d.ts.map +1 -0
  153. package/dist/utils/config-manager.js +339 -0
  154. package/dist/utils/config-manager.js.map +1 -0
  155. package/dist/utils/error-handler.d.ts +46 -0
  156. package/dist/utils/error-handler.d.ts.map +1 -0
  157. package/dist/utils/error-handler.js +169 -0
  158. package/dist/utils/error-handler.js.map +1 -0
  159. package/dist/utils/logger.d.ts +25 -0
  160. package/dist/utils/logger.d.ts.map +1 -0
  161. package/dist/utils/logger.js +94 -0
  162. package/dist/utils/logger.js.map +1 -0
  163. package/package.json +119 -0
  164. package/src/ai/ai-service.ts +595 -0
  165. package/src/ai/claude-client.ts +490 -0
  166. package/src/ai/conversation-manager.ts +907 -0
  167. package/src/ai/index.ts +8 -0
  168. package/src/cli.ts +202 -0
  169. package/src/commands/ai.ts +995 -0
  170. package/src/commands/analyze-optimized.ts +641 -0
  171. package/src/commands/analyze.ts +576 -0
  172. package/src/commands/batch.ts +935 -0
  173. package/src/commands/chat.ts +876 -0
  174. package/src/commands/claude-init.ts +715 -0
  175. package/src/commands/claude-setup.ts +697 -0
  176. package/src/commands/computer-setup-commands.ts +709 -0
  177. package/src/commands/computer-setup.ts +565 -0
  178. package/src/commands/create-command.ts +175 -0
  179. package/src/commands/create.ts +727 -0
  180. package/src/commands/dashboard.ts +691 -0
  181. package/src/commands/govern.ts +635 -0
  182. package/src/commands/init.ts +677 -0
  183. package/src/commands/performance-optimizer.ts +864 -0
  184. package/src/commands/plugins.ts +848 -0
  185. package/src/commands/setup.ts +508 -0
  186. package/src/commands/test-init.ts +242 -0
  187. package/src/commands/test.ts +264 -0
  188. package/src/commands/watch.ts +755 -0
  189. package/src/context/context-manager.ts +546 -0
  190. package/src/context/index.ts +9 -0
  191. package/src/context/session-manager.ts +1019 -0
  192. package/src/index.ts +64 -0
  193. package/src/interactive/interactive-mode.ts +830 -0
  194. package/src/nlp/command-mapper.ts +885 -0
  195. package/src/nlp/command-parser.ts +564 -0
  196. package/src/nlp/index.ts +4 -0
  197. package/src/nlp/intent-classifier.ts +458 -0
  198. package/src/nlp/intent-parser.ts +1101 -0
  199. package/src/plugins/plugin-manager.ts +744 -0
  200. package/src/types/index.ts +252 -0
  201. package/src/types/modules.d.ts +56 -0
  202. package/src/utils/config-manager.ts +391 -0
  203. package/src/utils/error-handler.ts +192 -0
  204. package/src/utils/logger.ts +104 -0
  205. package/templates/batch/ci-cd.yaml +62 -0
  206. package/templates/component/{{fileName}}.test.tsx +17 -0
  207. package/templates/component/{{fileName}}.tsx +21 -0
  208. package/templates/service/{{fileName}}.ts +98 -0
  209. package/templates/wundr-test.config.js +0 -0
  210. package/test-suites/api/health.spec.ts +134 -0
  211. package/test-suites/helpers/test-config.ts +84 -0
  212. package/test-suites/ui/accessibility.spec.ts +102 -0
  213. package/test-suites/ui/smoke.spec.ts +92 -0
@@ -0,0 +1,595 @@
1
+ import { ClaudeClient, ClaudeMessage } from './claude-client';
2
+ import { ConfigManager } from '../utils/config-manager';
3
+ import { logger } from '../utils/logger';
4
+ import { ChatSession, ChatMessage } from '../types';
5
+
6
+ /**
7
+ * AI service configuration
8
+ */
9
+ export interface AIServiceConfig {
10
+ provider: 'claude' | 'openai' | 'local';
11
+ model: string;
12
+ apiKey?: string;
13
+ baseUrl?: string;
14
+ maxTokens?: number;
15
+ temperature?: number;
16
+ systemPrompt?: string;
17
+ }
18
+
19
+ /**
20
+ * AI conversation context
21
+ */
22
+ export interface ConversationContext {
23
+ projectPath?: string;
24
+ projectType?: string;
25
+ recentCommands?: string[];
26
+ currentGoal?: string;
27
+ userPreferences?: Record<string, any>;
28
+ sessionMetadata?: Record<string, any>;
29
+ }
30
+
31
+ /**
32
+ * AI service for managing all AI interactions
33
+ */
34
+ export class AIService {
35
+ private claudeClient?: ClaudeClient;
36
+ private config: AIServiceConfig;
37
+ private configManager: ConfigManager;
38
+ private conversationHistory: Map<string, ClaudeMessage[]> = new Map();
39
+
40
+ constructor(configManager: ConfigManager) {
41
+ this.configManager = configManager;
42
+ this.config = this.loadAIConfig();
43
+ this.initializeProvider();
44
+ }
45
+
46
+ /**
47
+ * Initialize AI provider based on configuration
48
+ */
49
+ private initializeProvider(): void {
50
+ try {
51
+ if (this.config.provider === 'claude') {
52
+ if (!this.config.apiKey) {
53
+ logger.warn(
54
+ 'Claude API key not configured. AI features will be limited.'
55
+ );
56
+ logger.info('Configure your API key using: wundr ai setup');
57
+ logger.info('Or set the CLAUDE_API_KEY environment variable');
58
+ return; // Don't throw error, just warn
59
+ }
60
+
61
+ this.claudeClient = new ClaudeClient({
62
+ apiKey: this.config.apiKey,
63
+ model: this.config.model || 'claude-3-opus-20240229',
64
+ maxTokens: this.config.maxTokens || 4096,
65
+ temperature: this.config.temperature || 0.7,
66
+ baseUrl: this.config.baseUrl,
67
+ });
68
+
69
+ logger.info(
70
+ `Initialized Claude client with model: ${this.config.model}`
71
+ );
72
+ } else {
73
+ throw new Error(`Unsupported AI provider: ${this.config.provider}`);
74
+ }
75
+ } catch (error) {
76
+ logger.error('Failed to initialize AI provider:', error);
77
+ // Don't re-throw to avoid breaking CLI startup
78
+ }
79
+ }
80
+
81
+ /**
82
+ * Load AI configuration from config manager
83
+ */
84
+ private loadAIConfig(): AIServiceConfig {
85
+ try {
86
+ const wundrConfig = this.configManager.getConfig();
87
+ const apiKey = this.configManager.getAIApiKey();
88
+
89
+ return {
90
+ provider: (wundrConfig.ai?.provider || 'claude') as 'claude',
91
+ model: wundrConfig.ai?.model || 'claude-3-opus-20240229',
92
+ apiKey: apiKey,
93
+ maxTokens: 4096,
94
+ temperature: 0.7,
95
+ systemPrompt:
96
+ 'You are a helpful CLI assistant for the Wundr development platform.',
97
+ };
98
+ } catch (error) {
99
+ logger.warn('Failed to load AI configuration, using defaults');
100
+ return {
101
+ provider: 'claude',
102
+ model: 'claude-3-opus-20240229',
103
+ apiKey: process.env['CLAUDE_API_KEY'],
104
+ maxTokens: 4096,
105
+ temperature: 0.7,
106
+ systemPrompt:
107
+ 'You are a helpful CLI assistant for the Wundr development platform.',
108
+ };
109
+ }
110
+ }
111
+
112
+ /**
113
+ * Send a message with conversation context
114
+ */
115
+ async sendMessage(
116
+ sessionId: string,
117
+ message: string,
118
+ context?: ConversationContext
119
+ ): Promise<string> {
120
+ this.ensureClientInitialized();
121
+
122
+ try {
123
+ const conversationMessages = this.getConversationHistory(sessionId);
124
+
125
+ // Add user message to history
126
+ conversationMessages.push({
127
+ role: 'user',
128
+ content: message,
129
+ });
130
+
131
+ const systemPrompt = this.buildSystemPrompt(context);
132
+ const response = await this.claudeClient!.sendConversation(
133
+ conversationMessages,
134
+ systemPrompt
135
+ );
136
+
137
+ // Add AI response to history
138
+ conversationMessages.push({
139
+ role: 'assistant',
140
+ content: response,
141
+ });
142
+
143
+ // Store updated conversation history
144
+ this.conversationHistory.set(sessionId, conversationMessages);
145
+
146
+ return response;
147
+ } catch (error) {
148
+ logger.error('Failed to send message:', error);
149
+ throw error;
150
+ }
151
+ }
152
+
153
+ /**
154
+ * Stream a conversation response
155
+ */
156
+ async *streamMessage(
157
+ sessionId: string,
158
+ message: string,
159
+ context?: ConversationContext
160
+ ): AsyncGenerator<string, string, unknown> {
161
+ this.ensureClientInitialized();
162
+
163
+ try {
164
+ const conversationMessages = this.getConversationHistory(sessionId);
165
+
166
+ // Add user message to history
167
+ conversationMessages.push({
168
+ role: 'user',
169
+ content: message,
170
+ });
171
+
172
+ const systemPrompt = this.buildSystemPrompt(context);
173
+ let fullResponse = '';
174
+
175
+ for await (const chunk of this.claudeClient!.streamConversation(
176
+ conversationMessages,
177
+ systemPrompt
178
+ )) {
179
+ fullResponse += chunk;
180
+ yield chunk;
181
+ }
182
+
183
+ // Add AI response to history
184
+ conversationMessages.push({
185
+ role: 'assistant',
186
+ content: fullResponse,
187
+ });
188
+
189
+ // Store updated conversation history
190
+ this.conversationHistory.set(sessionId, conversationMessages);
191
+
192
+ return fullResponse;
193
+ } catch (error) {
194
+ logger.error('Failed to stream message:', error);
195
+ throw error;
196
+ }
197
+ }
198
+
199
+ /**
200
+ * Analyze natural language input and convert to CLI command
201
+ */
202
+ async parseNaturalLanguageCommand(
203
+ input: string,
204
+ _context?: ConversationContext
205
+ ): Promise<{
206
+ intent: string;
207
+ command: string;
208
+ confidence: number;
209
+ parameters: Record<string, any>;
210
+ needsConfirmation: boolean;
211
+ clarificationQuestion?: string;
212
+ }> {
213
+ this.ensureClientInitialized();
214
+
215
+ try {
216
+ const availableCommands = [
217
+ 'wundr init',
218
+ 'wundr create',
219
+ 'wundr analyze',
220
+ 'wundr govern',
221
+ 'wundr dashboard',
222
+ 'wundr watch',
223
+ 'wundr batch',
224
+ 'wundr plugins',
225
+ ];
226
+
227
+ const result = await this.claudeClient!.analyzeIntent(
228
+ input,
229
+ availableCommands
230
+ );
231
+
232
+ return {
233
+ intent: result.intent,
234
+ command: result.command || '',
235
+ confidence: result.confidence,
236
+ parameters: result.parameters || {},
237
+ needsConfirmation: result.confidence < 0.8,
238
+ clarificationQuestion: result.clarification,
239
+ };
240
+ } catch (error) {
241
+ logger.error('Failed to parse natural language command:', error);
242
+ throw error;
243
+ }
244
+ }
245
+
246
+ /**
247
+ * Generate contextual command suggestions
248
+ */
249
+ async suggestCommands(
250
+ goal: string,
251
+ context?: ConversationContext
252
+ ): Promise<
253
+ Array<{
254
+ command: string;
255
+ description: string;
256
+ confidence: number;
257
+ rationale: string;
258
+ }>
259
+ > {
260
+ this.ensureClientInitialized();
261
+
262
+ try {
263
+ const projectContext = this.buildProjectContext(context);
264
+ const availableCommands = [
265
+ 'wundr init - Initialize project or configuration',
266
+ 'wundr create - Create new components, services, templates',
267
+ 'wundr analyze - Analyze code, dependencies, quality',
268
+ 'wundr govern - Apply governance rules and compliance',
269
+ 'wundr dashboard - Start dashboard and visualization',
270
+ 'wundr watch - Monitor files and run automated tasks',
271
+ 'wundr batch - Execute batch operations',
272
+ 'wundr plugins - Manage CLI plugins',
273
+ 'wundr chat - Interactive AI assistance',
274
+ ];
275
+
276
+ const result = await this.claudeClient!.suggestCommands(
277
+ projectContext,
278
+ goal,
279
+ availableCommands
280
+ );
281
+
282
+ return result.suggestions.map(suggestion => ({
283
+ ...suggestion,
284
+ rationale: `Based on your goal and project context, this command will help you ${suggestion.description.toLowerCase()}`,
285
+ }));
286
+ } catch (error) {
287
+ logger.error('Failed to generate command suggestions:', error);
288
+ throw error;
289
+ }
290
+ }
291
+
292
+ /**
293
+ * Explain command results in natural language
294
+ */
295
+ async explainCommandResults(
296
+ command: string,
297
+ output: string,
298
+ context?: ConversationContext
299
+ ): Promise<string> {
300
+ this.ensureClientInitialized();
301
+
302
+ try {
303
+ const contextString = context
304
+ ? this.buildProjectContext(context)
305
+ : undefined;
306
+ return await this.claudeClient!.explainResults(
307
+ command,
308
+ output,
309
+ contextString
310
+ );
311
+ } catch (error) {
312
+ logger.error('Failed to explain command results:', error);
313
+ throw error;
314
+ }
315
+ }
316
+
317
+ /**
318
+ * Generate contextual help for commands
319
+ */
320
+ async generateContextualHelp(
321
+ command: string,
322
+ context?: ConversationContext,
323
+ userLevel: 'beginner' | 'intermediate' | 'advanced' = 'intermediate'
324
+ ): Promise<string> {
325
+ this.ensureClientInitialized();
326
+
327
+ try {
328
+ const userContext = this.buildProjectContext(context);
329
+ return await this.claudeClient!.generateHelp(
330
+ command,
331
+ userContext,
332
+ userLevel
333
+ );
334
+ } catch (error) {
335
+ logger.error('Failed to generate contextual help:', error);
336
+ throw error;
337
+ }
338
+ }
339
+
340
+ /**
341
+ * Convert ChatSession to conversation history
342
+ */
343
+ loadChatSession(session: ChatSession): void {
344
+ const messages: ClaudeMessage[] = session.history.map(msg => ({
345
+ role: msg.role as 'user' | 'assistant' | 'system',
346
+ content: msg.content,
347
+ }));
348
+
349
+ this.conversationHistory.set(session.id, messages);
350
+ }
351
+
352
+ /**
353
+ * Export conversation history to ChatSession format
354
+ */
355
+ exportChatSession(sessionId: string): ChatMessage[] {
356
+ const messages = this.conversationHistory.get(sessionId) || [];
357
+
358
+ return messages.map(msg => ({
359
+ role: msg.role as 'user' | 'assistant' | 'system',
360
+ content: msg.content,
361
+ timestamp: new Date(),
362
+ metadata: {},
363
+ }));
364
+ }
365
+
366
+ /**
367
+ * Clear conversation history for a session
368
+ */
369
+ clearConversation(sessionId: string): void {
370
+ this.conversationHistory.delete(sessionId);
371
+ }
372
+
373
+ /**
374
+ * Get conversation history for a session
375
+ */
376
+ private getConversationHistory(sessionId: string): ClaudeMessage[] {
377
+ return this.conversationHistory.get(sessionId) || [];
378
+ }
379
+
380
+ /**
381
+ * Build system prompt with context
382
+ */
383
+ private buildSystemPrompt(context?: ConversationContext): string {
384
+ let systemPrompt =
385
+ this.config.systemPrompt ||
386
+ 'You are a helpful CLI assistant for the Wundr development platform.';
387
+
388
+ if (context) {
389
+ systemPrompt += '\n\nContext Information:';
390
+
391
+ if (context.projectPath) {
392
+ systemPrompt += `\n- Project Path: ${context.projectPath}`;
393
+ }
394
+
395
+ if (context.projectType) {
396
+ systemPrompt += `\n- Project Type: ${context.projectType}`;
397
+ }
398
+
399
+ if (context.recentCommands?.length) {
400
+ systemPrompt += `\n- Recent Commands: ${context.recentCommands.join(', ')}`;
401
+ }
402
+
403
+ if (context.currentGoal) {
404
+ systemPrompt += `\n- Current Goal: ${context.currentGoal}`;
405
+ }
406
+ }
407
+
408
+ systemPrompt += `\n\nYou should:
409
+ 1. Provide helpful, accurate responses
410
+ 2. Suggest appropriate CLI commands when relevant
411
+ 3. Explain technical concepts clearly
412
+ 4. Ask for clarification when needed
413
+ 5. Focus on practical, actionable advice`;
414
+
415
+ return systemPrompt;
416
+ }
417
+
418
+ /**
419
+ * Build project context string
420
+ */
421
+ private buildProjectContext(context?: ConversationContext): string {
422
+ if (!context) {
423
+ return 'No project context available';
424
+ }
425
+
426
+ const parts: string[] = [];
427
+
428
+ if (context.projectPath) {
429
+ parts.push(`Project: ${context.projectPath}`);
430
+ }
431
+
432
+ if (context.projectType) {
433
+ parts.push(`Type: ${context.projectType}`);
434
+ }
435
+
436
+ if (context.recentCommands?.length) {
437
+ parts.push(`Recent commands: ${context.recentCommands.join(', ')}`);
438
+ }
439
+
440
+ if (context.currentGoal) {
441
+ parts.push(`Goal: ${context.currentGoal}`);
442
+ }
443
+
444
+ return parts.join(' | ') || 'Standard development project';
445
+ }
446
+
447
+ /**
448
+ * Validate AI service connection
449
+ */
450
+ async validateConnection(): Promise<{
451
+ connected: boolean;
452
+ error?: string;
453
+ provider: string;
454
+ model: string;
455
+ }> {
456
+ if (!this.claudeClient) {
457
+ return {
458
+ connected: false,
459
+ error: 'AI client not initialized. API key may be missing.',
460
+ provider: this.config.provider,
461
+ model: this.config.model,
462
+ };
463
+ }
464
+
465
+ try {
466
+ const isValid = await this.claudeClient.validateConnection();
467
+ return {
468
+ connected: isValid,
469
+ provider: this.config.provider,
470
+ model: this.config.model,
471
+ };
472
+ } catch (error: any) {
473
+ logger.error('AI connection validation failed:', error);
474
+ return {
475
+ connected: false,
476
+ error: error.message || 'Connection validation failed',
477
+ provider: this.config.provider,
478
+ model: this.config.model,
479
+ };
480
+ }
481
+ }
482
+
483
+ /**
484
+ * Ensure client is initialized and throw helpful error if not
485
+ */
486
+ private ensureClientInitialized(): void {
487
+ if (!this.claudeClient) {
488
+ const configuredKey = this.configManager.getAIApiKey();
489
+
490
+ if (!configuredKey) {
491
+ throw new Error(
492
+ `AI API key not configured.\n\nTo set up AI features:\n1. Run: wundr ai setup\n2. Or set environment variable: export CLAUDE_API_KEY=your_key_here\n3. Or add to config: wundr ai config set apiKey your_key_here`
493
+ );
494
+ }
495
+
496
+ throw new Error(
497
+ 'AI client failed to initialize. Please check your configuration.'
498
+ );
499
+ }
500
+ }
501
+
502
+ /**
503
+ * Setup AI configuration with API key
504
+ */
505
+ async setupAI(apiKey: string, provider: string = 'claude'): Promise<void> {
506
+ try {
507
+ // Save API key to config
508
+ await this.configManager.setAIApiKey(apiKey, provider);
509
+
510
+ // Update service configuration
511
+ this.config = this.loadAIConfig();
512
+
513
+ // Re-initialize provider
514
+ this.initializeProvider();
515
+
516
+ logger.success(`AI configured successfully with ${provider} provider`);
517
+ } catch (error) {
518
+ logger.error('Failed to setup AI configuration:', error);
519
+ throw error;
520
+ }
521
+ }
522
+
523
+ /**
524
+ * Check if AI is ready to use
525
+ */
526
+ isReady(): boolean {
527
+ return !!this.claudeClient && !!this.config.apiKey;
528
+ }
529
+
530
+ /**
531
+ * Get configuration status
532
+ */
533
+ getStatus(): {
534
+ configured: boolean;
535
+ provider: string;
536
+ model: string;
537
+ hasApiKey: boolean;
538
+ ready: boolean;
539
+ } {
540
+ const hasApiKey = !!this.config.apiKey;
541
+ return {
542
+ configured: this.configManager.isAIConfigured(),
543
+ provider: this.config.provider,
544
+ model: this.config.model,
545
+ hasApiKey,
546
+ ready: this.isReady(),
547
+ };
548
+ }
549
+
550
+ /**
551
+ * Update AI configuration
552
+ */
553
+ updateConfig(updates: Partial<AIServiceConfig>): void {
554
+ this.config = { ...this.config, ...updates };
555
+
556
+ if (this.config.provider === 'claude' && this.claudeClient) {
557
+ this.claudeClient.updateConfig({
558
+ apiKey: this.config.apiKey,
559
+ model: this.config.model,
560
+ maxTokens: this.config.maxTokens,
561
+ temperature: this.config.temperature,
562
+ });
563
+ }
564
+ }
565
+
566
+ /**
567
+ * Get current AI configuration
568
+ */
569
+ getConfig(): AIServiceConfig {
570
+ return { ...this.config };
571
+ }
572
+
573
+ /**
574
+ * Get provider-specific information
575
+ */
576
+ getProviderInfo(): {
577
+ provider: string;
578
+ model: string;
579
+ connected: boolean;
580
+ capabilities: string[];
581
+ } {
582
+ return {
583
+ provider: this.config.provider,
584
+ model: this.config.model,
585
+ connected: !!this.claudeClient,
586
+ capabilities: [
587
+ 'natural-language-parsing',
588
+ 'command-suggestions',
589
+ 'result-explanation',
590
+ 'contextual-help',
591
+ 'conversation-memory',
592
+ ],
593
+ };
594
+ }
595
+ }