@hailer/mcp 0.1.11 → 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 +127 -5
  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,35 @@
1
+ /**
2
+ * Bot Runner - Manages isolated bot processes per workspace
3
+ *
4
+ * Uses API key authentication (resolved to email/password internally via CLIENT_CONFIGS)
5
+ */
6
+ import type { WorkspaceConfig } from './types';
7
+ export declare class BotRunner {
8
+ private runningBots;
9
+ private botEntryPoint;
10
+ private maxRestarts;
11
+ private restartDelayMs;
12
+ constructor();
13
+ private getKey;
14
+ /**
15
+ * Start a bot for a workspace
16
+ */
17
+ startBot(workspace: WorkspaceConfig, botId: string): Promise<boolean>;
18
+ /**
19
+ * Stop a bot for a workspace
20
+ */
21
+ stopBot(workspaceId: string, botId: string): Promise<void>;
22
+ /**
23
+ * Check if a bot is running
24
+ */
25
+ isRunning(workspaceId: string, botId: string): boolean;
26
+ /**
27
+ * Get all running bots for a workspace
28
+ */
29
+ getRunningBots(workspaceId: string): string[];
30
+ /**
31
+ * Stop all bots
32
+ */
33
+ stopAll(): Promise<void>;
34
+ }
35
+ //# sourceMappingURL=bot-runner.d.ts.map
@@ -0,0 +1,188 @@
1
+ "use strict";
2
+ /**
3
+ * Bot Runner - Manages isolated bot processes per workspace
4
+ *
5
+ * Uses API key authentication (resolved to email/password internally via CLIENT_CONFIGS)
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
+ exports.BotRunner = void 0;
42
+ const child_process_1 = require("child_process");
43
+ const path = __importStar(require("path"));
44
+ const logger_1 = require("../lib/logger");
45
+ const logger = (0, logger_1.createLogger)({ component: 'bot-runner' });
46
+ class BotRunner {
47
+ runningBots = new Map();
48
+ botEntryPoint;
49
+ maxRestarts = 5;
50
+ restartDelayMs = 5000;
51
+ constructor() {
52
+ // In production, this would be the compiled JS
53
+ this.botEntryPoint = path.join(__dirname, 'bot-entrypoint.js');
54
+ }
55
+ getKey(workspaceId, botId) {
56
+ return `${workspaceId}:${botId}`;
57
+ }
58
+ /**
59
+ * Start a bot for a workspace
60
+ */
61
+ async startBot(workspace, botId) {
62
+ const key = this.getKey(workspace.id, botId);
63
+ if (this.runningBots.has(key)) {
64
+ logger.warn('Bot already running', { workspaceId: workspace.id, botId });
65
+ return true;
66
+ }
67
+ logger.info('Starting bot', { workspaceId: workspace.id, botId });
68
+ try {
69
+ const child = (0, child_process_1.fork)(this.botEntryPoint, [], {
70
+ env: {
71
+ ...process.env,
72
+ BOT_WORKSPACE_ID: workspace.id,
73
+ BOT_WORKSPACE_NAME: workspace.name,
74
+ BOT_API_KEY: workspace.apiKey, // Use API key instead of email/password
75
+ BOT_ID: botId,
76
+ // Isolate per workspace
77
+ NODE_UNIQUE_ID: workspace.id
78
+ },
79
+ stdio: ['pipe', 'pipe', 'pipe', 'ipc']
80
+ });
81
+ const running = {
82
+ workspaceId: workspace.id,
83
+ botId,
84
+ process: child,
85
+ startedAt: new Date(),
86
+ restartCount: 0
87
+ };
88
+ this.runningBots.set(key, running);
89
+ // Log output
90
+ child.stdout?.on('data', (data) => {
91
+ logger.info(`[${workspace.id}:${botId}] ${data.toString().trim()}`);
92
+ });
93
+ child.stderr?.on('data', (data) => {
94
+ logger.error(`[${workspace.id}:${botId}] ${data.toString().trim()}`);
95
+ });
96
+ // Handle exit
97
+ child.on('exit', (code, signal) => {
98
+ logger.warn('Bot process exited', { workspaceId: workspace.id, botId, code, signal });
99
+ this.runningBots.delete(key);
100
+ // Auto-restart on crash
101
+ if (code !== 0 && running.restartCount < this.maxRestarts) {
102
+ running.restartCount++;
103
+ setTimeout(() => {
104
+ this.startBot(workspace, botId);
105
+ }, this.restartDelayMs);
106
+ }
107
+ });
108
+ // Wait for ready signal
109
+ return new Promise((resolve) => {
110
+ const timeout = setTimeout(() => {
111
+ logger.warn('Bot startup timeout', { workspaceId: workspace.id, botId });
112
+ resolve(false);
113
+ }, 30000);
114
+ child.on('message', (msg) => {
115
+ if (msg.type === 'ready') {
116
+ clearTimeout(timeout);
117
+ logger.info('Bot ready', { workspaceId: workspace.id, botId });
118
+ resolve(true);
119
+ }
120
+ else if (msg.type === 'error') {
121
+ clearTimeout(timeout);
122
+ logger.error('Bot startup error', { workspaceId: workspace.id, botId, error: msg.error });
123
+ resolve(false);
124
+ }
125
+ });
126
+ });
127
+ }
128
+ catch (error) {
129
+ logger.error('Failed to start bot', { workspaceId: workspace.id, botId, error });
130
+ return false;
131
+ }
132
+ }
133
+ /**
134
+ * Stop a bot for a workspace
135
+ */
136
+ async stopBot(workspaceId, botId) {
137
+ const key = this.getKey(workspaceId, botId);
138
+ const running = this.runningBots.get(key);
139
+ if (!running) {
140
+ logger.warn('Bot not running', { workspaceId, botId });
141
+ return;
142
+ }
143
+ logger.info('Stopping bot', { workspaceId, botId });
144
+ // Prevent auto-restart
145
+ running.restartCount = this.maxRestarts;
146
+ // Send graceful shutdown
147
+ running.process.send({ type: 'shutdown' });
148
+ // Wait for exit or force kill
149
+ await new Promise((resolve) => {
150
+ const timeout = setTimeout(() => {
151
+ running.process.kill('SIGKILL');
152
+ resolve();
153
+ }, 10000);
154
+ running.process.once('exit', () => {
155
+ clearTimeout(timeout);
156
+ resolve();
157
+ });
158
+ });
159
+ this.runningBots.delete(key);
160
+ }
161
+ /**
162
+ * Check if a bot is running
163
+ */
164
+ isRunning(workspaceId, botId) {
165
+ return this.runningBots.has(this.getKey(workspaceId, botId));
166
+ }
167
+ /**
168
+ * Get all running bots for a workspace
169
+ */
170
+ getRunningBots(workspaceId) {
171
+ const running = [];
172
+ for (const [, bot] of this.runningBots) {
173
+ if (bot.workspaceId === workspaceId) {
174
+ running.push(bot.botId);
175
+ }
176
+ }
177
+ return running;
178
+ }
179
+ /**
180
+ * Stop all bots
181
+ */
182
+ async stopAll() {
183
+ const stops = Array.from(this.runningBots.values()).map(bot => this.stopBot(bot.workspaceId, bot.botId));
184
+ await Promise.all(stops);
185
+ }
186
+ }
187
+ exports.BotRunner = BotRunner;
188
+ //# sourceMappingURL=bot-runner.js.map
@@ -78,6 +78,10 @@ export declare class DaemonManager {
78
78
  * Check if running in orchestrator mode
79
79
  */
80
80
  isOrchestratorMode(): boolean;
81
+ /**
82
+ * Trigger HAL to respond in a discussion with context
83
+ */
84
+ triggerHalResponse(discussionId: string, activityId: string, context: string): Promise<void>;
81
85
  /**
82
86
  * Start periodic status logging
83
87
  */
@@ -228,6 +228,16 @@ class DaemonManager {
228
228
  isOrchestratorMode() {
229
229
  return !!this.options.orchestratorMode;
230
230
  }
231
+ /**
232
+ * Trigger HAL to respond in a discussion with context
233
+ */
234
+ async triggerHalResponse(discussionId, activityId, context) {
235
+ if (!this.orchestrator) {
236
+ logger.warn('Cannot trigger HAL response - orchestrator not running');
237
+ return;
238
+ }
239
+ await this.orchestrator.respondWithContext(discussionId, activityId, context);
240
+ }
231
241
  /**
232
242
  * Start periodic status logging
233
243
  */
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Bot Control Server - API for AI Hub app
3
+ *
4
+ * Uses API key authentication (resolved to email/password internally via CLIENT_CONFIGS)
5
+ */
6
+ declare const app: import("express-serve-static-core").Express;
7
+ export { app };
8
+ //# sourceMappingURL=server.d.ts.map
@@ -0,0 +1,251 @@
1
+ "use strict";
2
+ /**
3
+ * Bot Control Server - API for AI Hub app
4
+ *
5
+ * Uses API key authentication (resolved to email/password internally via CLIENT_CONFIGS)
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
+ var __importDefault = (this && this.__importDefault) || function (mod) {
41
+ return (mod && mod.__esModule) ? mod : { "default": mod };
42
+ };
43
+ Object.defineProperty(exports, "__esModule", { value: true });
44
+ exports.app = void 0;
45
+ const express_1 = __importDefault(require("express"));
46
+ const cors_1 = __importDefault(require("cors"));
47
+ const fs = __importStar(require("fs"));
48
+ const path = __importStar(require("path"));
49
+ const logger_1 = require("../lib/logger");
50
+ const bot_runner_1 = require("./bot-runner");
51
+ const types_1 = require("./types");
52
+ const logger = (0, logger_1.createLogger)({ component: 'bot-server' });
53
+ const app = (0, express_1.default)();
54
+ exports.app = app;
55
+ const runner = new bot_runner_1.BotRunner();
56
+ // State file
57
+ const STATE_FILE = path.join(__dirname, 'workspaces.json');
58
+ // Load/save state
59
+ function loadState() {
60
+ try {
61
+ if (fs.existsSync(STATE_FILE)) {
62
+ return JSON.parse(fs.readFileSync(STATE_FILE, 'utf-8'));
63
+ }
64
+ }
65
+ catch (error) {
66
+ logger.warn('Failed to load state', { error });
67
+ }
68
+ return { workspaces: {} };
69
+ }
70
+ function saveState(state) {
71
+ fs.writeFileSync(STATE_FILE, JSON.stringify(state, null, 2));
72
+ }
73
+ let state = loadState();
74
+ // Middleware
75
+ app.use((0, cors_1.default)());
76
+ app.use(express_1.default.json());
77
+ // Request logging
78
+ app.use((req, res, next) => {
79
+ logger.info(`${req.method} ${req.path}`, { body: req.body });
80
+ next();
81
+ });
82
+ /**
83
+ * GET /bots - List available bots
84
+ */
85
+ app.get('/bots', (req, res) => {
86
+ res.json({ bots: types_1.AVAILABLE_BOTS });
87
+ });
88
+ /**
89
+ * POST /workspaces/register - Register a new workspace
90
+ */
91
+ app.post('/workspaces/register', (req, res) => {
92
+ const { id, name, apiKey } = req.body;
93
+ if (!id || !apiKey) {
94
+ return res.status(400).json({ error: 'Missing required fields: id, apiKey' });
95
+ }
96
+ const workspace = {
97
+ id,
98
+ name: name || id,
99
+ apiKey, // Single API key - email/password resolved internally via CLIENT_CONFIGS
100
+ enabledBots: [],
101
+ registeredAt: new Date().toISOString()
102
+ };
103
+ state.workspaces[id] = workspace;
104
+ saveState(state);
105
+ logger.info('Workspace registered', { id, name });
106
+ res.json({ success: true, workspace: { id, name } });
107
+ });
108
+ /**
109
+ * DELETE /workspaces/:id - Unregister a workspace
110
+ */
111
+ app.delete('/workspaces/:id', async (req, res) => {
112
+ const { id } = req.params;
113
+ const workspace = state.workspaces[id];
114
+ if (!workspace) {
115
+ return res.status(404).json({ error: 'Workspace not found' });
116
+ }
117
+ // Stop all bots first
118
+ for (const botId of workspace.enabledBots) {
119
+ await runner.stopBot(id, botId);
120
+ }
121
+ delete state.workspaces[id];
122
+ saveState(state);
123
+ logger.info('Workspace unregistered', { id });
124
+ res.json({ success: true });
125
+ });
126
+ /**
127
+ * GET /workspaces/:id/status - Get workspace status
128
+ */
129
+ app.get('/workspaces/:id/status', (req, res) => {
130
+ const { id } = req.params;
131
+ const workspace = state.workspaces[id];
132
+ if (!workspace) {
133
+ return res.status(404).json({ error: 'Workspace not found' });
134
+ }
135
+ const status = {
136
+ id: workspace.id,
137
+ name: workspace.name,
138
+ registered: true,
139
+ bots: types_1.AVAILABLE_BOTS.map(bot => ({
140
+ id: bot.id,
141
+ name: bot.name,
142
+ enabled: workspace.enabledBots.includes(bot.id),
143
+ running: runner.isRunning(id, bot.id)
144
+ }))
145
+ };
146
+ res.json(status);
147
+ });
148
+ /**
149
+ * POST /workspaces/:id/bots/:botId/enable - Enable and start a bot
150
+ */
151
+ app.post('/workspaces/:id/bots/:botId/enable', async (req, res) => {
152
+ const { id, botId } = req.params;
153
+ const workspace = state.workspaces[id];
154
+ if (!workspace) {
155
+ return res.status(404).json({ error: 'Workspace not found' });
156
+ }
157
+ if (!types_1.AVAILABLE_BOTS.find(b => b.id === botId)) {
158
+ return res.status(404).json({ error: 'Bot not found' });
159
+ }
160
+ // Add to enabled list
161
+ if (!workspace.enabledBots.includes(botId)) {
162
+ workspace.enabledBots.push(botId);
163
+ saveState(state);
164
+ }
165
+ // Start the bot
166
+ const started = await runner.startBot(workspace, botId);
167
+ if (!started) {
168
+ return res.status(500).json({ error: 'Failed to start bot' });
169
+ }
170
+ logger.info('Bot enabled', { workspaceId: id, botId });
171
+ res.json({ success: true, running: true });
172
+ });
173
+ /**
174
+ * POST /workspaces/:id/bots/:botId/disable - Disable and stop a bot
175
+ */
176
+ app.post('/workspaces/:id/bots/:botId/disable', async (req, res) => {
177
+ const { id, botId } = req.params;
178
+ const workspace = state.workspaces[id];
179
+ if (!workspace) {
180
+ return res.status(404).json({ error: 'Workspace not found' });
181
+ }
182
+ // Remove from enabled list
183
+ workspace.enabledBots = workspace.enabledBots.filter(b => b !== botId);
184
+ saveState(state);
185
+ // Stop the bot
186
+ await runner.stopBot(id, botId);
187
+ logger.info('Bot disabled', { workspaceId: id, botId });
188
+ res.json({ success: true, running: false });
189
+ });
190
+ /**
191
+ * POST /workspaces/:id/start-all - Start all enabled bots
192
+ */
193
+ app.post('/workspaces/:id/start-all', async (req, res) => {
194
+ const { id } = req.params;
195
+ const workspace = state.workspaces[id];
196
+ if (!workspace) {
197
+ return res.status(404).json({ error: 'Workspace not found' });
198
+ }
199
+ const results = {};
200
+ for (const botId of workspace.enabledBots) {
201
+ results[botId] = await runner.startBot(workspace, botId);
202
+ }
203
+ res.json({ success: true, results });
204
+ });
205
+ /**
206
+ * GET /status - Overall server status
207
+ */
208
+ app.get('/status', (req, res) => {
209
+ const workspaceCount = Object.keys(state.workspaces).length;
210
+ const runningBots = [];
211
+ for (const workspace of Object.values(state.workspaces)) {
212
+ for (const botId of workspace.enabledBots) {
213
+ if (runner.isRunning(workspace.id, botId)) {
214
+ runningBots.push({ workspace: workspace.id, bot: botId });
215
+ }
216
+ }
217
+ }
218
+ res.json({
219
+ status: 'running',
220
+ workspaces: workspaceCount,
221
+ runningBots: runningBots.length,
222
+ bots: runningBots
223
+ });
224
+ });
225
+ // Start server
226
+ const PORT = process.env.BOT_SERVER_PORT || 4000;
227
+ // Graceful shutdown
228
+ process.on('SIGINT', async () => {
229
+ logger.info('Shutting down...');
230
+ await runner.stopAll();
231
+ process.exit(0);
232
+ });
233
+ process.on('SIGTERM', async () => {
234
+ logger.info('Shutting down...');
235
+ await runner.stopAll();
236
+ process.exit(0);
237
+ });
238
+ // Auto-start enabled bots on server start
239
+ async function startEnabledBots() {
240
+ for (const workspace of Object.values(state.workspaces)) {
241
+ for (const botId of workspace.enabledBots) {
242
+ logger.info('Auto-starting bot', { workspaceId: workspace.id, botId });
243
+ await runner.startBot(workspace, botId);
244
+ }
245
+ }
246
+ }
247
+ app.listen(PORT, async () => {
248
+ logger.info(`Bot Control Server running on port ${PORT}`);
249
+ await startEnabledBots();
250
+ });
251
+ //# sourceMappingURL=server.js.map
@@ -295,4 +295,33 @@ export declare const MCP_CONFIG: {
295
295
  };
296
296
  };
297
297
  export declare const SESSION_IDLE_TIMEOUT = 60000;
298
+ export interface BotDefinition {
299
+ id: string;
300
+ name: string;
301
+ description: string;
302
+ icon: string;
303
+ }
304
+ export { AVAILABLE_BOTS } from '../mcp/tools/bot-config';
305
+ export interface WorkspaceConfig {
306
+ id: string;
307
+ name: string;
308
+ apiKey: string;
309
+ enabledBots: string[];
310
+ registeredAt: string;
311
+ lastSeen?: string;
312
+ }
313
+ export interface WorkspacesState {
314
+ workspaces: Record<string, WorkspaceConfig>;
315
+ }
316
+ export interface WorkspaceStatus {
317
+ id: string;
318
+ name: string;
319
+ registered: boolean;
320
+ bots: Array<{
321
+ id: string;
322
+ name: string;
323
+ enabled: boolean;
324
+ running: boolean;
325
+ }>;
326
+ }
298
327
  //# sourceMappingURL=types.d.ts.map
@@ -4,7 +4,7 @@
4
4
  * All interfaces and types for the agent system
5
5
  */
6
6
  Object.defineProperty(exports, "__esModule", { value: true });
7
- exports.SESSION_IDLE_TIMEOUT = exports.MCP_CONFIG = exports.TOOL_REGISTRY = exports.TEAMS = exports.POSITIONS = exports.SESSION_LOG = exports.AGENT_DIRECTORY = void 0;
7
+ exports.AVAILABLE_BOTS = exports.SESSION_IDLE_TIMEOUT = exports.MCP_CONFIG = exports.TOOL_REGISTRY = exports.TEAMS = exports.POSITIONS = exports.SESSION_LOG = exports.AGENT_DIRECTORY = void 0;
8
8
  // ===== WORKFLOW CONSTANTS =====
9
9
  // DEPRECATED: These IDs are for ONE workspace only!
10
10
  // Use WorkspaceSchemaCacheService for dynamic per-workspace lookup.
@@ -115,4 +115,7 @@ exports.MCP_CONFIG = {
115
115
  };
116
116
  // ===== CONSTANTS =====
117
117
  exports.SESSION_IDLE_TIMEOUT = 60_000; // 60 seconds
118
+ // Export AVAILABLE_BOTS from bot-config tools (single source of truth)
119
+ var bot_config_1 = require("../mcp/tools/bot-config");
120
+ Object.defineProperty(exports, "AVAILABLE_BOTS", { enumerable: true, get: function () { return bot_config_1.AVAILABLE_BOTS; } });
118
121
  //# sourceMappingURL=types.js.map
package/dist/core.d.ts CHANGED
@@ -11,6 +11,7 @@ export declare class Core {
11
11
  private mcpServer?;
12
12
  private daemonManager;
13
13
  private statusLogInterval?;
14
+ private bugReportsModule?;
14
15
  constructor();
15
16
  /**
16
17
  * Public API for external tool registration
@@ -20,6 +21,8 @@ export declare class Core {
20
21
  start(): Promise<void>;
21
22
  private startMCPServer;
22
23
  private startMCPClient;
24
+ private startBugMonitor;
25
+ private initBotConfig;
23
26
  private initializeDaemonMode;
24
27
  /**
25
28
  * Get daemon status (for HTTP endpoint)
package/dist/core.js CHANGED
@@ -11,6 +11,9 @@ const config_1 = require("./config");
11
11
  const factory_1 = require("./client/factory");
12
12
  const mcp_server_1 = require("./mcp-server");
13
13
  const tool_registry_1 = require("./mcp/tool-registry");
14
+ const bug_reports_1 = require("./modules/bug-reports");
15
+ const UserContextCache_1 = require("./mcp/UserContextCache");
16
+ const bot_config_1 = require("./mcp/tools/bot-config");
14
17
  class Core {
15
18
  logger;
16
19
  appConfig;
@@ -18,6 +21,7 @@ class Core {
18
21
  mcpServer;
19
22
  daemonManager = null;
20
23
  statusLogInterval;
24
+ bugReportsModule;
21
25
  constructor() {
22
26
  // Initialize logger first
23
27
  this.logger = (0, logger_1.createLogger)({
@@ -58,10 +62,14 @@ class Core {
58
62
  await this.startMCPServer();
59
63
  }
60
64
  }
65
+ // Initialize bot config persistence (reads config from Hailer Agent Directory)
66
+ await this.initBotConfig();
61
67
  // Start client/daemon AFTER MCP server is ready
62
68
  if (this.appConfig.server.enableClient) {
63
69
  await this.startMCPClient();
64
70
  }
71
+ // Start Bug Monitor service (reads config from Hailer)
72
+ await this.startBugMonitor();
65
73
  this.setupGracefulShutdown();
66
74
  this.logger.info('All configured services started successfully');
67
75
  }
@@ -94,6 +102,66 @@ class Core {
94
102
  });
95
103
  }
96
104
  }
105
+ async startBugMonitor() {
106
+ try {
107
+ // Get first configured account for Bug Reports Module
108
+ const accounts = Object.entries(this.appConfig.hailerAccounts);
109
+ if (accounts.length === 0) {
110
+ this.logger.info('No Hailer accounts configured - Bug Reports Module disabled');
111
+ return;
112
+ }
113
+ const [apiKey] = accounts[0];
114
+ const userContext = await UserContextCache_1.UserContextCache.getContext(apiKey);
115
+ this.bugReportsModule = new bug_reports_1.BugReportsModule(userContext);
116
+ // Register bot user IDs to ignore (so bug monitor only processes human messages)
117
+ if (this.daemonManager) {
118
+ const daemonStatus = this.daemonManager.getStatus();
119
+ for (const daemon of daemonStatus) {
120
+ this.bugReportsModule.registerBotUser(daemon.botId);
121
+ this.logger.debug('Registered bot user for bug monitor to ignore', { botId: daemon.botId });
122
+ }
123
+ }
124
+ // Register giuseppe disabled handler to trigger HAL response (BEFORE start!)
125
+ this.bugReportsModule.onGiuseppeDisabled(async (bug) => {
126
+ if (this.daemonManager && bug.discussionId) {
127
+ const context = `[System notification: A new bug report "${bug.name}" was detected, but Giuseppe (the auto-fix bot) is currently disabled. The user may ask how to enable Giuseppe or want to know more about this bug. Be helpful and explain they can enable Giuseppe in the AI Hub app.]`;
128
+ await this.daemonManager.triggerHalResponse(bug.discussionId, bug.id, context);
129
+ }
130
+ });
131
+ await this.bugReportsModule.start();
132
+ if (this.bugReportsModule.isRunning()) {
133
+ const config = this.bugReportsModule.getConfig();
134
+ this.logger.info('Bug Reports Module started', {
135
+ autoFix: config.autoFix,
136
+ interval: `${config.intervalMs / 1000}s`
137
+ });
138
+ }
139
+ }
140
+ catch (error) {
141
+ this.logger.warn('Bug Reports Module failed to start - server will continue without bug monitoring', {
142
+ error: error instanceof Error ? error.message : String(error)
143
+ });
144
+ }
145
+ }
146
+ async initBotConfig() {
147
+ try {
148
+ // Get first configured account for bot config persistence
149
+ const accounts = Object.entries(this.appConfig.hailerAccounts);
150
+ if (accounts.length === 0) {
151
+ this.logger.info('No Hailer accounts configured - Bot config persistence disabled');
152
+ return;
153
+ }
154
+ const [apiKey] = accounts[0];
155
+ const userContext = await UserContextCache_1.UserContextCache.getContext(apiKey);
156
+ await (0, bot_config_1.initBotConfigPersistence)(userContext.hailer);
157
+ this.logger.info('Bot config persistence initialized');
158
+ }
159
+ catch (error) {
160
+ this.logger.warn('Bot config persistence failed to initialize - using in-memory defaults', {
161
+ error: error instanceof Error ? error.message : String(error)
162
+ });
163
+ }
164
+ }
97
165
  async initializeDaemonMode() {
98
166
  this.logger.info('Initializing Chat Agent Daemon');
99
167
  // Check for orchestrator mode via environment variable
@@ -126,6 +194,10 @@ class Core {
126
194
  if (this.statusLogInterval) {
127
195
  clearInterval(this.statusLogInterval);
128
196
  }
197
+ // Stop Bug Reports Module
198
+ if (this.bugReportsModule) {
199
+ await this.bugReportsModule.stop();
200
+ }
129
201
  if (this.daemonManager) {
130
202
  this.daemonManager.stopAll();
131
203
  this.logger.info('Chat Agent Daemon stopped');