@hailer/mcp 0.1.11 → 0.1.13

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 (59) hide show
  1. package/.claude/settings.json +12 -0
  2. package/CLAUDE.md +37 -1
  3. package/dist/app.js +5 -0
  4. package/dist/client/agents/base.d.ts +5 -0
  5. package/dist/client/agents/base.js +9 -2
  6. package/dist/client/agents/definitions.js +85 -0
  7. package/dist/client/agents/orchestrator.d.ts +21 -0
  8. package/dist/client/agents/orchestrator.js +292 -1
  9. package/dist/client/bot-entrypoint.d.ts +7 -0
  10. package/dist/client/bot-entrypoint.js +103 -0
  11. package/dist/client/bot-runner.d.ts +35 -0
  12. package/dist/client/bot-runner.js +188 -0
  13. package/dist/client/factory.d.ts +4 -0
  14. package/dist/client/factory.js +10 -0
  15. package/dist/client/server.d.ts +8 -0
  16. package/dist/client/server.js +251 -0
  17. package/dist/client/types.d.ts +29 -0
  18. package/dist/client/types.js +4 -1
  19. package/dist/core.d.ts +3 -0
  20. package/dist/core.js +72 -0
  21. package/dist/mcp/hailer-clients.d.ts +4 -0
  22. package/dist/mcp/hailer-clients.js +16 -1
  23. package/dist/mcp/tools/app-scaffold.js +127 -5
  24. package/dist/mcp/tools/bot-config.d.ts +78 -0
  25. package/dist/mcp/tools/bot-config.js +442 -0
  26. package/dist/mcp-server.js +109 -1
  27. package/dist/modules/bug-reports/bug-config.d.ts +25 -0
  28. package/dist/modules/bug-reports/bug-config.js +187 -0
  29. package/dist/modules/bug-reports/bug-monitor.d.ts +108 -0
  30. package/dist/modules/bug-reports/bug-monitor.js +510 -0
  31. package/dist/modules/bug-reports/giuseppe-ai.d.ts +59 -0
  32. package/dist/modules/bug-reports/giuseppe-ai.js +335 -0
  33. package/dist/modules/bug-reports/giuseppe-bot.d.ts +109 -0
  34. package/dist/modules/bug-reports/giuseppe-bot.js +765 -0
  35. package/dist/modules/bug-reports/giuseppe-files.d.ts +52 -0
  36. package/dist/modules/bug-reports/giuseppe-files.js +338 -0
  37. package/dist/modules/bug-reports/giuseppe-git.d.ts +48 -0
  38. package/dist/modules/bug-reports/giuseppe-git.js +298 -0
  39. package/dist/modules/bug-reports/giuseppe-prompt.d.ts +5 -0
  40. package/dist/modules/bug-reports/giuseppe-prompt.js +94 -0
  41. package/dist/modules/bug-reports/index.d.ts +76 -0
  42. package/dist/modules/bug-reports/index.js +213 -0
  43. package/dist/modules/bug-reports/pending-classification-registry.d.ts +28 -0
  44. package/dist/modules/bug-reports/pending-classification-registry.js +50 -0
  45. package/dist/modules/bug-reports/pending-fix-registry.d.ts +30 -0
  46. package/dist/modules/bug-reports/pending-fix-registry.js +42 -0
  47. package/dist/modules/bug-reports/pending-registry.d.ts +27 -0
  48. package/dist/modules/bug-reports/pending-registry.js +49 -0
  49. package/dist/modules/bug-reports/types.d.ts +123 -0
  50. package/dist/modules/bug-reports/types.js +9 -0
  51. package/dist/services/bug-monitor.d.ts +23 -0
  52. package/dist/services/bug-monitor.js +275 -0
  53. package/package.json +6 -2
  54. package/.claude.tar.xz +0 -0
  55. package/lineup-manager/dist/assets/index-8ce6041d.css +0 -1
  56. package/lineup-manager/dist/assets/index-e168f265.js +0 -600
  57. package/lineup-manager/dist/index.html +0 -15
  58. package/lineup-manager/dist/manifest.json +0 -17
  59. package/lineup-manager/dist/vite.svg +0 -1
