@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.
- 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 +29 -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 +219 -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,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.
|
|
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.
|
|
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.
|
|
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.
|
|
264
|
+
logger.debug('Current workspace cache refreshed');
|
|
260
265
|
}
|
|
261
266
|
if (init.networks) {
|
|
262
267
|
this.workspaceCache.allWorkspaces = init.networks;
|
|
263
|
-
logger.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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
|
-
*
|
|
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
|