@hailer/mcp 0.1.10 → 0.1.12

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 (62) hide show
  1. package/.claude/settings.json +12 -0
  2. package/CLAUDE.md +37 -1
  3. package/ai-hub/dist/assets/index-8ce6041d.css +1 -0
  4. package/ai-hub/dist/assets/index-930f01ca.js +348 -0
  5. package/ai-hub/dist/index.html +15 -0
  6. package/ai-hub/dist/manifest.json +14 -0
  7. package/ai-hub/dist/vite.svg +1 -0
  8. package/dist/app.js +5 -0
  9. package/dist/client/agents/base.d.ts +5 -0
  10. package/dist/client/agents/base.js +9 -2
  11. package/dist/client/agents/definitions.js +85 -0
  12. package/dist/client/agents/orchestrator.d.ts +21 -0
  13. package/dist/client/agents/orchestrator.js +292 -1
  14. package/dist/client/bot-entrypoint.d.ts +7 -0
  15. package/dist/client/bot-entrypoint.js +103 -0
  16. package/dist/client/bot-runner.d.ts +35 -0
  17. package/dist/client/bot-runner.js +188 -0
  18. package/dist/client/factory.d.ts +4 -0
  19. package/dist/client/factory.js +10 -0
  20. package/dist/client/server.d.ts +8 -0
  21. package/dist/client/server.js +251 -0
  22. package/dist/client/types.d.ts +29 -0
  23. package/dist/client/types.js +4 -1
  24. package/dist/core.d.ts +3 -0
  25. package/dist/core.js +72 -0
  26. package/dist/mcp/hailer-clients.d.ts +4 -0
  27. package/dist/mcp/hailer-clients.js +16 -1
  28. package/dist/mcp/tools/app-scaffold.js +148 -11
  29. package/dist/mcp/tools/bot-config.d.ts +78 -0
  30. package/dist/mcp/tools/bot-config.js +442 -0
  31. package/dist/mcp-server.js +109 -1
  32. package/dist/modules/bug-reports/bug-config.d.ts +25 -0
  33. package/dist/modules/bug-reports/bug-config.js +187 -0
  34. package/dist/modules/bug-reports/bug-monitor.d.ts +108 -0
  35. package/dist/modules/bug-reports/bug-monitor.js +510 -0
  36. package/dist/modules/bug-reports/giuseppe-ai.d.ts +59 -0
  37. package/dist/modules/bug-reports/giuseppe-ai.js +335 -0
  38. package/dist/modules/bug-reports/giuseppe-bot.d.ts +109 -0
  39. package/dist/modules/bug-reports/giuseppe-bot.js +765 -0
  40. package/dist/modules/bug-reports/giuseppe-files.d.ts +52 -0
  41. package/dist/modules/bug-reports/giuseppe-files.js +338 -0
  42. package/dist/modules/bug-reports/giuseppe-git.d.ts +48 -0
  43. package/dist/modules/bug-reports/giuseppe-git.js +298 -0
  44. package/dist/modules/bug-reports/giuseppe-prompt.d.ts +5 -0
  45. package/dist/modules/bug-reports/giuseppe-prompt.js +94 -0
  46. package/dist/modules/bug-reports/index.d.ts +76 -0
  47. package/dist/modules/bug-reports/index.js +213 -0
  48. package/dist/modules/bug-reports/pending-classification-registry.d.ts +28 -0
  49. package/dist/modules/bug-reports/pending-classification-registry.js +50 -0
  50. package/dist/modules/bug-reports/pending-fix-registry.d.ts +30 -0
  51. package/dist/modules/bug-reports/pending-fix-registry.js +42 -0
  52. package/dist/modules/bug-reports/pending-registry.d.ts +27 -0
  53. package/dist/modules/bug-reports/pending-registry.js +49 -0
  54. package/dist/modules/bug-reports/types.d.ts +123 -0
  55. package/dist/modules/bug-reports/types.js +9 -0
  56. package/dist/services/bug-monitor.d.ts +23 -0
  57. package/dist/services/bug-monitor.js +275 -0
  58. package/lineup-manager/dist/assets/index-b30c809f.js +600 -0
  59. package/lineup-manager/dist/index.html +1 -1
  60. package/lineup-manager/dist/manifest.json +5 -5
  61. package/package.json +6 -2
  62. package/lineup-manager/dist/assets/index-e168f265.js +0 -600
