@hailer/mcp 0.1.14 → 0.1.16

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 (112) hide show
  1. package/.claude/agents/agent-giuseppe-app-builder.md +7 -6
  2. package/.claude/agents/agent-lars-code-inspector.md +26 -14
  3. package/dist/agents/bot-manager.d.ts +48 -0
  4. package/dist/agents/bot-manager.js +254 -0
  5. package/dist/agents/factory.d.ts +150 -0
  6. package/dist/agents/factory.js +650 -0
  7. package/dist/agents/giuseppe/ai.d.ts +83 -0
  8. package/dist/agents/giuseppe/ai.js +466 -0
  9. package/dist/agents/giuseppe/bot.d.ts +110 -0
  10. package/dist/agents/giuseppe/bot.js +780 -0
  11. package/dist/agents/giuseppe/config.d.ts +25 -0
  12. package/dist/agents/giuseppe/config.js +227 -0
  13. package/dist/agents/giuseppe/files.d.ts +52 -0
  14. package/dist/agents/giuseppe/files.js +338 -0
  15. package/dist/agents/giuseppe/git.d.ts +48 -0
  16. package/dist/agents/giuseppe/git.js +298 -0
  17. package/dist/agents/giuseppe/index.d.ts +97 -0
  18. package/dist/agents/giuseppe/index.js +258 -0
  19. package/dist/agents/giuseppe/lsp.d.ts +113 -0
  20. package/dist/agents/giuseppe/lsp.js +485 -0
  21. package/dist/agents/giuseppe/monitor.d.ts +118 -0
  22. package/dist/agents/giuseppe/monitor.js +621 -0
  23. package/dist/agents/giuseppe/prompt.d.ts +5 -0
  24. package/dist/agents/giuseppe/prompt.js +94 -0
  25. package/dist/agents/giuseppe/registries/pending-classification.d.ts +28 -0
  26. package/dist/agents/giuseppe/registries/pending-classification.js +50 -0
  27. package/dist/agents/giuseppe/registries/pending-fix.d.ts +30 -0
  28. package/dist/agents/giuseppe/registries/pending-fix.js +42 -0
  29. package/dist/agents/giuseppe/registries/pending.d.ts +27 -0
  30. package/dist/agents/giuseppe/registries/pending.js +49 -0
  31. package/dist/agents/giuseppe/specialist.d.ts +47 -0
  32. package/dist/agents/giuseppe/specialist.js +237 -0
  33. package/dist/agents/giuseppe/types.d.ts +123 -0
  34. package/dist/agents/giuseppe/types.js +9 -0
  35. package/dist/agents/hailer-expert/index.d.ts +8 -0
  36. package/dist/agents/hailer-expert/index.js +14 -0
  37. package/dist/agents/hal/daemon.d.ts +142 -0
  38. package/dist/agents/hal/daemon.js +1103 -0
  39. package/dist/agents/hal/definitions.d.ts +55 -0
  40. package/dist/agents/hal/definitions.js +263 -0
  41. package/dist/agents/hal/index.d.ts +3 -0
  42. package/dist/agents/hal/index.js +8 -0
  43. package/dist/agents/index.d.ts +18 -0
  44. package/dist/agents/index.js +48 -0
  45. package/dist/agents/shared/base.d.ts +216 -0
  46. package/dist/agents/shared/base.js +846 -0
  47. package/dist/agents/shared/services/agent-registry.d.ts +107 -0
  48. package/dist/agents/shared/services/agent-registry.js +629 -0
  49. package/dist/agents/shared/services/conversation-manager.d.ts +50 -0
  50. package/dist/agents/shared/services/conversation-manager.js +136 -0
  51. package/dist/agents/shared/services/mcp-client.d.ts +56 -0
  52. package/dist/agents/shared/services/mcp-client.js +124 -0
  53. package/dist/agents/shared/services/message-classifier.d.ts +37 -0
  54. package/dist/agents/shared/services/message-classifier.js +187 -0
  55. package/dist/agents/shared/services/message-formatter.d.ts +89 -0
  56. package/dist/agents/shared/services/message-formatter.js +371 -0
  57. package/dist/agents/shared/services/session-logger.d.ts +106 -0
  58. package/dist/agents/shared/services/session-logger.js +446 -0
  59. package/dist/agents/shared/services/tool-executor.d.ts +41 -0
  60. package/dist/agents/shared/services/tool-executor.js +169 -0
  61. package/dist/agents/shared/services/workspace-schema-cache.d.ts +125 -0
  62. package/dist/agents/shared/services/workspace-schema-cache.js +578 -0
  63. package/dist/agents/shared/specialist.d.ts +91 -0
  64. package/dist/agents/shared/specialist.js +399 -0
  65. package/dist/agents/shared/tool-schema-loader.d.ts +62 -0
  66. package/dist/agents/shared/tool-schema-loader.js +232 -0
  67. package/dist/agents/shared/types.d.ts +327 -0
  68. package/dist/agents/shared/types.js +121 -0
  69. package/dist/app.js +21 -4
  70. package/dist/cli.js +0 -0
  71. package/dist/client/agents/orchestrator.d.ts +1 -0
  72. package/dist/client/agents/orchestrator.js +12 -1
  73. package/dist/commands/seed-config.d.ts +9 -0
  74. package/dist/commands/seed-config.js +372 -0
  75. package/dist/config.d.ts +10 -0
  76. package/dist/config.js +61 -1
  77. package/dist/core.d.ts +8 -0
  78. package/dist/core.js +137 -6
  79. package/dist/lib/discussion-lock.d.ts +42 -0
  80. package/dist/lib/discussion-lock.js +110 -0
  81. package/dist/mcp/UserContextCache.js +2 -2
  82. package/dist/mcp/hailer-clients.d.ts +15 -0
  83. package/dist/mcp/hailer-clients.js +100 -6
  84. package/dist/mcp/signal-handler.d.ts +16 -5
  85. package/dist/mcp/signal-handler.js +173 -122
  86. package/dist/mcp/tools/activity.js +9 -1
  87. package/dist/mcp/tools/bot-config.d.ts +184 -9
  88. package/dist/mcp/tools/bot-config.js +2177 -163
  89. package/dist/mcp/tools/giuseppe-tools.d.ts +21 -0
  90. package/dist/mcp/tools/giuseppe-tools.js +525 -0
  91. package/dist/mcp/utils/hailer-api-client.d.ts +42 -1
  92. package/dist/mcp/utils/hailer-api-client.js +128 -2
  93. package/dist/mcp/webhook-handler.d.ts +87 -0
  94. package/dist/mcp/webhook-handler.js +343 -0
  95. package/dist/mcp/workspace-cache.d.ts +5 -0
  96. package/dist/mcp/workspace-cache.js +11 -0
  97. package/dist/mcp-server.js +55 -5
  98. package/dist/modules/bug-reports/giuseppe-agent.d.ts +58 -0
  99. package/dist/modules/bug-reports/giuseppe-agent.js +467 -0
  100. package/dist/modules/bug-reports/giuseppe-ai.d.ts +25 -1
  101. package/dist/modules/bug-reports/giuseppe-ai.js +133 -2
  102. package/dist/modules/bug-reports/giuseppe-bot.d.ts +3 -2
  103. package/dist/modules/bug-reports/giuseppe-bot.js +75 -36
  104. package/dist/modules/bug-reports/giuseppe-daemon.d.ts +80 -0
  105. package/dist/modules/bug-reports/giuseppe-daemon.js +617 -0
  106. package/dist/modules/bug-reports/giuseppe-files.d.ts +12 -0
  107. package/dist/modules/bug-reports/giuseppe-files.js +37 -0
  108. package/dist/modules/bug-reports/giuseppe-lsp.d.ts +113 -0
  109. package/dist/modules/bug-reports/giuseppe-lsp.js +485 -0
  110. package/dist/modules/bug-reports/index.d.ts +1 -0
  111. package/dist/modules/bug-reports/index.js +31 -29
  112. package/package.json +5 -4
