@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.
- package/.claude/settings.json +12 -0
- package/CLAUDE.md +37 -1
- package/ai-hub/dist/assets/index-8ce6041d.css +1 -0
- package/ai-hub/dist/assets/index-930f01ca.js +348 -0
- package/ai-hub/dist/index.html +15 -0
- package/ai-hub/dist/manifest.json +14 -0
- package/ai-hub/dist/vite.svg +1 -0
- package/dist/app.js +5 -0
- package/dist/client/agents/base.d.ts +5 -0
- package/dist/client/agents/base.js +9 -2
- package/dist/client/agents/definitions.js +85 -0
- package/dist/client/agents/orchestrator.d.ts +21 -0
- package/dist/client/agents/orchestrator.js +292 -1
- package/dist/client/bot-entrypoint.d.ts +7 -0
- package/dist/client/bot-entrypoint.js +103 -0
- package/dist/client/bot-runner.d.ts +35 -0
- package/dist/client/bot-runner.js +188 -0
- package/dist/client/factory.d.ts +4 -0
- package/dist/client/factory.js +10 -0
- package/dist/client/server.d.ts +8 -0
- package/dist/client/server.js +251 -0
- package/dist/client/types.d.ts +29 -0
- package/dist/client/types.js +4 -1
- package/dist/core.d.ts +3 -0
- package/dist/core.js +72 -0
- package/dist/mcp/hailer-clients.d.ts +4 -0
- package/dist/mcp/hailer-clients.js +16 -1
- package/dist/mcp/tools/app-scaffold.js +148 -11
- package/dist/mcp/tools/bot-config.d.ts +78 -0
- package/dist/mcp/tools/bot-config.js +442 -0
- package/dist/mcp-server.js +109 -1
- package/dist/modules/bug-reports/bug-config.d.ts +25 -0
- package/dist/modules/bug-reports/bug-config.js +187 -0
- package/dist/modules/bug-reports/bug-monitor.d.ts +108 -0
- package/dist/modules/bug-reports/bug-monitor.js +510 -0
- package/dist/modules/bug-reports/giuseppe-ai.d.ts +59 -0
- package/dist/modules/bug-reports/giuseppe-ai.js +335 -0
- package/dist/modules/bug-reports/giuseppe-bot.d.ts +109 -0
- package/dist/modules/bug-reports/giuseppe-bot.js +765 -0
- package/dist/modules/bug-reports/giuseppe-files.d.ts +52 -0
- package/dist/modules/bug-reports/giuseppe-files.js +338 -0
- package/dist/modules/bug-reports/giuseppe-git.d.ts +48 -0
- package/dist/modules/bug-reports/giuseppe-git.js +298 -0
- package/dist/modules/bug-reports/giuseppe-prompt.d.ts +5 -0
- package/dist/modules/bug-reports/giuseppe-prompt.js +94 -0
- package/dist/modules/bug-reports/index.d.ts +76 -0
- package/dist/modules/bug-reports/index.js +213 -0
- package/dist/modules/bug-reports/pending-classification-registry.d.ts +28 -0
- package/dist/modules/bug-reports/pending-classification-registry.js +50 -0
- package/dist/modules/bug-reports/pending-fix-registry.d.ts +30 -0
- package/dist/modules/bug-reports/pending-fix-registry.js +42 -0
- package/dist/modules/bug-reports/pending-registry.d.ts +27 -0
- package/dist/modules/bug-reports/pending-registry.js +49 -0
- package/dist/modules/bug-reports/types.d.ts +123 -0
- package/dist/modules/bug-reports/types.js +9 -0
- package/dist/services/bug-monitor.d.ts +23 -0
- package/dist/services/bug-monitor.js +275 -0
- package/lineup-manager/dist/assets/index-b30c809f.js +600 -0
- package/lineup-manager/dist/index.html +1 -1
- package/lineup-manager/dist/manifest.json +5 -5
- package/package.json +6 -2
- package/lineup-manager/dist/assets/index-e168f265.js +0 -600
|
@@ -0,0 +1,442 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Bot Configuration MCP Tools
|
|
4
|
+
*
|
|
5
|
+
* Manages which bots are enabled/disabled in the workspace.
|
|
6
|
+
* Config is stored in the Agent Directory workflow - agents are activities.
|
|
7
|
+
* - Deployed agents phase = enabled
|
|
8
|
+
* - Retired agents phase = disabled
|
|
9
|
+
*
|
|
10
|
+
* Architecture:
|
|
11
|
+
* - In-memory state is primary (for speed)
|
|
12
|
+
* - Agent Directory workflow is persistence layer (agents as activities, phases for state)
|
|
13
|
+
* - On startup: Load config from Hailer by checking which phase each agent is in
|
|
14
|
+
* - On change: Move agent activity between phases
|
|
15
|
+
*/
|
|
16
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
exports.botConfigTools = exports.disableBotTool = exports.enableBotTool = exports.listBotsConfigTool = exports.AVAILABLE_BOTS = void 0;
|
|
18
|
+
exports.onBotStateChange = onBotStateChange;
|
|
19
|
+
exports.getBotState = getBotState;
|
|
20
|
+
exports.setBotEnabled = setBotEnabled;
|
|
21
|
+
exports.initBotConfigPersistence = initBotConfigPersistence;
|
|
22
|
+
exports.isPersistenceInitialized = isPersistenceInitialized;
|
|
23
|
+
exports.getPersistenceStatus = getPersistenceStatus;
|
|
24
|
+
const zod_1 = require("zod");
|
|
25
|
+
const tool_registry_1 = require("../tool-registry");
|
|
26
|
+
const index_1 = require("../utils/index");
|
|
27
|
+
const logger = (0, index_1.createLogger)({ component: 'bot-config-tools' });
|
|
28
|
+
// ============================================================================
|
|
29
|
+
// Agent Directory Workflow Configuration
|
|
30
|
+
// ============================================================================
|
|
31
|
+
// Agent Directory workflow config
|
|
32
|
+
const AGENT_DIRECTORY_WORKFLOW_ID = '695784898d347a6c707ee365';
|
|
33
|
+
const DEPLOYED_PHASE_ID = '695784898d347a6c707ee37d'; // enabled
|
|
34
|
+
const RETIRED_PHASE_ID = '695784898d347a6c707ee37e'; // disabled
|
|
35
|
+
// Mapping from bot IDs to their activity IDs in the Agent Directory workflow
|
|
36
|
+
const AGENT_ACTIVITY_IDS = {
|
|
37
|
+
hal: '6957848b8d347a6c707ee3f6',
|
|
38
|
+
hailerExpert: '695784913c659fc4d8fe0e02',
|
|
39
|
+
giuseppe: '695e42deca61319424bc8b23',
|
|
40
|
+
vastuullisuus: '695e42dfca61319424bc8b2e'
|
|
41
|
+
};
|
|
42
|
+
// Persistence state
|
|
43
|
+
let persistenceInitialized = false;
|
|
44
|
+
let hailerClient = null; // Will be set during initialization
|
|
45
|
+
/**
|
|
46
|
+
* Available bots - single source of truth
|
|
47
|
+
*
|
|
48
|
+
* All bots that can be enabled/disabled in the workspace.
|
|
49
|
+
* This list should match the AI Hub app and agent definitions.
|
|
50
|
+
*/
|
|
51
|
+
exports.AVAILABLE_BOTS = [
|
|
52
|
+
{
|
|
53
|
+
id: 'hal',
|
|
54
|
+
name: 'HAL',
|
|
55
|
+
description: 'Main orchestrator - handles general chat and coordinates specialists',
|
|
56
|
+
icon: '🤖'
|
|
57
|
+
},
|
|
58
|
+
{
|
|
59
|
+
id: 'giuseppe',
|
|
60
|
+
name: 'Giuseppe',
|
|
61
|
+
description: 'Bug fixing specialist - analyzes and repairs Hailer app issues',
|
|
62
|
+
icon: '🔧'
|
|
63
|
+
},
|
|
64
|
+
{
|
|
65
|
+
id: 'hailerExpert',
|
|
66
|
+
name: 'Hailer Expert',
|
|
67
|
+
description: 'Workflow & data specialist - bulk operations, insights, reports',
|
|
68
|
+
icon: '📊'
|
|
69
|
+
},
|
|
70
|
+
{
|
|
71
|
+
id: 'vastuullisuus',
|
|
72
|
+
name: 'Vastuullisuus',
|
|
73
|
+
description: 'Sustainability analysis for SMEs',
|
|
74
|
+
icon: '🌱'
|
|
75
|
+
}
|
|
76
|
+
];
|
|
77
|
+
// In-memory bot state (will be synced with workflow)
|
|
78
|
+
const botState = {
|
|
79
|
+
hal: true, // HAL enabled by default
|
|
80
|
+
giuseppe: false,
|
|
81
|
+
hailerExpert: false,
|
|
82
|
+
vastuullisuus: false
|
|
83
|
+
};
|
|
84
|
+
// Callbacks for when bot state changes
|
|
85
|
+
const stateChangeCallbacks = [];
|
|
86
|
+
function onBotStateChange(callback) {
|
|
87
|
+
stateChangeCallbacks.push(callback);
|
|
88
|
+
}
|
|
89
|
+
function getBotState() {
|
|
90
|
+
return { ...botState };
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* Set bot enabled state
|
|
94
|
+
*
|
|
95
|
+
* Updates in-memory state and persists to Agent Directory by moving
|
|
96
|
+
* the agent activity to the appropriate phase (deployed/retired).
|
|
97
|
+
*/
|
|
98
|
+
function setBotEnabled(botId, enabled) {
|
|
99
|
+
if (!exports.AVAILABLE_BOTS.find(b => b.id === botId)) {
|
|
100
|
+
throw new Error(`Unknown bot: ${botId}`);
|
|
101
|
+
}
|
|
102
|
+
botState[botId] = enabled;
|
|
103
|
+
// Notify listeners
|
|
104
|
+
stateChangeCallbacks.forEach(cb => cb(botId, enabled));
|
|
105
|
+
logger.info('Bot state changed', { botId, enabled });
|
|
106
|
+
// Persist single bot to Hailer asynchronously (more efficient than full sync)
|
|
107
|
+
persistBotToHailer(botId, enabled).catch(err => logger.warn('Persistence failed', { botId, err: err instanceof Error ? err.message : String(err) }));
|
|
108
|
+
}
|
|
109
|
+
// ============================================================================
|
|
110
|
+
// Persistence Layer Functions
|
|
111
|
+
// ============================================================================
|
|
112
|
+
/**
|
|
113
|
+
* Initialize persistence layer
|
|
114
|
+
* Called once during MCP server startup
|
|
115
|
+
*
|
|
116
|
+
* Loads agent enabled state from the Agent Directory workflow:
|
|
117
|
+
* - Agents in DEPLOYED_PHASE_ID are enabled
|
|
118
|
+
* - Agents in RETIRED_PHASE_ID are disabled
|
|
119
|
+
*
|
|
120
|
+
* @param client - HailerApiClient instance for API calls
|
|
121
|
+
*/
|
|
122
|
+
async function initBotConfigPersistence(client) {
|
|
123
|
+
if (persistenceInitialized) {
|
|
124
|
+
logger.debug('Bot config persistence already initialized');
|
|
125
|
+
return;
|
|
126
|
+
}
|
|
127
|
+
hailerClient = client;
|
|
128
|
+
try {
|
|
129
|
+
logger.info('Initializing bot config persistence from Agent Directory...', {
|
|
130
|
+
workflowId: AGENT_DIRECTORY_WORKFLOW_ID,
|
|
131
|
+
deployedPhaseId: DEPLOYED_PHASE_ID,
|
|
132
|
+
retiredPhaseId: RETIRED_PHASE_ID
|
|
133
|
+
});
|
|
134
|
+
// Load agent state from Agent Directory workflow
|
|
135
|
+
const existingConfig = await loadConfigFromHailer();
|
|
136
|
+
if (existingConfig) {
|
|
137
|
+
// Update in-memory state with persisted values
|
|
138
|
+
Object.keys(existingConfig).forEach(botId => {
|
|
139
|
+
if (exports.AVAILABLE_BOTS.find(b => b.id === botId)) {
|
|
140
|
+
botState[botId] = existingConfig[botId];
|
|
141
|
+
}
|
|
142
|
+
});
|
|
143
|
+
logger.info('Bot config loaded from Agent Directory', {
|
|
144
|
+
config: botState
|
|
145
|
+
});
|
|
146
|
+
}
|
|
147
|
+
logger.info('Bot config persistence initialized');
|
|
148
|
+
persistenceInitialized = true;
|
|
149
|
+
}
|
|
150
|
+
catch (error) {
|
|
151
|
+
logger.warn('Failed to initialize bot config persistence, using defaults', {
|
|
152
|
+
error: error instanceof Error ? error.message : String(error)
|
|
153
|
+
});
|
|
154
|
+
// Still mark as initialized to prevent repeated failures
|
|
155
|
+
persistenceInitialized = true;
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
/**
|
|
159
|
+
* Load config from Agent Directory workflow
|
|
160
|
+
*
|
|
161
|
+
* Checks which phase each agent activity is in:
|
|
162
|
+
* - DEPLOYED_PHASE_ID = enabled
|
|
163
|
+
* - RETIRED_PHASE_ID = disabled
|
|
164
|
+
*
|
|
165
|
+
* @returns bot config or null if not found
|
|
166
|
+
*/
|
|
167
|
+
async function loadConfigFromHailer() {
|
|
168
|
+
if (!hailerClient) {
|
|
169
|
+
logger.debug('Cannot load config: missing Hailer client');
|
|
170
|
+
return null;
|
|
171
|
+
}
|
|
172
|
+
try {
|
|
173
|
+
const config = {};
|
|
174
|
+
// Create reverse mapping: activityId -> botId
|
|
175
|
+
const activityIdToBotId = {};
|
|
176
|
+
for (const [botId, activityId] of Object.entries(AGENT_ACTIVITY_IDS)) {
|
|
177
|
+
activityIdToBotId[activityId] = botId;
|
|
178
|
+
}
|
|
179
|
+
// Fetch activities from deployed phase (enabled agents)
|
|
180
|
+
logger.debug('Fetching deployed agents...', { phaseId: DEPLOYED_PHASE_ID });
|
|
181
|
+
const deployedActivities = await hailerClient.fetchActivityList(AGENT_DIRECTORY_WORKFLOW_ID, DEPLOYED_PHASE_ID, 100, // limit
|
|
182
|
+
{ returnFlat: true });
|
|
183
|
+
// Mark agents in deployed phase as enabled
|
|
184
|
+
const deployedList = Array.isArray(deployedActivities)
|
|
185
|
+
? deployedActivities
|
|
186
|
+
: (deployedActivities?.activities || []);
|
|
187
|
+
for (const activity of deployedList) {
|
|
188
|
+
const botId = activityIdToBotId[activity._id];
|
|
189
|
+
if (botId) {
|
|
190
|
+
config[botId] = true;
|
|
191
|
+
logger.debug('Agent found in deployed phase (enabled)', { botId, activityId: activity._id });
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
// Fetch activities from retired phase (disabled agents)
|
|
195
|
+
logger.debug('Fetching retired agents...', { phaseId: RETIRED_PHASE_ID });
|
|
196
|
+
const retiredActivities = await hailerClient.fetchActivityList(AGENT_DIRECTORY_WORKFLOW_ID, RETIRED_PHASE_ID, 100, // limit
|
|
197
|
+
{ returnFlat: true });
|
|
198
|
+
// Mark agents in retired phase as disabled
|
|
199
|
+
const retiredList = Array.isArray(retiredActivities)
|
|
200
|
+
? retiredActivities
|
|
201
|
+
: (retiredActivities?.activities || []);
|
|
202
|
+
for (const activity of retiredList) {
|
|
203
|
+
const botId = activityIdToBotId[activity._id];
|
|
204
|
+
if (botId) {
|
|
205
|
+
config[botId] = false;
|
|
206
|
+
logger.debug('Agent found in retired phase (disabled)', { botId, activityId: activity._id });
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
// For any bots not found in either phase, default based on AVAILABLE_BOTS defaults
|
|
210
|
+
for (const bot of exports.AVAILABLE_BOTS) {
|
|
211
|
+
if (config[bot.id] === undefined) {
|
|
212
|
+
// Default: HAL enabled, others disabled
|
|
213
|
+
config[bot.id] = bot.id === 'hal';
|
|
214
|
+
logger.debug('Agent not found in any phase, using default', {
|
|
215
|
+
botId: bot.id,
|
|
216
|
+
default: config[bot.id]
|
|
217
|
+
});
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
logger.info('Bot config loaded from Agent Directory', {
|
|
221
|
+
deployedCount: deployedList.length,
|
|
222
|
+
retiredCount: retiredList.length,
|
|
223
|
+
config
|
|
224
|
+
});
|
|
225
|
+
return config;
|
|
226
|
+
}
|
|
227
|
+
catch (error) {
|
|
228
|
+
logger.warn('Failed to load bot config from Agent Directory', {
|
|
229
|
+
error: error instanceof Error ? error.message : String(error)
|
|
230
|
+
});
|
|
231
|
+
return null;
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
/**
|
|
235
|
+
* Persist a single bot's state to Hailer
|
|
236
|
+
*
|
|
237
|
+
* Moves the bot's agent activity between phases:
|
|
238
|
+
* - enabled = move to DEPLOYED_PHASE_ID
|
|
239
|
+
* - disabled = move to RETIRED_PHASE_ID
|
|
240
|
+
*
|
|
241
|
+
* @param botId - The bot ID to persist
|
|
242
|
+
* @param enabled - Whether the bot is enabled
|
|
243
|
+
*/
|
|
244
|
+
async function persistBotToHailer(botId, enabled) {
|
|
245
|
+
if (!hailerClient || !persistenceInitialized) {
|
|
246
|
+
logger.debug('Persistence not initialized, skipping save');
|
|
247
|
+
return;
|
|
248
|
+
}
|
|
249
|
+
const activityId = AGENT_ACTIVITY_IDS[botId];
|
|
250
|
+
if (!activityId) {
|
|
251
|
+
logger.warn('No activity ID found for bot', { botId });
|
|
252
|
+
return;
|
|
253
|
+
}
|
|
254
|
+
const targetPhaseId = enabled ? DEPLOYED_PHASE_ID : RETIRED_PHASE_ID;
|
|
255
|
+
try {
|
|
256
|
+
logger.debug('Moving agent to phase...', {
|
|
257
|
+
botId,
|
|
258
|
+
activityId,
|
|
259
|
+
enabled,
|
|
260
|
+
targetPhaseId
|
|
261
|
+
});
|
|
262
|
+
// Use updateActivities to move the agent activity to the appropriate phase
|
|
263
|
+
await hailerClient.updateActivities([{ _id: activityId }], { phaseId: targetPhaseId });
|
|
264
|
+
logger.info('Agent moved to phase', {
|
|
265
|
+
botId,
|
|
266
|
+
activityId,
|
|
267
|
+
phase: enabled ? 'deployed' : 'retired',
|
|
268
|
+
phaseId: targetPhaseId
|
|
269
|
+
});
|
|
270
|
+
}
|
|
271
|
+
catch (error) {
|
|
272
|
+
logger.warn('Failed to persist bot state to Hailer', {
|
|
273
|
+
botId,
|
|
274
|
+
activityId,
|
|
275
|
+
error: error instanceof Error ? error.message : String(error)
|
|
276
|
+
});
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
/**
|
|
280
|
+
* Save current bot state to Hailer (legacy function for full sync)
|
|
281
|
+
* Called asynchronously after state changes
|
|
282
|
+
*
|
|
283
|
+
* Note: This syncs all bots. For single bot changes, persistBotToHailer is more efficient.
|
|
284
|
+
*/
|
|
285
|
+
async function persistToHailer() {
|
|
286
|
+
if (!hailerClient || !persistenceInitialized) {
|
|
287
|
+
logger.debug('Persistence not initialized, skipping save');
|
|
288
|
+
return;
|
|
289
|
+
}
|
|
290
|
+
try {
|
|
291
|
+
logger.debug('Persisting all bot config to Hailer...', { state: botState });
|
|
292
|
+
// Build updates for all bots
|
|
293
|
+
const enabledUpdates = [];
|
|
294
|
+
const disabledUpdates = [];
|
|
295
|
+
for (const [botId, enabled] of Object.entries(botState)) {
|
|
296
|
+
const activityId = AGENT_ACTIVITY_IDS[botId];
|
|
297
|
+
if (!activityId) {
|
|
298
|
+
logger.debug('No activity ID for bot, skipping', { botId });
|
|
299
|
+
continue;
|
|
300
|
+
}
|
|
301
|
+
if (enabled) {
|
|
302
|
+
enabledUpdates.push({ _id: activityId });
|
|
303
|
+
}
|
|
304
|
+
else {
|
|
305
|
+
disabledUpdates.push({ _id: activityId });
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
// Move enabled agents to deployed phase
|
|
309
|
+
if (enabledUpdates.length > 0) {
|
|
310
|
+
await hailerClient.updateActivities(enabledUpdates, { phaseId: DEPLOYED_PHASE_ID });
|
|
311
|
+
logger.debug('Moved agents to deployed phase', {
|
|
312
|
+
count: enabledUpdates.length,
|
|
313
|
+
phaseId: DEPLOYED_PHASE_ID
|
|
314
|
+
});
|
|
315
|
+
}
|
|
316
|
+
// Move disabled agents to retired phase
|
|
317
|
+
if (disabledUpdates.length > 0) {
|
|
318
|
+
await hailerClient.updateActivities(disabledUpdates, { phaseId: RETIRED_PHASE_ID });
|
|
319
|
+
logger.debug('Moved agents to retired phase', {
|
|
320
|
+
count: disabledUpdates.length,
|
|
321
|
+
phaseId: RETIRED_PHASE_ID
|
|
322
|
+
});
|
|
323
|
+
}
|
|
324
|
+
logger.info('Bot config persisted to Agent Directory', {
|
|
325
|
+
enabledCount: enabledUpdates.length,
|
|
326
|
+
disabledCount: disabledUpdates.length
|
|
327
|
+
});
|
|
328
|
+
}
|
|
329
|
+
catch (error) {
|
|
330
|
+
logger.warn('Failed to persist bot config to Hailer', {
|
|
331
|
+
error: error instanceof Error ? error.message : String(error)
|
|
332
|
+
});
|
|
333
|
+
}
|
|
334
|
+
}
|
|
335
|
+
/**
|
|
336
|
+
* Check if persistence is initialized
|
|
337
|
+
*/
|
|
338
|
+
function isPersistenceInitialized() {
|
|
339
|
+
return persistenceInitialized;
|
|
340
|
+
}
|
|
341
|
+
/**
|
|
342
|
+
* Get persistence status info (for debugging)
|
|
343
|
+
*/
|
|
344
|
+
function getPersistenceStatus() {
|
|
345
|
+
return {
|
|
346
|
+
initialized: persistenceInitialized,
|
|
347
|
+
workflowId: AGENT_DIRECTORY_WORKFLOW_ID,
|
|
348
|
+
deployedPhaseId: DEPLOYED_PHASE_ID,
|
|
349
|
+
retiredPhaseId: RETIRED_PHASE_ID,
|
|
350
|
+
agentActivityIds: { ...AGENT_ACTIVITY_IDS },
|
|
351
|
+
hasClient: hailerClient !== null
|
|
352
|
+
};
|
|
353
|
+
}
|
|
354
|
+
/**
|
|
355
|
+
* List available bots and their status
|
|
356
|
+
*/
|
|
357
|
+
exports.listBotsConfigTool = {
|
|
358
|
+
name: 'list_bots_config',
|
|
359
|
+
group: tool_registry_1.ToolGroup.READ,
|
|
360
|
+
description: 'List available AI bots and their enabled/disabled status',
|
|
361
|
+
schema: zod_1.z.object({}),
|
|
362
|
+
execute: async (_params, _context) => {
|
|
363
|
+
const bots = exports.AVAILABLE_BOTS.map(bot => ({
|
|
364
|
+
...bot,
|
|
365
|
+
enabled: botState[bot.id] || false
|
|
366
|
+
}));
|
|
367
|
+
return {
|
|
368
|
+
content: [{
|
|
369
|
+
type: 'text',
|
|
370
|
+
text: JSON.stringify({ bots }, null, 2)
|
|
371
|
+
}]
|
|
372
|
+
};
|
|
373
|
+
}
|
|
374
|
+
};
|
|
375
|
+
/**
|
|
376
|
+
* Enable a bot
|
|
377
|
+
*/
|
|
378
|
+
exports.enableBotTool = {
|
|
379
|
+
name: 'enable_bot',
|
|
380
|
+
group: tool_registry_1.ToolGroup.WRITE,
|
|
381
|
+
description: 'Enable an AI bot in this workspace',
|
|
382
|
+
schema: zod_1.z.object({
|
|
383
|
+
botId: zod_1.z.string().describe('Bot ID to enable (hal, giuseppe, hailerExpert, vastuullisuus)')
|
|
384
|
+
}),
|
|
385
|
+
execute: async (params, _context) => {
|
|
386
|
+
const { botId } = params;
|
|
387
|
+
if (!exports.AVAILABLE_BOTS.find(b => b.id === botId)) {
|
|
388
|
+
return {
|
|
389
|
+
content: [{
|
|
390
|
+
type: 'text',
|
|
391
|
+
text: `Unknown bot: ${botId}. Available: ${exports.AVAILABLE_BOTS.map(b => b.id).join(', ')}`
|
|
392
|
+
}],
|
|
393
|
+
isError: true
|
|
394
|
+
};
|
|
395
|
+
}
|
|
396
|
+
// Use setBotEnabled to trigger persistence
|
|
397
|
+
setBotEnabled(botId, true);
|
|
398
|
+
return {
|
|
399
|
+
content: [{
|
|
400
|
+
type: 'text',
|
|
401
|
+
text: `${botId} bot enabled`
|
|
402
|
+
}]
|
|
403
|
+
};
|
|
404
|
+
}
|
|
405
|
+
};
|
|
406
|
+
/**
|
|
407
|
+
* Disable a bot
|
|
408
|
+
*/
|
|
409
|
+
exports.disableBotTool = {
|
|
410
|
+
name: 'disable_bot',
|
|
411
|
+
group: tool_registry_1.ToolGroup.WRITE,
|
|
412
|
+
description: 'Disable an AI bot in this workspace',
|
|
413
|
+
schema: zod_1.z.object({
|
|
414
|
+
botId: zod_1.z.string().describe('Bot ID to disable (hal, giuseppe, hailerExpert, vastuullisuus)')
|
|
415
|
+
}),
|
|
416
|
+
execute: async (params, _context) => {
|
|
417
|
+
const { botId } = params;
|
|
418
|
+
if (!exports.AVAILABLE_BOTS.find(b => b.id === botId)) {
|
|
419
|
+
return {
|
|
420
|
+
content: [{
|
|
421
|
+
type: 'text',
|
|
422
|
+
text: `Unknown bot: ${botId}. Available: ${exports.AVAILABLE_BOTS.map(b => b.id).join(', ')}`
|
|
423
|
+
}],
|
|
424
|
+
isError: true
|
|
425
|
+
};
|
|
426
|
+
}
|
|
427
|
+
// Use setBotEnabled to trigger persistence
|
|
428
|
+
setBotEnabled(botId, false);
|
|
429
|
+
return {
|
|
430
|
+
content: [{
|
|
431
|
+
type: 'text',
|
|
432
|
+
text: `${botId} bot disabled`
|
|
433
|
+
}]
|
|
434
|
+
};
|
|
435
|
+
}
|
|
436
|
+
};
|
|
437
|
+
exports.botConfigTools = [
|
|
438
|
+
exports.listBotsConfigTool,
|
|
439
|
+
exports.enableBotTool,
|
|
440
|
+
exports.disableBotTool
|
|
441
|
+
];
|
|
442
|
+
//# sourceMappingURL=bot-config.js.map
|
package/dist/mcp-server.js
CHANGED
|
@@ -5,6 +5,39 @@
|
|
|
5
5
|
* Implements JSON-RPC 2.0 MCP protocol over HTTP with Server-Sent Events (SSE)
|
|
6
6
|
* for LLM clients (Claude Desktop, etc.)
|
|
7
7
|
*/
|
|
8
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
9
|
+
if (k2 === undefined) k2 = k;
|
|
10
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
11
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
12
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
13
|
+
}
|
|
14
|
+
Object.defineProperty(o, k2, desc);
|
|
15
|
+
}) : (function(o, m, k, k2) {
|
|
16
|
+
if (k2 === undefined) k2 = k;
|
|
17
|
+
o[k2] = m[k];
|
|
18
|
+
}));
|
|
19
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
20
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
21
|
+
}) : function(o, v) {
|
|
22
|
+
o["default"] = v;
|
|
23
|
+
});
|
|
24
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
25
|
+
var ownKeys = function(o) {
|
|
26
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
27
|
+
var ar = [];
|
|
28
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
29
|
+
return ar;
|
|
30
|
+
};
|
|
31
|
+
return ownKeys(o);
|
|
32
|
+
};
|
|
33
|
+
return function (mod) {
|
|
34
|
+
if (mod && mod.__esModule) return mod;
|
|
35
|
+
var result = {};
|
|
36
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
37
|
+
__setModuleDefault(result, mod);
|
|
38
|
+
return result;
|
|
39
|
+
};
|
|
40
|
+
})();
|
|
8
41
|
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
9
42
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
10
43
|
};
|
|
@@ -218,11 +251,86 @@ class MCPServerService {
|
|
|
218
251
|
this.sendMcpError(res, req.body?.id || null, -32000, `Server error: ${error instanceof Error ? error.message : String(error)}`, 500);
|
|
219
252
|
}
|
|
220
253
|
});
|
|
254
|
+
// ===== Bot Configuration API =====
|
|
255
|
+
// GET /api/bots - List all bots and their status
|
|
256
|
+
this.app.get('/api/bots', async (req, res) => {
|
|
257
|
+
req.logger.debug('List bots requested');
|
|
258
|
+
try {
|
|
259
|
+
const { AVAILABLE_BOTS, getBotState } = await Promise.resolve().then(() => __importStar(require('./mcp/tools/bot-config')));
|
|
260
|
+
const state = getBotState();
|
|
261
|
+
const bots = AVAILABLE_BOTS.map(bot => ({
|
|
262
|
+
...bot,
|
|
263
|
+
enabled: state[bot.id] || false
|
|
264
|
+
}));
|
|
265
|
+
res.json({ bots });
|
|
266
|
+
}
|
|
267
|
+
catch (error) {
|
|
268
|
+
req.logger.error('Failed to list bots', { error });
|
|
269
|
+
res.status(500).json({ error: 'Failed to list bots' });
|
|
270
|
+
}
|
|
271
|
+
});
|
|
272
|
+
// POST /api/bots/:id/enable - Enable a bot
|
|
273
|
+
this.app.post('/api/bots/:id/enable', async (req, res) => {
|
|
274
|
+
const { id } = req.params;
|
|
275
|
+
req.logger.info('Enable bot requested', { botId: id });
|
|
276
|
+
try {
|
|
277
|
+
const { AVAILABLE_BOTS, setBotEnabled } = await Promise.resolve().then(() => __importStar(require('./mcp/tools/bot-config')));
|
|
278
|
+
const bot = AVAILABLE_BOTS.find(b => b.id === id);
|
|
279
|
+
if (!bot) {
|
|
280
|
+
return res.status(404).json({ error: `Unknown bot: ${id}` });
|
|
281
|
+
}
|
|
282
|
+
setBotEnabled(id, true);
|
|
283
|
+
res.json({ success: true, botId: id, enabled: true });
|
|
284
|
+
}
|
|
285
|
+
catch (error) {
|
|
286
|
+
req.logger.error('Failed to enable bot', { botId: id, error });
|
|
287
|
+
res.status(500).json({ error: 'Failed to enable bot' });
|
|
288
|
+
}
|
|
289
|
+
});
|
|
290
|
+
// POST /api/bots/:id/disable - Disable a bot
|
|
291
|
+
this.app.post('/api/bots/:id/disable', async (req, res) => {
|
|
292
|
+
const { id } = req.params;
|
|
293
|
+
req.logger.info('Disable bot requested', { botId: id });
|
|
294
|
+
try {
|
|
295
|
+
const { AVAILABLE_BOTS, setBotEnabled } = await Promise.resolve().then(() => __importStar(require('./mcp/tools/bot-config')));
|
|
296
|
+
const bot = AVAILABLE_BOTS.find(b => b.id === id);
|
|
297
|
+
if (!bot) {
|
|
298
|
+
return res.status(404).json({ error: `Unknown bot: ${id}` });
|
|
299
|
+
}
|
|
300
|
+
setBotEnabled(id, false);
|
|
301
|
+
res.json({ success: true, botId: id, enabled: false });
|
|
302
|
+
}
|
|
303
|
+
catch (error) {
|
|
304
|
+
req.logger.error('Failed to disable bot', { botId: id, error });
|
|
305
|
+
res.status(500).json({ error: 'Failed to disable bot' });
|
|
306
|
+
}
|
|
307
|
+
});
|
|
308
|
+
// POST /api/bots/:id/toggle - Toggle a bot
|
|
309
|
+
this.app.post('/api/bots/:id/toggle', async (req, res) => {
|
|
310
|
+
const { id } = req.params;
|
|
311
|
+
req.logger.info('Toggle bot requested', { botId: id });
|
|
312
|
+
try {
|
|
313
|
+
const { AVAILABLE_BOTS, getBotState, setBotEnabled } = await Promise.resolve().then(() => __importStar(require('./mcp/tools/bot-config')));
|
|
314
|
+
const bot = AVAILABLE_BOTS.find(b => b.id === id);
|
|
315
|
+
if (!bot) {
|
|
316
|
+
return res.status(404).json({ error: `Unknown bot: ${id}` });
|
|
317
|
+
}
|
|
318
|
+
const currentState = getBotState();
|
|
319
|
+
const newState = !currentState[id];
|
|
320
|
+
setBotEnabled(id, newState);
|
|
321
|
+
res.json({ success: true, botId: id, enabled: newState });
|
|
322
|
+
}
|
|
323
|
+
catch (error) {
|
|
324
|
+
req.logger.error('Failed to toggle bot', { botId: id, error });
|
|
325
|
+
res.status(500).json({ error: 'Failed to toggle bot' });
|
|
326
|
+
}
|
|
327
|
+
});
|
|
221
328
|
this.logger.info('Routes configured', {
|
|
222
329
|
routes: [
|
|
223
330
|
'/health - Server health check',
|
|
224
331
|
'/daemon/status - Daemon context monitor',
|
|
225
|
-
'/api/mcp - MCP protocol (JSON-RPC 2.0)'
|
|
332
|
+
'/api/mcp - MCP protocol (JSON-RPC 2.0)',
|
|
333
|
+
'/api/bots - Bot configuration API'
|
|
226
334
|
]
|
|
227
335
|
});
|
|
228
336
|
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Bug Reports Module - Configuration Discovery
|
|
3
|
+
*
|
|
4
|
+
* Discovers Bug Reports workflow by name pattern.
|
|
5
|
+
* No hardcoded IDs - works in any workspace.
|
|
6
|
+
*/
|
|
7
|
+
import type { UserContext } from '../../mcp/UserContextCache';
|
|
8
|
+
import type { BugReportsConfig, WorkflowDiscoveryResult } from './types';
|
|
9
|
+
/**
|
|
10
|
+
* Discover Bug Reports workflow in a workspace
|
|
11
|
+
*/
|
|
12
|
+
export declare function discoverWorkflow(userContext: UserContext, config: BugReportsConfig): Promise<WorkflowDiscoveryResult | null>;
|
|
13
|
+
/**
|
|
14
|
+
* Load config from MCP Config workflow or environment
|
|
15
|
+
*/
|
|
16
|
+
export declare function loadConfig(userContext: UserContext): Promise<BugReportsConfig>;
|
|
17
|
+
/**
|
|
18
|
+
* Get default configuration
|
|
19
|
+
*/
|
|
20
|
+
export declare function getDefaultConfig(): BugReportsConfig;
|
|
21
|
+
/**
|
|
22
|
+
* Save config back to Hailer (creates/updates config activity)
|
|
23
|
+
*/
|
|
24
|
+
export declare function saveConfig(userContext: UserContext, config: BugReportsConfig): Promise<boolean>;
|
|
25
|
+
//# sourceMappingURL=bug-config.d.ts.map
|