@@ -0,0 +1,15 @@
1
+ <!doctype html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8" />
5
+ <link rel="icon" type="image/svg+xml" href="./vite.svg" />
6
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
7
+ <title>Vite + React + TS</title>
8
+ <script type="module" crossorigin src="./assets/index-930f01ca.js"></script>
9
+ <link rel="stylesheet" href="./assets/index-8ce6041d.css">
10
+ </head>
11
+ <body>
12
+ <div id="root"></div>
13
+
14
+ </body>
15
+ </html>
@@ -0,0 +1,14 @@
1
+ {
2
+ "author": "Hailer Oy",
3
+ "contributors": [
4
+ "broman.robert+claude@gmail.com"
5
+ ],
6
+ "appId": "695e3665701ef8e3824beebe",
7
+ "config": {
8
+ "fields": {
9
+ "workflowId": {
10
+ "type": "string"
11
+ }
12
+ }
13
+ }
14
+ }
@@ -0,0 +1 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" class="iconify iconify--logos" width="31.88" height="32" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 257"><defs><linearGradient id="IconifyId1813088fe1fbc01fb466" x1="-.828%" x2="57.636%" y1="7.652%" y2="78.411%"><stop offset="0%" stop-color="#41D1FF"></stop><stop offset="100%" stop-color="#BD34FE"></stop></linearGradient><linearGradient id="IconifyId1813088fe1fbc01fb467" x1="43.376%" x2="50.316%" y1="2.242%" y2="89.03%"><stop offset="0%" stop-color="#FFEA83"></stop><stop offset="8.333%" stop-color="#FFDD35"></stop><stop offset="100%" stop-color="#FFA800"></stop></linearGradient></defs><path fill="url(#IconifyId1813088fe1fbc01fb466)" d="M255.153 37.938L134.897 252.976c-2.483 4.44-8.862 4.466-11.382.048L.875 37.958c-2.746-4.814 1.371-10.646 6.827-9.67l120.385 21.517a6.537 6.537 0 0 0 2.322-.004l117.867-21.483c5.438-.991 9.574 4.796 6.877 9.62Z"></path><path fill="url(#IconifyId1813088fe1fbc01fb467)" d="M185.432.063L96.44 17.501a3.268 3.268 0 0 0-2.634 3.014l-5.474 92.456a3.268 3.268 0 0 0 3.997 3.378l24.777-5.718c2.318-.535 4.413 1.507 3.936 3.838l-7.361 36.047c-.495 2.426 1.782 4.5 4.151 3.78l15.304-4.649c2.372-.72 4.652 1.36 4.15 3.788l-11.698 56.621c-.732 3.542 3.979 5.473 5.943 2.437l1.313-2.028l72.516-144.72c1.215-2.423-.88-5.186-3.54-4.672l-25.505 4.922c-2.396.462-4.435-1.77-3.759-4.114l16.646-57.705c.677-2.35-1.37-4.583-3.769-4.113Z"></path></svg>
package/dist/app.js CHANGED
@@ -9,6 +9,7 @@ const user_1 = require("./mcp/tools/user");
9
9
  const workflow_1 = require("./mcp/tools/workflow");
10
10
  const insight_1 = require("./mcp/tools/insight");
11
11
  const app_1 = require("./mcp/tools/app");
12
+ const bot_config_1 = require("./mcp/tools/bot-config");
12
13
  const core = new core_1.Core();
13
14
  console.log('Registering tools...');
14
15
  console.log(`Nuclear tools ${config_1.environment.ENABLE_NUCLEAR_TOOLS ? 'ENABLED' : 'DISABLED'} (set ENABLE_NUCLEAR_TOOLS=true in .env.local to enable)`);
@@ -72,6 +73,10 @@ core.addTool(app_1.getProductManifestTool);
72
73
  // Marketplace app tools
73
74
  core.addTool(app_1.publishAppTool);
74
75
  core.addTool(app_1.installMarketplaceAppTool);
76
+ // Bot configuration tools
77
+ core.addTool(bot_config_1.listBotsConfigTool);
78
+ core.addTool(bot_config_1.enableBotTool);
79
+ core.addTool(bot_config_1.disableBotTool);
75
80
  console.log('All tools registered successfully!');
76
81
  // Start the application
