@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,650 +0,0 @@
1
- "use strict";
2
- /**
3
- * Daemon Factory
4
- *
5
- * Creates and manages agent daemons in orchestrator mode:
6
- * - One orchestrator (HAL) handles general conversation
7
- * - Specialist daemons handle complex domain-specific tasks
8
- */
9
- var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
10
- if (k2 === undefined) k2 = k;
11
- var desc = Object.getOwnPropertyDescriptor(m, k);
12
- if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
13
- desc = { enumerable: true, get: function() { return m[k]; } };
14
- }
15
- Object.defineProperty(o, k2, desc);
16
- }) : (function(o, m, k, k2) {
17
- if (k2 === undefined) k2 = k;
18
- o[k2] = m[k];
19
- }));
20
- var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
21
- Object.defineProperty(o, "default", { enumerable: true, value: v });
22
- }) : function(o, v) {
23
- o["default"] = v;
24
- });
25
- var __importStar = (this && this.__importStar) || (function () {
26
- var ownKeys = function(o) {
27
- ownKeys = Object.getOwnPropertyNames || function (o) {
28
- var ar = [];
29
- for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
30
- return ar;
31
- };
32
- return ownKeys(o);
33
- };
34
- return function (mod) {
35
- if (mod && mod.__esModule) return mod;
36
- var result = {};
37
- if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
38
- __setModuleDefault(result, mod);
39
- return result;
40
- };
41
- })();
42
- Object.defineProperty(exports, "__esModule", { value: true });
43
- exports.DaemonManager = void 0;
44
- exports.createDaemonManager = createDaemonManager;
45
- exports.startDaemonMode = startDaemonMode;
46
- const fs = __importStar(require("fs"));
47
- const path = __importStar(require("path"));
48
- const daemon_1 = require("./hal/daemon");
49
- const specialist_1 = require("./shared/specialist");
50
- const definitions_1 = require("./hal/definitions");
51
- const bot_manager_1 = require("./bot-manager");
52
- const config_1 = require("../config");
53
- const logger_1 = require("../lib/logger");
54
- const bot_config_1 = require("../mcp/tools/bot-config");
55
- const hailer_clients_1 = require("../mcp/hailer-clients");
56
- const logger = (0, logger_1.createLogger)({ component: "DaemonFactory" });
57
- /**
58
- * Load workspace configurations from .bot-config/*.json files
59
- */
60
- function loadWorkspaceConfigs() {
61
- const configDir = path.join(process.cwd(), '.bot-config');
62
- if (!fs.existsSync(configDir)) {
63
- logger.warn('No .bot-config directory found');
64
- return [];
65
- }
66
- const files = fs.readdirSync(configDir).filter(f => f.endsWith('.json'));
67
- const configs = [];
68
- for (const file of files) {
69
- try {
70
- const content = fs.readFileSync(path.join(configDir, file), 'utf-8');
71
- configs.push(JSON.parse(content));
72
- }
73
- catch (error) {
74
- logger.warn('Failed to load workspace config', { file, error });
75
- }
76
- }
77
- return configs;
78
- }
79
- /**
80
- * Map botType from Agent Directory to specialist key
81
- * botType values come from the Agent Directory workflow
82
- */
83
- function mapBotTypeToSpecialistKey(botType) {
84
- if (!botType)
85
- return null;
86
- const mapping = {
87
- 'workflow-expert': 'hailerExpert',
88
- 'bug-fixer': 'giuseppe',
89
- // Add more mappings as new specialists are added
90
- };
91
- return mapping[botType] || null;
92
- }
93
- /**
94
- * Manages orchestrator + specialist daemons
95
- */
96
- class DaemonManager {
97
- daemons = new Map();
98
- orchestrator = null;
99
- specialists = new Map();
100
- botManager;
101
- options;
102
- botTypeMap;
103
- displayNameMap;
104
- constructor(botManager, options) {
105
- this.botManager = botManager;
106
- this.options = options;
107
- this.botTypeMap = options.botTypeMap || new Map();
108
- this.displayNameMap = options.displayNameMap || new Map();
109
- }
110
- /**
111
- * Get botType for a userId from the workspace config
112
- */
113
- getBotType(userId) {
114
- return this.botTypeMap.get(userId) || null;
115
- }
116
- /**
117
- * Get displayName for a userId from the workspace config (Agent Directory activity name)
118
- * Falls back to Hailer profile name if not set
119
- */
120
- getDisplayName(userId) {
121
- return this.displayNameMap.get(userId) || this.botManager.getUserName(userId);
122
- }
123
- /**
124
- * Start all daemons (orchestrator + specialists)
125
- */
126
- async startAll() {
127
- await this.startOrchestratorMode();
128
- }
129
- /**
130
- * Orchestrator mode: one orchestrator (HAL) + specialist daemons
131
- */
132
- async startOrchestratorMode() {
133
- const botClients = this.botManager.getAllBotClients();
134
- logger.info("Starting daemons in ORCHESTRATOR mode", {
135
- botCount: botClients.length,
136
- });
137
- // Find orchestrator bot
138
- let orchestratorClient;
139
- const specialistClients = new Map();
140
- for (const botClient of botClients) {
141
- const email = botClient.config.email;
142
- const botType = this.getBotType(botClient.userId);
143
- // Check if this is the orchestrator (by email match, botType, or first bot fallback)
144
- if (this.options.orchestratorEmail === email ||
145
- botType === 'orchestrator' ||
146
- (!this.options.orchestratorEmail && !orchestratorClient)) {
147
- orchestratorClient = botClient;
148
- logger.info("Orchestrator assigned", {
149
- userId: botClient.userId,
150
- email: (0, config_1.maskEmail)(email),
151
- botType,
152
- reason: this.options.orchestratorEmail === email ? 'email_match' :
153
- botType === 'orchestrator' ? 'botType' : 'first_bot_fallback'
154
- });
155
- continue;
156
- }
157
- // Check if this matches a specialist
158
- if (this.options.specialistEmails) {
159
- for (const [specialistKey, specialistEmail] of Object.entries(this.options.specialistEmails)) {
160
- if (email === specialistEmail) {
161
- specialistClients.set(specialistKey, botClient);
162
- break;
163
- }
164
- }
165
- }
166
- else {
167
- // Auto-assign based on botType from workspace config
168
- const specialistKey = mapBotTypeToSpecialistKey(botType);
169
- if (specialistKey && definitions_1.SPECIALISTS[specialistKey]) {
170
- specialistClients.set(specialistKey, botClient);
171
- logger.info("Specialist assigned by botType", {
172
- userId: botClient.userId,
173
- botType,
174
- specialistKey
175
- });
176
- }
177
- else {
178
- // Fallback: assign to first available specialist
179
- for (const key of Object.keys(definitions_1.SPECIALISTS)) {
180
- if (!specialistClients.has(key)) {
181
- specialistClients.set(key, botClient);
182
- logger.info("Specialist assigned by fallback", {
183
- userId: botClient.userId,
184
- specialistKey: key
185
- });
186
- break;
187
- }
188
- }
189
- }
190
- }
191
- }
192
- if (!orchestratorClient) {
193
- throw new Error("No orchestrator bot found");
194
- }
195
- // Create specialist user ID map for orchestrator
196
- const specialistUserIds = new Map();
197
- for (const [key, client] of specialistClients) {
198
- specialistUserIds.set(key, client.userId);
199
- }
200
- // Start orchestrator
201
- const orchestratorConfig = {
202
- botClient: orchestratorClient,
203
- mcpServerUrl: this.options.mcpServerUrl,
204
- anthropicApiKey: this.options.anthropicApiKey,
205
- model: this.options.model,
206
- specialistUserIds,
207
- };
208
- this.orchestrator = new daemon_1.OrchestratorDaemon(orchestratorConfig);
209
- await this.orchestrator.initialize();
210
- // Register specialist user IDs with orchestrator (with display names from workspace)
211
- for (const [key, userId] of specialistUserIds) {
212
- const displayName = this.getDisplayName(userId);
213
- this.orchestrator.registerSpecialistUserId(key, userId, displayName);
214
- }
215
- this.daemons.set(orchestratorClient.userId, this.orchestrator);
216
- logger.info("Orchestrator started", {
217
- botId: orchestratorClient.userId,
218
- email: (0, config_1.maskEmail)(orchestratorClient.config.email),
219
- specialistCount: specialistClients.size,
220
- });
221
- // Subscribe to bot state changes to update specialist availability
222
- (0, bot_config_1.onBotStateChange)((userId, enabled) => {
223
- const botType = this.getBotType(userId);
224
- // Skip orchestrator changes (handled by daemon restart)
225
- if (botType === 'orchestrator')
226
- return;
227
- // Find the specialist key for this user
228
- const specialistKey = mapBotTypeToSpecialistKey(botType);
229
- if (!specialistKey) {
230
- logger.debug('No specialist mapping for botType', { userId, botType });
231
- return;
232
- }
233
- if (enabled) {
234
- // Re-register the specialist (with display name from workspace)
235
- const displayName = this.getDisplayName(userId);
236
- this.orchestrator?.registerSpecialistUserId(specialistKey, userId, displayName);
237
- logger.info('Specialist re-enabled', { specialistKey, userId, displayName });
238
- }
239
- else {
240
- // Unregister the specialist
241
- this.orchestrator?.unregisterSpecialist(specialistKey);
242
- logger.info('Specialist disabled', { specialistKey, userId });
243
- }
244
- });
245
- // Start specialist daemons
246
- for (const [specialistKey, botClient] of specialistClients) {
247
- const specialistDef = definitions_1.SPECIALISTS[specialistKey];
248
- if (!specialistDef) {
249
- logger.warn("Unknown specialist key", { key: specialistKey });
250
- continue;
251
- }
252
- // Clone the specialist to avoid cross-workspace contamination
253
- const specialist = { ...specialistDef, botUserId: botClient.userId };
254
- const specialistConfig = {
255
- botClient,
256
- mcpServerUrl: this.options.mcpServerUrl,
257
- anthropicApiKey: this.options.anthropicApiKey,
258
- model: specialist.model || this.options.model,
259
- specialist,
260
- };
261
- const specialistDaemon = new specialist_1.SpecialistDaemon(specialistConfig);
262
- await specialistDaemon.initialize();
263
- this.specialists.set(specialistKey, specialistDaemon);
264
- this.daemons.set(botClient.userId, specialistDaemon);
265
- logger.info("Specialist daemon started", {
266
- key: specialistKey,
267
- name: specialist.name,
268
- botId: botClient.userId,
269
- email: (0, config_1.maskEmail)(botClient.config.email),
270
- });
271
- }
272
- logger.info("Orchestrator mode started", {
273
- orchestratorId: orchestratorClient.userId,
274
- specialistCount: this.specialists.size,
275
- totalDaemons: this.daemons.size,
276
- });
277
- }
278
- /**
279
- * Stop all daemons
280
- * Flushes session logs for each daemon before stopping
281
- */
282
- async stopAll() {
283
- const stopPromises = Array.from(this.daemons.entries()).map(async ([botId, daemon]) => {
284
- await daemon.stop();
285
- logger.info("Daemon stopped", { botId });
286
- });
287
- await Promise.all(stopPromises);
288
- this.daemons.clear();
289
- }
290
- /**
291
- * Get daemon for a specific bot
292
- */
293
- getDaemon(botId) {
294
- return this.daemons.get(botId);
295
- }
296
- /**
297
- * Get status of all daemons
298
- */
299
- getStatus() {
300
- return Array.from(this.daemons.entries()).map(([botId, daemon]) => ({
301
- botId,
302
- state: daemon.getConversationState(),
303
- }));
304
- }
305
- /**
306
- * Log current status to console (for monitoring)
307
- */
308
- logStatus() {
309
- const status = this.getStatus();
310
- if (this.options.orchestratorMode) {
311
- logger.info("=== ORCHESTRATOR MODE STATUS ===");
312
- // Log orchestrator
313
- if (this.orchestrator) {
314
- const orchStatus = this.orchestrator.getOrchestratorStatus();
315
- logger.info("ORCHESTRATOR (HAL):", {
316
- discussions: orchStatus.conversationState.discussionCount,
317
- messages: orchStatus.conversationState.currentMessageCount,
318
- queue: orchStatus.conversationState.queueLength,
319
- processing: orchStatus.conversationState.isProcessing,
320
- specialists: orchStatus.specialists.filter(s => s.available).length,
321
- });
322
- }
323
- // Log specialists
324
- for (const [key, specialist] of this.specialists) {
325
- const specStatus = specialist.getSpecialistStatus();
326
- logger.info(`SPECIALIST [${key}] ${specStatus.name}:`, {
327
- discussions: specStatus.conversationState.discussionCount,
328
- messages: specStatus.conversationState.currentMessageCount,
329
- queue: specStatus.conversationState.queueLength,
330
- processing: specStatus.conversationState.isProcessing,
331
- });
332
- }
333
- }
334
- else {
335
- logger.info("=== DAEMON STATUS ===");
336
- for (const { botId, state } of status) {
337
- logger.info(`Bot ${botId.substring(0, 8)}...`, {
338
- discussions: state.discussionCount,
339
- messages: state.currentMessageCount,
340
- queue: state.queueLength,
341
- processing: state.isProcessing,
342
- });
343
- if (state.lastMessages.length > 0) {
344
- logger.info("Last messages:");
345
- for (const msg of state.lastMessages) {
346
- logger.info(` [${msg.role}] ${msg.preview}`);
347
- }
348
- }
349
- }
350
- }
351
- logger.info("=====================");
352
- }
353
- /**
354
- * Get orchestrator instance (only in orchestrator mode)
355
- */
356
- getOrchestrator() {
357
- return this.orchestrator;
358
- }
359
- /**
360
- * Get specialist by key (only in orchestrator mode)
361
- */
362
- getSpecialist(key) {
363
- return this.specialists.get(key);
364
- }
365
- /**
366
- * Check if running in orchestrator mode
367
- */
368
- isOrchestratorMode() {
369
- return !!this.options.orchestratorMode;
370
- }
371
- /**
372
- * Trigger HAL to respond in a discussion with context
373
- */
374
- async triggerHalResponse(discussionId, activityId, context) {
375
- if (!this.orchestrator) {
376
- logger.warn('Cannot trigger HAL response - orchestrator not running');
377
- return;
378
- }
379
- await this.orchestrator.respondWithContext(discussionId, activityId, context);
380
- }
381
- /**
382
- * Hot-reload: Start a specialist daemon dynamically
383
- * Preserves orchestrator conversation context
384
- */
385
- async startSpecialist(email, password, botType, userId) {
386
- const specialistKey = mapBotTypeToSpecialistKey(botType);
387
- if (!specialistKey) {
388
- logger.warn('Unknown botType for specialist', { botType });
389
- return false;
390
- }
391
- // Check if already running
392
- if (this.specialists.has(specialistKey)) {
393
- logger.info('Specialist already running', { specialistKey });
394
- return true;
395
- }
396
- const specialistDef = definitions_1.SPECIALISTS[specialistKey];
397
- if (!specialistDef) {
398
- logger.warn('Specialist definition not found', { specialistKey });
399
- return false;
400
- }
401
- try {
402
- // Initialize bot client
403
- const actualUserId = userId || email;
404
- const apiKey = (0, hailer_clients_1.registerBotCredentials)(actualUserId, email, password);
405
- await this.botManager.initializeBotClient(email, password, apiKey);
406
- const botClient = this.botManager.getBotClientByBotId(specialistKey) ||
407
- Array.from(this.botManager.getAllBotClients())
408
- .find(bc => bc.config.email === email);
409
- if (!botClient) {
410
- logger.error('Failed to get bot client after initialization', { email: (0, config_1.maskEmail)(email) });
411
- return false;
412
- }
413
- // Update botType map
414
- this.botTypeMap.set(botClient.userId, botType);
415
- // Clone the specialist to avoid cross-workspace contamination
416
- const specialist = { ...specialistDef, botUserId: botClient.userId };
417
- // Create and start specialist daemon
418
- const specialistConfig = {
419
- botClient,
420
- mcpServerUrl: this.options.mcpServerUrl,
421
- anthropicApiKey: this.options.anthropicApiKey,
422
- model: specialist.model || this.options.model,
423
- specialist,
424
- };
425
- const specialistDaemon = new specialist_1.SpecialistDaemon(specialistConfig);
426
- await specialistDaemon.initialize();
427
- this.specialists.set(specialistKey, specialistDaemon);
428
- this.daemons.set(botClient.userId, specialistDaemon);
429
- // Register with orchestrator (with display name from workspace)
430
- const displayName = this.getDisplayName(botClient.userId);
431
- this.orchestrator?.registerSpecialistUserId(specialistKey, botClient.userId, displayName);
432
- logger.info('Specialist hot-loaded successfully', {
433
- specialistKey,
434
- name: specialist.name,
435
- botId: botClient.userId,
436
- email,
437
- });
438
- return true;
439
- }
440
- catch (error) {
441
- logger.error('Failed to hot-load specialist', {
442
- specialistKey,
443
- email,
444
- error: error instanceof Error ? error.message : String(error),
445
- });
446
- return false;
447
- }
448
- }
449
- /**
450
- * Hot-reload: Stop a specialist daemon dynamically
451
- * Preserves orchestrator conversation context
452
- */
453
- async stopSpecialist(botType) {
454
- const specialistKey = mapBotTypeToSpecialistKey(botType);
455
- if (!specialistKey) {
456
- logger.warn('Unknown botType for specialist', { botType });
457
- return false;
458
- }
459
- const specialistDaemon = this.specialists.get(specialistKey);
460
- if (!specialistDaemon) {
461
- logger.info('Specialist not running', { specialistKey });
462
- return true;
463
- }
464
- try {
465
- // Find botId by looking through daemons map
466
- let botId;
467
- for (const [id, daemon] of this.daemons) {
468
- if (daemon === specialistDaemon) {
469
- botId = id;
470
- break;
471
- }
472
- }
473
- // Unregister from orchestrator first
474
- this.orchestrator?.unregisterSpecialist(specialistKey);
475
- // Stop the daemon
476
- await specialistDaemon.stop();
477
- // Remove from maps
478
- this.specialists.delete(specialistKey);
479
- if (botId) {
480
- this.daemons.delete(botId);
481
- this.botTypeMap.delete(botId);
482
- // Remove bot client connection
483
- await this.botManager.removeBotClient(botId);
484
- }
485
- logger.info('Specialist stopped successfully', {
486
- specialistKey,
487
- botId,
488
- });
489
- return true;
490
- }
491
- catch (error) {
492
- logger.error('Failed to stop specialist', {
493
- specialistKey,
494
- error: error instanceof Error ? error.message : String(error),
495
- });
496
- return false;
497
- }
498
- }
499
- /**
500
- * Hot-reload a specialist (stop if running, start if enabled)
501
- */
502
- async hotReloadSpecialist(email, password, botType, enabled, userId) {
503
- if (enabled) {
504
- return this.startSpecialist(email, password, botType, userId);
505
- }
506
- else {
507
- return this.stopSpecialist(botType);
508
- }
509
- }
510
- /**
511
- * Start periodic status logging
512
- */
513
- startStatusLogging(intervalMs = 30000) {
514
- return setInterval(() => {
515
- this.logStatus();
516
- }, intervalMs);
517
- }
518
- }
519
- exports.DaemonManager = DaemonManager;
520
- /**
521
- * Create and start the daemon manager
522
- * This is the main entry point for daemon mode
523
- *
524
- * @param options - Optional settings for orchestrator mode
525
- */
526
- async function createDaemonManager(options) {
527
- const appConfig = (0, config_1.createApplicationConfig)();
528
- const mcpClientConfig = appConfig.mcpClient;
529
- if (!mcpClientConfig) {
530
- logger.error("MCP Client not configured - cannot start daemon mode");
531
- return null;
532
- }
533
- // Find Anthropic API key from providers
534
- const anthropicProvider = mcpClientConfig.providers.find(p => p.type === "anthropic");
535
- if (!anthropicProvider) {
536
- logger.error("Anthropic provider not configured - daemon mode requires Anthropic");
537
- return null;
538
- }
539
- // Create bot manager
540
- const botManager = new bot_manager_1.MultiBotManager([]);
541
- // Load workspace configs from .bot-config/*.json
542
- const workspaceConfigs = loadWorkspaceConfigs();
543
- if (workspaceConfigs.length === 0) {
544
- logger.warn('No workspace configs found in .bot-config/ - run npm run seed-config first');
545
- return null;
546
- }
547
- // For now, use first workspace with an orchestrator
548
- // TODO: Support multiple workspaces
549
- const workspaceConfig = options?.workspaceId
550
- ? workspaceConfigs.find(c => c.workspaceId === options.workspaceId && c.orchestrator)
551
- : workspaceConfigs.find(c => c.orchestrator);
552
- if (!workspaceConfig) {
553
- logger.error('No workspace with orchestrator found');
554
- return null;
555
- }
556
- logger.info('Using workspace config', {
557
- workspaceId: workspaceConfig.workspaceId,
558
- workspaceName: workspaceConfig.workspaceName
559
- });
560
- // Build botTypeMap and displayNameMap for runtime lookups
561
- const botTypeMap = new Map();
562
- const displayNameMap = new Map();
563
- // Initialize orchestrator
564
- const orch = workspaceConfig.orchestrator;
565
- const orchestratorEmail = orch.email;
566
- try {
567
- logger.info('Loading orchestrator', { email: (0, config_1.maskEmail)(orch.email), displayName: orch.displayName });
568
- const orchestratorUserId = orch.userId || 'orchestrator';
569
- const apiKey = (0, hailer_clients_1.registerBotCredentials)(orchestratorUserId, orch.email, orch.password);
570
- await botManager.initializeBotClient(orch.email, orch.password, apiKey);
571
- // Register orchestrator botType and displayName
572
- botTypeMap.set(orchestratorUserId, 'orchestrator');
573
- if (orch.displayName) {
574
- displayNameMap.set(orchestratorUserId, orch.displayName);
575
- }
576
- }
577
- catch (error) {
578
- logger.error('Failed to initialize orchestrator', { error });
579
- return null;
580
- }
581
- // Initialize enabled specialists
582
- for (const spec of workspaceConfig.specialists) {
583
- if (!spec.enabled) {
584
- logger.debug('Skipping disabled specialist', { email: (0, config_1.maskEmail)(spec.email), botType: spec.botType });
585
- continue;
586
- }
587
- try {
588
- logger.info('Loading specialist', { email: (0, config_1.maskEmail)(spec.email), botType: spec.botType, displayName: spec.displayName });
589
- const specialistUserId = spec.userId || spec.email;
590
- const apiKey = (0, hailer_clients_1.registerBotCredentials)(specialistUserId, spec.email, spec.password);
591
- await botManager.initializeBotClient(spec.email, spec.password, apiKey);
592
- // Register specialist botType and displayName
593
- if (spec.botType) {
594
- botTypeMap.set(specialistUserId, spec.botType);
595
- }
596
- if (spec.displayName) {
597
- displayNameMap.set(specialistUserId, spec.displayName);
598
- }
599
- }
600
- catch (error) {
601
- logger.warn('Failed to initialize specialist', {
602
- email: spec.email,
603
- error: error instanceof Error ? error.message : String(error)
604
- });
605
- }
606
- }
607
- // Check environment for orchestrator mode (defaults to TRUE)
608
- const orchestratorMode = options?.orchestratorMode ??
609
- process.env.DAEMON_ORCHESTRATOR_MODE !== "false";
610
- // Create daemon manager
611
- const daemonManager = new DaemonManager(botManager, {
612
- mcpServerUrl: mcpClientConfig.mcpServerUrl,
613
- anthropicApiKey: anthropicProvider.apiKey,
614
- model: anthropicProvider.model,
615
- orchestratorMode,
616
- orchestratorEmail: orchestratorEmail || options?.orchestratorEmail,
617
- specialistEmails: options?.specialistEmails,
618
- botTypeMap,
619
- displayNameMap,
620
- });
621
- // Start all daemons
622
- await daemonManager.startAll();
623
- return daemonManager;
624
- }
625
- /**
626
- * Quick start function for testing
627
- *
628
- * @param orchestratorMode - Enable orchestrator mode (default: true)
629
- */
630
- async function startDaemonMode(orchestratorMode = true) {
631
- logger.info("Starting Chat Agent Daemon Mode (ORCHESTRATOR)...");
632
- const manager = await createDaemonManager({ orchestratorMode });
633
- if (!manager) {
634
- logger.error("Failed to create daemon manager");
635
- process.exit(1);
636
- }
637
- // Handle shutdown - await async stopAll() to flush session logs
638
- process.on("SIGINT", () => {
639
- logger.info("Shutting down daemons...");
640
- manager.stopAll().then(() => process.exit(0));
641
- });
642
- process.on("SIGTERM", () => {
643
- logger.info("Shutting down daemons...");
644
- manager.stopAll().then(() => process.exit(0));
645
- });
646
- logger.info("Chat Agent Daemon Mode (ORCHESTRATOR) running. Press Ctrl+C to stop.");
647
- // Start periodic status logging
648
- manager.startStatusLogging(60000);
649
- }
650
- //# sourceMappingURL=factory.js.map