@hailer/mcp 1.0.29 → 1.1.3
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/.session-checked +1 -0
- package/.claude/agents/agent-ada-skill-builder.md +10 -2
- package/.claude/agents/agent-alejandro-function-fields.md +104 -37
- package/.claude/agents/agent-bjorn-config-audit.md +41 -21
- package/.claude/agents/agent-builder-agent-creator.md +13 -3
- package/.claude/agents/agent-code-simplifier.md +53 -0
- package/.claude/agents/agent-dmitri-activity-crud.md +126 -11
- package/.claude/agents/agent-giuseppe-app-builder.md +212 -22
- package/.claude/agents/agent-gunther-mcp-tools.md +7 -36
- package/.claude/agents/agent-helga-workflow-config.md +75 -10
- package/.claude/agents/agent-igor-activity-mover-automation.md +125 -0
- package/.claude/agents/agent-ingrid-doc-templates.md +164 -36
- package/.claude/agents/agent-ivan-monolith.md +154 -0
- package/.claude/agents/agent-kenji-data-reader.md +15 -8
- package/.claude/agents/agent-lars-code-inspector.md +56 -8
- package/.claude/agents/agent-marco-mockup-builder.md +110 -0
- package/.claude/agents/agent-marcus-api-documenter.md +323 -0
- package/.claude/agents/agent-marketplace-publisher.md +232 -72
- package/.claude/agents/agent-marketplace-reviewer.md +255 -79
- package/.claude/agents/agent-permissions-handler.md +208 -0
- package/.claude/agents/agent-simple-writer.md +48 -0
- package/.claude/agents/agent-svetlana-code-review.md +127 -14
- package/.claude/agents/agent-tanya-test-runner.md +333 -0
- package/.claude/agents/agent-ui-designer.md +100 -0
- package/.claude/agents/agent-viktor-sql-insights.md +19 -6
- package/.claude/agents/agent-web-search.md +55 -0
- package/.claude/agents/agent-yevgeni-discussions.md +7 -1
- package/.claude/agents/agent-zara-zapier.md +159 -0
- package/.claude/commands/app-squad.md +135 -0
- package/.claude/commands/audit-squad.md +158 -0
- package/.claude/commands/autoplan.md +563 -0
- package/.claude/commands/cleanup-squad.md +98 -0
- package/.claude/commands/config-squad.md +106 -0
- package/.claude/commands/crud-squad.md +87 -0
- package/.claude/commands/data-squad.md +97 -0
- package/.claude/commands/debug-squad.md +303 -0
- package/.claude/commands/doc-squad.md +65 -0
- package/.claude/commands/handoff.md +137 -0
- package/.claude/commands/health.md +49 -0
- package/.claude/commands/help.md +2 -1
- package/.claude/commands/help:agents.md +96 -16
- package/.claude/commands/help:commands.md +55 -11
- package/.claude/commands/help:faq.md +16 -1
- package/.claude/commands/help:skills.md +93 -0
- package/.claude/commands/hotfix-squad.md +112 -0
- package/.claude/commands/integration-squad.md +82 -0
- package/.claude/commands/janitor-squad.md +167 -0
- package/.claude/commands/learn-auto.md +120 -0
- package/.claude/commands/learn.md +120 -0
- package/.claude/commands/mcp-list.md +27 -0
- package/.claude/commands/onboard-squad.md +140 -0
- package/.claude/commands/plan-workspace.md +732 -0
- package/.claude/commands/prd.md +131 -0
- package/.claude/commands/project-status.md +82 -0
- package/.claude/commands/publish.md +138 -0
- package/.claude/commands/recap.md +69 -0
- package/.claude/commands/restore.md +64 -0
- package/.claude/commands/review-squad.md +152 -0
- package/.claude/commands/save.md +24 -0
- package/.claude/commands/stats.md +19 -0
- package/.claude/commands/swarm.md +210 -0
- package/.claude/commands/tool-builder.md +3 -1
- package/.claude/commands/ws-pull.md +1 -1
- package/.claude/commands/yolo-off.md +17 -0
- package/.claude/commands/yolo.md +82 -0
- package/.claude/hooks/_shared-memory.cjs +305 -0
- package/.claude/hooks/_utils.cjs +134 -0
- package/.claude/hooks/agent-failure-detector.cjs +164 -79
- package/.claude/hooks/agent-usage-logger.cjs +204 -0
- package/.claude/hooks/app-edit-guard.cjs +20 -4
- package/.claude/hooks/auto-learn.cjs +316 -0
- package/.claude/hooks/bash-guard.cjs +282 -0
- package/.claude/hooks/builder-mode-manager.cjs +183 -54
- package/.claude/hooks/bulk-activity-guard.cjs +283 -0
- package/.claude/hooks/context-watchdog.cjs +292 -0
- package/.claude/hooks/delegation-reminder.cjs +478 -0
- package/.claude/hooks/design-system-lint.cjs +283 -0
- package/.claude/hooks/post-scaffold-hook.cjs +16 -3
- package/.claude/hooks/prompt-guard.cjs +366 -0
- package/.claude/hooks/publish-template-guard.cjs +16 -0
- package/.claude/hooks/session-start.cjs +35 -0
- package/.claude/hooks/shared-memory-writer.cjs +147 -0
- package/.claude/hooks/skill-injector.cjs +140 -0
- package/.claude/hooks/skill-usage-logger.cjs +258 -0
- package/.claude/hooks/src-edit-guard.cjs +16 -1
- package/.claude/hooks/sync-marketplace-agents.cjs +53 -8
- package/.claude/scripts/yolo-toggle.cjs +142 -0
- package/.claude/settings.json +141 -14
- package/.claude/skills/SDK-activity-patterns/SKILL.md +428 -0
- package/.claude/skills/SDK-document-templates/SKILL.md +1033 -0
- package/.claude/skills/SDK-function-fields/SKILL.md +542 -0
- package/.claude/skills/SDK-generate-skill/SKILL.md +92 -0
- package/.claude/skills/SDK-init-skill/SKILL.md +127 -0
- package/.claude/skills/SDK-insight-queries/SKILL.md +787 -0
- package/.claude/skills/SDK-ws-config-skill/SKILL.md +1139 -0
- package/.claude/skills/agent-structure/SKILL.md +98 -0
- package/.claude/skills/api-documentation-patterns/SKILL.md +474 -0
- package/.claude/skills/chrome-mcp-reference/SKILL.md +370 -0
- package/.claude/skills/delegation-routing/SKILL.md +202 -0
- package/.claude/skills/frontend-design/SKILL.md +254 -0
- package/.claude/skills/hailer-activity-mover/SKILL.md +213 -0
- package/.claude/skills/hailer-api-client/SKILL.md +518 -0
- package/.claude/skills/hailer-app-builder/SKILL.md +939 -11
- package/.claude/skills/hailer-apps-pictures/SKILL.md +269 -0
- package/.claude/skills/hailer-design-system/SKILL.md +235 -0
- package/.claude/skills/hailer-monolith-automations/SKILL.md +686 -0
- package/.claude/skills/hailer-permissions-system/SKILL.md +121 -0
- package/.claude/skills/hailer-project-protocol/SKILL.md +488 -0
- package/.claude/skills/hailer-rest-api/SKILL.md +61 -0
- package/.claude/skills/hailer-rest-api/hailer-activities.md +184 -0
- package/.claude/skills/hailer-rest-api/hailer-admin.md +473 -0
- package/.claude/skills/hailer-rest-api/hailer-calendar.md +256 -0
- package/.claude/skills/hailer-rest-api/hailer-feed.md +249 -0
- package/.claude/skills/hailer-rest-api/hailer-insights.md +195 -0
- package/.claude/skills/hailer-rest-api/hailer-messaging.md +276 -0
- package/.claude/skills/hailer-rest-api/hailer-workflows.md +283 -0
- package/.claude/skills/insight-join-patterns/SKILL.md +3 -0
- package/.claude/skills/integration-patterns/SKILL.md +421 -0
- package/.claude/skills/json-only-output/SKILL.md +52 -12
- package/.claude/skills/lsp-setup/SKILL.md +160 -0
- package/.claude/skills/mcp-direct-tools/SKILL.md +153 -0
- package/.claude/skills/optional-parameters/SKILL.md +32 -23
- package/.claude/skills/publish-hailer-app/SKILL.md +76 -12
- package/.claude/skills/testing-patterns/SKILL.md +630 -0
- package/.claude/skills/tool-builder/SKILL.md +250 -0
- package/.claude/skills/tool-parameter-usage/SKILL.md +59 -45
- package/.claude/skills/tool-response-verification/SKILL.md +82 -48
- package/.claude/skills/zapier-hailer-patterns/SKILL.md +581 -0
- package/.env.example +26 -7
- package/CLAUDE.md +290 -224
- package/dist/CLAUDE.md +370 -0
- package/dist/app.d.ts +1 -1
- package/dist/app.js +101 -101
- package/dist/bot/bot-config.d.ts +26 -0
- package/dist/bot/bot-config.js +135 -0
- package/dist/bot/bot-manager.d.ts +40 -0
- package/dist/bot/bot-manager.js +137 -0
- package/dist/bot/bot.d.ts +127 -0
- package/dist/bot/bot.js +1328 -0
- package/dist/bot/operation-logger.d.ts +28 -0
- package/dist/bot/operation-logger.js +132 -0
- package/dist/bot/services/conversation-manager.d.ts +60 -0
- package/dist/bot/services/conversation-manager.js +246 -0
- package/dist/bot/services/index.d.ts +9 -0
- package/dist/bot/services/index.js +18 -0
- package/dist/bot/services/message-classifier.d.ts +42 -0
- package/dist/bot/services/message-classifier.js +228 -0
- package/dist/bot/services/message-formatter.d.ts +88 -0
- package/dist/bot/services/message-formatter.js +411 -0
- package/dist/bot/services/session-logger.d.ts +162 -0
- package/dist/bot/services/session-logger.js +724 -0
- package/dist/bot/services/token-billing.d.ts +78 -0
- package/dist/bot/services/token-billing.js +233 -0
- package/dist/bot/services/types.d.ts +169 -0
- package/dist/bot/services/types.js +12 -0
- package/dist/bot/services/typing-indicator.d.ts +23 -0
- package/dist/bot/services/typing-indicator.js +60 -0
- package/dist/bot/services/workspace-schema-cache.d.ts +122 -0
- package/dist/bot/services/workspace-schema-cache.js +506 -0
- package/dist/bot/tool-executor.d.ts +28 -0
- package/dist/bot/tool-executor.js +48 -0
- package/dist/bot/workspace-overview.d.ts +12 -0
- package/dist/bot/workspace-overview.js +94 -0
- package/dist/cli.d.ts +1 -8
- package/dist/cli.js +1 -253
- package/dist/config.d.ts +96 -3
- package/dist/config.js +148 -37
- package/dist/core.d.ts +5 -0
- package/dist/core.js +61 -8
- package/dist/lib/discussion-lock.d.ts +42 -0
- package/dist/lib/discussion-lock.js +110 -0
- package/dist/lib/logger.d.ts +0 -1
- package/dist/lib/logger.js +39 -23
- package/dist/lib/request-logger.d.ts +77 -0
- package/dist/lib/request-logger.js +147 -0
- package/dist/mcp/UserContextCache.js +16 -13
- package/dist/mcp/hailer-clients.js +18 -17
- package/dist/mcp/signal-handler.js +43 -13
- package/dist/mcp/tool-registry.d.ts +4 -15
- package/dist/mcp/tool-registry.js +94 -32
- package/dist/mcp/tools/activity.js +28 -69
- package/dist/mcp/tools/app-core.js +9 -4
- package/dist/mcp/tools/app-marketplace.js +22 -12
- package/dist/mcp/tools/app-member.js +5 -2
- package/dist/mcp/tools/app-scaffold.js +32 -18
- package/dist/mcp/tools/bot-config/constants.d.ts +23 -0
- package/dist/mcp/tools/bot-config/constants.js +94 -0
- package/dist/mcp/tools/bot-config/core.d.ts +253 -0
- package/dist/mcp/tools/bot-config/core.js +2456 -0
- package/dist/mcp/tools/bot-config/index.d.ts +10 -0
- package/dist/mcp/tools/bot-config/index.js +59 -0
- package/dist/mcp/tools/bot-config/tools.d.ts +7 -0
- package/dist/mcp/tools/bot-config/tools.js +15 -0
- package/dist/mcp/tools/bot-config/types.d.ts +50 -0
- package/dist/mcp/tools/bot-config/types.js +6 -0
- package/dist/mcp/tools/discussion.js +107 -77
- package/dist/mcp/tools/document.d.ts +11 -0
- package/dist/mcp/tools/document.js +741 -0
- package/dist/mcp/tools/file.js +5 -2
- package/dist/mcp/tools/insight.js +36 -12
- package/dist/mcp/tools/investigate.d.ts +9 -0
- package/dist/mcp/tools/investigate.js +254 -0
- package/dist/mcp/tools/user.d.ts +2 -4
- package/dist/mcp/tools/user.js +9 -50
- package/dist/mcp/tools/workflow.d.ts +1 -0
- package/dist/mcp/tools/workflow.js +164 -52
- package/dist/mcp/utils/hailer-api-client.js +26 -17
- package/dist/mcp/webhook-handler.d.ts +64 -3
- package/dist/mcp/webhook-handler.js +227 -9
- package/dist/mcp-server.d.ts +4 -0
- package/dist/mcp-server.js +237 -25
- package/dist/plugins/bug-fixer/index.d.ts +2 -0
- package/dist/plugins/bug-fixer/index.js +18 -0
- package/dist/plugins/bug-fixer/tools.d.ts +45 -0
- package/dist/plugins/bug-fixer/tools.js +1096 -0
- package/package.json +10 -10
- package/scripts/test-hal-tools.ts +154 -0
- package/.claude/agents/agent-nora-name-functions.md +0 -123
- package/.claude/assistant-knowledge.md +0 -23
- package/.claude/commands/install-plugin.md +0 -261
- package/.claude/commands/list-plugins.md +0 -42
- package/.claude/commands/marketplace-setup.md +0 -33
- package/.claude/commands/publish-plugin.md +0 -55
- package/.claude/commands/uninstall-plugin.md +0 -87
- package/.claude/hooks/interactive-mode.cjs +0 -87
- package/.claude/hooks/mcp-server-guard.cjs +0 -108
- package/.claude/skills/marketplace-publishing.md +0 -155
- package/dist/bot/chat-bot.d.ts +0 -31
- package/dist/bot/chat-bot.js +0 -357
- package/dist/mcp/tools/metrics.d.ts +0 -13
- package/dist/mcp/tools/metrics.js +0 -546
- package/dist/stdio-server.d.ts +0 -14
- 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.
|
|
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.
|
|
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
|
-
//
|
|
109
|
-
|
|
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
|
|
114
|
-
|
|
111
|
+
const networks = (init.networks || {});
|
|
112
|
+
const workspaceNames = Object.values(networks)
|
|
113
|
+
.map((ws) => ws.name)
|
|
115
114
|
.join(', ');
|
|
116
|
-
logger.
|
|
115
|
+
logger.error('Multi-workspace credentials detected', {
|
|
117
116
|
workspaceCount,
|
|
118
|
-
workspaces:
|
|
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.
|
|
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
|
|
94
|
+
// Track timeout with single settled flag to prevent race conditions
|
|
95
95
|
let timeoutId = null;
|
|
96
|
-
let
|
|
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
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
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 (!
|
|
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
|
|
119
|
-
if (timeoutId && !
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
364
|
+
logger.debug('Bot credentials unregistered');
|
|
364
365
|
}
|
|
365
366
|
//# sourceMappingURL=hailer-clients.js.map
|
|
@@ -2,6 +2,17 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.SignalHandler = void 0;
|
|
4
4
|
const logger_1 = require("../lib/logger");
|
|
5
|
+
// Optional: bot-config only available in bot server mode, not MCP terminal
|
|
6
|
+
let reloadConfigFromHailer = null;
|
|
7
|
+
let setActiveWorkspace = null;
|
|
8
|
+
try {
|
|
9
|
+
const botConfig = require('../bot-config');
|
|
10
|
+
reloadConfigFromHailer = botConfig.reloadConfigFromHailer;
|
|
11
|
+
setActiveWorkspace = botConfig.setActiveWorkspace;
|
|
12
|
+
}
|
|
13
|
+
catch {
|
|
14
|
+
// Not available in MCP-only installs — safe to skip
|
|
15
|
+
}
|
|
5
16
|
const logger = (0, logger_1.createLogger)({ component: 'signal-handler' });
|
|
6
17
|
class SignalHandler {
|
|
7
18
|
client;
|
|
@@ -233,7 +244,7 @@ class SignalHandler {
|
|
|
233
244
|
// Update workspace cache with fresh data
|
|
234
245
|
if (init.processes) {
|
|
235
246
|
this.workspaceCache.rawInit.processes = init.processes;
|
|
236
|
-
logger.
|
|
247
|
+
logger.debug('Workflows cache refreshed', {
|
|
237
248
|
workflowCount: init.processes.length
|
|
238
249
|
});
|
|
239
250
|
// Check if Agent Directory workflow now exists (hot-load after template install)
|
|
@@ -244,23 +255,29 @@ class SignalHandler {
|
|
|
244
255
|
return agentDirectoryPatterns.some(pattern => name.includes(pattern));
|
|
245
256
|
});
|
|
246
257
|
if (hasAgentDirectory) {
|
|
247
|
-
logger.
|
|
258
|
+
logger.debug('Agent Directory workflow detected after cache refresh, triggering bot config reload');
|
|
259
|
+
// Async reload - don't await to avoid blocking signal handling
|
|
260
|
+
if (reloadConfigFromHailer) {
|
|
261
|
+
reloadConfigFromHailer().catch(err => {
|
|
262
|
+
logger.warn('Bot config reload failed after Agent Directory detection', { error: err });
|
|
263
|
+
});
|
|
264
|
+
}
|
|
248
265
|
}
|
|
249
266
|
}
|
|
250
267
|
if (init.users) {
|
|
251
268
|
// Store raw users in rawInit - the users array is derived from this
|
|
252
269
|
this.workspaceCache.rawInit.users = init.users;
|
|
253
|
-
logger.
|
|
270
|
+
logger.debug('Users cache refreshed', {
|
|
254
271
|
userCount: Object.keys(init.users).length
|
|
255
272
|
});
|
|
256
273
|
}
|
|
257
274
|
if (init.network) {
|
|
258
275
|
this.workspaceCache.currentWorkspace = init.network;
|
|
259
|
-
logger.
|
|
276
|
+
logger.debug('Current workspace cache refreshed');
|
|
260
277
|
}
|
|
261
278
|
if (init.networks) {
|
|
262
279
|
this.workspaceCache.allWorkspaces = init.networks;
|
|
263
|
-
logger.
|
|
280
|
+
logger.debug('All workspaces cache refreshed', {
|
|
264
281
|
workspaceCount: Object.keys(init.networks).length
|
|
265
282
|
});
|
|
266
283
|
}
|
|
@@ -281,7 +298,7 @@ class SignalHandler {
|
|
|
281
298
|
logger.debug('No pending invitations to accept');
|
|
282
299
|
return;
|
|
283
300
|
}
|
|
284
|
-
logger.
|
|
301
|
+
logger.debug('Found pending invitations', { count: invites.length });
|
|
285
302
|
// Accept each invitation
|
|
286
303
|
for (const invite of invites) {
|
|
287
304
|
try {
|
|
@@ -290,11 +307,24 @@ class SignalHandler {
|
|
|
290
307
|
workspaceId: invite.cid,
|
|
291
308
|
workspaceName: invite.network?.name
|
|
292
309
|
});
|
|
293
|
-
// Switch to the new workspace
|
|
310
|
+
// Switch to the new workspace so the existing automation can discover Agent Directory
|
|
294
311
|
try {
|
|
295
|
-
logger.
|
|
312
|
+
logger.debug('Switching to new workspace', { workspaceId: invite.cid });
|
|
296
313
|
await this.client.socket.request('core.switch_ecosystem', [invite.cid]);
|
|
297
314
|
logger.info('Switched to workspace successfully', { workspaceId: invite.cid });
|
|
315
|
+
// Update active workspace for bot-config
|
|
316
|
+
if (setActiveWorkspace)
|
|
317
|
+
setActiveWorkspace(invite.cid);
|
|
318
|
+
// Trigger Agent Directory discovery and bot initialization
|
|
319
|
+
try {
|
|
320
|
+
logger.debug('Triggering bot config reload for new workspace');
|
|
321
|
+
if (reloadConfigFromHailer)
|
|
322
|
+
await reloadConfigFromHailer();
|
|
323
|
+
logger.debug('Bot config reload completed');
|
|
324
|
+
}
|
|
325
|
+
catch (reloadError) {
|
|
326
|
+
logger.error('Failed to reload bot config', reloadError);
|
|
327
|
+
}
|
|
298
328
|
}
|
|
299
329
|
catch (switchError) {
|
|
300
330
|
logger.error('Failed to switch to workspace', switchError, {
|
|
@@ -314,7 +344,7 @@ class SignalHandler {
|
|
|
314
344
|
const init = await this.client.socket.request('v2.core.init', [['networks']]);
|
|
315
345
|
if (init.networks) {
|
|
316
346
|
this.workspaceCache.allWorkspaces = init.networks;
|
|
317
|
-
logger.
|
|
347
|
+
logger.debug('Workspaces cache refreshed after accepting invitations', {
|
|
318
348
|
workspaceCount: Object.keys(init.networks).length
|
|
319
349
|
});
|
|
320
350
|
}
|
|
@@ -328,7 +358,7 @@ class SignalHandler {
|
|
|
328
358
|
subscribe(id, types, handler, workspaceId) {
|
|
329
359
|
// Check if subscription already exists
|
|
330
360
|
if (this.subscriptions.has(id)) {
|
|
331
|
-
logger.
|
|
361
|
+
logger.debug('Replacing existing signal subscription', { subscriptionId: id });
|
|
332
362
|
}
|
|
333
363
|
const subscription = {
|
|
334
364
|
id,
|
|
@@ -337,7 +367,7 @@ class SignalHandler {
|
|
|
337
367
|
workspaceId,
|
|
338
368
|
};
|
|
339
369
|
this.subscriptions.set(id, subscription);
|
|
340
|
-
logger.
|
|
370
|
+
logger.debug('Created signal subscription', {
|
|
341
371
|
subscriptionId: id,
|
|
342
372
|
signalTypes: types,
|
|
343
373
|
workspaceId
|
|
@@ -346,7 +376,7 @@ class SignalHandler {
|
|
|
346
376
|
unsubscribe(id) {
|
|
347
377
|
const removed = this.subscriptions.delete(id);
|
|
348
378
|
if (removed) {
|
|
349
|
-
logger.
|
|
379
|
+
logger.debug('Removed signal subscription', { subscriptionId: id });
|
|
350
380
|
}
|
|
351
381
|
return removed;
|
|
352
382
|
}
|
|
@@ -369,7 +399,7 @@ class SignalHandler {
|
|
|
369
399
|
clearHistory() {
|
|
370
400
|
const previousCount = this.signalHistory.length;
|
|
371
401
|
this.signalHistory = [];
|
|
372
|
-
logger.
|
|
402
|
+
logger.debug('Signal history cleared', { previousHistorySize: previousCount });
|
|
373
403
|
}
|
|
374
404
|
}
|
|
375
405
|
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
|
-
*
|
|
113
|
+
* Pre-transform install_workflow args to fix common LLM mistakes BEFORE validation
|
|
114
114
|
*/
|
|
115
|
-
|
|
115
|
+
private preTransformInstallWorkflow;
|
|
116
116
|
/**
|
|
117
|
-
* Get
|
|
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
|
-
|
|
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.
|
|
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.
|
|
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.
|
|
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(
|
|
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
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
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
|
-
*
|
|
335
|
+
* Pre-transform install_workflow args to fix common LLM mistakes BEFORE validation
|
|
323
336
|
*/
|
|
324
|
-
|
|
325
|
-
|
|
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
|
|
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
|
-
|
|
335
|
-
|
|
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
|