@hailer/mcp 0.1.16 → 0.2.1

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 (202) hide show
  1. package/dist/app.js +24 -20
  2. package/dist/core.d.ts +33 -9
  3. package/dist/core.js +279 -147
  4. package/dist/mcp/UserContextCache.js +18 -0
  5. package/dist/mcp/hailer-clients.d.ts +9 -1
  6. package/dist/mcp/hailer-clients.js +13 -3
  7. package/dist/mcp/signal-handler.js +1 -1
  8. package/dist/mcp/tool-registry.d.ts +3 -1
  9. package/dist/mcp/tool-registry.js +4 -1
  10. package/dist/mcp/tools/activity.js +43 -34
  11. package/dist/mcp/tools/bot-config/constants.d.ts +23 -0
  12. package/dist/mcp/tools/bot-config/constants.js +94 -0
  13. package/dist/mcp/tools/{bot-config.d.ts → bot-config/core.d.ts} +6 -6
  14. package/dist/mcp/tools/{bot-config.js → bot-config/core.js} +15 -15
  15. package/dist/mcp/tools/bot-config/index.d.ts +10 -0
  16. package/dist/mcp/tools/bot-config/index.js +59 -0
  17. package/dist/mcp/tools/bot-config/tools.d.ts +7 -0
  18. package/dist/mcp/tools/bot-config/tools.js +15 -0
  19. package/dist/mcp/tools/bot-config/types.d.ts +50 -0
  20. package/dist/mcp/tools/bot-config/types.js +6 -0
  21. package/dist/mcp/tools/bug-fixer-tools.d.ts +21 -0
  22. package/dist/mcp/tools/{giuseppe-tools.js → bug-fixer-tools.js} +61 -61
  23. package/dist/mcp/tools/user.js +10 -29
  24. package/dist/mcp/tools/workflow.js +36 -2
  25. package/dist/mcp/utils/data-transformers.d.ts +0 -8
  26. package/dist/mcp/utils/data-transformers.js +0 -28
  27. package/dist/mcp/utils/index.d.ts +4 -1
  28. package/dist/mcp/utils/index.js +17 -3
  29. package/dist/mcp/utils/pagination.d.ts +40 -0
  30. package/dist/mcp/utils/pagination.js +55 -0
  31. package/dist/mcp/utils/response-builder.d.ts +53 -0
  32. package/dist/mcp/utils/response-builder.js +110 -0
  33. package/dist/mcp/utils/tool-helpers.d.ts +0 -8
  34. package/dist/mcp/utils/tool-helpers.js +0 -24
  35. package/dist/mcp/utils/types.d.ts +1 -33
  36. package/dist/mcp/webhook-handler.d.ts +2 -2
  37. package/dist/mcp/webhook-handler.js +5 -3
  38. package/dist/mcp-server.d.ts +2 -2
  39. package/dist/mcp-server.js +167 -140
  40. package/package.json +1 -1
  41. package/REFACTOR_STATUS.md +0 -127
  42. package/dist/agents/bot-manager.d.ts +0 -48
  43. package/dist/agents/bot-manager.js +0 -254
  44. package/dist/agents/factory.d.ts +0 -150
  45. package/dist/agents/factory.js +0 -650
  46. package/dist/agents/giuseppe/ai.d.ts +0 -83
  47. package/dist/agents/giuseppe/ai.js +0 -466
  48. package/dist/agents/giuseppe/bot.d.ts +0 -110
  49. package/dist/agents/giuseppe/bot.js +0 -780
  50. package/dist/agents/giuseppe/config.d.ts +0 -25
  51. package/dist/agents/giuseppe/config.js +0 -227
  52. package/dist/agents/giuseppe/files.d.ts +0 -52
  53. package/dist/agents/giuseppe/files.js +0 -338
  54. package/dist/agents/giuseppe/git.d.ts +0 -48
  55. package/dist/agents/giuseppe/git.js +0 -298
  56. package/dist/agents/giuseppe/index.d.ts +0 -97
  57. package/dist/agents/giuseppe/index.js +0 -258
  58. package/dist/agents/giuseppe/lsp.d.ts +0 -113
  59. package/dist/agents/giuseppe/lsp.js +0 -485
  60. package/dist/agents/giuseppe/monitor.d.ts +0 -118
  61. package/dist/agents/giuseppe/monitor.js +0 -621
  62. package/dist/agents/giuseppe/prompt.d.ts +0 -5
  63. package/dist/agents/giuseppe/prompt.js +0 -94
  64. package/dist/agents/giuseppe/registries/pending-classification.d.ts +0 -28
  65. package/dist/agents/giuseppe/registries/pending-classification.js +0 -50
  66. package/dist/agents/giuseppe/registries/pending-fix.d.ts +0 -30
  67. package/dist/agents/giuseppe/registries/pending-fix.js +0 -42
  68. package/dist/agents/giuseppe/registries/pending.d.ts +0 -27
  69. package/dist/agents/giuseppe/registries/pending.js +0 -49
  70. package/dist/agents/giuseppe/specialist.d.ts +0 -47
  71. package/dist/agents/giuseppe/specialist.js +0 -237
  72. package/dist/agents/giuseppe/types.d.ts +0 -123
  73. package/dist/agents/giuseppe/types.js +0 -9
  74. package/dist/agents/hailer-expert/index.d.ts +0 -8
  75. package/dist/agents/hailer-expert/index.js +0 -14
  76. package/dist/agents/hal/daemon.d.ts +0 -142
  77. package/dist/agents/hal/daemon.js +0 -1103
  78. package/dist/agents/hal/definitions.d.ts +0 -55
  79. package/dist/agents/hal/definitions.js +0 -263
  80. package/dist/agents/hal/index.d.ts +0 -3
  81. package/dist/agents/hal/index.js +0 -8
  82. package/dist/agents/index.d.ts +0 -18
  83. package/dist/agents/index.js +0 -48
  84. package/dist/agents/shared/base.d.ts +0 -216
  85. package/dist/agents/shared/base.js +0 -846
  86. package/dist/agents/shared/services/agent-registry.d.ts +0 -107
  87. package/dist/agents/shared/services/agent-registry.js +0 -629
  88. package/dist/agents/shared/services/conversation-manager.d.ts +0 -50
  89. package/dist/agents/shared/services/conversation-manager.js +0 -136
  90. package/dist/agents/shared/services/mcp-client.d.ts +0 -56
  91. package/dist/agents/shared/services/mcp-client.js +0 -124
  92. package/dist/agents/shared/services/message-classifier.d.ts +0 -37
  93. package/dist/agents/shared/services/message-classifier.js +0 -187
  94. package/dist/agents/shared/services/message-formatter.d.ts +0 -89
  95. package/dist/agents/shared/services/message-formatter.js +0 -371
  96. package/dist/agents/shared/services/session-logger.d.ts +0 -106
  97. package/dist/agents/shared/services/session-logger.js +0 -446
  98. package/dist/agents/shared/services/tool-executor.d.ts +0 -41
  99. package/dist/agents/shared/services/tool-executor.js +0 -169
  100. package/dist/agents/shared/services/workspace-schema-cache.d.ts +0 -125
  101. package/dist/agents/shared/services/workspace-schema-cache.js +0 -578
  102. package/dist/agents/shared/specialist.d.ts +0 -91
  103. package/dist/agents/shared/specialist.js +0 -399
  104. package/dist/agents/shared/tool-schema-loader.d.ts +0 -62
  105. package/dist/agents/shared/tool-schema-loader.js +0 -232
  106. package/dist/agents/shared/types.d.ts +0 -327
  107. package/dist/agents/shared/types.js +0 -121
  108. package/dist/client/agents/base.d.ts +0 -207
  109. package/dist/client/agents/base.js +0 -744
  110. package/dist/client/agents/definitions.d.ts +0 -53
  111. package/dist/client/agents/definitions.js +0 -263
  112. package/dist/client/agents/orchestrator.d.ts +0 -141
  113. package/dist/client/agents/orchestrator.js +0 -1062
  114. package/dist/client/agents/specialist.d.ts +0 -86
  115. package/dist/client/agents/specialist.js +0 -340
  116. package/dist/client/bot-entrypoint.d.ts +0 -7
  117. package/dist/client/bot-entrypoint.js +0 -103
  118. package/dist/client/bot-manager.d.ts +0 -44
  119. package/dist/client/bot-manager.js +0 -173
  120. package/dist/client/bot-runner.d.ts +0 -35
  121. package/dist/client/bot-runner.js +0 -188
  122. package/dist/client/chat-agent-daemon.d.ts +0 -464
  123. package/dist/client/chat-agent-daemon.js +0 -1774
  124. package/dist/client/daemon-factory.d.ts +0 -106
  125. package/dist/client/daemon-factory.js +0 -301
  126. package/dist/client/factory.d.ts +0 -111
  127. package/dist/client/factory.js +0 -314
  128. package/dist/client/index.d.ts +0 -17
  129. package/dist/client/index.js +0 -38
  130. package/dist/client/multi-bot-manager.d.ts +0 -42
  131. package/dist/client/multi-bot-manager.js +0 -161
  132. package/dist/client/orchestrator-daemon.d.ts +0 -87
  133. package/dist/client/orchestrator-daemon.js +0 -444
  134. package/dist/client/server.d.ts +0 -8
  135. package/dist/client/server.js +0 -251
  136. package/dist/client/services/agent-registry.d.ts +0 -108
  137. package/dist/client/services/agent-registry.js +0 -630
  138. package/dist/client/services/conversation-manager.d.ts +0 -50
  139. package/dist/client/services/conversation-manager.js +0 -136
  140. package/dist/client/services/mcp-client.d.ts +0 -48
  141. package/dist/client/services/mcp-client.js +0 -105
  142. package/dist/client/services/message-classifier.d.ts +0 -37
  143. package/dist/client/services/message-classifier.js +0 -187
  144. package/dist/client/services/message-formatter.d.ts +0 -84
  145. package/dist/client/services/message-formatter.js +0 -353
  146. package/dist/client/services/session-logger.d.ts +0 -106
  147. package/dist/client/services/session-logger.js +0 -446
  148. package/dist/client/services/tool-executor.d.ts +0 -41
  149. package/dist/client/services/tool-executor.js +0 -169
  150. package/dist/client/services/workspace-schema-cache.d.ts +0 -149
  151. package/dist/client/services/workspace-schema-cache.js +0 -732
  152. package/dist/client/specialist-daemon.d.ts +0 -77
  153. package/dist/client/specialist-daemon.js +0 -197
  154. package/dist/client/specialists.d.ts +0 -53
  155. package/dist/client/specialists.js +0 -178
  156. package/dist/client/tool-schema-loader.d.ts +0 -62
  157. package/dist/client/tool-schema-loader.js +0 -232
  158. package/dist/client/types.d.ts +0 -327
  159. package/dist/client/types.js +0 -121
  160. package/dist/commands/seed-config.d.ts +0 -9
  161. package/dist/commands/seed-config.js +0 -372
  162. package/dist/lib/context-manager.d.ts +0 -111
  163. package/dist/lib/context-manager.js +0 -431
  164. package/dist/lib/prompt-length-manager.d.ts +0 -81
  165. package/dist/lib/prompt-length-manager.js +0 -457
  166. package/dist/mcp/tools/giuseppe-tools.d.ts +0 -21
  167. package/dist/modules/bug-reports/bug-config.d.ts +0 -25
  168. package/dist/modules/bug-reports/bug-config.js +0 -187
  169. package/dist/modules/bug-reports/bug-monitor.d.ts +0 -108
  170. package/dist/modules/bug-reports/bug-monitor.js +0 -510
  171. package/dist/modules/bug-reports/giuseppe-agent.d.ts +0 -58
  172. package/dist/modules/bug-reports/giuseppe-agent.js +0 -467
  173. package/dist/modules/bug-reports/giuseppe-ai.d.ts +0 -83
  174. package/dist/modules/bug-reports/giuseppe-ai.js +0 -466
  175. package/dist/modules/bug-reports/giuseppe-bot.d.ts +0 -110
  176. package/dist/modules/bug-reports/giuseppe-bot.js +0 -804
  177. package/dist/modules/bug-reports/giuseppe-daemon.d.ts +0 -80
  178. package/dist/modules/bug-reports/giuseppe-daemon.js +0 -617
  179. package/dist/modules/bug-reports/giuseppe-files.d.ts +0 -64
  180. package/dist/modules/bug-reports/giuseppe-files.js +0 -375
  181. package/dist/modules/bug-reports/giuseppe-git.d.ts +0 -48
  182. package/dist/modules/bug-reports/giuseppe-git.js +0 -298
  183. package/dist/modules/bug-reports/giuseppe-lsp.d.ts +0 -113
  184. package/dist/modules/bug-reports/giuseppe-lsp.js +0 -485
  185. package/dist/modules/bug-reports/giuseppe-prompt.d.ts +0 -5
  186. package/dist/modules/bug-reports/giuseppe-prompt.js +0 -94
  187. package/dist/modules/bug-reports/index.d.ts +0 -77
  188. package/dist/modules/bug-reports/index.js +0 -215
  189. package/dist/modules/bug-reports/pending-classification-registry.d.ts +0 -28
  190. package/dist/modules/bug-reports/pending-classification-registry.js +0 -50
  191. package/dist/modules/bug-reports/pending-fix-registry.d.ts +0 -30
  192. package/dist/modules/bug-reports/pending-fix-registry.js +0 -42
  193. package/dist/modules/bug-reports/pending-registry.d.ts +0 -27
  194. package/dist/modules/bug-reports/pending-registry.js +0 -49
  195. package/dist/modules/bug-reports/types.d.ts +0 -123
  196. package/dist/modules/bug-reports/types.js +0 -9
  197. package/dist/routes/agents.d.ts +0 -44
  198. package/dist/routes/agents.js +0 -311
  199. package/dist/services/agent-credential-store.d.ts +0 -73
  200. package/dist/services/agent-credential-store.js +0 -212
  201. package/dist/services/bug-monitor.d.ts +0 -23
  202. package/dist/services/bug-monitor.js +0 -275