@@ -0,0 +1,335 @@
1
+ "use strict";
2
+ /**
3
+ * Giuseppe AI Module - Claude API interactions for bug analysis and fix generation
4
+ */
5
+ var __importDefault = (this && this.__importDefault) || function (mod) {
6
+ return (mod && mod.__esModule) ? mod : { "default": mod };
7
+ };
8
+ Object.defineProperty(exports, "__esModule", { value: true });
9
+ exports.GiuseppeAI = void 0;
10
+ const sdk_1 = __importDefault(require("@anthropic-ai/sdk"));
11
+ const logger_1 = require("../../lib/logger");
12
+ const giuseppe_prompt_1 = require("./giuseppe-prompt");
13
+ const logger = (0, logger_1.createLogger)({ component: 'giuseppe-ai' });
14
+ class GiuseppeAI {
15
+ anthropic;
16
+ constructor(apiKey) {
17
+ if (apiKey) {
18
+ this.anthropic = new sdk_1.default({ apiKey });
19
+ }
20
+ }
21
+ get isAvailable() {
22
+ return !!this.anthropic;
23
+ }
24
+ /**
25
+ * Classify a report as bug or feature request
26
+ */
27
+ async classifyReport(bug) {
28
+ if (!this.anthropic) {
29
+ return { classification: 'unclear', reason: 'No AI available for classification' };
30
+ }
31
+ try {
32
+ const prompt = `Classify this report as either a BUG or a FEATURE REQUEST.
33
+
34
+ **Title:** ${bug.name}
35
+ **Description:** ${bug.description || 'No description'}
36
+ ${bug.stepsToReproduce ? `**Steps:** ${bug.stepsToReproduce}` : ''}
37
+ ${bug.expectedBehavior ? `**Expected:** ${bug.expectedBehavior}` : ''}
38
+ ${bug.actualBehavior ? `**Actual:** ${bug.actualBehavior}` : ''}
39
+
40
+ A BUG is something BROKEN - it was working or should work but doesn't.
41
+ Examples: "button doesn't respond", "crashes when clicking", "data not saving", "display is wrong"
42
+
43
+ A FEATURE REQUEST is asking for something NEW or DIFFERENT - not broken, just wanted.
44
+ Examples: "change color to blue", "add dark mode", "make it bigger", "add new button"
45
+
46
+ Respond with JSON only:
47
+ {
48
+ "classification": "bug" | "feature_request" | "unclear",
49
+ "reason": "One sentence explaining why"
50
+ }`;
51
+ const response = await this.anthropic.messages.create({
52
+ model: 'claude-haiku-4-5-20251001',
53
+ max_tokens: 200,
54
+ messages: [{ role: 'user', content: prompt }]
55
+ });
56
+ const content = response.content[0];
57
+ if (content.type !== 'text') {
58
+ return { classification: 'unclear', reason: 'Could not classify' };
59
+ }
60
+ const parsed = JSON.parse(content.text.replace(/```json\n?|\n?```/g, ''));
61
+ return {
62
+ classification: parsed.classification || 'unclear',
63
+ reason: parsed.reason || 'No reason provided'
64
+ };
65
+ }
66
+ catch (error) {
67
+ logger.error('Classification failed', { error });
68
+ return { classification: 'unclear', reason: 'Classification error' };
69
+ }
70
+ }
71
+ /**
72
+ * Analyze bug and generate fix plan using Claude (two-phase approach)
73
+ * Phase 1: Send file list -> Claude picks relevant files
74
+ * Phase 2: Send those files -> Claude generates fix
75
+ */
76
+ async analyzeAndPlanFix(bug, app, allFiles, readFiles) {
77
+ if (!this.anthropic) {
78
+ logger.warn('Anthropic client not initialized - cannot generate fix');
79
+ return null;
80
+ }
81
+ try {
82
+ // Phase 1: Get file list and ask Claude which files to examine
83
+ logger.info('Phase 1: Asking Claude which files to examine', { fileCount: allFiles.length });
84
+ const phase1Prompt = `
85
+ Bug Report:
86
+ - Title: ${bug.name}
87
+ - Description: ${bug.description}
88
+ ${bug.stepsToReproduce ? `- Steps to reproduce: ${bug.stepsToReproduce}` : ''}
89
+ ${bug.expectedBehavior ? `- Expected: ${bug.expectedBehavior}` : ''}
90
+ ${bug.actualBehavior ? `- Actual: ${bug.actualBehavior}` : ''}
91
+
92
+ App: ${app.name}
93
+
94
+ Source files in this project:
95
+ ${allFiles.map(f => `- ${f}`).join('\n')}
96
+
97
+ Based on the bug description, which files should I examine to fix this bug?
98
+ Return ONLY a JSON array of file paths, maximum 10 files. Example: ["src/App.tsx", "src/components/Player.tsx"]`;
99
+ const phase1Response = await this.anthropic.messages.create({
100
+ model: 'claude-sonnet-4-20250514',
101
+ max_tokens: 1024,
102
+ system: 'You are a code analyst. Return only a JSON array of file paths that are most relevant to the bug. No explanation.',
103
+ messages: [{ role: 'user', content: phase1Prompt }]
104
+ });
105
+ const phase1Content = phase1Response.content[0];
106
+ if (phase1Content.type !== 'text')
107
+ return null;
108
+ // Parse file list from response
109
+ let relevantFiles = [];
110
+ try {
111
+ // Try to extract JSON array
112
+ const jsonMatch = phase1Content.text.match(/\[[\s\S]*?\]/);
113
+ if (jsonMatch) {
114
+ relevantFiles = JSON.parse(jsonMatch[0]);
115
+ }
116
+ }
117
+ catch {
118
+ logger.warn('Could not parse file list from Phase 1', { response: phase1Content.text });
119
+ // Fallback: take first 5 files from src/
120
+ relevantFiles = allFiles.filter(f => f.startsWith('src/')).slice(0, 5);
121
+ }
122
+ logger.info('Phase 1 complete: Files to examine', { files: relevantFiles });
123
+ // Phase 2: Read selected files and generate fix
124
+ const sourceFiles = await readFiles(relevantFiles);
125
+ logger.info('Phase 2: Generating fix', { filesRead: sourceFiles.length });
126
+ const phase2Prompt = `
127
+ Bug Report:
128
+ - Title: ${bug.name}
129
+ - Description: ${bug.description}
130
+ ${bug.stepsToReproduce ? `- Steps to reproduce: ${bug.stepsToReproduce}` : ''}
131
+ ${bug.expectedBehavior ? `- Expected: ${bug.expectedBehavior}` : ''}
132
+ ${bug.actualBehavior ? `- Actual: ${bug.actualBehavior}` : ''}
133
+ - Priority: ${bug.priority || 'unknown'}
134
+
135
+ App: ${app.name}
136
+ Project path: ${app.projectPath}
137
+
138
+ Source files:
139
+ ${sourceFiles.map(f => `--- ${f.path} ---\n${f.content}\n`).join('\n')}
140
+
141
+ Analyze this bug and provide a fix. Output JSON only.`;
142
+ const phase2Response = await this.anthropic.messages.create({
143
+ model: 'claude-sonnet-4-20250514',
144
+ max_tokens: 4096,
145
+ system: giuseppe_prompt_1.GIUSEPPE_SYSTEM_PROMPT,
146
+ messages: [{ role: 'user', content: phase2Prompt }]
147
+ });
148
+ // Extract JSON from response
149
+ const content = phase2Response.content[0];
150
+ if (content.type !== 'text')
151
+ return null;
152
+ const jsonMatch = content.text.match(/```json\n([\s\S]*?)\n```/);
153
+ if (!jsonMatch) {
154
+ // Try parsing whole response as JSON
155
+ try {
156
+ return JSON.parse(content.text);
157
+ }
158
+ catch {
159
+ logger.warn('Could not parse fix plan from response');
160
+ return null;
161
+ }
162
+ }
163
+ return JSON.parse(jsonMatch[1]);
164
+ }
165
+ catch (error) {
166
+ logger.error('Failed to analyze bug', { error });
167
+ return null;
168
+ }
169
+ }
170
+ /**
171
+ * Retry fix based on apply error (search string not found) - re-reads file and generates new fix
172
+ */
173
+ async retryFixFromApplyError(bug, previousFix, applyError, currentFiles, attempt) {
174
+ if (!this.anthropic)
175
+ return null;
176
+ try {
177
+ logger.info('Retrying fix after apply error', { attempt, error: applyError });
178
+ const retryPrompt = `
179
+ The previous fix attempt FAILED to apply with this error:
180
+ \`\`\`
181
+ ${applyError}
182
+ \`\`\`
183
+
184
+ This usually means the search string didn't match the actual file content.
185
+
186
+ Previous fix that was attempted:
187
+ ${JSON.stringify(previousFix.fix, null, 2)}
188
+
189
+ Bug Report:
190
+ - Title: ${bug.name}
191
+ - Description: ${bug.description}
192
+
193
+ CURRENT state of the files (read just now):
194
+ ${currentFiles.map(f => `--- ${f.path} ---\n${f.content}\n`).join('\n')}
195
+
196
+ Please analyze the current file content and provide a CORRECTED fix.
197
+ Make sure the "search" strings EXACTLY match what's in the current files.
198
+ Output JSON only.`;
199
+ const response = await this.anthropic.messages.create({
200
+ model: 'claude-sonnet-4-20250514',
201
+ max_tokens: 4096,
202
+ system: giuseppe_prompt_1.GIUSEPPE_SYSTEM_PROMPT + '\n\nIMPORTANT: Your previous fix could not be applied because the search string was not found. Read the CURRENT file content carefully and make sure your search strings match EXACTLY.',
203
+ messages: [{ role: 'user', content: retryPrompt }]
204
+ });
205
+ const content = response.content[0];
206
+ if (content.type !== 'text')
207
+ return null;
208
+ const jsonMatch = content.text.match(/```json\n([\s\S]*?)\n```/);
209
+ if (!jsonMatch) {
210
+ try {
211
+ return JSON.parse(content.text);
212
+ }
213
+ catch {
214
+ return null;
215
+ }
216
+ }
217
+ return JSON.parse(jsonMatch[1]);
218
+ }
219
+ catch (error) {
220
+ logger.error('Failed to generate retry fix from apply error', { error });
221
+ return null;
222
+ }
223
+ }
224
+ /**
225
+ * Retry fix based on build error - sends error to Claude to generate corrected fix
226
+ */
227
+ async retryFixFromError(bug, previousFix, buildError, currentFiles, attempt) {
228
+ if (!this.anthropic)
229
+ return null;
230
+ try {
231
+ logger.info('Retrying fix based on build error', { attempt, error: buildError.substring(0, 200) });
232
+ const retryPrompt = `
233
+ The previous fix attempt FAILED with this build error:
234
+ \`\`\`
235
+ ${buildError}
236
+ \`\`\`
237
+
238
+ Previous fix that was attempted:
239
+ ${JSON.stringify(previousFix.fix, null, 2)}
240
+
241
+ Bug Report:
242
+ - Title: ${bug.name}
243
+ - Description: ${bug.description}
244
+
245
+ Current state of the files after the failed fix:
246
+ ${currentFiles.map(f => `--- ${f.path} ---\n${f.content}\n`).join('\n')}
247
+
248
+ Please analyze the build error and provide a CORRECTED fix.
249
+ The fix must resolve the TypeScript/build error while still addressing the original bug.
250
+ Output JSON only.`;
251
+ const response = await this.anthropic.messages.create({
252
+ model: 'claude-sonnet-4-20250514',
253
+ max_tokens: 4096,
254
+ system: giuseppe_prompt_1.GIUSEPPE_SYSTEM_PROMPT + '\n\nIMPORTANT: Your previous fix caused a build error. Analyze the error carefully and provide a corrected fix that compiles successfully.',
255
+ messages: [{ role: 'user', content: retryPrompt }]
256
+ });
257
+ const content = response.content[0];
258
+ if (content.type !== 'text')
259
+ return null;
260
+ const jsonMatch = content.text.match(/```json\n([\s\S]*?)\n```/);
261
+ if (!jsonMatch) {
262
+ try {
263
+ return JSON.parse(content.text);
264
+ }
265
+ catch {
266
+ return null;
267
+ }
268
+ }
269
+ return JSON.parse(jsonMatch[1]);
270
+ }
271
+ catch (error) {
272
+ logger.error('Failed to generate retry fix', { error });
273
+ return null;
274
+ }
275
+ }
276
+ /**
277
+ * Generate a new fix based on user feedback
278
+ */
279
+ async retryFixWithFeedback(bug, previousFix, feedback, allSourceFiles, currentFiles) {
280
+ if (!this.anthropic)
281
+ return null;
282
+ try {
283
+ const prompt = `
284
+ The previous fix was REJECTED by the user. Here's their feedback:
285
+
286
+ **User feedback:**
287
+ ${feedback}
288
+
289
+ **Original bug:**
290
+ - Title: ${bug.name}
291
+ - Description: ${bug.description}
292
+ ${bug.stepsToReproduce ? `- Steps to reproduce: ${bug.stepsToReproduce}` : ''}
293
+ ${bug.expectedBehavior ? `- Expected: ${bug.expectedBehavior}` : ''}
294
+ ${bug.actualBehavior ? `- Actual: ${bug.actualBehavior}` : ''}
295
+
296
+ **Previous fix that was rejected:**
297
+ ${JSON.stringify(previousFix.fix, null, 2)}
298
+
299
+ **AVAILABLE SOURCE FILES (use ONLY these exact paths):**
300
+ ${allSourceFiles.map(f => `- ${f}`).join('\n')}
301
+
302
+ **Relevant source files (searched based on your feedback):**
303
+ ${currentFiles.map(f => `--- ${f.path} ---\n${f.content}\n`).join('\n')}
304
+
305
+ Based on the user's feedback, generate a DIFFERENT fix that addresses their concerns.
306
+ IMPORTANT: Use ONLY file paths from the AVAILABLE SOURCE FILES list above.
307
+ Output JSON only.`;
308
+ const response = await this.anthropic.messages.create({
309
+ model: 'claude-sonnet-4-20250514',
310
+ max_tokens: 4096,
311
+ system: giuseppe_prompt_1.GIUSEPPE_SYSTEM_PROMPT + '\n\nIMPORTANT: The user rejected the previous fix. Read their feedback carefully and try a different approach.',
312
+ messages: [{ role: 'user', content: prompt }]
313
+ });
314
+ const content = response.content[0];
315
+ if (content.type !== 'text')
316
+ return null;
317
+ const jsonMatch = content.text.match(/```json\n([\s\S]*?)\n```/);
318
+ if (!jsonMatch) {
319
+ try {
320
+ return JSON.parse(content.text);
321
+ }
322
+ catch {
323
+ return null;
324
+ }
325
+ }
326
+ return JSON.parse(jsonMatch[1]);
327
+ }
328
+ catch (error) {
329
+ logger.error('Failed to generate retry fix with feedback', { error });
330
+ return null;
331
+ }
332
+ }
333
+ }
334
+ exports.GiuseppeAI = GiuseppeAI;
335
+ //# sourceMappingURL=giuseppe-ai.js.map
@@ -0,0 +1,109 @@
1
+ /**
2
+ * Bug Reports Module - Giuseppe Bot
3
+ *
4
+ * Autonomous app fixer that:
5
+ * 1. Analyzes bug reports
6
+ * 2. Finds app project code
7
+ * 3. Generates fixes using Claude
8
+ * 4. Tests locally
9
+ * 5. Publishes to production
10
+ */
11
+ import type { UserContext } from '../../mcp/UserContextCache';
12
+ import type { BugReport, BugReportsConfig, FixResult } from './types';
13
+ import type { BugMonitor } from './bug-monitor';
14
+ export declare class GiuseppeBot {
15
+ private userContext;
16
+ private config;
17
+ private monitor;
18
+ private ai;
19
+ private git;
20
+ private files;
21
+ private appsRegistry;
22
+ constructor(userContext: UserContext, config: BugReportsConfig, monitor: BugMonitor);
23
+ /**
24
+ * Create a session log entry in Context Log workflow
25
+ * Links to the bug report for traceability
26
+ */
27
+ private createSessionLogEntry;
28
+ /**
29
+ * Check if this bug was already classified by looking for classification message in discussion
30
+ */
31
+ private wasAlreadyClassified;
32
+ /**
33
+ * Handle a new bug - main entry point
34
+ */
35
+ handleBug(bug: BugReport): Promise<FixResult>;
36
+ /**
37
+ * Continue with bug fix after user confirms
38
+ */
39
+ proceedWithFix(bug: BugReport): Promise<FixResult>;
40
+ /**
41
+ * Handle a message in a bug discussion - state machine for approval flow
42
+ */
43
+ handleDiscussionMessage(discussionId: string, message: string, senderId: string): Promise<{
44
+ approved: boolean;
45
+ published: boolean;
46
+ retrying?: boolean;
47
+ error?: string;
48
+ }>;
49
+ /**
50
+ * Handle "fix it" confirmation - proceed with bug fix
51
+ */
52
+ private handleFixItConfirmation;
53
+ /**
54
+ * Handle "not a bug" confirmation - close without fixing
55
+ */
56
+ private handleNotABugConfirmation;
57
+ /**
58
+ * Handle "approved" - publish to production
59
+ */
60
+ private handleApproval;
61
+ /**
62
+ * Handle "denied" - ask for explanation
63
+ */
64
+ private handleDenial;
65
+ /**
66
+ * Handle explanation after denial - retry the fix
67
+ */
68
+ private handleExplanationAndRetry;
69
+ /**
70
+ * Check if there's a pending fix for a discussion
71
+ */
72
+ hasPendingFix(discussionId: string): boolean;
73
+ /**
74
+ * Retry a pending fix with explanation from HAL
75
+ * Called by HAL after gathering info through conversation
76
+ */
77
+ retryWithExplanation(discussionId: string, explanation: string): Promise<boolean>;
78
+ /**
79
+ * Initialize registry callback (call this after construction)
80
+ */
81
+ initializeRegistryCallback(): void;
82
+ /**
83
+ * Initialize classification registry callbacks for HAL coordination
84
+ * This allows HAL to trigger "fix it" or "not a bug" via natural conversation
85
+ */
86
+ initializeClassificationCallbacks(): void;
87
+ /**
88
+ * Helper to send a message to a discussion
89
+ */
90
+ private sendDiscussionMessage;
91
+ /**
92
+ * Build and test the app
93
+ */
94
+ private buildAndTest;
95
+ /**
96
+ * Join a bug's discussion using the activity ID (not discussion ID)
97
+ * For activity discussions, we must use joinActivityDiscussion
98
+ */
99
+ private joinBugDiscussion;
100
+ /**
101
+ * Publish app to production using expect script (same as MCP tool)
102
+ */
103
+ private publishApp;
104
+ /**
105
+ * Report progress to bug discussion
106
+ */
107
+ private reportProgress;
108
+ }
109
+ //# sourceMappingURL=giuseppe-bot.d.ts.map