@hailer/mcp 1.0.29 → 1.1.2

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 (233) hide show
  1. package/.claude/.session-checked +1 -0
  2. package/.claude/agents/agent-ada-skill-builder.md +10 -2
  3. package/.claude/agents/agent-alejandro-function-fields.md +104 -37
  4. package/.claude/agents/agent-bjorn-config-audit.md +41 -21
  5. package/.claude/agents/agent-builder-agent-creator.md +13 -3
  6. package/.claude/agents/agent-code-simplifier.md +53 -0
  7. package/.claude/agents/agent-dmitri-activity-crud.md +126 -11
  8. package/.claude/agents/agent-giuseppe-app-builder.md +212 -22
  9. package/.claude/agents/agent-gunther-mcp-tools.md +7 -36
  10. package/.claude/agents/agent-helga-workflow-config.md +75 -10
  11. package/.claude/agents/agent-igor-activity-mover-automation.md +125 -0
  12. package/.claude/agents/agent-ingrid-doc-templates.md +164 -36
  13. package/.claude/agents/agent-ivan-monolith.md +154 -0
  14. package/.claude/agents/agent-kenji-data-reader.md +15 -8
  15. package/.claude/agents/agent-lars-code-inspector.md +56 -8
  16. package/.claude/agents/agent-marco-mockup-builder.md +110 -0
  17. package/.claude/agents/agent-marcus-api-documenter.md +323 -0
  18. package/.claude/agents/agent-marketplace-publisher.md +232 -72
  19. package/.claude/agents/agent-marketplace-reviewer.md +255 -79
  20. package/.claude/agents/agent-permissions-handler.md +208 -0
  21. package/.claude/agents/agent-simple-writer.md +48 -0
  22. package/.claude/agents/agent-svetlana-code-review.md +127 -14
  23. package/.claude/agents/agent-tanya-test-runner.md +333 -0
  24. package/.claude/agents/agent-ui-designer.md +100 -0
  25. package/.claude/agents/agent-viktor-sql-insights.md +19 -6
  26. package/.claude/agents/agent-web-search.md +55 -0
  27. package/.claude/agents/agent-yevgeni-discussions.md +7 -1
  28. package/.claude/agents/agent-zara-zapier.md +159 -0
  29. package/.claude/commands/app-squad.md +135 -0
  30. package/.claude/commands/audit-squad.md +158 -0
  31. package/.claude/commands/autoplan.md +563 -0
  32. package/.claude/commands/cleanup-squad.md +98 -0
  33. package/.claude/commands/config-squad.md +106 -0
  34. package/.claude/commands/crud-squad.md +87 -0
  35. package/.claude/commands/data-squad.md +97 -0
  36. package/.claude/commands/debug-squad.md +303 -0
  37. package/.claude/commands/doc-squad.md +65 -0
  38. package/.claude/commands/handoff.md +137 -0
  39. package/.claude/commands/health.md +49 -0
  40. package/.claude/commands/help.md +2 -1
  41. package/.claude/commands/help:agents.md +96 -16
  42. package/.claude/commands/help:commands.md +55 -11
  43. package/.claude/commands/help:faq.md +16 -1
  44. package/.claude/commands/help:skills.md +93 -0
  45. package/.claude/commands/hotfix-squad.md +112 -0
  46. package/.claude/commands/integration-squad.md +82 -0
  47. package/.claude/commands/janitor-squad.md +167 -0
  48. package/.claude/commands/learn-auto.md +120 -0
  49. package/.claude/commands/learn.md +120 -0
  50. package/.claude/commands/mcp-list.md +27 -0
  51. package/.claude/commands/onboard-squad.md +140 -0
  52. package/.claude/commands/plan-workspace.md +732 -0
  53. package/.claude/commands/prd.md +131 -0
  54. package/.claude/commands/project-status.md +82 -0
  55. package/.claude/commands/publish.md +138 -0
  56. package/.claude/commands/recap.md +69 -0
  57. package/.claude/commands/restore.md +64 -0
  58. package/.claude/commands/review-squad.md +152 -0
  59. package/.claude/commands/save.md +24 -0
  60. package/.claude/commands/stats.md +19 -0
  61. package/.claude/commands/swarm.md +210 -0
  62. package/.claude/commands/tool-builder.md +3 -1
  63. package/.claude/commands/ws-pull.md +1 -1
  64. package/.claude/commands/yolo-off.md +17 -0
  65. package/.claude/commands/yolo.md +82 -0
  66. package/.claude/hooks/_shared-memory.cjs +305 -0
  67. package/.claude/hooks/_utils.cjs +134 -0
  68. package/.claude/hooks/agent-failure-detector.cjs +164 -79
  69. package/.claude/hooks/agent-usage-logger.cjs +204 -0
  70. package/.claude/hooks/app-edit-guard.cjs +20 -4
  71. package/.claude/hooks/auto-learn.cjs +316 -0
  72. package/.claude/hooks/bash-guard.cjs +282 -0
  73. package/.claude/hooks/builder-mode-manager.cjs +183 -54
  74. package/.claude/hooks/bulk-activity-guard.cjs +283 -0
  75. package/.claude/hooks/context-watchdog.cjs +292 -0
  76. package/.claude/hooks/delegation-reminder.cjs +478 -0
  77. package/.claude/hooks/design-system-lint.cjs +283 -0
  78. package/.claude/hooks/post-scaffold-hook.cjs +16 -3
  79. package/.claude/hooks/prompt-guard.cjs +366 -0
  80. package/.claude/hooks/publish-template-guard.cjs +16 -0
  81. package/.claude/hooks/session-start.cjs +35 -0
  82. package/.claude/hooks/shared-memory-writer.cjs +147 -0
  83. package/.claude/hooks/skill-injector.cjs +140 -0
  84. package/.claude/hooks/skill-usage-logger.cjs +258 -0
  85. package/.claude/hooks/src-edit-guard.cjs +16 -1
  86. package/.claude/hooks/sync-marketplace-agents.cjs +53 -8
  87. package/.claude/scripts/yolo-toggle.cjs +142 -0
  88. package/.claude/settings.json +141 -14
  89. package/.claude/skills/SDK-activity-patterns/SKILL.md +428 -0
  90. package/.claude/skills/SDK-document-templates/SKILL.md +1033 -0
  91. package/.claude/skills/SDK-function-fields/SKILL.md +542 -0
  92. package/.claude/skills/SDK-generate-skill/SKILL.md +92 -0
  93. package/.claude/skills/SDK-init-skill/SKILL.md +127 -0
  94. package/.claude/skills/SDK-insight-queries/SKILL.md +787 -0
  95. package/.claude/skills/SDK-ws-config-skill/SKILL.md +1139 -0
  96. package/.claude/skills/agent-structure/SKILL.md +98 -0
  97. package/.claude/skills/api-documentation-patterns/SKILL.md +474 -0
  98. package/.claude/skills/chrome-mcp-reference/SKILL.md +370 -0
  99. package/.claude/skills/delegation-routing/SKILL.md +202 -0
  100. package/.claude/skills/frontend-design/SKILL.md +254 -0
  101. package/.claude/skills/hailer-activity-mover/SKILL.md +213 -0
  102. package/.claude/skills/hailer-api-client/SKILL.md +518 -0
  103. package/.claude/skills/hailer-app-builder/SKILL.md +939 -11
  104. package/.claude/skills/hailer-apps-pictures/SKILL.md +269 -0
  105. package/.claude/skills/hailer-design-system/SKILL.md +235 -0
  106. package/.claude/skills/hailer-monolith-automations/SKILL.md +686 -0
  107. package/.claude/skills/hailer-permissions-system/SKILL.md +121 -0
  108. package/.claude/skills/hailer-project-protocol/SKILL.md +488 -0
  109. package/.claude/skills/hailer-rest-api/SKILL.md +61 -0
  110. package/.claude/skills/hailer-rest-api/hailer-activities.md +184 -0
  111. package/.claude/skills/hailer-rest-api/hailer-admin.md +473 -0
  112. package/.claude/skills/hailer-rest-api/hailer-calendar.md +256 -0
  113. package/.claude/skills/hailer-rest-api/hailer-feed.md +249 -0
  114. package/.claude/skills/hailer-rest-api/hailer-insights.md +195 -0
  115. package/.claude/skills/hailer-rest-api/hailer-messaging.md +276 -0
  116. package/.claude/skills/hailer-rest-api/hailer-workflows.md +283 -0
  117. package/.claude/skills/insight-join-patterns/SKILL.md +3 -0
  118. package/.claude/skills/integration-patterns/SKILL.md +421 -0
  119. package/.claude/skills/json-only-output/SKILL.md +52 -12
  120. package/.claude/skills/lsp-setup/SKILL.md +160 -0
  121. package/.claude/skills/mcp-direct-tools/SKILL.md +153 -0
  122. package/.claude/skills/optional-parameters/SKILL.md +32 -23
  123. package/.claude/skills/publish-hailer-app/SKILL.md +76 -12
  124. package/.claude/skills/testing-patterns/SKILL.md +630 -0
  125. package/.claude/skills/tool-builder/SKILL.md +250 -0
  126. package/.claude/skills/tool-parameter-usage/SKILL.md +59 -45
  127. package/.claude/skills/tool-response-verification/SKILL.md +82 -48
  128. package/.claude/skills/zapier-hailer-patterns/SKILL.md +581 -0
  129. package/.env.example +26 -7
  130. package/CLAUDE.md +290 -224
  131. package/dist/CLAUDE.md +370 -0
  132. package/dist/app.d.ts +1 -1
  133. package/dist/app.js +101 -101
  134. package/dist/bot/bot-config.d.ts +26 -0
  135. package/dist/bot/bot-config.js +135 -0
  136. package/dist/bot/bot-manager.d.ts +40 -0
  137. package/dist/bot/bot-manager.js +137 -0
  138. package/dist/bot/bot.d.ts +127 -0
  139. package/dist/bot/bot.js +1328 -0
  140. package/dist/bot/operation-logger.d.ts +28 -0
  141. package/dist/bot/operation-logger.js +132 -0
  142. package/dist/bot/services/conversation-manager.d.ts +60 -0
  143. package/dist/bot/services/conversation-manager.js +246 -0
  144. package/dist/bot/services/index.d.ts +9 -0
  145. package/dist/bot/services/index.js +18 -0
  146. package/dist/bot/services/message-classifier.d.ts +42 -0
  147. package/dist/bot/services/message-classifier.js +228 -0
  148. package/dist/bot/services/message-formatter.d.ts +88 -0
  149. package/dist/bot/services/message-formatter.js +411 -0
  150. package/dist/bot/services/session-logger.d.ts +162 -0
  151. package/dist/bot/services/session-logger.js +724 -0
  152. package/dist/bot/services/token-billing.d.ts +78 -0
  153. package/dist/bot/services/token-billing.js +233 -0
  154. package/dist/bot/services/types.d.ts +169 -0
  155. package/dist/bot/services/types.js +12 -0
  156. package/dist/bot/services/typing-indicator.d.ts +23 -0
  157. package/dist/bot/services/typing-indicator.js +60 -0
  158. package/dist/bot/services/workspace-schema-cache.d.ts +122 -0
  159. package/dist/bot/services/workspace-schema-cache.js +506 -0
  160. package/dist/bot/tool-executor.d.ts +28 -0
  161. package/dist/bot/tool-executor.js +48 -0
  162. package/dist/bot/workspace-overview.d.ts +12 -0
  163. package/dist/bot/workspace-overview.js +94 -0
  164. package/dist/cli.d.ts +1 -8
  165. package/dist/cli.js +1 -253
  166. package/dist/config.d.ts +96 -3
  167. package/dist/config.js +148 -37
  168. package/dist/core.d.ts +5 -0
  169. package/dist/core.js +61 -8
  170. package/dist/lib/discussion-lock.d.ts +42 -0
  171. package/dist/lib/discussion-lock.js +110 -0
  172. package/dist/lib/logger.d.ts +0 -1
  173. package/dist/lib/logger.js +39 -23
  174. package/dist/lib/request-logger.d.ts +77 -0
  175. package/dist/lib/request-logger.js +147 -0
  176. package/dist/mcp/UserContextCache.js +16 -13
  177. package/dist/mcp/hailer-clients.js +18 -17
  178. package/dist/mcp/signal-handler.js +29 -13
  179. package/dist/mcp/tool-registry.d.ts +4 -15
  180. package/dist/mcp/tool-registry.js +94 -32
  181. package/dist/mcp/tools/activity.js +28 -69
  182. package/dist/mcp/tools/app-core.js +9 -4
  183. package/dist/mcp/tools/app-marketplace.js +22 -12
  184. package/dist/mcp/tools/app-member.js +5 -2
  185. package/dist/mcp/tools/app-scaffold.js +32 -18
  186. package/dist/mcp/tools/bot-config/constants.d.ts +23 -0
  187. package/dist/mcp/tools/bot-config/constants.js +94 -0
  188. package/dist/mcp/tools/bot-config/core.d.ts +253 -0
  189. package/dist/mcp/tools/bot-config/core.js +2456 -0
  190. package/dist/mcp/tools/bot-config/index.d.ts +10 -0
  191. package/dist/mcp/tools/bot-config/index.js +59 -0
  192. package/dist/mcp/tools/bot-config/tools.d.ts +7 -0
  193. package/dist/mcp/tools/bot-config/tools.js +15 -0
  194. package/dist/mcp/tools/bot-config/types.d.ts +50 -0
  195. package/dist/mcp/tools/bot-config/types.js +6 -0
  196. package/dist/mcp/tools/discussion.js +107 -77
  197. package/dist/mcp/tools/document.d.ts +11 -0
  198. package/dist/mcp/tools/document.js +741 -0
  199. package/dist/mcp/tools/file.js +5 -2
  200. package/dist/mcp/tools/insight.js +36 -12
  201. package/dist/mcp/tools/investigate.d.ts +9 -0
  202. package/dist/mcp/tools/investigate.js +254 -0
  203. package/dist/mcp/tools/user.d.ts +2 -4
  204. package/dist/mcp/tools/user.js +9 -50
  205. package/dist/mcp/tools/workflow.d.ts +1 -0
  206. package/dist/mcp/tools/workflow.js +164 -52
  207. package/dist/mcp/utils/hailer-api-client.js +26 -17
  208. package/dist/mcp/webhook-handler.d.ts +64 -3
  209. package/dist/mcp/webhook-handler.js +219 -9
  210. package/dist/mcp-server.d.ts +4 -0
  211. package/dist/mcp-server.js +237 -25
  212. package/dist/plugins/bug-fixer/index.d.ts +2 -0
  213. package/dist/plugins/bug-fixer/index.js +18 -0
  214. package/dist/plugins/bug-fixer/tools.d.ts +45 -0
  215. package/dist/plugins/bug-fixer/tools.js +1096 -0
  216. package/package.json +10 -10
  217. package/scripts/test-hal-tools.ts +154 -0
  218. package/.claude/agents/agent-nora-name-functions.md +0 -123
  219. package/.claude/assistant-knowledge.md +0 -23
  220. package/.claude/commands/install-plugin.md +0 -261
  221. package/.claude/commands/list-plugins.md +0 -42
  222. package/.claude/commands/marketplace-setup.md +0 -33
  223. package/.claude/commands/publish-plugin.md +0 -55
  224. package/.claude/commands/uninstall-plugin.md +0 -87
  225. package/.claude/hooks/interactive-mode.cjs +0 -87
  226. package/.claude/hooks/mcp-server-guard.cjs +0 -108
  227. package/.claude/skills/marketplace-publishing.md +0 -155
  228. package/dist/bot/chat-bot.d.ts +0 -31
  229. package/dist/bot/chat-bot.js +0 -357
  230. package/dist/mcp/tools/metrics.d.ts +0 -13
  231. package/dist/mcp/tools/metrics.js +0 -546
  232. package/dist/stdio-server.d.ts +0 -14
  233. package/dist/stdio-server.js +0 -114