@@ -1,804 +0,0 @@
1
- "use strict";
2
- /**
3
- * Bug Reports Module - Giuseppe Bot
4
- *
5
- * Autonomous app fixer that:
6
- * 1. Analyzes bug reports
7
- * 2. Finds app project code
8
- * 3. Generates fixes using Claude
9
- * 4. Tests locally
10
- * 5. Publishes to production
11
- */
12
- Object.defineProperty(exports, "__esModule", { value: true });
13
- exports.GiuseppeBot = void 0;
14
- const child_process_1 = require("child_process");
15
- const logger_1 = require("../../lib/logger");
16
- const pending_fix_registry_1 = require("./pending-fix-registry");
17
- const pending_classification_registry_1 = require("./pending-classification-registry");
18
- const app_scaffold_1 = require("../../mcp/tools/app-scaffold");
19
- // Import extracted modules
20
- const giuseppe_ai_1 = require("./giuseppe-ai");
21
- const giuseppe_git_1 = require("./giuseppe-git");
22
- const giuseppe_files_1 = require("./giuseppe-files");
23
- const giuseppe_lsp_1 = require("./giuseppe-lsp");
24
- const discussion_lock_1 = require("../../lib/discussion-lock");
25
- const logger = (0, logger_1.createLogger)({ component: 'giuseppe-bot' });
26
- // Session Log (Context Log) field IDs for logging
27
- const SESSION_LOG_CONFIG = {
28
- workflowId: '695784898d347a6c707ee397',
29
- phaseId: '695784898d347a6c707ee3c3', // Active phase
30
- teamId: '6901c67b4e80fecb6fd7b38b', // Required team
31
- fields: {
32
- contextSummary: '695784898d347a6c707ee3be',
33
- linkedWork: '695784898d347a6c707ee3c0', // Link to bug report
34
- madeBy: '695784898d347a6c707ee3c2' // Link to agent
35
- }
36
- };
37
- class GiuseppeBot {
38
- userContext;
39
- config;
40
- monitor;
41
- ai;
42
- git;
43
- files;
44
- lsp;
45
- appsRegistry = new Map();
46
- constructor(userContext, config, monitor) {
47
- this.userContext = userContext;
48
- this.config = config;
49
- this.monitor = monitor;
50
- // Initialize extracted modules
51
- const apiKey = config.anthropicApiKey || process.env.ANTHROPIC_API_KEY;
52
- this.ai = new giuseppe_ai_1.GiuseppeAI(apiKey);
53
- this.git = new giuseppe_git_1.GiuseppeGit();
54
- this.files = new giuseppe_files_1.GiuseppeFiles(process.env.DEV_APPS_PATH);
55
- this.lsp = new giuseppe_lsp_1.GiuseppeLsp();
56
- // Load apps registry from config
57
- if (config.appsRegistry) {
58
- for (const [appId, entry] of Object.entries(config.appsRegistry)) {
59
- this.appsRegistry.set(appId, entry);
60
- }
61
- }
62
- }
63
- /**
64
- * Create a session log entry in Context Log workflow
65
- * Links to the bug report for traceability
66
- */
67
- async createSessionLogEntry(title, summary, bugActivityId) {
68
- try {
69
- const { hailer } = this.userContext;
70
- // createActivities expects array of activity objects with 'fields' (not 'fieldsAndValues')
71
- const activities = [{
72
- name: title,
73
- phaseId: SESSION_LOG_CONFIG.phaseId,
74
- teamId: SESSION_LOG_CONFIG.teamId,
75
- fields: {
76
- [SESSION_LOG_CONFIG.fields.contextSummary]: summary,
77
- [SESSION_LOG_CONFIG.fields.linkedWork]: bugActivityId
78
- }
79
- }];
80
- const result = await hailer.createActivities(SESSION_LOG_CONFIG.workflowId, activities);
81
- // Result is array of created activity IDs
82
- const createdId = result?.[0];
83
- if (createdId) {
84
- logger.info('Created session log entry', {
85
- logId: createdId,
86
- title,
87
- linkedBugId: bugActivityId
88
- });
89
- return createdId;
90
- }
91
- return null;
92
- }
93
- catch (error) {
94
- logger.warn('Failed to create session log entry', {
95
- title,
96
- bugActivityId,
97
- error: error instanceof Error ? error.message : String(error)
98
- });
99
- return null;
100
- }
101
- }
102
- /**
103
- * Check if this bug was already classified by looking for classification message in discussion
104
- */
105
- async wasAlreadyClassified(bug) {
106
- if (!bug.discussionId)
107
- return false;
108
- try {
109
- const { hailer } = this.userContext;
110
- const result = await hailer.fetchDiscussionMessages(bug.discussionId, 20);
111
- const messages = result?.messages || [];
112
- // Check if any message contains our classification pattern
113
- return messages.some((msg) => {
114
- const content = msg.content || msg.msg || msg.message || '';
115
- return content.includes('**Classification:') && content.includes('Reply **"fix it"**');
116
- });
117
- }
118
- catch (error) {
119
- logger.debug('Failed to check classification history', { bugId: bug.id, error });
120
- return false;
121
- }
122
- }
123
- /**
124
- * Handle a new bug - main entry point
125
- */
126
- async handleBug(bug) {
127
- logger.info('Giuseppe analyzing report', {
128
- bugId: bug.id,
129
- bugName: bug.name,
130
- appId: bug.appId
131
- });
132
- // Acquire lock on this discussion to prevent other bots (Orchestrator) from responding
133
- if (bug.discussionId) {
134
- (0, discussion_lock_1.acquireDiscussionLock)(bug.discussionId, 'giuseppe', 10 * 60 * 1000); // 10 minute lock
135
- }
136
- const result = {
137
- success: false,
138
- summary: '',
139
- log: []
140
- };
141
- // Check if already classified (e.g., after server restart)
142
- const alreadyClassified = await this.wasAlreadyClassified(bug);
143
- if (alreadyClassified) {
144
- logger.info('Bug already classified, skipping re-classification', { bugId: bug.id });
145
- // Re-register in pending registry for message watching (in case server restarted)
146
- if (bug.discussionId) {
147
- // Just register with unknown classification - we're waiting for user response
148
- pending_classification_registry_1.pendingClassificationRegistry.register({
149
- discussionId: bug.discussionId,
150
- bugId: bug.id,
151
- bugName: bug.name,
152
- appId: bug.appId,
153
- appName: bug.appName,
154
- classification: 'unclear', // Unknown at this point
155
- reason: 'Previously classified',
156
- timestamp: Date.now(),
157
- bug
158
- });
159
- this.monitor.watchDiscussion(bug.discussionId);
160
- }
161
- return {
162
- success: false,
163
- summary: 'Already classified - awaiting confirmation'
164
- };
165
- }
166
- try {
167
- // 0. Join the bug's discussion so we can post updates
168
- await this.joinBugDiscussion(bug.id);
169
- // 1. Classify the report first
170
- const { classification, reason } = await this.ai.classifyReport(bug);
171
- result.log?.push(`Classification: ${classification} - ${reason}`);
172
- // 2. Post classification and ask for confirmation
173
- const classificationEmoji = classification === 'bug' ? '🐛' : classification === 'feature_request' ? '✨' : '❓';
174
- const classificationLabel = classification === 'bug' ? 'Bug' : classification === 'feature_request' ? 'Feature Request' : 'Unclear';
175
- const confirmMessage = [
176
- `${classificationEmoji} **Classification: ${classificationLabel}**`,
177
- '',
178
- `**Reason:** ${reason}`,
179
- '',
180
- classification === 'bug'
181
- ? `This looks like a bug I can try to fix.\n\n👉 Reply **"fix it"** to proceed with auto-fix.\n👉 Reply **"not a bug"** if this is actually a feature request.`
182
- : `This looks like a feature request, not a bug.\n\n👉 Reply **"fix it"** if you still want me to try.\n👉 Reply **"not a bug"** to confirm and close.`
183
- ].join('\n');
184
- await this.reportProgress(bug, confirmMessage);
185
- // 3. Store pending classification and wait for user response
186
- if (bug.discussionId) {
187
- pending_classification_registry_1.pendingClassificationRegistry.register({
188
- discussionId: bug.discussionId,
189
- bugId: bug.id,
190
- bugName: bug.name,
191
- appId: bug.appId,
192
- appName: bug.appName,
193
- classification,
194
- reason,
195
- timestamp: Date.now(),
196
- bug
197
- });
198
- logger.info('Stored pending classification', {
199
- discussionId: bug.discussionId,
200
- bugId: bug.id,
201
- classification,
202
- pendingClassificationsSize: pending_classification_registry_1.pendingClassificationRegistry.size
203
- });
204
- this.monitor.watchDiscussion(bug.discussionId);
205
- }
206
- result.summary = `Classified as ${classificationLabel} - awaiting confirmation`;
207
- result.log?.push('Waiting for user to confirm with "fix it"');
208
- return result;
209
- }
210
- catch (error) {
211
- const errorMessage = error instanceof Error ? error.message : String(error);
212
- logger.error('Classification failed', { bugId: bug.id, error: errorMessage });
213
- result.summary = `Classification error: ${errorMessage}`;
214
- return result;
215
- }
216
- }
217
- /**
218
- * Continue with bug fix after user confirms
219
- */
220
- async proceedWithFix(bug) {
221
- logger.info('Giuseppe proceeding with fix', {
222
- bugId: bug.id,
223
- bugName: bug.name,
224
- appId: bug.appId
225
- });
226
- const result = {
227
- success: false,
228
- summary: '',
229
- log: []
230
- };
231
- try {
232
- // 1. Find app project
233
- const app = await this.files.findAppProject(bug, this.appsRegistry);
234
- if (!app) {
235
- result.summary = `Could not find app project for appId: ${bug.appId}`;
236
- result.log?.push('App project not found');
237
- await this.reportProgress(bug, `❌ ${result.summary}`);
238
- return result;
239
- }
240
- result.log?.push(`Found app project: ${app.projectPath}`);
241
- await this.reportProgress(bug, `📁 Found app project: ${app.name}`);
242
- // Note: LSP analysis now runs AFTER Phase 1 identifies relevant files
243
- // This is more efficient - we only analyze files related to the bug
244
- // 2. Analyze and generate fix
245
- const allFiles = await this.files.scanSourceFiles(app.projectPath);
246
- // Create LSP analysis callback - runs TARGETED analysis on specific files
247
- const runLspAnalysis = async (files, keywords) => {
248
- logger.info('Running targeted LSP analysis', { files: files.length, keywords });
249
- const analysis = await this.lsp.analyzeRelevantFiles(app.projectPath, files, keywords);
250
- return {
251
- unusedProps: (analysis.unusedProps || []).map((p) => ({
252
- name: p.name,
253
- line: p.line,
254
- file: p.file || 'unknown'
255
- })),
256
- issues: (analysis.issues || []).map(i => ({
257
- file: i.file,
258
- line: i.line,
259
- message: i.message
260
- }))
261
- };
262
- };
263
- const fixPlan = await this.ai.analyzeAndPlanFix(bug, app, allFiles, (paths) => this.files.readSelectedFiles(app.projectPath, paths), runLspAnalysis);
264
- if (!fixPlan) {
265
- result.summary = 'Could not generate fix plan';
266
- result.log?.push('Fix plan generation failed');
267
- await this.reportProgress(bug, '❌ Could not analyze bug - manual review needed');
268
- return result;
269
- }
270
- result.log?.push(`Fix plan: ${fixPlan.analysis}`);
271
- await this.reportProgress(bug, `🔍 Analysis: ${fixPlan.analysis}\n🔧 Root cause: ${fixPlan.rootCause}`);
272
- // 3. Move to "In Progress"
273
- await this.monitor.moveBugToPhase(bug.id, 'inProgress');
274
- // 4. Apply fixes and build (with retry on any failure)
275
- const MAX_RETRIES = 3;
276
- let currentFixPlan = fixPlan;
277
- let fixSuccess = false;
278
- for (let attempt = 1; attempt <= MAX_RETRIES; attempt++) {
279
- // Try to apply the fix
280
- const applyResult = await this.files.applyFixes(app, currentFixPlan.fix.files);
281
- if (!applyResult.success) {
282
- // Apply failed - likely search string not found
283
- result.log?.push(`Apply failed (attempt ${attempt}): ${applyResult.error}`);
284
- await this.reportProgress(bug, `❌ Apply failed (attempt ${attempt}/${MAX_RETRIES}): ${applyResult.error}`);
285
- if (attempt < MAX_RETRIES) {
286
- await this.reportProgress(bug, `🔄 Re-reading file and generating new fix...`);
287
- // Re-read the current state of files that need to be modified
288
- const filePaths = currentFixPlan.fix.files.map(f => f.path);
289
- const currentFiles = await this.files.readSelectedFiles(app.projectPath, filePaths);
290
- // Re-generate fix with current file state
291
- const retryFix = await this.ai.retryFixFromApplyError(bug, currentFixPlan, applyResult.error || 'Unknown error', currentFiles, attempt);
292
- if (!retryFix) {
293
- result.log?.push('Could not generate retry fix');
294
- await this.reportProgress(bug, `❌ Could not generate corrected fix`);
295
- break;
296
- }
297
- currentFixPlan = retryFix;
298
- continue; // Try applying again
299
- }
300
- break;
301
- }
302
- // Apply succeeded - now build
303
- result.filesModified = [...new Set([...(result.filesModified || []), ...applyResult.files])];
304
- result.log?.push(`Modified ${applyResult.files.length} file(s)`);
305
- await this.reportProgress(bug, `✏️ Applied fixes to ${applyResult.files.length} file(s)`);
306
- const buildResult = await this.buildAndTest(app);
307
- if (buildResult.success) {
308
- // Run LSP analysis to check for remaining issues
309
- const lspResult = await this.lsp.validateFix(app.projectPath);
310
- if (!lspResult.valid) {
311
- result.log?.push(`LSP found ${lspResult.errors.length} issue(s)`);
312
- await this.reportProgress(bug, `⚠️ Build passed but LSP found issues:\n${lspResult.errors.slice(0, 3).join('\n')}`);
313
- }
314
- fixSuccess = true;
315
- result.log?.push(`Build successful (attempt ${attempt})`);
316
- await this.reportProgress(bug, '✅ Build successful');
317
- break;
318
- }
319
- // Build failed
320
- result.log?.push(`Build failed (attempt ${attempt}): ${buildResult.error}`);
321
- await this.reportProgress(bug, `❌ Build failed (attempt ${attempt}/${MAX_RETRIES}):\n\`\`\`\n${buildResult.error}\n\`\`\``);
322
- if (attempt < MAX_RETRIES) {
323
- await this.reportProgress(bug, `🔄 Analyzing error and retrying...`);
324
- // Read the current state of files that were modified
325
- const currentFiles = await this.files.readSelectedFiles(app.projectPath, currentFixPlan.fix.files.map(f => f.path));
326
- const retryFix = await this.ai.retryFixFromError(bug, currentFixPlan, buildResult.error || 'Unknown error', currentFiles, attempt);
327
- if (!retryFix) {
328
- result.log?.push('Could not generate retry fix');
329
- await this.reportProgress(bug, `❌ Could not generate corrected fix`);
330
- break;
331
- }
332
- currentFixPlan = retryFix;
333
- // Continue to next attempt - will apply the new fix
334
- }
335
- }
336
- if (!fixSuccess) {
337
- result.summary = `Fix failed after ${MAX_RETRIES} attempts`;
338
- // Revert all changes
339
- if (result.filesModified && result.filesModified.length > 0) {
340
- await this.git.revertChanges(app, result.filesModified);
341
- }
342
- await this.reportProgress(bug, `❌ Could not fix bug after ${MAX_RETRIES} attempts. Changes reverted.`);
343
- return result;
344
- }
345
- // 6. Commit changes
346
- const commitResult = await this.git.commitChanges(app, bug);
347
- if (commitResult.hash) {
348
- result.commitHash = commitResult.hash;
349
- result.log?.push(`Committed: ${commitResult.hash}`);
350
- }
351
- // 7. Stay in "In Progress" - will move to "Fixed" only after approval
352
- // (already moved to inProgress in step 3)
353
- // 8. Store pending fix and ask owner to test
354
- if (bug.discussionId) {
355
- pending_fix_registry_1.pendingFixRegistry.register({
356
- discussionId: bug.discussionId,
357
- bugId: bug.id,
358
- appId: bug.appId || app.name,
359
- state: 'awaiting_test',
360
- fixSummary: currentFixPlan.explanation,
361
- timestamp: Date.now(),
362
- bug,
363
- app,
364
- fixPlan: currentFixPlan,
365
- filesModified: result.filesModified || [],
366
- commitHash: result.commitHash
367
- });
368
- logger.info('Stored pending fix awaiting approval', { bugId: bug.id, discussionId: bug.discussionId });
369
- // Start watching this discussion for approval messages
370
- this.monitor.watchDiscussion(bug.discussionId);
371
- }
372
- result.success = true;
373
- result.summary = `Fixed: ${currentFixPlan.explanation} (awaiting approval)`;
374
- // Ask owner to test with clear magic words
375
- await this.reportProgress(bug, `✅ **Bug Fixed!**
376
-
377
- ${currentFixPlan.explanation}
378
-
379
- **Files changed:** ${result.filesModified?.join(', ') || 'none'}
380
-
381
- ---
382
-
383
- 🧪 **Please test the fix locally**, then reply with:
384
- - **\`approved\`** - to publish to production
385
- - **\`denied\`** - if the fix doesn't work (I'll ask what's wrong)`);
386
- return result;
387
- }
388
- catch (error) {
389
- result.summary = `Error: ${error instanceof Error ? error.message : String(error)}`;
390
- result.log?.push(`Exception: ${result.summary}`);
391
- logger.error('Giuseppe failed', { bugId: bug.id, error });
392
- await this.reportProgress(bug, `❌ Giuseppe encountered an error: ${result.summary}`);
393
- return result;
394
- }
395
- }
396
- /**
397
- * Handle a message in a bug discussion - uses LLM to understand intent
398
- */
399
- async handleDiscussionMessage(discussionId, message, _senderId) {
400
- logger.debug('handleDiscussionMessage called', {
401
- discussionId,
402
- message: message.substring(0, 50),
403
- pendingClassificationsSize: pending_classification_registry_1.pendingClassificationRegistry.size,
404
- hasPendingForDiscussion: pending_classification_registry_1.pendingClassificationRegistry.has(discussionId)
405
- });
406
- // Check for pending classification first (waiting for user to confirm fix or mark as not-a-bug)
407
- const pendingClassification = pending_classification_registry_1.pendingClassificationRegistry.get(discussionId);
408
- if (pendingClassification) {
409
- // Use LLM to understand user intent (replaces hardcoded magic words)
410
- const { intent, confidence } = await this.ai.detectIntent(message, 'classification');
411
- logger.debug('Classification intent detected', {
412
- discussionId,
413
- message: message.substring(0, 50),
414
- intent,
415
- confidence
416
- });
417
- if (intent === 'fix_it' && confidence !== 'low') {
418
- logger.debug('User wants to fix - calling handleFixItConfirmation');
419
- return await this.handleFixItConfirmation(discussionId, pendingClassification);
420
- }
421
- if (intent === 'not_a_bug' && confidence !== 'low') {
422
- logger.debug('User says not a bug - calling handleNotABugConfirmation');
423
- return await this.handleNotABugConfirmation(discussionId, pendingClassification);
424
- }
425
- // Unknown or clarify intent - ignore and wait for clearer response
426
- logger.debug('Unclear intent - waiting for clearer response', { intent, confidence });
427
- return { approved: false, published: false };
428
- }
429
- // Check for pending fix (waiting for approval to publish)
430
- const pendingFix = pending_fix_registry_1.pendingFixRegistry.get(discussionId);
431
- if (!pendingFix) {
432
- return { approved: false, published: false };
433
- }
434
- // Use LLM to understand approval intent
435
- const { intent, confidence } = await this.ai.detectIntent(message, 'approval');
436
- logger.debug('Approval intent detected', {
437
- discussionId,
438
- message: message.substring(0, 50),
439
- intent,
440
- confidence
441
- });
442
- if (intent === 'approved' && confidence !== 'low') {
443
- return await this.handleApproval(discussionId, pendingFix);
444
- }
445
- if (intent === 'denied' && confidence !== 'low') {
446
- // Handle denial - revert changes
447
- return await this.handleDenial(discussionId, pendingFix);
448
- }
449
- if (intent === 'retry' && confidence !== 'low') {
450
- // User wants to try again - not implemented yet
451
- await this.sendDiscussionMessage(discussionId, "🔄 Retry is not implemented yet. Please say 'approved' to publish or 'denied' to cancel.");
452
- return { approved: false, published: false };
453
- }
454
- // Unknown intent - let HAL or user clarify
455
- return { approved: false, published: false };
456
- }
457
- /**
458
- * Handle "fix it" confirmation - proceed with bug fix
459
- */
460
- async handleFixItConfirmation(discussionId, pending) {
461
- logger.info('User confirmed fix', { discussionId, bugId: pending.bugId });
462
- // Remove from pending classifications
463
- pending_classification_registry_1.pendingClassificationRegistry.unregister(discussionId);
464
- await this.sendDiscussionMessage(discussionId, `✅ Got it! Starting bug fix...`);
465
- // Proceed with the actual fix (creates commit, stores pending fix awaiting approval)
466
- const result = await this.proceedWithFix(pending.bug);
467
- // Return false for both - the CLASSIFICATION was approved ("fix it"),
468
- // but the FIX itself is not yet approved (waiting for "approved" message)
469
- // The fix was applied locally but NOT published to production
470
- return {
471
- approved: false, // Fix not approved yet, just classification
472
- published: false, // Not published, just committed locally
473
- error: result.success ? undefined : result.summary
474
- };
475
- }
476
- /**
477
- * Handle "not a bug" confirmation - close without fixing
478
- */
479
- async handleNotABugConfirmation(discussionId, pending) {
480
- logger.info('User confirmed not a bug', { discussionId, bugId: pending.bugId });
481
- // Remove from pending classifications
482
- pending_classification_registry_1.pendingClassificationRegistry.unregister(discussionId);
483
- this.monitor.unwatchDiscussion(discussionId);
484
- await this.sendDiscussionMessage(discussionId, `✅ Understood. This has been marked as a feature request and moved to Declined.\n\nPlease create a feature request if you'd like this change implemented.`);
485
- // Move to declined phase (not a bug)
486
- await this.monitor.moveBugToPhase(pending.bugId, 'declined');
487
- return { approved: false, published: false };
488
- }
489
- /**
490
- * Handle "approved" - publish to production
491
- */
492
- async handleApproval(discussionId, pending) {
493
- logger.info('Fix approved', { discussionId, bugId: pending.bugId });
494
- await this.sendDiscussionMessage(discussionId, `🚀 Publishing to production...`);
495
- const publishResult = await this.publishApp(pending.app, pending.bug);
496
- if (publishResult.success) {
497
- // Move to Fixed phase (published successfully)
498
- await this.monitor.moveBugToPhase(pending.bugId, 'fixed');
499
- // Remove from pending and stop watching
500
- pending_fix_registry_1.pendingFixRegistry.unregister(discussionId);
501
- this.monitor.unwatchDiscussion(discussionId);
502
- // Log to Session Log - fix published
503
- await this.createSessionLogEntry(`Giuseppe: Published fix for ${pending.bug.name}`, [
504
- `**Bug Report:** ${pending.bug.name}`,
505
- `**App:** ${pending.app.name}`,
506
- `**Version:** ${publishResult.version || 'latest'}`,
507
- `**Files changed:** ${pending.filesModified.join(', ') || 'none'}`,
508
- '',
509
- `**Fix summary:** ${pending.fixPlan.explanation}`,
510
- '',
511
- `Fix has been tested, approved, and published to production.`
512
- ].join('\n'), pending.bugId);
513
- await this.sendDiscussionMessage(discussionId, `✅ **Published to production!** v${publishResult.version || 'latest'}\n\nBug marked as Fixed. Thank you for testing!`);
514
- logger.info('Fix published', { bugId: pending.bugId, version: publishResult.version });
515
- return { approved: true, published: true };
516
- }
517
- else {
518
- await this.sendDiscussionMessage(discussionId, `❌ Publish failed: ${publishResult.error}\n\nPlease try publishing manually or contact support.`);
519
- return { approved: true, published: false, error: publishResult.error };
520
- }
521
- }
522
- /**
523
- * Handle "denied" - ask for explanation
524
- */
525
- async handleDenial(discussionId, pending) {
526
- logger.info('Fix denied, asking for explanation', { discussionId, bugId: pending.bugId });
527
- // Change state to awaiting_explanation
528
- pending_fix_registry_1.pendingFixRegistry.updateState(discussionId, 'awaiting_explanation');
529
- await this.sendDiscussionMessage(discussionId, `📝 **What's not working?**\n\nPlease describe what's still broken or what the fix didn't address. I'll analyze your feedback and try again.`);
530
- return { approved: false, published: false };
531
- }
532
- /**
533
- * Handle explanation after denial - retry the fix
534
- */
535
- async handleExplanationAndRetry(discussionId, pending, explanation) {
536
- logger.info('Received explanation, retrying fix', {
537
- discussionId,
538
- bugId: pending.bugId,
539
- explanation: explanation.substring(0, 100)
540
- });
541
- await this.sendDiscussionMessage(discussionId, `🔄 Got it. Analyzing your feedback and generating a new fix...`);
542
- // Revert previous changes first
543
- if (pending.filesModified.length > 0) {
544
- await this.git.revertChanges(pending.app, pending.filesModified);
545
- await this.sendDiscussionMessage(discussionId, `↩️ Reverted previous changes`);
546
- }
547
- // Get file list from git (fast, accurate)
548
- let allSourceFiles = await this.git.getSourceFilesFromGit(pending.app.projectPath);
549
- if (allSourceFiles.length === 0) {
550
- // Fallback to directory scan if git fails
551
- allSourceFiles = await this.files.scanSourceFiles(pending.app.projectPath);
552
- }
553
- // Search for relevant files based on feedback keywords
554
- const relevantFiles = await this.files.findRelevantFiles(pending.app.projectPath, explanation, pending.bug);
555
- // Always include files from previous fix
556
- const previousFixFiles = pending.fixPlan.fix.files.map(f => f.path);
557
- // Combine all relevant files (deduplicated)
558
- const filesToRead = [...new Set([
559
- ...previousFixFiles,
560
- ...relevantFiles,
561
- 'src/App.tsx' // Always include main app file
562
- ])].filter(f => allSourceFiles.includes(f));
563
- const currentFiles = await this.files.readSelectedFiles(pending.app.projectPath, filesToRead);
564
- // Generate new fix based on feedback
565
- const retryFix = await this.ai.retryFixWithFeedback(pending.bug, pending.fixPlan, explanation, allSourceFiles, currentFiles);
566
- if (!retryFix) {
567
- await this.sendDiscussionMessage(discussionId, `❌ Could not generate a new fix based on your feedback. Please provide more details or contact support.`);
568
- // Reset state to allow another try
569
- pending_fix_registry_1.pendingFixRegistry.updateState(discussionId, 'awaiting_explanation');
570
- return { approved: false, published: false, error: 'Could not generate retry fix' };
571
- }
572
- // Apply the new fix
573
- const applyResult = await this.files.applyFixes(pending.app, retryFix.fix.files);
574
- if (!applyResult.success) {
575
- await this.sendDiscussionMessage(discussionId, `❌ Failed to apply new fix: ${applyResult.error}\n\nPlease provide more details about the issue.`);
576
- pending_fix_registry_1.pendingFixRegistry.updateState(discussionId, 'awaiting_explanation');
577
- return { approved: false, published: false, error: applyResult.error };
578
- }
579
- // Build and test
580
- const buildResult = await this.buildAndTest(pending.app);
581
- if (!buildResult.success) {
582
- await this.sendDiscussionMessage(discussionId, `❌ Build failed:\n\`\`\`\n${buildResult.error}\n\`\`\`\n\nI'll need to try a different approach. What exactly is broken?`);
583
- // Revert and ask again
584
- await this.git.revertChanges(pending.app, applyResult.files);
585
- pending_fix_registry_1.pendingFixRegistry.updateState(discussionId, 'awaiting_explanation');
586
- return { approved: false, published: false, error: buildResult.error };
587
- }
588
- // Success! Update pending fix and ask for approval again
589
- pending.fixPlan = retryFix;
590
- pending.filesModified = applyResult.files;
591
- pending_fix_registry_1.pendingFixRegistry.updateState(discussionId, 'awaiting_test');
592
- await this.sendDiscussionMessage(discussionId, `✅ **New fix applied!**
593
-
594
- ${retryFix.explanation}
595
-
596
- **Files changed:** ${applyResult.files.join(', ')}
597
-
598
- ---
599
-
600
- 🧪 **Please test again**, then reply with:
601
- - **\`approved\`** - to publish to production
602
- - **\`denied\`** - if still not working`);
603
- return { approved: false, published: false, retrying: true };
604
- }
605
- /**
606
- * Check if there's a pending fix for a discussion
607
- */
608
- hasPendingFix(discussionId) {
609
- return pending_fix_registry_1.pendingFixRegistry.has(discussionId);
610
- }
611
- /**
612
- * Retry a pending fix with explanation from HAL
613
- * Called by HAL after gathering info through conversation
614
- */
615
- async retryWithExplanation(discussionId, explanation) {
616
- const pending = pending_fix_registry_1.pendingFixRegistry.get(discussionId);
617
- if (!pending) {
618
- logger.warn('No pending fix found for retry', { discussionId });
619
- return false;
620
- }
621
- logger.info('HAL triggered retry with explanation', {
622
- discussionId,
623
- bugId: pending.bugId,
624
- explanationLength: explanation.length
625
- });
626
- // Update registry state
627
- pending_fix_registry_1.pendingFixRegistry.updateState(discussionId, 'awaiting_explanation');
628
- // Trigger the retry
629
- const result = await this.handleExplanationAndRetry(discussionId, pending, explanation);
630
- // Update registry state based on result
631
- if (result.retrying) {
632
- pending_fix_registry_1.pendingFixRegistry.updateState(discussionId, 'awaiting_test');
633
- }
634
- return result.retrying || false;
635
- }
636
- /**
637
- * Initialize registry callback (call this after construction)
638
- */
639
- initializeRegistryCallback() {
640
- pending_fix_registry_1.pendingFixRegistry.setRetryCallback(async (discussionId, explanation) => {
641
- await this.retryWithExplanation(discussionId, explanation);
642
- });
643
- logger.info('Registry retry callback initialized');
644
- }
645
- /**
646
- * Initialize classification registry callbacks for HAL coordination
647
- * This allows HAL to trigger "fix it" or "not a bug" via natural conversation
648
- */
649
- initializeClassificationCallbacks() {
650
- pending_classification_registry_1.pendingClassificationRegistry.setCallbacks(
651
- // fixIt callback
652
- async (discussionId) => {
653
- const pending = pending_classification_registry_1.pendingClassificationRegistry.get(discussionId);
654
- if (pending) {
655
- await this.handleFixItConfirmation(discussionId, pending);
656
- }
657
- },
658
- // notABug callback
659
- async (discussionId) => {
660
- const pending = pending_classification_registry_1.pendingClassificationRegistry.get(discussionId);
661
- if (pending) {
662
- await this.handleNotABugConfirmation(discussionId, pending);
663
- }
664
- });
665
- logger.info('Classification callbacks initialized');
666
- }
667
- /**
668
- * Helper to send a message to a discussion
669
- */
670
- async sendDiscussionMessage(discussionId, message) {
671
- try {
672
- const { hailer } = this.userContext;
673
- await hailer.sendDiscussionMessage(discussionId, message);
674
- }
675
- catch (error) {
676
- logger.warn('Failed to send discussion message', { discussionId, error });
677
- }
678
- }
679
- /**
680
- * Build and test the app
681
- */
682
- async buildAndTest(app) {
683
- return new Promise((resolve) => {
684
- const child = (0, child_process_1.spawn)('npm', ['run', 'build'], {
685
- cwd: app.projectPath,
686
- shell: true
687
- });
688
- let stdout = '';
689
- let stderr = '';
690
- child.stdout.on('data', (data) => {
691
- stdout += data.toString();
692
- });
693
- child.stderr.on('data', (data) => {
694
- stderr += data.toString();
695
- });
696
- child.on('close', (code) => {
697
- if (code === 0) {
698
- resolve({ success: true });
699
- }
700
- else {
701
- // TypeScript errors often go to stdout, combine both
702
- const allOutput = stdout + '\n' + stderr;
703
- // Extract just the error lines (look for .tsx/.ts errors)
704
- const errorLines = allOutput.split('\n')
705
- .filter(line => line.includes('error TS') || line.includes('Error:') || line.includes('error:'))
706
- .slice(0, 10)
707
- .join('\n');
708
- resolve({ success: false, error: errorLines || allOutput.slice(-1000) });
709
- }
710
- });
711
- child.on('error', (error) => {
712
- resolve({ success: false, error: error.message });
713
- });
714
- // Timeout after 2 minutes
715
- setTimeout(() => {
716
- child.kill();
717
- resolve({ success: false, error: 'Build timeout' });
718
- }, 120000);
719
- });
720
- }
721
- /**
722
- * Join a bug's discussion using the activity ID (not discussion ID)
723
- * For activity discussions, we must use joinActivityDiscussion
724
- */
725
- async joinBugDiscussion(activityId) {
726
- try {
727
- const { hailer } = this.userContext;
728
- await hailer.joinActivityDiscussion(activityId);
729
- logger.info('Joined bug discussion', { activityId });
730
- }
731
- catch (error) {
732
- // Might already be a member, that's OK
733
- logger.debug('Could not join bug discussion (may already be member)', { activityId, error });
734
- }
735
- }
736
- /**
737
- * Publish app to production using expect script (same as MCP tool)
738
- */
739
- async publishApp(app, bug) {
740
- try {
741
- // Bump patch version before publishing (bug fix = patch)
742
- const versionBump = await this.git.bumpPatchVersion(app.projectPath);
743
- const version = versionBump?.newVersion || '1.0.0';
744
- if (versionBump) {
745
- logger.info('Version bumped for bug fix', {
746
- oldVersion: versionBump.oldVersion,
747
- newVersion: versionBump.newVersion,
748
- bugId: bug.id
749
- });
750
- // Stage and commit the version bump
751
- await this.git.commitVersionBump(app.projectPath, version);
752
- }
753
- logger.info('Publishing app via MCP tool', {
754
- projectPath: app.projectPath,
755
- version
756
- });
757
- // Use the MCP publish_hailer_app tool directly
758
- const result = await app_scaffold_1.publishHailerAppTool.execute({
759
- projectDirectory: app.projectPath,
760
- publishToMarket: false
761
- }, this.userContext);
762
- // Parse the result
763
- const text = result.content?.[0]?.type === 'text' ? result.content[0].text : '';
764
- if (text.includes('✅') || text.includes('Successfully') || text.includes('Published')) {
765
- logger.info('App published successfully', { version });
766
- // Push to git after successful publish
767
- await this.git.push(app.projectPath);
768
- // Create and push version tag (persists version history across code resets)
769
- this.git.createVersionTag(app.projectPath, version);
770
- return { success: true, version };
771
- }
772
- else {
773
- // Extract error message from response
774
- const errorMatch = text.match(/❌.*?(?:\n|$)/)?.[0] || text.substring(0, 200);
775
- logger.error('Publish failed', { error: errorMatch });
776
- return { success: false, error: errorMatch };
777
- }
778
- }
779
- catch (error) {
780
- const errorMessage = error instanceof Error ? error.message : String(error);
781
- logger.error('Publish exception', { error: errorMessage });
782
- return {
783
- success: false,
784
- error: errorMessage
785
- };
786
- }
787
- }
788
- /**
789
- * Report progress to bug discussion
790
- */
791
- async reportProgress(bug, message) {
792
- if (!bug.discussionId)
793
- return;
794
- try {
795
- const { hailer } = this.userContext;
796
- await hailer.sendDiscussionMessage(bug.discussionId, message);
797
- }
798
- catch (error) {
799
- logger.warn('Failed to report progress', { bugId: bug.id, error });
800
- }
801
- }
802
- }
803
- exports.GiuseppeBot = GiuseppeBot;
804
- //# sourceMappingURL=giuseppe-bot.js.map