@@ -49,6 +49,7 @@ const logger_1 = require("./lib/logger");
49
49
  const config_1 = require("./config");
50
50
  const UserContextCache_1 = require("./mcp/UserContextCache");
51
51
  const tool_registry_1 = require("./mcp/tool-registry");
52
+ const webhook_handler_1 = require("./mcp/webhook-handler");
52
53
  class MCPServerService {
53
54
  app;
54
55
  server;
@@ -325,12 +326,61 @@ class MCPServerService {
325
326
  res.status(500).json({ error: 'Failed to toggle bot' });
326
327
  }
327
328
  });
328
- this.logger.info('Routes configured', {
329
+ // ===== Bot Config Webhook API =====
330
+ // Get secure webhook path (auto-generated token)
331
+ const webhookPath = (0, webhook_handler_1.getWebhookPath)();
332
+ // POST /webhook/{token} - Receives updates from Hailer workflow webhooks
333
+ this.app.post(webhookPath, (req, res) => {
334
+ req.logger.info('Bot config webhook received', {
335
+ activityId: req.body?._id,
336
+ activityName: req.body?.name,
337
+ workspaceId: req.body?.cid,
338
+ });
339
+ try {
340
+ const result = (0, webhook_handler_1.handleBotConfigWebhook)(req.body);
341
+ if (result.success) {
342
+ req.logger.info('Bot config updated via webhook', {
343
+ action: result.action,
344
+ workspaceId: result.workspaceId,
345
+ botType: result.botType,
346
+ });
347
+ res.status(200).json(result);
348
+ }
349
+ else {
350
+ req.logger.warn('Bot config webhook failed', { error: result.error });
351
+ res.status(400).json(result);
352
+ }
353
+ }
354
+ catch (error) {
355
+ req.logger.error('Bot config webhook error', { error });
356
+ res.status(500).json({
357
+ success: false,
358
+ error: error instanceof Error ? error.message : 'Internal error',
359
+ });
360
+ }
361
+ });
362
+ // GET /webhook/{token}/status - Status endpoint to see all workspace configs
363
+ this.app.get(`${webhookPath}/status`, (_req, res) => {
364
+ const configs = (0, webhook_handler_1.listWorkspaceConfigs)();
365
+ res.json({
366
+ timestamp: new Date().toISOString(),
367
+ workspaceCount: configs.length,
368
+ workspaces: configs.map((c) => ({
369
+ workspaceId: c.workspaceId,
370
+ workspaceName: c.workspaceName,
371
+ hasOrchestrator: !!c.orchestrator,
372
+ specialistCount: c.specialists.length,
373
+ enabledSpecialists: c.specialists.filter((s) => s.enabled).length,
374
+ lastSynced: c.lastSynced,
375
+ })),
376
+ });
377
+ });
378
+ this.logger.debug('Routes configured', {
329
379
  routes: [
330
- '/health - Server health check',
331
- '/daemon/status - Daemon context monitor',
332
- '/api/mcp - MCP protocol (JSON-RPC 2.0)',
333
- '/api/bots - Bot configuration API'
380
+ '/health',
381
+ '/daemon/status',
382
+ '/api/mcp',
383
+ '/api/bots'
334
384
  ]
335
385
  });
336
386
  }
@@ -0,0 +1,58 @@
1
+ /**
2
+ * Giuseppe Agent - Full Conversational Bug Fixer
3
+ *
4
+ * A natural language agent that handles bug fixing through conversation.
5
+ * No keywords, no intent detection - just natural dialogue with tools.
6
+ */
7
+ import type { UserContext } from '../../mcp/UserContextCache';
8
+ import type { BugReport } from './types';
9
+ import type { BugMonitor } from './bug-monitor';
10
+ export declare class GiuseppeAgent {
11
+ private userContext;
12
+ private monitor;
13
+ private appsBasePath;
14
+ private anthropic;
15
+ private conversations;
16
+ private bugContexts;
17
+ private files;
18
+ private git;
19
+ private lsp;
20
+ constructor(userContext: UserContext, monitor: BugMonitor, appsBasePath: string, apiKey?: string);
21
+ /**
22
+ * Handle a new bug - start the conversation
23
+ */
24
+ handleNewBug(bug: BugReport): Promise<void>;
25
+ /**
26
+ * Handle any message in the bug discussion
27
+ */
28
+ handleMessage(discussionId: string, message: string, senderName: string): Promise<void>;
29
+ /**
30
+ * Chat with the LLM - handles tool calls automatically
31
+ */
32
+ private chat;
33
+ /**
34
+ * Execute tool calls and return results
35
+ */
36
+ private executeToolCalls;
37
+ /**
38
+ * Execute a single tool
39
+ */
40
+ private executeTool;
41
+ /**
42
+ * Post message to discussion
43
+ */
44
+ private postMessage;
45
+ /**
46
+ * Build initial prompt with bug context
47
+ */
48
+ private buildInitialPrompt;
49
+ /**
50
+ * System prompt for natural conversation
51
+ */
52
+ private getSystemPrompt;
53
+ /**
54
+ * Tool definitions
55
+ */
56
+ private getTools;
57
+ }
58
+ //# sourceMappingURL=giuseppe-agent.d.ts.map
@@ -0,0 +1,467 @@
1
+ "use strict";
2
+ /**
3
+ * Giuseppe Agent - Full Conversational Bug Fixer
4
+ *
5
+ * A natural language agent that handles bug fixing through conversation.
6
+ * No keywords, no intent detection - just natural dialogue with tools.
7
+ */
8
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
9
+ if (k2 === undefined) k2 = k;
10
+ var desc = Object.getOwnPropertyDescriptor(m, k);
11
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
12
+ desc = { enumerable: true, get: function() { return m[k]; } };
13
+ }
14
+ Object.defineProperty(o, k2, desc);
15
+ }) : (function(o, m, k, k2) {
16
+ if (k2 === undefined) k2 = k;
17
+ o[k2] = m[k];
18
+ }));
19
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
20
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
21
+ }) : function(o, v) {
22
+ o["default"] = v;
23
+ });
24
+ var __importStar = (this && this.__importStar) || (function () {
25
+ var ownKeys = function(o) {
26
+ ownKeys = Object.getOwnPropertyNames || function (o) {
27
+ var ar = [];
28
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
29
+ return ar;
30
+ };
31
+ return ownKeys(o);
32
+ };
33
+ return function (mod) {
34
+ if (mod && mod.__esModule) return mod;
35
+ var result = {};
36
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
37
+ __setModuleDefault(result, mod);
38
+ return result;
39
+ };
40
+ })();
41
+ var __importDefault = (this && this.__importDefault) || function (mod) {
42
+ return (mod && mod.__esModule) ? mod : { "default": mod };
43
+ };
44
+ Object.defineProperty(exports, "__esModule", { value: true });
45
+ exports.GiuseppeAgent = void 0;
46
+ const sdk_1 = __importDefault(require("@anthropic-ai/sdk"));
47
+ const child_process_1 = require("child_process");
48
+ const logger_1 = require("../../lib/logger");
49
+ const giuseppe_files_1 = require("./giuseppe-files");
50
+ const giuseppe_git_1 = require("./giuseppe-git");
51
+ const giuseppe_lsp_1 = require("./giuseppe-lsp");
52
+ const logger = (0, logger_1.createLogger)({ component: 'giuseppe-agent' });
53
+ class GiuseppeAgent {
54
+ userContext;
55
+ monitor;
56
+ appsBasePath;
57
+ anthropic;
58
+ conversations = new Map();
59
+ bugContexts = new Map();
60
+ // Sub-modules
61
+ files;
62
+ git;
63
+ lsp;
64
+ constructor(userContext, monitor, appsBasePath, apiKey) {
65
+ this.userContext = userContext;
66
+ this.monitor = monitor;
67
+ this.appsBasePath = appsBasePath;
68
+ this.anthropic = new sdk_1.default({ apiKey: apiKey || process.env.ANTHROPIC_API_KEY });
69
+ this.files = new giuseppe_files_1.GiuseppeFiles(appsBasePath);
70
+ this.git = new giuseppe_git_1.GiuseppeGit();
71
+ this.lsp = new giuseppe_lsp_1.GiuseppeLsp();
72
+ }
73
+ /**
74
+ * Handle a new bug - start the conversation
75
+ */
76
+ async handleNewBug(bug) {
77
+ if (!bug.discussionId) {
78
+ logger.warn('Bug has no discussion, cannot start conversation', { bugId: bug.id });
79
+ return;
80
+ }
81
+ // Store bug context
82
+ this.bugContexts.set(bug.discussionId, { bug });
83
+ // Find the app
84
+ const app = await this.files.findAppFromBugTitle(bug.name);
85
+ if (app) {
86
+ this.bugContexts.get(bug.discussionId).app = app;
87
+ }
88
+ // Start fresh conversation
89
+ this.conversations.set(bug.discussionId, []);
90
+ // Send initial message with bug context
91
+ const initialPrompt = this.buildInitialPrompt(bug, app);
92
+ const response = await this.chat(bug.discussionId, initialPrompt, true);
93
+ // Post response to discussion
94
+ await this.postMessage(bug.discussionId, response);
95
+ }
96
+ /**
97
+ * Handle any message in the bug discussion
98
+ */
99
+ async handleMessage(discussionId, message, senderName) {
100
+ const context = this.bugContexts.get(discussionId);
101
+ if (!context) {
102
+ logger.debug('No bug context for discussion, ignoring', { discussionId });
103
+ return;
104
+ }
105
+ // Add user message to conversation
106
+ const userMessage = `${senderName}: ${message}`;
107
+ const response = await this.chat(discussionId, userMessage, false);
108
+ // Post response
109
+ await this.postMessage(discussionId, response);
110
+ }
111
+ /**
112
+ * Chat with the LLM - handles tool calls automatically
113
+ */
114
+ async chat(discussionId, userMessage, isSystemContext) {
115
+ const conversation = this.conversations.get(discussionId) || [];
116
+ // Add user message
117
+ conversation.push({ role: 'user', content: userMessage });
118
+ // Keep conversation manageable
119
+ if (conversation.length > 30) {
120
+ conversation.splice(0, conversation.length - 20);
121
+ }
122
+ try {
123
+ const response = await this.anthropic.messages.create({
124
+ model: 'claude-sonnet-4-20250514',
125
+ max_tokens: 4096,
126
+ system: this.getSystemPrompt(),
127
+ messages: conversation,
128
+ tools: this.getTools(),
129
+ });
130
+ // Handle tool calls
131
+ let finalResponse = response;
132
+ while (finalResponse.stop_reason === 'tool_use') {
133
+ const toolResults = await this.executeToolCalls(finalResponse.content, discussionId);
134
+ // Add assistant response and tool results
135
+ conversation.push({ role: 'assistant', content: finalResponse.content });
136
+ conversation.push({ role: 'user', content: toolResults });
137
+ // Continue conversation
138
+ finalResponse = await this.anthropic.messages.create({
139
+ model: 'claude-sonnet-4-20250514',
140
+ max_tokens: 4096,
141
+ system: this.getSystemPrompt(),
142
+ messages: conversation,
143
+ tools: this.getTools(),
144
+ });
145
+ }
146
+ // Extract text response
147
+ const textContent = finalResponse.content
148
+ .filter((block) => block.type === 'text')
149
+ .map(block => block.text)
150
+ .join('\n');
151
+ // Save final response
152
+ conversation.push({ role: 'assistant', content: finalResponse.content });
153
+ this.conversations.set(discussionId, conversation);
154
+ return textContent || "I'm not sure how to respond to that.";
155
+ }
156
+ catch (error) {
157
+ logger.error('Chat failed', { error, discussionId });
158
+ return "Sorry, I encountered an error. Please try again.";
159
+ }
160
+ }
161
+ /**
162
+ * Execute tool calls and return results
163
+ */
164
+ async executeToolCalls(content, discussionId) {
165
+ const toolUses = content.filter((block) => block.type === 'tool_use');
166
+ const results = [];
167
+ const context = this.bugContexts.get(discussionId);
168
+ for (const tool of toolUses) {
169
+ try {
170
+ const result = await this.executeTool(tool.name, tool.input, context);
171
+ results.push({
172
+ type: 'tool_result',
173
+ tool_use_id: tool.id,
174
+ content: JSON.stringify(result),
175
+ });
176
+ }
177
+ catch (error) {
178
+ results.push({
179
+ type: 'tool_result',
180
+ tool_use_id: tool.id,
181
+ content: JSON.stringify({ error: error.message }),
182
+ is_error: true,
183
+ });
184
+ }
185
+ }
186
+ return results;
187
+ }
188
+ /**
189
+ * Execute a single tool
190
+ */
191
+ async executeTool(name, input, context) {
192
+ const projectPath = context?.app?.projectPath || input.projectPath;
193
+ switch (name) {
194
+ case 'check_git_status': {
195
+ try {
196
+ const status = (0, child_process_1.execSync)('git status --short', { cwd: projectPath, encoding: 'utf-8' });
197
+ const branch = (0, child_process_1.execSync)('git branch --show-current', { cwd: projectPath, encoding: 'utf-8' }).trim();
198
+ const behindAhead = (0, child_process_1.execSync)('git rev-list --left-right --count HEAD...@{upstream} 2>/dev/null || echo "0 0"', { cwd: projectPath, encoding: 'utf-8' }).trim().split(/\s+/);
199
+ return {
200
+ branch,
201
+ status: status || 'clean',
202
+ behind: parseInt(behindAhead[1]) || 0,
203
+ ahead: parseInt(behindAhead[0]) || 0
204
+ };
205
+ }
206
+ catch (e) {
207
+ return { error: e.message };
208
+ }
209
+ }
210
+ case 'git_pull': {
211
+ try {
212
+ const output = (0, child_process_1.execSync)('git pull', { cwd: projectPath, encoding: 'utf-8' });
213
+ return { success: true, output };
214
+ }
215
+ catch (e) {
216
+ return { success: false, error: e.stderr || e.message };
217
+ }
218
+ }
219
+ case 'git_commit': {
220
+ try {
221
+ (0, child_process_1.execSync)('git add -A', { cwd: projectPath });
222
+ const msg = input.message || 'fix: bug fix by Giuseppe';
223
+ (0, child_process_1.execSync)(`git commit -m "${msg.replace(/"/g, '\\"')}"`, { cwd: projectPath });
224
+ const hash = (0, child_process_1.execSync)('git rev-parse --short HEAD', { cwd: projectPath, encoding: 'utf-8' }).trim();
225
+ return { success: true, hash };
226
+ }
227
+ catch (e) {
228
+ return { success: false, error: e.stderr || e.stdout || e.message };
229
+ }
230
+ }
231
+ case 'git_push': {
232
+ const pushed = await this.git.push(projectPath);
233
+ return { success: pushed };
234
+ }
235
+ case 'git_revert': {
236
+ try {
237
+ (0, child_process_1.execSync)('git checkout -- .', { cwd: projectPath });
238
+ return { success: true };
239
+ }
240
+ catch (e) {
241
+ return { success: false, error: e.message };
242
+ }
243
+ }
244
+ case 'list_files': {
245
+ const files = await this.files.scanSourceFiles(projectPath);
246
+ return { files: files.slice(0, 50), total: files.length };
247
+ }
248
+ case 'read_file': {
249
+ const content = await this.files.readFile(projectPath, input.path);
250
+ return content ? { content } : { error: 'File not found' };
251
+ }
252
+ case 'write_file': {
253
+ const success = await this.files.writeFile(projectPath, input.path, input.content);
254
+ return { success };
255
+ }
256
+ case 'run_build': {
257
+ const result = await this.lsp.validateFix(projectPath);
258
+ return result;
259
+ }
260
+ case 'analyze_code': {
261
+ const analysis = await this.lsp.analyzeProject(projectPath);
262
+ return {
263
+ issues: analysis.issues.slice(0, 10),
264
+ unusedProps: analysis.unusedProps.slice(0, 10),
265
+ summary: analysis.summary
266
+ };
267
+ }
268
+ case 'publish_app': {
269
+ try {
270
+ const appScaffold = await Promise.resolve().then(() => __importStar(require('../../mcp/tools/app-scaffold')));
271
+ const tool = appScaffold.publishHailerAppTool;
272
+ const result = await tool.execute({ projectDirectory: projectPath }, this.userContext);
273
+ const text = result.content?.[0]?.text || '';
274
+ return {
275
+ success: !text.includes('❌'),
276
+ message: text.substring(0, 500)
277
+ };
278
+ }
279
+ catch (e) {
280
+ return { success: false, error: e.message };
281
+ }
282
+ }
283
+ case 'move_bug_phase': {
284
+ const phase = input.phase;
285
+ const bugId = context?.bug.id || input.bugId;
286
+ const moved = await this.monitor.moveBugToPhase(bugId, phase);
287
+ return { success: moved, phase };
288
+ }
289
+ default:
290
+ return { error: `Unknown tool: ${name}` };
291
+ }
292
+ }
293
+ /**
294
+ * Post message to discussion
295
+ */
296
+ async postMessage(discussionId, message) {
297
+ try {
298
+ await this.userContext.hailer.sendDiscussionMessage(discussionId, message);
299
+ }
300
+ catch (error) {
301
+ logger.error('Failed to post message', { discussionId, error });
302
+ }
303
+ }
304
+ /**
305
+ * Build initial prompt with bug context
306
+ */
307
+ buildInitialPrompt(bug, app) {
308
+ return `A new bug report has been filed. Here are the details:
309
+
310
+ **Bug Report**
311
+ - Title: ${bug.name}
312
+ - Description: ${bug.description || 'No description provided'}
313
+ ${bug.stepsToReproduce ? `- Steps to reproduce: ${bug.stepsToReproduce}` : ''}
314
+ ${bug.expectedBehavior ? `- Expected: ${bug.expectedBehavior}` : ''}
315
+ ${bug.actualBehavior ? `- Actual: ${bug.actualBehavior}` : ''}
316
+
317
+ **App Info**
318
+ ${app ? `- Found app: ${app.name} at ${app.projectPath}` : '- Could not find matching app project'}
319
+
320
+ Please introduce yourself, analyze this bug report, and let the user know what you think. Ask any clarifying questions if needed.`;
321
+ }
322
+ /**
323
+ * System prompt for natural conversation
324
+ */
325
+ getSystemPrompt() {
326
+ return `You are Giuseppe, a friendly AI assistant specialized in fixing bugs in React/TypeScript applications.
327
+
328
+ **Your personality:**
329
+ - Friendly and conversational
330
+ - Technical but explains things clearly
331
+ - Proactive - you take initiative but ask before destructive actions
332
+ - Honest about limitations and errors
333
+
334
+ **Your workflow:**
335
+ 1. When a bug is reported, analyze it and share your understanding
336
+ 2. Ask clarifying questions if the bug is unclear
337
+ 3. Check git status before making changes
338
+ 4. If git is behind, pull first
339
+ 5. Read relevant files to understand the code
340
+ 6. Make fixes by writing to files
341
+ 7. Run the build to verify the fix works
342
+ 8. Commit the changes
343
+ 9. Ask the user if they want to publish to production
344
+ 10. Only publish when the user confirms
345
+
346
+ **Important rules:**
347
+ - ALWAYS ask before publishing to production
348
+ - If the build fails, explain the error and try to fix it
349
+ - If git has issues, explain and resolve them
350
+ - Keep the user informed of what you're doing
351
+ - Be conversational - this is a chat, not a report
352
+
353
+ **Tools available:**
354
+ - check_git_status: See branch, changes, sync status
355
+ - git_pull: Pull latest from remote
356
+ - git_commit: Stage and commit changes
357
+ - git_push: Push to remote
358
+ - git_revert: Discard uncommitted changes
359
+ - list_files: See source files in the project
360
+ - read_file: Read a file's contents
361
+ - write_file: Write/update a file
362
+ - run_build: Check if code compiles
363
+ - analyze_code: LSP analysis for issues
364
+ - publish_app: Deploy to Hailer (ASK FIRST!)
365
+ - move_bug_phase: Update bug status (inProgress, fixed, closed, declined)
366
+
367
+ Start by understanding the bug, then work through fixing it naturally.`;
368
+ }
369
+ /**
370
+ * Tool definitions
371
+ */
372
+ getTools() {
373
+ return [
374
+ {
375
+ name: 'check_git_status',
376
+ description: 'Check git status - branch, changes, sync with remote',
377
+ input_schema: { type: 'object', properties: {}, required: [] }
378
+ },
379
+ {
380
+ name: 'git_pull',
381
+ description: 'Pull latest changes from remote',
382
+ input_schema: { type: 'object', properties: {}, required: [] }
383
+ },
384
+ {
385
+ name: 'git_commit',
386
+ description: 'Stage all changes and commit',
387
+ input_schema: {
388
+ type: 'object',
389
+ properties: {
390
+ message: { type: 'string', description: 'Commit message' }
391
+ },
392
+ required: ['message']
393
+ }
394
+ },
395
+ {
396
+ name: 'git_push',
397
+ description: 'Push commits to remote',
398
+ input_schema: { type: 'object', properties: {}, required: [] }
399
+ },
400
+ {
401
+ name: 'git_revert',
402
+ description: 'Discard all uncommitted changes',
403
+ input_schema: { type: 'object', properties: {}, required: [] }
404
+ },
405
+ {
406
+ name: 'list_files',
407
+ description: 'List source files in the project',
408
+ input_schema: { type: 'object', properties: {}, required: [] }
409
+ },
410
+ {
411
+ name: 'read_file',
412
+ description: 'Read a source file',
413
+ input_schema: {
414
+ type: 'object',
415
+ properties: {
416
+ path: { type: 'string', description: 'Relative path to file' }
417
+ },
418
+ required: ['path']
419
+ }
420
+ },
421
+ {
422
+ name: 'write_file',
423
+ description: 'Write content to a file',
424
+ input_schema: {
425
+ type: 'object',
426
+ properties: {
427
+ path: { type: 'string', description: 'Relative path to file' },
428
+ content: { type: 'string', description: 'New file content' }
429
+ },
430
+ required: ['path', 'content']
431
+ }
432
+ },
433
+ {
434
+ name: 'run_build',
435
+ description: 'Run TypeScript build to check for errors',
436
+ input_schema: { type: 'object', properties: {}, required: [] }
437
+ },
438
+ {
439
+ name: 'analyze_code',
440
+ description: 'Run LSP analysis to find issues',
441
+ input_schema: { type: 'object', properties: {}, required: [] }
442
+ },
443
+ {
444
+ name: 'publish_app',
445
+ description: 'Publish app to Hailer production - ALWAYS ASK USER FIRST',
446
+ input_schema: { type: 'object', properties: {}, required: [] }
447
+ },
448
+ {
449
+ name: 'move_bug_phase',
450
+ description: 'Move bug to a different phase',
451
+ input_schema: {
452
+ type: 'object',
453
+ properties: {
454
+ phase: {
455
+ type: 'string',
456
+ enum: ['inProgress', 'fixed', 'closed', 'declined'],
457
+ description: 'Target phase'
458
+ }
459
+ },
460
+ required: ['phase']
461
+ }
462
+ }
463
+ ];
464
+ }
465
+ }
466
+ exports.GiuseppeAgent = GiuseppeAgent;
467
+ //# sourceMappingURL=giuseppe-agent.js.map
@@ -37,12 +37,36 @@ export declare class GiuseppeAI {
37
37
  * Classify a report as bug or feature request
38
38
  */
39
39
  classifyReport(bug: BugReport): Promise<ClassificationResult>;
40
+ /**
41
+ * Detect user intent from a message (replaces magic word detection)
42
+ * Returns the intent and confidence level
43
+ */
44
+ detectIntent(message: string, context: 'classification' | 'approval'): Promise<{
45
+ intent: string;
46
+ confidence: 'high' | 'medium' | 'low';
47
+ explanation: string;
48
+ }>;
49
+ /**
50
+ * Extract keywords from bug description for LSP filtering
51
+ */
52
+ private extractKeywords;
40
53
  /**
41
54
  * Analyze bug and generate fix plan using Claude (two-phase approach)
42
55
  * Phase 1: Send file list -> Claude picks relevant files
43
56
  * Phase 2: Send those files -> Claude generates fix
44
57
  */
45
- analyzeAndPlanFix(bug: BugReport, app: AppRegistryEntry, allFiles: string[], readFiles: (paths: string[]) => Promise<FileContent[]>): Promise<FixPlan | null>;
58
+ analyzeAndPlanFix(bug: BugReport, app: AppRegistryEntry, allFiles: string[], readFiles: (paths: string[]) => Promise<FileContent[]>, runLspAnalysis?: (files: string[], keywords: string[]) => Promise<{
59
+ unusedProps: {
60
+ name: string;
61
+ line: number;
62
+ file: string;
63
+ }[];
64
+ issues: {
65
+ file: string;
66
+ line: number;
67
+ message: string;
68
+ }[];
69
+ }>): Promise<FixPlan | null>;
46
70
  /**
47
71
  * Retry fix based on apply error (search string not found) - re-reads file and generates new fix
48
72
  */