@@ -57,7 +57,7 @@ class UserContextCache {
57
57
  else {
58
58
  // Cache expired, remove stale entry
59
59
  this.cache.delete(apiKey);
60
- logger.info('Cache expired, refreshing user context', {
60
+ logger.debug('Cache expired, refreshing user context', {
61
61
  apiKey: apiKey.substring(0, 8) + '...',
62
62
  ageMinutes: Math.round(age / (1000 * 60))
63
63
  });
@@ -66,7 +66,7 @@ class UserContextCache {
66
66
  else if (forceRefresh && this.cache.has(apiKey)) {
67
67
  // Force refresh requested, clear existing cache
68
68
  this.cache.delete(apiKey);
69
- logger.info('Force refresh requested, clearing cached user context', {
69
+ logger.debug('Force refresh requested, clearing cached user context', {
70
70
  apiKey: apiKey.substring(0, 8) + '...'
71
71
  });
72
72
  }
@@ -105,20 +105,23 @@ class UserContextCache {
105
105
  const init = await client.socket.request('v2.core.init', [
106
106
  ['processes', 'users', 'network', 'networks', 'teams']
107
107
  ]);
108
- // Multi-workspace support: log available workspaces, use first one as default
109
- // User can switch workspaces using list_my_workspaces tool and specifying workspaceId
110
- const networks = (init.networks || {});
111
- const workspaceCount = Object.keys(networks).length;
108
+ // Validate single workspace access - MCP requires bot credentials with access to one workspace only
109
+ const workspaceCount = Object.keys(init.networks || {}).length;
112
110
  if (workspaceCount > 1) {
113
- const workspaceList = Object.entries(networks)
114
- .map(([id, ws]) => `${ws.name} (${id})`)
111
+ const networks = (init.networks || {});
112
+ const workspaceNames = Object.values(networks)
113
+ .map((ws) => ws.name)
115
114
  .join(', ');
116
- logger.info('Multi-workspace user detected', {
115
+ logger.error('Multi-workspace credentials detected', {
117
116
  workspaceCount,
118
- workspaces: workspaceList,
119
- apiKey: apiKey.substring(0, 8) + '...',
120
- hint: 'Use list_my_workspaces tool to see all workspaces and switch between them'
117
+ workspaces: workspaceNames,
118
+ apiKey: apiKey.substring(0, 8) + '...'
121
119
  });
120
+ // Clean up the connection before throwing - prevents dangling socket
121
+ (0, hailer_clients_1.disconnectHailerClientByApiKey)(apiKey);
122
+ throw new Error(`Multi-workspace credentials detected (${workspaceCount} workspaces: ${workspaceNames}). ` +
123
+ `MCP requires bot credentials with access to a single workspace. ` +
124
+ `Please use the bot account created during 'hailer-sdk init'.`);
122
125
  }
123
126
  // Create workspace cache from init data
124
127
  const appConfig = (0, config_1.createApplicationConfig)();
@@ -173,7 +176,7 @@ class UserContextCache {
173
176
  static clearAll() {
174
177
  const size = this.cache.size;
175
178
  this.cache.clear();
176
- logger.info('Cleared all user contexts from cache', { clearedCount: size });
179
+ logger.debug('Cleared all user contexts from cache', { clearedCount: size });
177
180
  }
178
181
  /**
179
182
  * Get cache statistics (for monitoring and debugging)
@@ -91,23 +91,24 @@ class HailerClientManager {
91
91
  password: this.password,
92
92
  ...(isLocalDev && { rejectUnauthorized: false }), // Add for local dev with self-signed certs
93
93
  };
94
- // Track timeout for proper cleanup
94
+ // Track timeout with single settled flag to prevent race conditions
95
95
  let timeoutId = null;
96
- let timeoutCleared = false;
96
+ let settled = false;
97
97
  try {
98
98
  // Create socket client using @hailer/cli with cancellable timeout
99
99
  this.socketClient = (await Promise.race([
100
100
  cli_1.Client.create(clientOptions).then(client => {
101
- // Clear timeout on success
102
- if (timeoutId && !timeoutCleared) {
103
- clearTimeout(timeoutId);
104
- timeoutCleared = true;
101
+ if (!settled) {
102
+ settled = true;
103
+ if (timeoutId)
104
+ clearTimeout(timeoutId);
105
105
  }
106
106
  return client;
107
107
  }),
108
108
  new Promise((_, reject) => {
109
109
  timeoutId = setTimeout(() => {
110
- if (!timeoutCleared) {
110
+ if (!settled) {
111
+ settled = true;
111
112
  reject(new Error(`Timeout connecting to: ${this.host}`));
112
113
  }
113
114
  }, 30000);
@@ -115,10 +116,10 @@ class HailerClientManager {
115
116
  ]));
116
117
  }
117
118
  catch (error) {
118
- // Ensure timeout is cleared on error too
119
- if (timeoutId && !timeoutCleared) {
119
+ // Ensure timeout is cleared on error
120
+ if (timeoutId && !settled) {
121
+ settled = true;
120
122
  clearTimeout(timeoutId);
121
- timeoutCleared = true;
122
123
  }
123
124
  logger.error('Failed to create socket client', error, { username: this.username });
124
125
  throw error;
@@ -162,13 +163,13 @@ class HailerClientManager {
162
163
  logger.info('Socket reconnected and session resumed', { username: this.username });
163
164
  });
164
165
  this.socketClient.on("connect", () => {
165
- logger.info('Socket connected', { username: this.username });
166
+ logger.debug('Socket connected', { username: this.username });
166
167
  });
167
168
  this.socketClient.on("connect_error", (error) => {
168
169
  logger.error('Socket connection error', { error: error.message, username: this.username });
169
170
  });
170
171
  this.socketClient.on("reconnect_attempt", (attempt) => {
171
- logger.info('Socket reconnection attempt', { attempt, username: this.username });
172
+ logger.debug('Socket reconnection attempt', { attempt, username: this.username });
172
173
  });
173
174
  this.socketClient.on("reconnect_failed", () => {
174
175
  logger.error('Socket reconnection failed permanently', { username: this.username });
@@ -279,7 +280,7 @@ const createHailerClientByApiKey = async (apiKey) => {
279
280
  connectionPool.delete(connectionKey);
280
281
  }
281
282
  // Create new connection
282
- logger.info('Creating new connection', {
283
+ logger.debug('Creating new connection', {
283
284
  apiKey: apiKey.substring(0, 8) + '...',
284
285
  email: (0, config_1.maskEmail)(account.email),
285
286
  host: account.apiBaseUrl
@@ -311,7 +312,7 @@ const clearAllConnections = () => {
311
312
  clientManager.disconnect();
312
313
  }
313
314
  connectionPool.clear();
314
- logger.info('Cleared Hailer connections', { count });
315
+ logger.debug('Cleared Hailer connections', { count });
315
316
  };
316
317
  exports.clearAllConnections = clearAllConnections;
317
318
  /**
@@ -345,10 +346,10 @@ function registerBotCredentials(botId, email, password, options) {
345
346
  config_1.environment.CLIENT_CONFIGS[apiKey] = {
346
347
  email,
347
348
  password,
348
- apiBaseUrl: 'https://api.hailer.com',
349
+ apiBaseUrl: config_1.environment.BOT_API_BASE_URL || 'https://api.hailer.com',
349
350
  ...(options?.allowedGroups && { allowedGroups: options.allowedGroups }),
350
351
  };
351
- logger.info('Bot credentials registered', {
352
+ logger.debug('Bot credentials registered', {
352
353
  botId,
353
354
  hasAllowedGroups: !!options?.allowedGroups
354
355
  });
@@ -360,6 +361,6 @@ function registerBotCredentials(botId, email, password, options) {
360
361
  function unregisterBotCredentials(apiKey) {
361
362
  delete config_1.environment.CLIENT_CONFIGS[apiKey];
362
363
  (0, exports.disconnectHailerClientByApiKey)(apiKey);
363
- logger.info('Bot credentials unregistered');
364
+ logger.debug('Bot credentials unregistered');
364
365
  }
365
366
  //# sourceMappingURL=hailer-clients.js.map
@@ -2,6 +2,7 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.SignalHandler = void 0;
4
4
  const logger_1 = require("../lib/logger");
5
+ const bot_config_1 = require("../bot-config");
5
6
  const logger = (0, logger_1.createLogger)({ component: 'signal-handler' });
6
7
  class SignalHandler {
7
8
  client;
@@ -233,7 +234,7 @@ class SignalHandler {
233
234
  // Update workspace cache with fresh data
234
235
  if (init.processes) {
235
236
  this.workspaceCache.rawInit.processes = init.processes;
236
- logger.info('Workflows cache refreshed', {
237
+ logger.debug('Workflows cache refreshed', {
237
238
  workflowCount: init.processes.length
238
239
  });
239
240
  // Check if Agent Directory workflow now exists (hot-load after template install)
@@ -244,23 +245,27 @@ class SignalHandler {
244
245
  return agentDirectoryPatterns.some(pattern => name.includes(pattern));
245
246
  });
246
247
  if (hasAgentDirectory) {
247
- logger.info('Agent Directory workflow detected after cache refresh');
248
+ logger.debug('Agent Directory workflow detected after cache refresh, triggering bot config reload');
249
+ // Async reload - don't await to avoid blocking signal handling
250
+ (0, bot_config_1.reloadConfigFromHailer)().catch(err => {
251
+ logger.warn('Bot config reload failed after Agent Directory detection', { error: err });
252
+ });
248
253
  }
249
254
  }
250
255
  if (init.users) {
251
256
  // Store raw users in rawInit - the users array is derived from this
252
257
  this.workspaceCache.rawInit.users = init.users;
253
- logger.info('Users cache refreshed', {
258
+ logger.debug('Users cache refreshed', {
254
259
  userCount: Object.keys(init.users).length
255
260
  });
256
261
  }
257
262
  if (init.network) {
258
263
  this.workspaceCache.currentWorkspace = init.network;
259
- logger.info('Current workspace cache refreshed');
264
+ logger.debug('Current workspace cache refreshed');
260
265
  }
261
266
  if (init.networks) {
262
267
  this.workspaceCache.allWorkspaces = init.networks;
263
- logger.info('All workspaces cache refreshed', {
268
+ logger.debug('All workspaces cache refreshed', {
264
269
  workspaceCount: Object.keys(init.networks).length
265
270
  });
266
271
  }
@@ -281,7 +286,7 @@ class SignalHandler {
281
286
  logger.debug('No pending invitations to accept');
282
287
  return;
283
288
  }
284
- logger.info('Found pending invitations', { count: invites.length });
289
+ logger.debug('Found pending invitations', { count: invites.length });
285
290
  // Accept each invitation
286
291
  for (const invite of invites) {
287
292
  try {
@@ -290,11 +295,22 @@ class SignalHandler {
290
295
  workspaceId: invite.cid,
291
296
  workspaceName: invite.network?.name
292
297
  });
293
- // Switch to the new workspace
298
+ // Switch to the new workspace so the existing automation can discover Agent Directory
294
299
  try {
295
- logger.info('Switching to new workspace', { workspaceId: invite.cid });
300
+ logger.debug('Switching to new workspace', { workspaceId: invite.cid });
296
301
  await this.client.socket.request('core.switch_ecosystem', [invite.cid]);
297
302
  logger.info('Switched to workspace successfully', { workspaceId: invite.cid });
303
+ // Update active workspace for bot-config
304
+ (0, bot_config_1.setActiveWorkspace)(invite.cid);
305
+ // Trigger Agent Directory discovery and bot initialization
306
+ try {
307
+ logger.debug('Triggering bot config reload for new workspace');
308
+ await (0, bot_config_1.reloadConfigFromHailer)();
309
+ logger.debug('Bot config reload completed');
310
+ }
311
+ catch (reloadError) {
312
+ logger.error('Failed to reload bot config', reloadError);
313
+ }
298
314
  }
299
315
  catch (switchError) {
300
316
  logger.error('Failed to switch to workspace', switchError, {
@@ -314,7 +330,7 @@ class SignalHandler {
314
330
  const init = await this.client.socket.request('v2.core.init', [['networks']]);
315
331
  if (init.networks) {
316
332
  this.workspaceCache.allWorkspaces = init.networks;
317
- logger.info('Workspaces cache refreshed after accepting invitations', {
333
+ logger.debug('Workspaces cache refreshed after accepting invitations', {
318
334
  workspaceCount: Object.keys(init.networks).length
319
335
  });
320
336
  }
@@ -328,7 +344,7 @@ class SignalHandler {
328
344
  subscribe(id, types, handler, workspaceId) {
329
345
  // Check if subscription already exists
330
346
  if (this.subscriptions.has(id)) {
331
- logger.info('Replacing existing signal subscription', { subscriptionId: id });
347
+ logger.debug('Replacing existing signal subscription', { subscriptionId: id });
332
348
  }
333
349
  const subscription = {
334
350
  id,
@@ -337,7 +353,7 @@ class SignalHandler {
337
353
  workspaceId,
338
354
  };
339
355
  this.subscriptions.set(id, subscription);
340
- logger.info('Created signal subscription', {
356
+ logger.debug('Created signal subscription', {
341
357
  subscriptionId: id,
342
358
  signalTypes: types,
343
359
  workspaceId
@@ -346,7 +362,7 @@ class SignalHandler {
346
362
  unsubscribe(id) {
347
363
  const removed = this.subscriptions.delete(id);
348
364
  if (removed) {
349
- logger.info('Removed signal subscription', { subscriptionId: id });
365
+ logger.debug('Removed signal subscription', { subscriptionId: id });
350
366
  }
351
367
  return removed;
352
368
  }
@@ -369,7 +385,7 @@ class SignalHandler {
369
385
  clearHistory() {
370
386
  const previousCount = this.signalHistory.length;
371
387
  this.signalHistory = [];
372
- logger.info('Signal history cleared', { previousHistorySize: previousCount });
388
+ logger.debug('Signal history cleared', { previousHistorySize: previousCount });
373
389
  }
374
390
  }
375
391
  exports.SignalHandler = SignalHandler;
@@ -110,24 +110,13 @@ export declare class ToolRegistry {
110
110
  */
111
111
  executeTool(name: string, args: any, context: UserContext): Promise<any>;
112
112
  /**
113
- * Get tool metadata (for access control checks)
113
+ * Pre-transform install_workflow args to fix common LLM mistakes BEFORE validation
114
114
  */
115
- getTool(name: string): Tool | undefined;
115
+ private preTransformInstallWorkflow;
116
116
  /**
117
- * Get tools with their original Zod schemas for MCP SDK registration.
118
- * MCP SDK requires Zod schemas, not JSON Schema objects.
119
- *
120
- * @param filter - Optional filter configuration
121
- * @returns Array of tools with name, description, and Zod schema
117
+ * Get tool metadata (for access control checks)
122
118
  */
123
- getToolsWithZodSchemas(filter?: {
124
- allowedGroups?: ToolGroup[];
125
- allowedTools?: string[];
126
- }): Array<{
127
- name: string;
128
- description: string;
129
- schema: z.ZodType;
130
- }>;
119
+ getTool(name: string): Tool | undefined;
131
120
  /**
132
121
  * Get total tool count
133
122
  */
@@ -47,6 +47,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
47
47
  exports.ToolRegistry = exports.ToolGroup = void 0;
48
48
  const zod_1 = require("zod");
49
49
  const logger_1 = require("../lib/logger");
50
+ const request_logger_1 = require("../lib/request-logger");
50
51
  const fs = __importStar(require("fs"));
51
52
  const path = __importStar(require("path"));
52
53
  const logger = (0, logger_1.createLogger)({ component: 'tool-registry' });
@@ -121,7 +122,7 @@ class ToolRegistry {
121
122
  }
122
123
  }
123
124
  this.workspaceSchemasLoaded = true;
124
- logger.info('Workspace schemas loaded for structured outputs', {
125
+ logger.debug('Workspace schemas loaded for structured outputs', {
125
126
  count: this.workspaceSchemas.size,
126
127
  schemas: Array.from(this.workspaceSchemas.keys()),
127
128
  path: claudeSchemasPath
@@ -150,7 +151,7 @@ class ToolRegistry {
150
151
  addTool(tool) {
151
152
  // Short-circuit: Skip NUCLEAR tools when not enabled
152
153
  if (tool.group === ToolGroup.NUCLEAR && !this.enableNuclearTools) {
153
- logger.info('Skipping NUCLEAR tool (not enabled)', {
154
+ logger.debug('Skipping NUCLEAR tool (not enabled)', {
154
155
  name: tool.name,
155
156
  group: tool.group
156
157
  });
@@ -214,7 +215,7 @@ class ToolRegistry {
214
215
  (toolName === 'create_activity' || toolName === 'update_activity')) {
215
216
  const masterSchema = this.workspaceSchemas.get('_master_activity');
216
217
  if (masterSchema) {
217
- logger.info('Using master workspace schema with enum constraints', {
218
+ logger.debug('Using master workspace schema with enum constraints', {
218
219
  toolName,
219
220
  workflowCount: masterSchema.properties?.workflowId?.enum?.length || 0,
220
221
  phaseCount: masterSchema.properties?.phaseId?.enum?.length || 0
@@ -277,19 +278,31 @@ class ToolRegistry {
277
278
  name,
278
279
  apiKey: context.apiKey.substring(0, 8) + '...'
279
280
  });
281
+ // Pre-transform for specific tools (fix common LLM mistakes before validation)
282
+ let transformedArgs = args;
283
+ if (name === 'install_workflow' && args.workflowTemplates) {
284
+ transformedArgs = this.preTransformInstallWorkflow(args);
285
+ }
280
286
  // Zod validation
281
287
  try {
282
- const validated = tool.schema.parse(args);
288
+ const validated = tool.schema.parse(transformedArgs);
283
289
  return await tool.execute(validated, context);
284
290
  }
285
291
  catch (error) {
286
292
  if (error instanceof zod_1.z.ZodError) {
287
293
  const errorDetails = error.errors.map(e => `${e.path.join('.')}: ${e.message}`).join(', ');
288
- logger.warn('Tool validation failed', {
289
- toolName: name,
290
- errors: errorDetails,
291
- receivedArgs: JSON.stringify(args)
292
- });
294
+ // Track in request logger or log separately
295
+ const reqLogger = request_logger_1.RequestLogger.getCurrent();
296
+ if (reqLogger) {
297
+ reqLogger.toolError(name, errorDetails);
298
+ }
299
+ else {
300
+ logger.warn('Tool validation failed', {
301
+ toolName: name,
302
+ errors: errorDetails,
303
+ receivedArgs: JSON.stringify(args)
304
+ });
305
+ }
293
306
  // Check if tool has a skill hint
294
307
  const hasSkillHint = tool.description.includes('Use Skill');
295
308
  const skillName = hasSkillHint ? tool.description.match(/`([^`]+)-skill`/)?.[1] + '-skill' : null;
@@ -319,33 +332,82 @@ Then retry \`${name}\` with the correct format from the skill examples.` : `💡
319
332
  }
320
333
  }
321
334
  /**
322
- * Get tool metadata (for access control checks)
335
+ * Pre-transform install_workflow args to fix common LLM mistakes BEFORE validation
323
336
  */
324
- getTool(name) {
325
- return this.tools.get(name);
337
+ preTransformInstallWorkflow(args) {
338
+ let templates = args.workflowTemplates;
339
+ // Fix: single object instead of array
340
+ if (!Array.isArray(templates)) {
341
+ templates = [templates];
342
+ }
343
+ // Transform each template
344
+ templates = templates.map((template, tIdx) => {
345
+ const result = { ...template };
346
+ // Fix: fields as array instead of object
347
+ if (Array.isArray(template.fields)) {
348
+ const fieldsObj = {};
349
+ template.fields.forEach((field, idx) => {
350
+ const fieldId = `_${1000 + idx}`;
351
+ const { name, ...rest } = field;
352
+ fieldsObj[fieldId] = { ...rest, label: rest.label || name };
353
+ });
354
+ result.fields = fieldsObj;
355
+ }
356
+ else if (template.fields) {
357
+ // Fix: field IDs not matching pattern
358
+ const fieldsObj = {};
359
+ let idx = 0;
360
+ for (const [key, field] of Object.entries(template.fields)) {
361
+ const fieldId = /^_\d{4}$/.test(key) ? key : `_${1000 + idx}`;
362
+ const f = field;
363
+ const { name, ...rest } = f;
364
+ fieldsObj[fieldId] = { ...rest, label: rest.label || name || key };
365
+ idx++;
366
+ }
367
+ result.fields = fieldsObj;
368
+ }
369
+ // Fix: phases as array instead of object
370
+ if (Array.isArray(template.phases)) {
371
+ const phasesObj = {};
372
+ template.phases.forEach((phase, idx) => {
373
+ const phaseId = `_${2000 + idx}`;
374
+ phasesObj[phaseId] = { name: phase.name };
375
+ });
376
+ result.phases = phasesObj;
377
+ }
378
+ else if (template.phases) {
379
+ // Fix: phase IDs not matching pattern
380
+ const phasesObj = {};
381
+ let idx = 0;
382
+ for (const [key, phase] of Object.entries(template.phases)) {
383
+ const phaseId = /^_\d{4}$/.test(key) ? key : `_${2000 + idx}`;
384
+ const p = phase;
385
+ phasesObj[phaseId] = { name: p.name || key };
386
+ idx++;
387
+ }
388
+ result.phases = phasesObj;
389
+ }
390
+ // Fix: wrong field types
391
+ if (result.fields) {
392
+ for (const fieldId of Object.keys(result.fields)) {
393
+ const f = result.fields[fieldId];
394
+ // select → textpredefinedoptions
395
+ if (f.type === 'select')
396
+ f.type = 'textpredefinedoptions';
397
+ // user → users
398
+ if (f.type === 'user')
399
+ f.type = 'users';
400
+ }
401
+ }
402
+ return result;
403
+ });
404
+ return { ...args, workflowTemplates: templates };
326
405
  }
327
406
  /**
328
- * Get tools with their original Zod schemas for MCP SDK registration.
329
- * MCP SDK requires Zod schemas, not JSON Schema objects.
330
- *
331
- * @param filter - Optional filter configuration
332
- * @returns Array of tools with name, description, and Zod schema
407
+ * Get tool metadata (for access control checks)
333
408
  */
334
- getToolsWithZodSchemas(filter) {
335
- let toolsToExpose = Array.from(this.tools.values());
336
- if (filter) {
337
- if (filter.allowedTools) {
338
- toolsToExpose = toolsToExpose.filter(t => filter.allowedTools.includes(t.name));
339
- }
340
- else if (filter.allowedGroups) {
341
- toolsToExpose = toolsToExpose.filter(t => filter.allowedGroups.includes(t.group));
342
- }
343
- }
344
- return toolsToExpose.map(tool => ({
345
- name: tool.name,
346
- description: tool.description,
347
- schema: tool.schema
348
- }));
409
+ getTool(name) {
410
+ return this.tools.get(name);
349
411
  }
350
412
  /**
351
413
  * Get total tool count