77
82
  core.start().catch((error) => {
@@ -133,6 +133,11 @@ export declare class ChatAgentDaemon {
133
133
  * MUST be overridden in subclasses
134
134
  */
135
135
  protected getSystemPrompt(): string;
136
+ /**
137
+ * Get tools for LLM calls
138
+ * Override in subclass to add custom tools (like trigger_giuseppe_retry)
139
+ */
140
+ protected getTools(): Anthropic.Tool[];
136
141
  /**
137
142
  * Get tool whitelist for this agent
138
143
  * Override in subclass to limit which tools are available
@@ -290,7 +290,7 @@ class ChatAgentDaemon {
290
290
  max_tokens: 2000,
291
291
  system: this.getSystemPrompt(),
292
292
  messages: conversation,
293
- tools: this.minimalTools,
293
+ tools: this.getTools(),
294
294
  });
295
295
  // Track token usage in the activity session
296
296
  if (response.usage) {
@@ -395,7 +395,7 @@ ${message.content}
395
395
  max_tokens: 2000,
396
396
  system: this.getSystemPrompt(),
397
397
  messages: conversation,
398
- tools: this.minimalTools,
398
+ tools: this.getTools(),
399
399
  });
400
400
  // Track token usage in session
401
401
  if (session && response.usage) {
@@ -586,6 +586,13 @@ ${message.content}
586
586
  getSystemPrompt() {
587
587
  throw new Error("getSystemPrompt() must be implemented by subclass");
588
588
  }
589
+ /**
590
+ * Get tools for LLM calls
591
+ * Override in subclass to add custom tools (like trigger_giuseppe_retry)
592
+ */
593
+ getTools() {
594
+ return this.minimalTools;
595
+ }
589
596
  /**
590
597
  * Get tool whitelist for this agent
591
598
  * Override in subclass to limit which tools are available
@@ -21,6 +21,91 @@ exports.getSpecialistKeys = getSpecialistKeys;
21
21
  * Key is the specialist identifier used internally
22
22
  */
23
23
  exports.SPECIALISTS = {
24
+ giuseppe: {
25
+ name: "Giuseppe",
26
+ botEmail: "", // Set from config at runtime (uses same bot as orchestrator for now)
27
+ expertise: [
28
+ "bug fixing",
29
+ "app debugging",
30
+ "React/TypeScript fixes",
31
+ "Hailer app development",
32
+ "automated code repair",
33
+ ],
34
+ triggerPatterns: [
35
+ // Bug reports
36
+ /bug\s+(report|in|with|found)/i,
37
+ /report\s+(a\s+)?bug/i,
38
+ /found\s+(a\s+)?bug/i,
39
+ /there('s|\s+is)\s+(a\s+)?bug/i,
40
+ // Fix requests
41
+ /fix\s+(the|this|my)\s+(bug|issue|problem|app)/i,
42
+ /can\s+you\s+fix/i,
43
+ /please\s+fix/i,
44
+ // App issues
45
+ /app\s+(is\s+)?(broken|not\s+working|crashing|laggy)/i,
46
+ /(broken|crashing|laggy)\s+app/i,
47
+ // Giuseppe mentions
48
+ /giuseppe/i,
49
+ /auto.?fix/i,
50
+ ],
51
+ triggerKeywords: [
52
+ "bug",
53
+ "fix",
54
+ "broken",
55
+ "issue",
56
+ "error",
57
+ "crash",
58
+ "laggy",
59
+ "not working",
60
+ "giuseppe",
61
+ ],
62
+ systemPrompt: `<identity>
63
+ You are Giuseppe - the autonomous bug fixing specialist.
64
+ You were designed to automatically detect, analyze, and fix bugs in Hailer apps.
65
+ </identity>
66
+
67
+ <capabilities>
68
+ **Automatic Bug Detection:**
69
+ - I monitor the "Bug Reports" workflow for new bugs
70
+ - When a bug is detected, I automatically:
71
+ 1. Find the app project
72
+ 2. Analyze the code
73
+ 3. Generate a fix using Claude
74
+ 4. Apply and test the fix
75
+ 5. Ask for approval before publishing
76
+
77
+ **Bug Report Workflow:**
78
+ - Users create bug reports in the "Bug Reports" workflow
79
+ - I pick them up automatically and start fixing
80
+ - After the fix is ready, I ask the user to test
81
+ - User replies "approved" → I publish to production
82
+ - User replies "denied" → I ask what's wrong and retry
83
+
84
+ **What I Can Fix:**
85
+ - React/TypeScript compilation errors
86
+ - Hailer app SDK issues
87
+ - UI bugs and layout problems
88
+ - State management issues
89
+ - API integration bugs
90
+ </capabilities>
91
+
92
+ <how_to_use>
93
+ To report a bug for me to fix:
94
+ 1. Create a new activity in the "Bug Reports" workflow
95
+ 2. Set the title to include the app name (e.g., "Bug Report - My App")
96
+ 3. Describe the bug in detail
97
+ 4. I'll automatically pick it up and start working on it!
98
+
99
+ Or just tell HAL about a bug and ask to create a bug report.
100
+ </how_to_use>
101
+
102
+ <response_format>
103
+ When asked about bugs or my capabilities:
104
+ - Explain what I can do
105
+ - Offer to create a bug report if they describe a bug
106
+ - Tell them to check the Bug Reports workflow for status
107
+ </response_format>`,
108
+ },
24
109
  hailerExpert: {
25
110
  name: "Hailer Expert",
26
111
  botEmail: "", // Set from config at runtime
@@ -33,6 +33,11 @@ export declare class OrchestratorDaemon extends ChatAgentDaemon {
33
33
  private lastKnownActivityTime;
34
34
  private static CONTEXT_MEMORY_TIMEOUT;
35
35
  constructor(config: OrchestratorDaemonConfig);
36
+ /**
37
+ * Trigger HAL to respond in a discussion with specific context
38
+ * Used when bug monitor needs HAL to naturally inform users about Giuseppe being disabled
39
+ */
40
+ respondWithContext(discussionId: string, activityId: string, contextMessage: string): Promise<void>;
36
41
  /**
37
42
  * Override agent name for Agent Directory
38
43
  * Uses the actual Hailer user name from BotClient (set in workspace)
@@ -94,6 +99,22 @@ export declare class OrchestratorDaemon extends ChatAgentDaemon {
94
99
  * Invite a specialist to a discussion
95
100
  */
96
101
  private inviteSpecialist;
102
+ /**
103
+ * Override getTools to include Giuseppe retry tool when there's a pending fix
104
+ */
105
+ protected getTools(): Anthropic.Tool[];
106
+ /**
107
+ * Get tools list with Giuseppe retry tool added
108
+ */
109
+ private getToolsWithGiuseppeRetry;
110
+ /**
111
+ * Get pending fix context for a discussion (if any)
112
+ */
113
+ private getPendingFixContext;
114
+ /**
115
+ * Get pending classification context for a discussion (if any)
116
+ */
117
+ private getPendingClassificationContext;
97
118
  /**
98
119
  * Override system prompt to include orchestrator capabilities
99
120
  */
@@ -17,6 +17,8 @@ exports.OrchestratorDaemon = void 0;
17
17
  const base_1 = require("./base");
18
18
  const definitions_1 = require("./definitions");
19
19
  const logger_1 = require("../../lib/logger");
20
+ const pending_fix_registry_1 = require("../../modules/bug-reports/pending-fix-registry");
21
+ const pending_classification_registry_1 = require("../../modules/bug-reports/pending-classification-registry");
20
22
  class OrchestratorDaemon extends base_1.ChatAgentDaemon {
21
23
  orchestratorLogger;
22
24
  specialists = new Map();
@@ -47,6 +49,41 @@ class OrchestratorDaemon extends base_1.ChatAgentDaemon {
47
49
  this.specialistUserIds = config.specialistUserIds;
48
50
  }
49
51
  }
52
+ /**
53
+ * Trigger HAL to respond in a discussion with specific context
54
+ * Used when bug monitor needs HAL to naturally inform users about Giuseppe being disabled
55
+ */
56
+ async respondWithContext(discussionId, activityId, contextMessage) {
57
+ this.orchestratorLogger.info('Triggering contextual response', { discussionId, activityId });
58
+ try {
59
+ // Join the discussion first using MCP tool
60
+ await this.callMcpTool("join_discussion", { activityId });
61
+ // Get workspace ID from bot client cache
62
+ const workspaceId = this.config.botClient.workspaceCache?.currentWorkspace?._id || '';
63
+ // Create a synthetic incoming message with the context
64
+ const syntheticMessage = {
65
+ id: `synthetic-${Date.now()}`,
66
+ discussionId,
67
+ linkedActivityId: activityId,
68
+ workspaceId,
69
+ content: contextMessage,
70
+ senderName: 'System',
71
+ senderId: 'system',
72
+ timestamp: Date.now(),
73
+ priority: 'high',
74
+ priorityReason: 'system_notification',
75
+ isReplyToBot: false,
76
+ isMention: false,
77
+ isDirectMessage: false,
78
+ };
79
+ // Process through normal LLM pipeline
80
+ // This will make HAL respond naturally with the context
81
+ await this['processMessage'](syntheticMessage);
82
+ }
83
+ catch (error) {
84
+ this.orchestratorLogger.error('Failed to respond with context', { error });
85
+ }
86
+ }
50
87
  // ===== AGENT DIRECTORY OVERRIDES =====
51
88
  /**
52
89
  * Override agent name for Agent Directory
@@ -161,6 +198,110 @@ class OrchestratorDaemon extends base_1.ChatAgentDaemon {
161
198
  async executeToolsAndContinue(toolUseBlocks, originalMessage) {
162
199
  // Reset failure flag before executing tools
163
200
  this.lastToolsFailed = false;
201
+ // Handle local tools (not sent to MCP)
202
+ const localToolResults = [];
203
+ const mcpToolBlocks = [];
204
+ for (const toolBlock of toolUseBlocks) {
205
+ if (toolBlock.name === 'trigger_giuseppe_retry') {
206
+ // Handle locally - trigger Giuseppe retry
207
+ const input = toolBlock.input;
208
+ const explanation = input.explanation || '';
209
+ const discussionId = originalMessage.discussionId;
210
+ const pendingFix = pending_fix_registry_1.pendingFixRegistry.getPendingFix(discussionId);
211
+ if (!pendingFix) {
212
+ localToolResults.push({
213
+ type: 'tool_result',
214
+ tool_use_id: toolBlock.id,
215
+ content: 'No pending fix found for this discussion. The fix may have already been approved or cancelled.',
216
+ is_error: true,
217
+ });
218
+ }
219
+ else {
220
+ // Trigger the retry
221
+ const success = await pending_fix_registry_1.pendingFixRegistry.triggerRetry(discussionId, explanation);
222
+ localToolResults.push({
223
+ type: 'tool_result',
224
+ tool_use_id: toolBlock.id,
225
+ content: success
226
+ ? `✅ Triggered Giuseppe retry with explanation: "${explanation.substring(0, 100)}...". Giuseppe will analyze and apply a new fix.`
227
+ : '❌ Failed to trigger retry. Giuseppe may not be available.',
228
+ is_error: !success,
229
+ });
230
+ }
231
+ }
232
+ else if (toolBlock.name === 'confirm_bug_fix') {
233
+ // Handle locally - trigger Giuseppe fix confirmation
234
+ const discussionId = originalMessage.discussionId;
235
+ const hasPending = pending_classification_registry_1.pendingClassificationRegistry.has(discussionId);
236
+ if (!hasPending) {
237
+ localToolResults.push({
238
+ type: 'tool_result',
239
+ tool_use_id: toolBlock.id,
240
+ content: 'No pending classification found for this discussion. Giuseppe may have already processed it.',
241
+ is_error: true,
242
+ });
243
+ }
244
+ else {
245
+ const success = await pending_classification_registry_1.pendingClassificationRegistry.triggerFixIt(discussionId);
246
+ localToolResults.push({
247
+ type: 'tool_result',
248
+ tool_use_id: toolBlock.id,
249
+ content: success
250
+ ? '✅ Triggered Giuseppe to proceed with bug fix.'
251
+ : '❌ Failed to trigger fix. Giuseppe may not be available.',
252
+ is_error: !success,
253
+ });
254
+ }
255
+ }
256
+ else if (toolBlock.name === 'decline_bug_report') {
257
+ // Handle locally - trigger Giuseppe decline
258
+ const discussionId = originalMessage.discussionId;
259
+ const hasPending = pending_classification_registry_1.pendingClassificationRegistry.has(discussionId);
260
+ if (!hasPending) {
261
+ localToolResults.push({
262
+ type: 'tool_result',
263
+ tool_use_id: toolBlock.id,
264
+ content: 'No pending classification found for this discussion. Giuseppe may have already processed it.',
265
+ is_error: true,
266
+ });
267
+ }
268
+ else {
269
+ const success = await pending_classification_registry_1.pendingClassificationRegistry.triggerNotABug(discussionId);
270
+ localToolResults.push({
271
+ type: 'tool_result',
272
+ tool_use_id: toolBlock.id,
273
+ content: success
274
+ ? '✅ Marked as not a bug. Report moved to Declined.'
275
+ : '❌ Failed to decline. Giuseppe may not be available.',
276
+ is_error: !success,
277
+ });
278
+ }
279
+ }
280
+ else {
281
+ // Send to MCP
282
+ mcpToolBlocks.push(toolBlock);
283
+ }
284
+ }
285
+ // If we handled all tools locally, skip MCP execution
286
+ if (mcpToolBlocks.length === 0 && localToolResults.length > 0) {
287
+ const conversation = this.conversationManager.getConversation(originalMessage.discussionId);
288
+ conversation.push({
289
+ role: 'user',
290
+ content: localToolResults,
291
+ });
292
+ // Continue with LLM
293
+ const response = await this.client.messages.create({
294
+ model: this.config.model || 'claude-haiku-4-5-20251001',
295
+ max_tokens: 2000,
296
+ system: this.getSystemPrompt(),
297
+ messages: conversation,
298
+ tools: this.getToolsWithGiuseppeRetry(),
299
+ });
300
+ await this.handleLlmResponse(response, originalMessage);
301
+ return;
302
+ }
303
+ // If we have local results, add them to be processed together with MCP results
304
+ // (for now, just continue with original flow for MCP tools)
164
305
  // Get current activity session
165
306
  const sessionKey = this.currentLinkedActivityId || this.currentDiscussionId || "default";
166
307
  const session = this.sessionLogger.getSession(sessionKey);
@@ -319,6 +460,114 @@ class OrchestratorDaemon extends base_1.ChatAgentDaemon {
319
460
  return false;
320
461
  }
321
462
  }
463
+ /**
464
+ * Override getTools to include Giuseppe retry tool when there's a pending fix
465
+ */
466
+ getTools() {
467
+ // Always include the Giuseppe retry tool so LLM knows about it
468
+ return this.getToolsWithGiuseppeRetry();
469
+ }
470
+ /**
471
+ * Get tools list with Giuseppe retry tool added
472
+ */
473
+ getToolsWithGiuseppeRetry() {
474
+ const giuseppeRetryTool = {
475
+ name: 'trigger_giuseppe_retry',
476
+ description: 'Trigger Giuseppe to retry fixing a bug with new explanation. Use this after gathering enough info about what went wrong with the previous fix. Only works in discussions with a pending bug fix.',
477
+ input_schema: {
478
+ type: 'object',
479
+ properties: {
480
+ explanation: {
481
+ type: 'string',
482
+ description: 'Clear explanation of what is wrong with the current fix and what the expected behavior should be. Include: (1) what is broken, (2) expected vs actual behavior, (3) any specific details the user mentioned.',
483
+ },
484
+ },
485
+ required: ['explanation'],
486
+ },
487
+ };
488
+ const confirmBugFixTool = {
489
+ name: 'confirm_bug_fix',
490
+ description: 'Confirm that a bug report should be fixed. Use when user indicates they want the bug fixed (variations of "fix it", "yes fix", "please fix", etc.). Only works in discussions with a pending classification.',
491
+ input_schema: {
492
+ type: 'object',
493
+ properties: {},
494
+ required: [],
495
+ },
496
+ };
497
+ const declineBugReportTool = {
498
+ name: 'decline_bug_report',
499
+ description: 'Decline a bug report as not actually a bug. Use when user indicates it\'s not a bug (variations of "not a bug", "feature request", "not actually broken", etc.). Only works in discussions with a pending classification.',
500
+ input_schema: {
501
+ type: 'object',
502
+ properties: {},
503
+ required: [],
504
+ },
505
+ };
506
+ return [...this.minimalTools, giuseppeRetryTool, confirmBugFixTool, declineBugReportTool];
507
+ }
508
+ /**
509
+ * Get pending fix context for a discussion (if any)
510
+ */
511
+ getPendingFixContext(discussionId) {
512
+ const pendingFix = pending_fix_registry_1.pendingFixRegistry.getPendingFix(discussionId);
513
+ if (!pendingFix) {
514
+ return '';
515
+ }
516
+ return `
517
+ <pending_bug_fix>
518
+ **IMPORTANT: This discussion has a pending bug fix from Giuseppe!**
519
+
520
+ - Bug ID: ${pendingFix.bugId}
521
+ - State: ${pendingFix.state}
522
+ - Fix Summary: ${pendingFix.fixSummary}
523
+
524
+ **Your role:**
525
+ - If user says "approved" → Giuseppe handles it automatically (you do nothing)
526
+ - If user expresses ANY dissatisfaction (denied, not working, still broken, etc.):
527
+ 1. Ask what's wrong (if not clear)
528
+ 2. Gather: what's broken + expected behavior
529
+ 3. Use trigger_giuseppe_retry tool with the explanation
530
+
531
+ **Remember:** You're gathering info for Giuseppe. Be concise, ask ONE question at a time.
532
+ </pending_bug_fix>
533
+ `;
534
+ }
535
+ /**
536
+ * Get pending classification context for a discussion (if any)
537
+ */
538
+ getPendingClassificationContext(discussionId) {
539
+ const pending = pending_classification_registry_1.pendingClassificationRegistry.getPendingClassification(discussionId);
540
+ if (!pending) {
541
+ return '';
542
+ }
543
+ const classificationLabel = pending.classification === 'bug' ? 'Bug' :
544
+ pending.classification === 'feature_request' ? 'Feature Request' : 'Unclear';
545
+ return `
546
+ <pending_classification>
547
+ **IMPORTANT: Giuseppe just classified this report and is waiting for user decision!**
548
+
549
+ - Bug: ${pending.bugName}
550
+ - App: ${pending.appName || pending.appId || 'Unknown'}
551
+ - Classification: ${classificationLabel}
552
+ - Reason: ${pending.reason}
553
+
554
+ **User options:**
555
+ - "fix it" → Giuseppe will proceed to fix the bug
556
+ - "not a bug" → Report will be moved to Declined
557
+
558
+ **Your role - Use tools for user intent:**
559
+ - User wants to fix the bug → Call confirm_bug_fix tool
560
+ - User says it's not a bug / feature request → Call decline_bug_report tool
561
+ - User has questions → Help explain the classification
562
+
563
+ **Detecting intent (use tools, don't wait for exact words):**
564
+ - "fix it", "yes fix", "go ahead", "please fix", "fix this" → confirm_bug_fix
565
+ - "not a bug", "feature request", "not broken", "close it", "decline" → decline_bug_report
566
+
567
+ **Remember:** Use the tools to trigger actions. Don't tell user to type magic words.
568
+ </pending_classification>
569
+ `;
570
+ }
322
571
  /**
323
572
  * Override system prompt to include orchestrator capabilities
324
573
  */
@@ -447,6 +696,45 @@ Use 'fieldId' not 'id' for the field identifier.
447
696
  </after_invite>
448
697
  </specialists>
449
698
 
699
+ <giuseppe_autonomous>
700
+ **Giuseppe - Autonomous Bug Fixer**
701
+
702
+ Giuseppe is SPECIAL - he works AUTONOMOUSLY, not through invites!
703
+
704
+ **How Giuseppe works:**
705
+ 1. Users create a bug report in the "Bug Reports" workflow
706
+ 2. Giuseppe automatically detects new bugs and starts fixing them
707
+ 3. He analyzes the code, generates a fix, tests it
708
+ 4. He asks the user to verify with "approved" or "denied"
709
+ 5. On "approved" → Giuseppe publishes to production automatically
710
+ 6. On "denied" or complaint → YOU (HAL) gather info, then trigger Giuseppe retry
711
+
712
+ **YOUR ROLE IN BUG FIX DENIALS:**
713
+ When a discussion has a pending bug fix and the user expresses dissatisfaction:
714
+ 1. YOU handle the conversation - ask what's wrong, what behavior they expected
715
+ 2. Gather enough context: what's broken, expected vs actual behavior
716
+ 3. Once you have clear info, use trigger_giuseppe_retry tool to pass the explanation
717
+ 4. Giuseppe will receive your gathered info and retry the fix
718
+
719
+ **Detecting denial signals:**
720
+ - "denied", "not working", "still broken", "wrong", "doesn't work"
721
+ - Any complaint about the fix behavior
722
+ - User describing unexpected behavior
723
+
724
+ **Gathering info (ask ONE question at a time):**
725
+ - "What behavior are you seeing?"
726
+ - "What did you expect to happen instead?"
727
+ - "Is the issue consistent or intermittent?"
728
+
729
+ **When to trigger retry:**
730
+ Once you have: (1) what's wrong, (2) expected behavior → trigger the retry
731
+
732
+ **When someone mentions bugs (NEW bugs):**
733
+ - Tell them to create a bug report in "Bug Reports" workflow
734
+ - Explain Giuseppe will pick it up automatically
735
+ - Offer to help create the bug report for them
736
+ </giuseppe_autonomous>
737
+
450
738
  <your_tools>
451
739
  You have access to basic MCP tools for simple operations:
452
740
  - list_workflows, list_workflow_phases, get_workflow_schema
@@ -532,7 +820,10 @@ Only use <respond> when you have the FINAL answer to share.
532
820
  - When inviting specialists, explain to the user what's happening
533
821
  - After specialist responds, summarize for the user if needed
534
822
  - **Complete work before responding** - Never say "I'm going to do X", just DO X with tool calls
535
- </rules>`;
823
+ </rules>
824
+
825
+ ${this.currentDiscussionId ? this.getPendingFixContext(this.currentDiscussionId) : ''}
826
+ ${this.currentDiscussionId ? this.getPendingClassificationContext(this.currentDiscussionId) : ''}`;
536
827
  }
537
828
  /**
538
829
  * Override response handling to detect specialist invitations
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Bot Entry Point - Single workspace, single bot
3
+ *
4
+ * Uses API key authentication via UserContextCache (which resolves to email/password internally)
5
+ */
6
+ export {};
7
+ //# sourceMappingURL=bot-entrypoint.d.ts.map
@@ -0,0 +1,103 @@
1
+ "use strict";
2
+ /**
3
+ * Bot Entry Point - Single workspace, single bot
4
+ *
5
+ * Uses API key authentication via UserContextCache (which resolves to email/password internally)
6
+ */
7
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
8
+ if (k2 === undefined) k2 = k;
9
+ var desc = Object.getOwnPropertyDescriptor(m, k);
10
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
11
+ desc = { enumerable: true, get: function() { return m[k]; } };
12
+ }
13
+ Object.defineProperty(o, k2, desc);
14
+ }) : (function(o, m, k, k2) {
15
+ if (k2 === undefined) k2 = k;
16
+ o[k2] = m[k];
17
+ }));
18
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
19
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
20
+ }) : function(o, v) {
21
+ o["default"] = v;
22
+ });
23
+ var __importStar = (this && this.__importStar) || (function () {
24
+ var ownKeys = function(o) {
25
+ ownKeys = Object.getOwnPropertyNames || function (o) {
26
+ var ar = [];
27
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
28
+ return ar;
29
+ };
30
+ return ownKeys(o);
31
+ };
32
+ return function (mod) {
33
+ if (mod && mod.__esModule) return mod;
34
+ var result = {};
35
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
36
+ __setModuleDefault(result, mod);
37
+ return result;
38
+ };
39
+ })();
40
+ Object.defineProperty(exports, "__esModule", { value: true });
41
+ const logger_1 = require("../lib/logger");
42
+ const workspaceId = process.env.BOT_WORKSPACE_ID || 'unknown';
43
+ const botId = process.env.BOT_ID || 'unknown';
44
+ const logger = (0, logger_1.createLogger)({ component: `bot-${workspaceId}-${botId}` });
45
+ async function main() {
46
+ const apiKey = process.env.BOT_API_KEY;
47
+ const workspaceName = process.env.BOT_WORKSPACE_NAME || workspaceId;
48
+ if (!apiKey) {
49
+ throw new Error('Missing BOT_API_KEY');
50
+ }
51
+ logger.info('Bot starting', { workspaceId, workspaceName, botId });
52
+ try {
53
+ // Dynamic import based on bot ID
54
+ if (botId === 'giuseppe') {
55
+ // Import UserContextCache and Bug Reports module
56
+ const { UserContextCache } = await Promise.resolve().then(() => __importStar(require('../mcp/UserContextCache')));
57
+ const { BugReportsModule } = await Promise.resolve().then(() => __importStar(require('../modules/bug-reports')));
58
+ // Get user context via API key (handles Hailer connection internally)
59
+ const userContext = await UserContextCache.getContext(apiKey);
60
+ logger.info('Connected to Hailer', { workspaceId });
61
+ // Start Giuseppe
62
+ const bugReports = new BugReportsModule(userContext);
63
+ await bugReports.start();
64
+ logger.info('Giuseppe bot started', { workspaceId });
65
+ // Notify parent
66
+ if (process.send) {
67
+ process.send({ type: 'ready' });
68
+ }
69
+ // Handle shutdown
70
+ process.on('message', async (msg) => {
71
+ if (msg.type === 'shutdown') {
72
+ logger.info('Shutting down');
73
+ await bugReports.stop();
74
+ process.exit(0);
75
+ }
76
+ });
77
+ }
78
+ else if (botId === 'vastuullisuus') {
79
+ // TODO: Implement Vastuullisuus bot
80
+ logger.info('Vastuullisuus bot not yet implemented');
81
+ if (process.send) {
82
+ process.send({ type: 'ready' });
83
+ }
84
+ process.on('message', async (msg) => {
85
+ if (msg.type === 'shutdown') {
86
+ process.exit(0);
87
+ }
88
+ });
89
+ }
90
+ else {
91
+ throw new Error(`Unknown bot: ${botId}`);
92
+ }
93
+ }
94
+ catch (error) {
95
+ logger.error('Bot failed', { error });
96
+ if (process.send) {
97
+ process.send({ type: 'error', error: error instanceof Error ? error.message : String(error) });
98
+ }
99
+ process.exit(1);
100
+ }
101
+ }
102
+ main();
103
+ //# sourceMappingURL=bot-entrypoint.js.map