@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,490 @@
|
|
|
1
|
+
import axios from 'axios';
|
|
2
|
+
import { logger } from '../utils/logger';
|
|
3
|
+
import { WundrError } from '../types';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Claude API client configuration
|
|
7
|
+
*/
|
|
8
|
+
export interface ClaudeConfig {
|
|
9
|
+
apiKey: string;
|
|
10
|
+
model: string;
|
|
11
|
+
maxTokens: number;
|
|
12
|
+
temperature: number;
|
|
13
|
+
baseUrl?: string;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Claude API message structure
|
|
18
|
+
*/
|
|
19
|
+
export interface ClaudeMessage {
|
|
20
|
+
role: 'user' | 'assistant' | 'system';
|
|
21
|
+
content: string;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Claude API response structure
|
|
26
|
+
*/
|
|
27
|
+
export interface ClaudeResponse {
|
|
28
|
+
id: string;
|
|
29
|
+
object: string;
|
|
30
|
+
created: number;
|
|
31
|
+
model: string;
|
|
32
|
+
choices: {
|
|
33
|
+
index: number;
|
|
34
|
+
message: ClaudeMessage;
|
|
35
|
+
finish_reason: string;
|
|
36
|
+
}[];
|
|
37
|
+
usage: {
|
|
38
|
+
prompt_tokens: number;
|
|
39
|
+
completion_tokens: number;
|
|
40
|
+
total_tokens: number;
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Claude API streaming response
|
|
46
|
+
*/
|
|
47
|
+
export interface ClaudeStreamChunk {
|
|
48
|
+
id: string;
|
|
49
|
+
object: string;
|
|
50
|
+
created: number;
|
|
51
|
+
model: string;
|
|
52
|
+
choices: {
|
|
53
|
+
index: number;
|
|
54
|
+
delta: {
|
|
55
|
+
role?: string;
|
|
56
|
+
content?: string;
|
|
57
|
+
};
|
|
58
|
+
finish_reason?: string;
|
|
59
|
+
}[];
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Claude API client for Claude-Opus-4.1 integration
|
|
64
|
+
*/
|
|
65
|
+
export class ClaudeClient {
|
|
66
|
+
private client: any;
|
|
67
|
+
private config: ClaudeConfig;
|
|
68
|
+
|
|
69
|
+
constructor(config: ClaudeConfig) {
|
|
70
|
+
this.config = {
|
|
71
|
+
baseUrl: 'https://api.anthropic.com',
|
|
72
|
+
...config,
|
|
73
|
+
};
|
|
74
|
+
|
|
75
|
+
this.client = axios.create({
|
|
76
|
+
baseURL: this.config.baseUrl,
|
|
77
|
+
headers: {
|
|
78
|
+
'Content-Type': 'application/json',
|
|
79
|
+
'x-api-key': this.config.apiKey,
|
|
80
|
+
'anthropic-version': '2023-06-01',
|
|
81
|
+
},
|
|
82
|
+
timeout: 30000,
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
// Add request/response interceptors for logging and error handling
|
|
86
|
+
this.setupInterceptors();
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* Send a single message to Claude
|
|
91
|
+
*/
|
|
92
|
+
async sendMessage(
|
|
93
|
+
message: string,
|
|
94
|
+
systemPrompt?: string,
|
|
95
|
+
options?: Partial<ClaudeConfig>
|
|
96
|
+
): Promise<string> {
|
|
97
|
+
try {
|
|
98
|
+
const messages: ClaudeMessage[] = [];
|
|
99
|
+
|
|
100
|
+
if (systemPrompt) {
|
|
101
|
+
messages.push({ role: 'system', content: systemPrompt });
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
messages.push({ role: 'user', content: message });
|
|
105
|
+
|
|
106
|
+
const response = await this.client.post('/v1/messages', {
|
|
107
|
+
model: options?.model || this.config.model,
|
|
108
|
+
max_tokens: options?.maxTokens || this.config.maxTokens,
|
|
109
|
+
temperature: options?.temperature ?? this.config.temperature,
|
|
110
|
+
messages,
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
return this.extractContent(response.data);
|
|
114
|
+
} catch (error) {
|
|
115
|
+
throw this.handleError(error, 'Failed to send message to Claude');
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
/**
|
|
120
|
+
* Send conversation history to Claude
|
|
121
|
+
*/
|
|
122
|
+
async sendConversation(
|
|
123
|
+
messages: ClaudeMessage[],
|
|
124
|
+
systemPrompt?: string,
|
|
125
|
+
options?: Partial<ClaudeConfig>
|
|
126
|
+
): Promise<string> {
|
|
127
|
+
try {
|
|
128
|
+
const conversationMessages = [...messages];
|
|
129
|
+
|
|
130
|
+
if (systemPrompt) {
|
|
131
|
+
conversationMessages.unshift({ role: 'system', content: systemPrompt });
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
const response = await this.client.post('/v1/messages', {
|
|
135
|
+
model: options?.model || this.config.model,
|
|
136
|
+
max_tokens: options?.maxTokens || this.config.maxTokens,
|
|
137
|
+
temperature: options?.temperature ?? this.config.temperature,
|
|
138
|
+
messages: conversationMessages,
|
|
139
|
+
});
|
|
140
|
+
|
|
141
|
+
return this.extractContent(response.data);
|
|
142
|
+
} catch (error) {
|
|
143
|
+
throw this.handleError(error, 'Failed to send conversation to Claude');
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
/**
|
|
148
|
+
* Stream a conversation with Claude
|
|
149
|
+
*/
|
|
150
|
+
async *streamConversation(
|
|
151
|
+
messages: ClaudeMessage[],
|
|
152
|
+
systemPrompt?: string,
|
|
153
|
+
options?: Partial<ClaudeConfig>
|
|
154
|
+
): AsyncGenerator<string, void, unknown> {
|
|
155
|
+
try {
|
|
156
|
+
const conversationMessages = [...messages];
|
|
157
|
+
|
|
158
|
+
if (systemPrompt) {
|
|
159
|
+
conversationMessages.unshift({ role: 'system', content: systemPrompt });
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
const response = await this.client.post(
|
|
163
|
+
'/v1/messages',
|
|
164
|
+
{
|
|
165
|
+
model: options?.model || this.config.model,
|
|
166
|
+
max_tokens: options?.maxTokens || this.config.maxTokens,
|
|
167
|
+
temperature: options?.temperature ?? this.config.temperature,
|
|
168
|
+
messages: conversationMessages,
|
|
169
|
+
stream: true,
|
|
170
|
+
},
|
|
171
|
+
{
|
|
172
|
+
responseType: 'stream',
|
|
173
|
+
}
|
|
174
|
+
);
|
|
175
|
+
|
|
176
|
+
let buffer = '';
|
|
177
|
+
|
|
178
|
+
for await (const chunk of response.data) {
|
|
179
|
+
buffer += chunk.toString();
|
|
180
|
+
const lines = buffer.split('\n');
|
|
181
|
+
buffer = lines.pop() || '';
|
|
182
|
+
|
|
183
|
+
for (const line of lines) {
|
|
184
|
+
if (line.startsWith('data: ')) {
|
|
185
|
+
const data = line.slice(6);
|
|
186
|
+
if (data === '[DONE]') return;
|
|
187
|
+
|
|
188
|
+
try {
|
|
189
|
+
const parsed: ClaudeStreamChunk = JSON.parse(data);
|
|
190
|
+
const content = parsed.choices[0]?.delta?.content;
|
|
191
|
+
if (content) {
|
|
192
|
+
yield content;
|
|
193
|
+
}
|
|
194
|
+
} catch (e) {
|
|
195
|
+
// Skip malformed chunks
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
} catch (error) {
|
|
201
|
+
throw this.handleError(
|
|
202
|
+
error,
|
|
203
|
+
'Failed to stream conversation with Claude'
|
|
204
|
+
);
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
/**
|
|
209
|
+
* Analyze intent from natural language input
|
|
210
|
+
*/
|
|
211
|
+
async analyzeIntent(
|
|
212
|
+
input: string,
|
|
213
|
+
availableCommands: string[]
|
|
214
|
+
): Promise<{
|
|
215
|
+
intent: string;
|
|
216
|
+
confidence: number;
|
|
217
|
+
command?: string;
|
|
218
|
+
parameters?: Record<string, any>;
|
|
219
|
+
clarification?: string;
|
|
220
|
+
}> {
|
|
221
|
+
const systemPrompt = `You are a CLI intent analyzer. Analyze user input and determine:
|
|
222
|
+
1. The intended CLI command from available options: ${availableCommands.join(', ')}
|
|
223
|
+
2. Extracted parameters
|
|
224
|
+
3. Confidence level (0-1)
|
|
225
|
+
4. Whether clarification is needed
|
|
226
|
+
|
|
227
|
+
Respond with JSON only in this format:
|
|
228
|
+
{
|
|
229
|
+
"intent": "command_name",
|
|
230
|
+
"confidence": 0.9,
|
|
231
|
+
"command": "wundr analyze --path ./src",
|
|
232
|
+
"parameters": {"path": "./src"},
|
|
233
|
+
"clarification": "optional clarification question"
|
|
234
|
+
}`;
|
|
235
|
+
|
|
236
|
+
try {
|
|
237
|
+
const response = await this.sendMessage(input, systemPrompt, {
|
|
238
|
+
temperature: 0.2,
|
|
239
|
+
maxTokens: 1024,
|
|
240
|
+
});
|
|
241
|
+
|
|
242
|
+
return JSON.parse(response);
|
|
243
|
+
} catch (error) {
|
|
244
|
+
throw this.handleError(error, 'Failed to analyze intent');
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
/**
|
|
249
|
+
* Generate command suggestions based on context
|
|
250
|
+
*/
|
|
251
|
+
async suggestCommands(
|
|
252
|
+
projectContext: string,
|
|
253
|
+
userGoal: string,
|
|
254
|
+
availableCommands: string[]
|
|
255
|
+
): Promise<{
|
|
256
|
+
suggestions: Array<{
|
|
257
|
+
command: string;
|
|
258
|
+
description: string;
|
|
259
|
+
confidence: number;
|
|
260
|
+
}>;
|
|
261
|
+
}> {
|
|
262
|
+
const systemPrompt = `You are a CLI assistant. Based on the project context and user goal, suggest the most appropriate CLI commands.
|
|
263
|
+
|
|
264
|
+
Project Context: ${projectContext}
|
|
265
|
+
User Goal: ${userGoal}
|
|
266
|
+
Available Commands: ${availableCommands.join(', ')}
|
|
267
|
+
|
|
268
|
+
Respond with JSON only:
|
|
269
|
+
{
|
|
270
|
+
"suggestions": [
|
|
271
|
+
{
|
|
272
|
+
"command": "wundr analyze --focus dependencies",
|
|
273
|
+
"description": "Analyze project dependencies",
|
|
274
|
+
"confidence": 0.9
|
|
275
|
+
}
|
|
276
|
+
]
|
|
277
|
+
}`;
|
|
278
|
+
|
|
279
|
+
try {
|
|
280
|
+
const response = await this.sendMessage('', systemPrompt, {
|
|
281
|
+
temperature: 0.3,
|
|
282
|
+
maxTokens: 1024,
|
|
283
|
+
});
|
|
284
|
+
|
|
285
|
+
return JSON.parse(response);
|
|
286
|
+
} catch (error) {
|
|
287
|
+
throw this.handleError(error, 'Failed to generate command suggestions');
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
/**
|
|
292
|
+
* Explain command results in natural language
|
|
293
|
+
*/
|
|
294
|
+
async explainResults(
|
|
295
|
+
command: string,
|
|
296
|
+
output: string,
|
|
297
|
+
context?: string
|
|
298
|
+
): Promise<string> {
|
|
299
|
+
const systemPrompt = `You are a helpful CLI assistant. Explain the results of a CLI command in clear, natural language. Focus on:
|
|
300
|
+
1. What the command did
|
|
301
|
+
2. Key findings or results
|
|
302
|
+
3. Next steps or recommendations
|
|
303
|
+
4. Any issues or warnings
|
|
304
|
+
|
|
305
|
+
Be concise but informative.`;
|
|
306
|
+
|
|
307
|
+
const message = `Command: ${command}
|
|
308
|
+
${context ? `Context: ${context}\n` : ''}Output:
|
|
309
|
+
${output}`;
|
|
310
|
+
|
|
311
|
+
try {
|
|
312
|
+
return await this.sendMessage(message, systemPrompt, {
|
|
313
|
+
temperature: 0.4,
|
|
314
|
+
maxTokens: 2048,
|
|
315
|
+
});
|
|
316
|
+
} catch (error) {
|
|
317
|
+
throw this.handleError(error, 'Failed to explain results');
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
/**
|
|
322
|
+
* Generate help content for commands
|
|
323
|
+
*/
|
|
324
|
+
async generateHelp(
|
|
325
|
+
command: string,
|
|
326
|
+
userContext: string,
|
|
327
|
+
difficulty: 'beginner' | 'intermediate' | 'advanced' = 'intermediate'
|
|
328
|
+
): Promise<string> {
|
|
329
|
+
const systemPrompt = `You are a CLI documentation assistant. Generate helpful, contextual guidance for CLI commands. Adapt the explanation level to: ${difficulty}
|
|
330
|
+
|
|
331
|
+
Provide:
|
|
332
|
+
1. What the command does
|
|
333
|
+
2. When to use it
|
|
334
|
+
3. Common options and examples
|
|
335
|
+
4. Tips and best practices
|
|
336
|
+
5. Related commands
|
|
337
|
+
|
|
338
|
+
Keep it practical and actionable.`;
|
|
339
|
+
|
|
340
|
+
const message = `Command: ${command}
|
|
341
|
+
User Context: ${userContext}`;
|
|
342
|
+
|
|
343
|
+
try {
|
|
344
|
+
return await this.sendMessage(message, systemPrompt, {
|
|
345
|
+
temperature: 0.3,
|
|
346
|
+
maxTokens: 2048,
|
|
347
|
+
});
|
|
348
|
+
} catch (error) {
|
|
349
|
+
throw this.handleError(error, 'Failed to generate help content');
|
|
350
|
+
}
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
/**
|
|
354
|
+
* Validate and test the API connection
|
|
355
|
+
*/
|
|
356
|
+
async validateConnection(): Promise<boolean> {
|
|
357
|
+
try {
|
|
358
|
+
await this.sendMessage(
|
|
359
|
+
'Hello',
|
|
360
|
+
'Respond with just "OK" if you can understand this message.',
|
|
361
|
+
{
|
|
362
|
+
maxTokens: 10,
|
|
363
|
+
}
|
|
364
|
+
);
|
|
365
|
+
return true;
|
|
366
|
+
} catch (error) {
|
|
367
|
+
logger.error('Claude API connection validation failed:', error);
|
|
368
|
+
return false;
|
|
369
|
+
}
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
/**
|
|
373
|
+
* Get model information
|
|
374
|
+
*/
|
|
375
|
+
getModelInfo(): {
|
|
376
|
+
model: string;
|
|
377
|
+
maxTokens: number;
|
|
378
|
+
temperature: number;
|
|
379
|
+
} {
|
|
380
|
+
return {
|
|
381
|
+
model: this.config.model,
|
|
382
|
+
maxTokens: this.config.maxTokens,
|
|
383
|
+
temperature: this.config.temperature,
|
|
384
|
+
};
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
/**
|
|
388
|
+
* Update configuration
|
|
389
|
+
*/
|
|
390
|
+
updateConfig(updates: Partial<ClaudeConfig>): void {
|
|
391
|
+
this.config = { ...this.config, ...updates };
|
|
392
|
+
|
|
393
|
+
if (updates.apiKey) {
|
|
394
|
+
this.client.defaults.headers['x-api-key'] = updates.apiKey;
|
|
395
|
+
}
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
/**
|
|
399
|
+
* Extract content from Claude API response
|
|
400
|
+
*/
|
|
401
|
+
private extractContent(response: ClaudeResponse): string {
|
|
402
|
+
if (!response.choices || response.choices.length === 0) {
|
|
403
|
+
throw new Error('No choices in Claude API response');
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
return response.choices?.[0]?.message?.content || '';
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
/**
|
|
410
|
+
* Setup request/response interceptors
|
|
411
|
+
*/
|
|
412
|
+
private setupInterceptors(): void {
|
|
413
|
+
// Request interceptor
|
|
414
|
+
this.client.interceptors.request.use(
|
|
415
|
+
(config: any) => {
|
|
416
|
+
logger.debug(
|
|
417
|
+
`Claude API Request: ${config.method?.toUpperCase()} ${config.url}`
|
|
418
|
+
);
|
|
419
|
+
return config;
|
|
420
|
+
},
|
|
421
|
+
(error: any) => {
|
|
422
|
+
logger.error('Claude API Request Error:', error);
|
|
423
|
+
return Promise.reject(error);
|
|
424
|
+
}
|
|
425
|
+
);
|
|
426
|
+
|
|
427
|
+
// Response interceptor
|
|
428
|
+
this.client.interceptors.response.use(
|
|
429
|
+
(response: any) => {
|
|
430
|
+
logger.debug(
|
|
431
|
+
`Claude API Response: ${response.status} ${response.statusText}`
|
|
432
|
+
);
|
|
433
|
+
return response;
|
|
434
|
+
},
|
|
435
|
+
(error: any) => {
|
|
436
|
+
logger.error('Claude API Response Error:', error);
|
|
437
|
+
return Promise.reject(error);
|
|
438
|
+
}
|
|
439
|
+
);
|
|
440
|
+
}
|
|
441
|
+
|
|
442
|
+
/**
|
|
443
|
+
* Handle API errors and convert to WundrError
|
|
444
|
+
*/
|
|
445
|
+
private handleError(error: any, message: string): WundrError {
|
|
446
|
+
logger.error(`Claude API Error: ${message}`, error);
|
|
447
|
+
|
|
448
|
+
let errorCode = 'CLAUDE_API_ERROR';
|
|
449
|
+
let errorMessage = message;
|
|
450
|
+
let recoverable = false;
|
|
451
|
+
|
|
452
|
+
if (error.response) {
|
|
453
|
+
const status = error.response.status;
|
|
454
|
+
const data = error.response.data;
|
|
455
|
+
|
|
456
|
+
switch (status) {
|
|
457
|
+
case 401:
|
|
458
|
+
errorCode = 'CLAUDE_AUTH_ERROR';
|
|
459
|
+
errorMessage =
|
|
460
|
+
'Invalid API key. Please check your Claude API configuration.';
|
|
461
|
+
recoverable = true;
|
|
462
|
+
break;
|
|
463
|
+
case 429:
|
|
464
|
+
errorCode = 'CLAUDE_RATE_LIMIT';
|
|
465
|
+
errorMessage = 'Rate limit exceeded. Please try again in a moment.';
|
|
466
|
+
recoverable = true;
|
|
467
|
+
break;
|
|
468
|
+
case 500:
|
|
469
|
+
errorCode = 'CLAUDE_SERVER_ERROR';
|
|
470
|
+
errorMessage = 'Claude API server error. Please try again later.';
|
|
471
|
+
recoverable = true;
|
|
472
|
+
break;
|
|
473
|
+
default:
|
|
474
|
+
errorMessage = `${message}: ${data?.error?.message || error.message}`;
|
|
475
|
+
}
|
|
476
|
+
} else if (error.code === 'ECONNREFUSED' || error.code === 'ENOTFOUND') {
|
|
477
|
+
errorCode = 'CLAUDE_CONNECTION_ERROR';
|
|
478
|
+
errorMessage =
|
|
479
|
+
'Unable to connect to Claude API. Please check your internet connection.';
|
|
480
|
+
recoverable = true;
|
|
481
|
+
}
|
|
482
|
+
|
|
483
|
+
const wundrError = new Error(errorMessage) as WundrError;
|
|
484
|
+
wundrError.code = errorCode;
|
|
485
|
+
wundrError.context = { originalError: error };
|
|
486
|
+
wundrError.recoverable = recoverable;
|
|
487
|
+
|
|
488
|
+
return wundrError;
|
|
489
|
+
}
|
|
490
|
+
}
|