@hailer/mcp 1.1.11 → 1.1.13
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/dist/app.js +18 -5
- package/dist/bot/bot-config.d.ts +12 -1
- package/dist/bot/bot-config.js +98 -14
- package/dist/bot/bot-manager.d.ts +13 -3
- package/dist/bot/bot-manager.js +80 -25
- package/dist/bot/bot.d.ts +46 -0
- package/dist/bot/bot.js +542 -166
- package/dist/bot/services/message-classifier.js +17 -0
- package/dist/bot/services/permission-guard.d.ts +52 -0
- package/dist/bot/services/permission-guard.js +149 -0
- package/dist/bot/services/types.d.ts +5 -0
- package/dist/bot/services/typing-indicator.d.ts +6 -1
- package/dist/bot/services/typing-indicator.js +19 -3
- package/dist/config.d.ts +6 -1
- package/dist/config.js +43 -0
- package/dist/core.js +3 -6
- package/dist/mcp/UserContextCache.d.ts +5 -0
- package/dist/mcp/UserContextCache.js +51 -19
- package/dist/mcp/hailer-clients.d.ts +19 -1
- package/dist/mcp/hailer-clients.js +157 -20
- package/dist/mcp/session-store.d.ts +68 -0
- package/dist/mcp/session-store.js +169 -0
- package/dist/mcp/signal-handler.js +12 -12
- package/dist/mcp/tool-registry.d.ts +17 -4
- package/dist/mcp/tool-registry.js +37 -7
- package/dist/mcp/tools/activity.js +99 -7
- package/dist/mcp/tools/app-scaffold.js +304 -336
- package/dist/mcp/tools/company.d.ts +9 -0
- package/dist/mcp/tools/company.js +88 -0
- package/dist/mcp/tools/discussion.js +68 -0
- package/dist/mcp/tools/workflow-permissions.d.ts +15 -0
- package/dist/mcp/tools/workflow-permissions.js +204 -0
- package/dist/mcp/tools/workflow.js +57 -18
- package/dist/mcp/utils/index.d.ts +2 -0
- package/dist/mcp/utils/index.js +12 -1
- package/dist/mcp/utils/role-utils.d.ts +74 -0
- package/dist/mcp/utils/role-utils.js +151 -0
- package/dist/mcp/utils/types.d.ts +43 -1
- package/dist/mcp/utils/types.js +14 -0
- package/dist/mcp/webhook-handler.d.ts +6 -0
- package/dist/mcp/webhook-handler.js +11 -0
- package/dist/mcp-server.d.ts +23 -2
- package/dist/mcp-server.js +639 -111
- package/dist/plugins/vipunen/client.d.ts +150 -0
- package/dist/plugins/vipunen/client.js +535 -0
- package/dist/plugins/vipunen/config/schema-config.json +19 -0
- package/dist/plugins/vipunen/config/schema-doc.json +22 -0
- package/dist/plugins/vipunen/index.d.ts +41 -0
- package/dist/plugins/vipunen/index.js +88 -0
- package/dist/plugins/vipunen/tools.d.ts +26 -0
- package/dist/plugins/vipunen/tools.js +501 -0
- package/package.json +2 -1
- package/.claude/.context-watchdog.json +0 -1
- package/.claude/.session-checked +0 -1
- package/.claude/CLAUDE.md +0 -370
- package/.claude/agents/agent-ada-skill-builder.md +0 -94
- package/.claude/agents/agent-alejandro-function-fields.md +0 -342
- package/.claude/agents/agent-bjorn-config-audit.md +0 -103
- package/.claude/agents/agent-builder-agent-creator.md +0 -130
- package/.claude/agents/agent-code-simplifier.md +0 -53
- package/.claude/agents/agent-dmitri-activity-crud.md +0 -159
- package/.claude/agents/agent-giuseppe-app-builder.md +0 -247
- package/.claude/agents/agent-gunther-mcp-tools.md +0 -39
- package/.claude/agents/agent-helga-workflow-config.md +0 -204
- package/.claude/agents/agent-igor-activity-mover-automation.md +0 -125
- package/.claude/agents/agent-ingrid-doc-templates.md +0 -261
- package/.claude/agents/agent-ivan-monolith.md +0 -154
- package/.claude/agents/agent-kenji-data-reader.md +0 -86
- package/.claude/agents/agent-lars-code-inspector.md +0 -102
- package/.claude/agents/agent-marco-mockup-builder.md +0 -110
- package/.claude/agents/agent-marcus-api-documenter.md +0 -323
- package/.claude/agents/agent-marketplace-publisher.md +0 -280
- package/.claude/agents/agent-marketplace-reviewer.md +0 -309
- package/.claude/agents/agent-permissions-handler.md +0 -208
- package/.claude/agents/agent-simple-writer.md +0 -48
- package/.claude/agents/agent-svetlana-code-review.md +0 -171
- package/.claude/agents/agent-tanya-test-runner.md +0 -333
- package/.claude/agents/agent-ui-designer.md +0 -100
- package/.claude/agents/agent-viktor-sql-insights.md +0 -212
- package/.claude/agents/agent-web-search.md +0 -55
- package/.claude/agents/agent-yevgeni-discussions.md +0 -45
- package/.claude/agents/agent-zara-zapier.md +0 -159
- package/.claude/commands/app-squad.md +0 -135
- package/.claude/commands/audit-squad.md +0 -158
- package/.claude/commands/autoplan.md +0 -563
- package/.claude/commands/cleanup-squad.md +0 -98
- package/.claude/commands/config-squad.md +0 -106
- package/.claude/commands/crud-squad.md +0 -87
- package/.claude/commands/data-squad.md +0 -97
- package/.claude/commands/debug-squad.md +0 -303
- package/.claude/commands/doc-squad.md +0 -65
- package/.claude/commands/handoff.md +0 -137
- package/.claude/commands/health.md +0 -49
- package/.claude/commands/help.md +0 -29
- package/.claude/commands/help:agents.md +0 -151
- package/.claude/commands/help:commands.md +0 -78
- package/.claude/commands/help:faq.md +0 -79
- package/.claude/commands/help:plugins.md +0 -50
- package/.claude/commands/help:skills.md +0 -93
- package/.claude/commands/help:tools.md +0 -75
- package/.claude/commands/hotfix-squad.md +0 -112
- package/.claude/commands/integration-squad.md +0 -82
- package/.claude/commands/janitor-squad.md +0 -167
- package/.claude/commands/learn-auto.md +0 -120
- package/.claude/commands/learn.md +0 -120
- package/.claude/commands/mcp-list.md +0 -27
- package/.claude/commands/onboard-squad.md +0 -140
- package/.claude/commands/plan-workspace.md +0 -732
- package/.claude/commands/prd.md +0 -130
- package/.claude/commands/project-status.md +0 -82
- package/.claude/commands/publish.md +0 -138
- package/.claude/commands/recap.md +0 -69
- package/.claude/commands/restore.md +0 -64
- package/.claude/commands/review-squad.md +0 -152
- package/.claude/commands/save.md +0 -24
- package/.claude/commands/stats.md +0 -19
- package/.claude/commands/swarm.md +0 -210
- package/.claude/commands/tool-builder.md +0 -39
- package/.claude/commands/ws-pull.md +0 -44
- package/.claude/hooks/_shared-memory.cjs +0 -305
- package/.claude/hooks/_utils.cjs +0 -108
- package/.claude/hooks/agent-failure-detector.cjs +0 -383
- package/.claude/hooks/agent-usage-logger.cjs +0 -204
- package/.claude/hooks/app-edit-guard.cjs +0 -494
- package/.claude/hooks/auto-learn.cjs +0 -304
- package/.claude/hooks/bash-guard.cjs +0 -272
- package/.claude/hooks/builder-mode-manager.cjs +0 -354
- package/.claude/hooks/bulk-activity-guard.cjs +0 -271
- package/.claude/hooks/context-watchdog.cjs +0 -230
- package/.claude/hooks/delegation-reminder.cjs +0 -465
- package/.claude/hooks/design-system-lint.cjs +0 -271
- package/.claude/hooks/post-scaffold-hook.cjs +0 -181
- package/.claude/hooks/prompt-guard.cjs +0 -354
- package/.claude/hooks/publish-template-guard.cjs +0 -147
- package/.claude/hooks/session-start.cjs +0 -35
- package/.claude/hooks/shared-memory-writer.cjs +0 -147
- package/.claude/hooks/skill-injector.cjs +0 -140
- package/.claude/hooks/skill-usage-logger.cjs +0 -258
- package/.claude/hooks/src-edit-guard.cjs +0 -240
- package/.claude/hooks/sync-marketplace-agents.cjs +0 -346
- package/.claude/settings.json +0 -257
- package/.claude/skills/SDK-activity-patterns/SKILL.md +0 -428
- package/.claude/skills/SDK-document-templates/SKILL.md +0 -1033
- package/.claude/skills/SDK-function-fields/SKILL.md +0 -542
- package/.claude/skills/SDK-generate-skill/SKILL.md +0 -92
- package/.claude/skills/SDK-init-skill/SKILL.md +0 -127
- package/.claude/skills/SDK-insight-queries/SKILL.md +0 -787
- package/.claude/skills/SDK-ws-config-skill/SKILL.md +0 -1139
- package/.claude/skills/agent-structure/SKILL.md +0 -98
- package/.claude/skills/api-documentation-patterns/SKILL.md +0 -474
- package/.claude/skills/chrome-mcp-reference/SKILL.md +0 -370
- package/.claude/skills/delegation-routing/SKILL.md +0 -202
- package/.claude/skills/frontend-design/SKILL.md +0 -254
- package/.claude/skills/hailer-activity-mover/SKILL.md +0 -213
- package/.claude/skills/hailer-api-client/SKILL.md +0 -518
- package/.claude/skills/hailer-app-builder/SKILL.md +0 -1434
- package/.claude/skills/hailer-apps-pictures/SKILL.md +0 -269
- package/.claude/skills/hailer-design-system/SKILL.md +0 -235
- package/.claude/skills/hailer-monolith-automations/SKILL.md +0 -686
- package/.claude/skills/hailer-permissions-system/SKILL.md +0 -121
- package/.claude/skills/hailer-project-protocol/SKILL.md +0 -488
- package/.claude/skills/hailer-rest-api/SKILL.md +0 -61
- package/.claude/skills/hailer-rest-api/hailer-activities.md +0 -184
- package/.claude/skills/hailer-rest-api/hailer-admin.md +0 -473
- package/.claude/skills/hailer-rest-api/hailer-calendar.md +0 -256
- package/.claude/skills/hailer-rest-api/hailer-feed.md +0 -249
- package/.claude/skills/hailer-rest-api/hailer-insights.md +0 -195
- package/.claude/skills/hailer-rest-api/hailer-messaging.md +0 -276
- package/.claude/skills/hailer-rest-api/hailer-workflows.md +0 -283
- package/.claude/skills/insight-join-patterns/SKILL.md +0 -174
- package/.claude/skills/integration-patterns/SKILL.md +0 -421
- package/.claude/skills/json-only-output/SKILL.md +0 -72
- package/.claude/skills/lsp-setup/SKILL.md +0 -160
- package/.claude/skills/mcp-direct-tools/SKILL.md +0 -153
- package/.claude/skills/optional-parameters/SKILL.md +0 -72
- package/.claude/skills/publish-hailer-app/SKILL.md +0 -244
- package/.claude/skills/testing-patterns/SKILL.md +0 -630
- package/.claude/skills/tool-builder/SKILL.md +0 -250
- package/.claude/skills/tool-parameter-usage/SKILL.md +0 -126
- package/.claude/skills/tool-response-verification/SKILL.md +0 -92
- package/.claude/skills/zapier-hailer-patterns/SKILL.md +0 -581
- package/.hailer-mcp-port +0 -1
- package/.mcp.json +0 -13
- package/.opencode/agent/agent-ada-skill-builder.md +0 -35
- package/.opencode/agent/agent-alejandro-function-fields.md +0 -39
- package/.opencode/agent/agent-bjorn-config-audit.md +0 -36
- package/.opencode/agent/agent-builder-agent-creator.md +0 -39
- package/.opencode/agent/agent-code-simplifier.md +0 -31
- package/.opencode/agent/agent-dmitri-activity-crud.md +0 -40
- package/.opencode/agent/agent-giuseppe-app-builder.md +0 -37
- package/.opencode/agent/agent-gunther-mcp-tools.md +0 -39
- package/.opencode/agent/agent-helga-workflow-config.md +0 -204
- package/.opencode/agent/agent-igor-activity-mover-automation.md +0 -46
- package/.opencode/agent/agent-ingrid-doc-templates.md +0 -39
- package/.opencode/agent/agent-ivan-monolith.md +0 -46
- package/.opencode/agent/agent-kenji-data-reader.md +0 -53
- package/.opencode/agent/agent-lars-code-inspector.md +0 -28
- package/.opencode/agent/agent-marco-mockup-builder.md +0 -42
- package/.opencode/agent/agent-marcus-api-documenter.md +0 -53
- package/.opencode/agent/agent-marketplace-publisher.md +0 -44
- package/.opencode/agent/agent-marketplace-reviewer.md +0 -42
- package/.opencode/agent/agent-permissions-handler.md +0 -50
- package/.opencode/agent/agent-simple-writer.md +0 -45
- package/.opencode/agent/agent-svetlana-code-review.md +0 -39
- package/.opencode/agent/agent-tanya-test-runner.md +0 -57
- package/.opencode/agent/agent-ui-designer.md +0 -56
- package/.opencode/agent/agent-viktor-sql-insights.md +0 -34
- package/.opencode/agent/agent-web-search.md +0 -42
- package/.opencode/agent/agent-yevgeni-discussions.md +0 -37
- package/.opencode/agent/agent-zara-zapier.md +0 -53
- package/.opencode/commands/app-squad.md +0 -135
- package/.opencode/commands/audit-squad.md +0 -158
- package/.opencode/commands/autoplan.md +0 -563
- package/.opencode/commands/cleanup-squad.md +0 -98
- package/.opencode/commands/config-squad.md +0 -106
- package/.opencode/commands/crud-squad.md +0 -87
- package/.opencode/commands/data-squad.md +0 -97
- package/.opencode/commands/debug-squad.md +0 -303
- package/.opencode/commands/doc-squad.md +0 -65
- package/.opencode/commands/handoff.md +0 -137
- package/.opencode/commands/health.md +0 -49
- package/.opencode/commands/help-agents.md +0 -151
- package/.opencode/commands/help-commands.md +0 -32
- package/.opencode/commands/help-faq.md +0 -29
- package/.opencode/commands/help-plugins.md +0 -28
- package/.opencode/commands/help-skills.md +0 -7
- package/.opencode/commands/help-tools.md +0 -40
- package/.opencode/commands/help.md +0 -28
- package/.opencode/commands/hotfix-squad.md +0 -112
- package/.opencode/commands/integration-squad.md +0 -82
- package/.opencode/commands/janitor-squad.md +0 -167
- package/.opencode/commands/learn-auto.md +0 -120
- package/.opencode/commands/learn.md +0 -120
- package/.opencode/commands/mcp-list.md +0 -27
- package/.opencode/commands/onboard-squad.md +0 -140
- package/.opencode/commands/plan-workspace.md +0 -732
- package/.opencode/commands/prd.md +0 -131
- package/.opencode/commands/project-status.md +0 -82
- package/.opencode/commands/publish.md +0 -138
- package/.opencode/commands/recap.md +0 -69
- package/.opencode/commands/restore.md +0 -64
- package/.opencode/commands/review-squad.md +0 -152
- package/.opencode/commands/save.md +0 -24
- package/.opencode/commands/stats.md +0 -19
- package/.opencode/commands/swarm.md +0 -210
- package/.opencode/commands/tool-builder.md +0 -39
- package/.opencode/commands/ws-pull.md +0 -44
- package/.opencode/opencode.json +0 -21
- package/inbox/failures.log +0 -1
- package/inbox/usage.jsonl +0 -4
- package/scripts/postinstall.cjs +0 -64
- package/scripts/test-hal-tools.ts +0 -154
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.subscribeToSignal = exports.clearAllConnections = exports.disconnectHailerClientByApiKey = exports.createHailerClientByApiKey = exports.HailerClientManager = void 0;
|
|
3
|
+
exports.subscribeToSignal = exports.clearAllConnections = exports.disconnectHailerClientByApiKey = exports.createHailerClientByApiKey = exports.HailerClientManager = exports.RestOnlySocket = void 0;
|
|
4
4
|
exports.getCurrentUserId = getCurrentUserId;
|
|
5
5
|
exports.registerBotCredentials = registerBotCredentials;
|
|
6
6
|
exports.unregisterBotCredentials = unregisterBotCredentials;
|
|
@@ -9,6 +9,70 @@ const auth_1 = require("./auth");
|
|
|
9
9
|
const logger_1 = require("../lib/logger");
|
|
10
10
|
const config_1 = require("../config");
|
|
11
11
|
const logger = (0, logger_1.createLogger)({ component: 'hailer-clients' });
|
|
12
|
+
// Default API base URL for OAuth sessions (User API Keys)
|
|
13
|
+
const DEFAULT_API_BASE_URL = process.env.BOT_API_BASE_URL || 'https://api.hailer.com';
|
|
14
|
+
/**
|
|
15
|
+
* REST-only socket mock for User API Key sessions
|
|
16
|
+
* User API Keys require IP for validation, which socket.resume() doesn't provide.
|
|
17
|
+
* This mock implements the socket.request() interface using REST API calls.
|
|
18
|
+
*/
|
|
19
|
+
class RestOnlySocket {
|
|
20
|
+
host;
|
|
21
|
+
apiKey;
|
|
22
|
+
constructor(baseUrl, apiKey) {
|
|
23
|
+
this.host = baseUrl;
|
|
24
|
+
this.apiKey = apiKey;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Make RPC request via REST API instead of socket
|
|
28
|
+
* Hailer's /api endpoint accepts the same RPC format as socket
|
|
29
|
+
*/
|
|
30
|
+
async request(method, args = []) {
|
|
31
|
+
const url = `${this.host}/api/${method.replace(/\./g, '/')}`;
|
|
32
|
+
logger.debug('RestOnlySocket making request', {
|
|
33
|
+
url,
|
|
34
|
+
method,
|
|
35
|
+
apiKeyPrefix: this.apiKey.substring(0, 20) + '...',
|
|
36
|
+
});
|
|
37
|
+
const response = await (0, auth_1.safeFetch)(url, {
|
|
38
|
+
method: 'POST',
|
|
39
|
+
headers: {
|
|
40
|
+
'Content-Type': 'application/json',
|
|
41
|
+
'hlrkey': this.apiKey,
|
|
42
|
+
},
|
|
43
|
+
body: JSON.stringify({ args }),
|
|
44
|
+
});
|
|
45
|
+
if (!response.ok) {
|
|
46
|
+
const errorText = await response.text();
|
|
47
|
+
logger.error('RestOnlySocket request failed', {
|
|
48
|
+
url,
|
|
49
|
+
method,
|
|
50
|
+
status: response.status,
|
|
51
|
+
errorText,
|
|
52
|
+
});
|
|
53
|
+
throw new Error(`REST API request failed: ${response.status} ${errorText}`);
|
|
54
|
+
}
|
|
55
|
+
const result = await response.json();
|
|
56
|
+
logger.debug('RestOnlySocket request succeeded', { method });
|
|
57
|
+
return result;
|
|
58
|
+
}
|
|
59
|
+
// Stub methods for socket interface compatibility
|
|
60
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
61
|
+
on(_event, _handler) {
|
|
62
|
+
// REST-only client doesn't support real-time events
|
|
63
|
+
logger.debug('RestOnlySocket.on() called - events not supported for User API Key sessions');
|
|
64
|
+
}
|
|
65
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
66
|
+
off(_event, _handler) {
|
|
67
|
+
// REST-only client doesn't support real-time events
|
|
68
|
+
logger.debug('RestOnlySocket.off() called - events not supported for User API Key sessions');
|
|
69
|
+
}
|
|
70
|
+
disconnect() {
|
|
71
|
+
// Nothing to disconnect for REST-only client
|
|
72
|
+
logger.debug('RestOnlySocket.disconnect() called - no-op for REST client');
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
exports.RestOnlySocket = RestOnlySocket;
|
|
12
76
|
/**
|
|
13
77
|
* Get the current user ID from the authenticated session
|
|
14
78
|
* This is called after authentication to retrieve the user ID automatically
|
|
@@ -91,24 +155,23 @@ class HailerClientManager {
|
|
|
91
155
|
password: this.password,
|
|
92
156
|
...(isLocalDev && { rejectUnauthorized: false }), // Add for local dev with self-signed certs
|
|
93
157
|
};
|
|
94
|
-
// Track timeout
|
|
158
|
+
// Track timeout for proper cleanup
|
|
95
159
|
let timeoutId = null;
|
|
96
|
-
let
|
|
160
|
+
let timeoutCleared = false;
|
|
97
161
|
try {
|
|
98
162
|
// Create socket client using @hailer/cli with cancellable timeout
|
|
99
163
|
this.socketClient = (await Promise.race([
|
|
100
164
|
cli_1.Client.create(clientOptions).then(client => {
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
165
|
+
// Clear timeout on success
|
|
166
|
+
if (timeoutId && !timeoutCleared) {
|
|
167
|
+
clearTimeout(timeoutId);
|
|
168
|
+
timeoutCleared = true;
|
|
105
169
|
}
|
|
106
170
|
return client;
|
|
107
171
|
}),
|
|
108
172
|
new Promise((_, reject) => {
|
|
109
173
|
timeoutId = setTimeout(() => {
|
|
110
|
-
if (!
|
|
111
|
-
settled = true;
|
|
174
|
+
if (!timeoutCleared) {
|
|
112
175
|
reject(new Error(`Timeout connecting to: ${this.host}`));
|
|
113
176
|
}
|
|
114
177
|
}, 30000);
|
|
@@ -116,10 +179,10 @@ class HailerClientManager {
|
|
|
116
179
|
]));
|
|
117
180
|
}
|
|
118
181
|
catch (error) {
|
|
119
|
-
// Ensure timeout is cleared on error
|
|
120
|
-
if (timeoutId && !
|
|
121
|
-
settled = true;
|
|
182
|
+
// Ensure timeout is cleared on error too
|
|
183
|
+
if (timeoutId && !timeoutCleared) {
|
|
122
184
|
clearTimeout(timeoutId);
|
|
185
|
+
timeoutCleared = true;
|
|
123
186
|
}
|
|
124
187
|
logger.error('Failed to create socket client', error, { username: this.username });
|
|
125
188
|
throw error;
|
|
@@ -163,13 +226,13 @@ class HailerClientManager {
|
|
|
163
226
|
logger.info('Socket reconnected and session resumed', { username: this.username });
|
|
164
227
|
});
|
|
165
228
|
this.socketClient.on("connect", () => {
|
|
166
|
-
logger.
|
|
229
|
+
logger.info('Socket connected', { username: this.username });
|
|
167
230
|
});
|
|
168
231
|
this.socketClient.on("connect_error", (error) => {
|
|
169
232
|
logger.error('Socket connection error', { error: error.message, username: this.username });
|
|
170
233
|
});
|
|
171
234
|
this.socketClient.on("reconnect_attempt", (attempt) => {
|
|
172
|
-
logger.
|
|
235
|
+
logger.info('Socket reconnection attempt', { attempt, username: this.username });
|
|
173
236
|
});
|
|
174
237
|
this.socketClient.on("reconnect_failed", () => {
|
|
175
238
|
logger.error('Socket reconnection failed permanently', { username: this.username });
|
|
@@ -244,12 +307,86 @@ class HailerClientManager {
|
|
|
244
307
|
exports.HailerClientManager = HailerClientManager;
|
|
245
308
|
// Connection pool for the MCP server
|
|
246
309
|
const connectionPool = new Map();
|
|
310
|
+
// Pool for User API Key socket clients
|
|
311
|
+
const userApiKeyClients = new Map();
|
|
312
|
+
/**
|
|
313
|
+
* Create a REST-only client for User API Keys
|
|
314
|
+
*
|
|
315
|
+
* User API Keys require IP address for validation (see validateApiKey in backend).
|
|
316
|
+
* Socket.IO resume() doesn't pass IP, so we use REST API with hlrkey header instead.
|
|
317
|
+
* The REST API passes req.ip to core.getSession() which then validates the key.
|
|
318
|
+
*/
|
|
319
|
+
async function createUserApiKeyClient(userApiKey) {
|
|
320
|
+
// Check if we already have this client
|
|
321
|
+
const existing = userApiKeyClients.get(userApiKey);
|
|
322
|
+
if (existing) {
|
|
323
|
+
logger.debug('Reusing existing User API Key client', {
|
|
324
|
+
apiKey: userApiKey.substring(0, 20) + '...'
|
|
325
|
+
});
|
|
326
|
+
return existing;
|
|
327
|
+
}
|
|
328
|
+
logger.info('Creating REST-only client for User API Key', {
|
|
329
|
+
apiKey: userApiKey.substring(0, 20) + '...',
|
|
330
|
+
apiBaseUrl: DEFAULT_API_BASE_URL
|
|
331
|
+
});
|
|
332
|
+
try {
|
|
333
|
+
// Create REST-only socket mock that uses HTTP API instead of WebSocket
|
|
334
|
+
const restSocket = new RestOnlySocket(DEFAULT_API_BASE_URL, userApiKey);
|
|
335
|
+
// Verify the API key works by making a test request
|
|
336
|
+
logger.debug('Verifying User API Key via REST...');
|
|
337
|
+
const testResult = await restSocket.request('v2.core.init', [['user']]);
|
|
338
|
+
if (!testResult?.user?._id) {
|
|
339
|
+
throw new Error('User API Key validation failed - could not get user info');
|
|
340
|
+
}
|
|
341
|
+
logger.info('User API Key validated successfully via REST', {
|
|
342
|
+
apiKey: userApiKey.substring(0, 20) + '...',
|
|
343
|
+
userId: testResult.user._id
|
|
344
|
+
});
|
|
345
|
+
// Create REST client
|
|
346
|
+
const restClient = {
|
|
347
|
+
fetch: (url, options = {}) => {
|
|
348
|
+
const fullUrl = url.startsWith('http') ? url : `${DEFAULT_API_BASE_URL}${url}`;
|
|
349
|
+
const headers = {
|
|
350
|
+
...options.headers,
|
|
351
|
+
hlrkey: userApiKey,
|
|
352
|
+
'Content-Type': 'application/json',
|
|
353
|
+
};
|
|
354
|
+
return (0, auth_1.safeFetch)(fullUrl, { ...options, headers });
|
|
355
|
+
},
|
|
356
|
+
sessionKey: userApiKey,
|
|
357
|
+
};
|
|
358
|
+
const client = {
|
|
359
|
+
socket: restSocket,
|
|
360
|
+
rest: restClient,
|
|
361
|
+
sessionKey: userApiKey,
|
|
362
|
+
};
|
|
363
|
+
userApiKeyClients.set(userApiKey, client);
|
|
364
|
+
return client;
|
|
365
|
+
}
|
|
366
|
+
catch (error) {
|
|
367
|
+
const errorMsg = error instanceof Error
|
|
368
|
+
? error.message
|
|
369
|
+
: (typeof error === 'object' && error !== null)
|
|
370
|
+
? JSON.stringify(error)
|
|
371
|
+
: String(error);
|
|
372
|
+
logger.error('Failed to create User API Key client', {
|
|
373
|
+
error: errorMsg,
|
|
374
|
+
errorType: typeof error,
|
|
375
|
+
});
|
|
376
|
+
throw new Error(`Failed to create User API Key session: ${errorMsg}`);
|
|
377
|
+
}
|
|
378
|
+
}
|
|
247
379
|
/**
|
|
248
380
|
* Create Hailer client by API key (O(1) lookup)
|
|
249
381
|
* This is the new efficient method for MCP Server to get connections
|
|
250
382
|
*/
|
|
251
383
|
const createHailerClientByApiKey = async (apiKey) => {
|
|
252
|
-
//
|
|
384
|
+
// Check if this is a User API Key (from OAuth flow)
|
|
385
|
+
// User API Keys start with "userapikey_" and can authenticate via socket resume()
|
|
386
|
+
if (apiKey.startsWith('userapikey_')) {
|
|
387
|
+
return await createUserApiKeyClient(apiKey);
|
|
388
|
+
}
|
|
389
|
+
// O(1) lookup in Map-based CLIENT_CONFIGS (for bot accounts)
|
|
253
390
|
const account = config_1.environment.CLIENT_CONFIGS[apiKey];
|
|
254
391
|
if (!account) {
|
|
255
392
|
throw new Error(`No Hailer account found for API key: ${apiKey}`);
|
|
@@ -280,7 +417,7 @@ const createHailerClientByApiKey = async (apiKey) => {
|
|
|
280
417
|
connectionPool.delete(connectionKey);
|
|
281
418
|
}
|
|
282
419
|
// Create new connection
|
|
283
|
-
logger.
|
|
420
|
+
logger.info('Creating new connection', {
|
|
284
421
|
apiKey: apiKey.substring(0, 8) + '...',
|
|
285
422
|
email: (0, config_1.maskEmail)(account.email),
|
|
286
423
|
host: account.apiBaseUrl
|
|
@@ -312,7 +449,7 @@ const clearAllConnections = () => {
|
|
|
312
449
|
clientManager.disconnect();
|
|
313
450
|
}
|
|
314
451
|
connectionPool.clear();
|
|
315
|
-
logger.
|
|
452
|
+
logger.info('Cleared Hailer connections', { count });
|
|
316
453
|
};
|
|
317
454
|
exports.clearAllConnections = clearAllConnections;
|
|
318
455
|
/**
|
|
@@ -346,10 +483,10 @@ function registerBotCredentials(botId, email, password, options) {
|
|
|
346
483
|
config_1.environment.CLIENT_CONFIGS[apiKey] = {
|
|
347
484
|
email,
|
|
348
485
|
password,
|
|
349
|
-
apiBaseUrl:
|
|
486
|
+
apiBaseUrl: 'https://api.hailer.com',
|
|
350
487
|
...(options?.allowedGroups && { allowedGroups: options.allowedGroups }),
|
|
351
488
|
};
|
|
352
|
-
logger.
|
|
489
|
+
logger.info('Bot credentials registered', {
|
|
353
490
|
botId,
|
|
354
491
|
hasAllowedGroups: !!options?.allowedGroups
|
|
355
492
|
});
|
|
@@ -361,6 +498,6 @@ function registerBotCredentials(botId, email, password, options) {
|
|
|
361
498
|
function unregisterBotCredentials(apiKey) {
|
|
362
499
|
delete config_1.environment.CLIENT_CONFIGS[apiKey];
|
|
363
500
|
(0, exports.disconnectHailerClientByApiKey)(apiKey);
|
|
364
|
-
logger.
|
|
501
|
+
logger.info('Bot credentials unregistered');
|
|
365
502
|
}
|
|
366
503
|
//# sourceMappingURL=hailer-clients.js.map
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SessionStore - Maps key_id to real api_key for Claude App authentication
|
|
3
|
+
*
|
|
4
|
+
* Purpose: Keep real Hailer API keys on server side, Claude only gets a reference (key_id).
|
|
5
|
+
* Multiple concurrent sessions supported - each user gets their own key_id.
|
|
6
|
+
*
|
|
7
|
+
* Flow:
|
|
8
|
+
* 1. User logs in via Hailer auth page
|
|
9
|
+
* 2. Frontend generates key_id, sends {key_id, api_key} to MCP /auth/register
|
|
10
|
+
* 3. Frontend redirects to Claude with key_id as "access_token"
|
|
11
|
+
* 4. Claude sends key_id in Authorization header
|
|
12
|
+
* 5. MCP looks up real api_key from this store
|
|
13
|
+
*/
|
|
14
|
+
export interface Session {
|
|
15
|
+
apiKey: string;
|
|
16
|
+
workspaceId: string;
|
|
17
|
+
createdAt: number;
|
|
18
|
+
lastAccessedAt: number;
|
|
19
|
+
}
|
|
20
|
+
export declare class SessionStore {
|
|
21
|
+
private store;
|
|
22
|
+
private maxTtlMs;
|
|
23
|
+
private inactivityTtlMs;
|
|
24
|
+
private cleanupInterval;
|
|
25
|
+
/**
|
|
26
|
+
* @param maxTtlHours - Maximum session lifetime in hours (default 24)
|
|
27
|
+
* @param inactivityMinutes - Session expires after this many minutes of inactivity (default 30)
|
|
28
|
+
*/
|
|
29
|
+
constructor(maxTtlHours?: number, inactivityMinutes?: number);
|
|
30
|
+
/**
|
|
31
|
+
* Register a new session (called by /auth/register endpoint)
|
|
32
|
+
*/
|
|
33
|
+
set(keyId: string, apiKey: string, workspaceId: string): void;
|
|
34
|
+
/**
|
|
35
|
+
* Get session by key_id (returns null if expired or not found)
|
|
36
|
+
* Updates lastAccessedAt to extend inactivity timeout
|
|
37
|
+
*/
|
|
38
|
+
get(keyId: string): Session | null;
|
|
39
|
+
/**
|
|
40
|
+
* Delete session (logout)
|
|
41
|
+
*/
|
|
42
|
+
delete(keyId: string): boolean;
|
|
43
|
+
/**
|
|
44
|
+
* Remove all expired sessions (both max TTL and inactivity)
|
|
45
|
+
*/
|
|
46
|
+
cleanup(): void;
|
|
47
|
+
/**
|
|
48
|
+
* Get store statistics
|
|
49
|
+
*/
|
|
50
|
+
getStats(): {
|
|
51
|
+
size: number;
|
|
52
|
+
config: {
|
|
53
|
+
maxTtlHours: number;
|
|
54
|
+
inactivityMinutes: number;
|
|
55
|
+
};
|
|
56
|
+
sessions: Array<{
|
|
57
|
+
keyId: string;
|
|
58
|
+
ageMinutes: number;
|
|
59
|
+
inactivityMinutes: number;
|
|
60
|
+
}>;
|
|
61
|
+
};
|
|
62
|
+
/**
|
|
63
|
+
* Stop cleanup interval (for graceful shutdown)
|
|
64
|
+
*/
|
|
65
|
+
destroy(): void;
|
|
66
|
+
}
|
|
67
|
+
export declare const sessionStore: SessionStore;
|
|
68
|
+
//# sourceMappingURL=session-store.d.ts.map
|
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* SessionStore - Maps key_id to real api_key for Claude App authentication
|
|
4
|
+
*
|
|
5
|
+
* Purpose: Keep real Hailer API keys on server side, Claude only gets a reference (key_id).
|
|
6
|
+
* Multiple concurrent sessions supported - each user gets their own key_id.
|
|
7
|
+
*
|
|
8
|
+
* Flow:
|
|
9
|
+
* 1. User logs in via Hailer auth page
|
|
10
|
+
* 2. Frontend generates key_id, sends {key_id, api_key} to MCP /auth/register
|
|
11
|
+
* 3. Frontend redirects to Claude with key_id as "access_token"
|
|
12
|
+
* 4. Claude sends key_id in Authorization header
|
|
13
|
+
* 5. MCP looks up real api_key from this store
|
|
14
|
+
*/
|
|
15
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
16
|
+
exports.sessionStore = exports.SessionStore = void 0;
|
|
17
|
+
const logger_1 = require("../lib/logger");
|
|
18
|
+
const logger = (0, logger_1.createLogger)({ component: 'session-store' });
|
|
19
|
+
class SessionStore {
|
|
20
|
+
store = new Map();
|
|
21
|
+
maxTtlMs; // Maximum session lifetime (absolute)
|
|
22
|
+
inactivityTtlMs; // Session expires after inactivity
|
|
23
|
+
cleanupInterval = null;
|
|
24
|
+
/**
|
|
25
|
+
* @param maxTtlHours - Maximum session lifetime in hours (default 24)
|
|
26
|
+
* @param inactivityMinutes - Session expires after this many minutes of inactivity (default 30)
|
|
27
|
+
*/
|
|
28
|
+
constructor(maxTtlHours = 24, inactivityMinutes = 30) {
|
|
29
|
+
this.maxTtlMs = maxTtlHours * 60 * 60 * 1000;
|
|
30
|
+
this.inactivityTtlMs = inactivityMinutes * 60 * 1000;
|
|
31
|
+
// Cleanup expired sessions every 5 minutes (more frequent for inactivity-based expiry)
|
|
32
|
+
this.cleanupInterval = setInterval(() => this.cleanup(), 5 * 60 * 1000);
|
|
33
|
+
logger.info('SessionStore initialized', {
|
|
34
|
+
maxTtlHours,
|
|
35
|
+
inactivityMinutes,
|
|
36
|
+
maxTtlMs: this.maxTtlMs,
|
|
37
|
+
inactivityTtlMs: this.inactivityTtlMs
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Register a new session (called by /auth/register endpoint)
|
|
42
|
+
*/
|
|
43
|
+
set(keyId, apiKey, workspaceId) {
|
|
44
|
+
const now = Date.now();
|
|
45
|
+
const session = {
|
|
46
|
+
apiKey,
|
|
47
|
+
workspaceId,
|
|
48
|
+
createdAt: now,
|
|
49
|
+
lastAccessedAt: now,
|
|
50
|
+
};
|
|
51
|
+
this.store.set(keyId, session);
|
|
52
|
+
logger.info('Session registered', {
|
|
53
|
+
keyId: keyId.substring(0, 8) + '...',
|
|
54
|
+
workspaceId: workspaceId.substring(0, 8) + '...',
|
|
55
|
+
totalSessions: this.store.size,
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Get session by key_id (returns null if expired or not found)
|
|
60
|
+
* Updates lastAccessedAt to extend inactivity timeout
|
|
61
|
+
*/
|
|
62
|
+
get(keyId) {
|
|
63
|
+
const session = this.store.get(keyId);
|
|
64
|
+
if (!session) {
|
|
65
|
+
logger.debug('Session not found', { keyId: keyId.substring(0, 8) + '...' });
|
|
66
|
+
return null;
|
|
67
|
+
}
|
|
68
|
+
const now = Date.now();
|
|
69
|
+
const age = now - session.createdAt;
|
|
70
|
+
const inactivity = now - session.lastAccessedAt;
|
|
71
|
+
// Check if max lifetime exceeded (absolute expiry)
|
|
72
|
+
if (age > this.maxTtlMs) {
|
|
73
|
+
logger.info('Session expired (max TTL)', {
|
|
74
|
+
keyId: keyId.substring(0, 8) + '...',
|
|
75
|
+
ageHours: Math.round(age / (1000 * 60 * 60)),
|
|
76
|
+
});
|
|
77
|
+
this.store.delete(keyId);
|
|
78
|
+
return null;
|
|
79
|
+
}
|
|
80
|
+
// Check if inactivity timeout exceeded
|
|
81
|
+
if (inactivity > this.inactivityTtlMs) {
|
|
82
|
+
logger.info('Session expired (inactivity)', {
|
|
83
|
+
keyId: keyId.substring(0, 8) + '...',
|
|
84
|
+
inactivityMinutes: Math.round(inactivity / (1000 * 60)),
|
|
85
|
+
});
|
|
86
|
+
this.store.delete(keyId);
|
|
87
|
+
return null;
|
|
88
|
+
}
|
|
89
|
+
// Update lastAccessedAt to extend session
|
|
90
|
+
session.lastAccessedAt = now;
|
|
91
|
+
logger.debug('Session found', {
|
|
92
|
+
keyId: keyId.substring(0, 8) + '...',
|
|
93
|
+
ageMinutes: Math.round(age / (1000 * 60)),
|
|
94
|
+
inactivityMinutes: Math.round(inactivity / (1000 * 60)),
|
|
95
|
+
});
|
|
96
|
+
return session;
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* Delete session (logout)
|
|
100
|
+
*/
|
|
101
|
+
delete(keyId) {
|
|
102
|
+
const existed = this.store.delete(keyId);
|
|
103
|
+
if (existed) {
|
|
104
|
+
logger.info('Session deleted', { keyId: keyId.substring(0, 8) + '...' });
|
|
105
|
+
}
|
|
106
|
+
return existed;
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* Remove all expired sessions (both max TTL and inactivity)
|
|
110
|
+
*/
|
|
111
|
+
cleanup() {
|
|
112
|
+
const now = Date.now();
|
|
113
|
+
let removedMaxTtl = 0;
|
|
114
|
+
let removedInactivity = 0;
|
|
115
|
+
for (const [keyId, session] of this.store.entries()) {
|
|
116
|
+
const age = now - session.createdAt;
|
|
117
|
+
const inactivity = now - session.lastAccessedAt;
|
|
118
|
+
if (age > this.maxTtlMs) {
|
|
119
|
+
this.store.delete(keyId);
|
|
120
|
+
removedMaxTtl++;
|
|
121
|
+
}
|
|
122
|
+
else if (inactivity > this.inactivityTtlMs) {
|
|
123
|
+
this.store.delete(keyId);
|
|
124
|
+
removedInactivity++;
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
const totalRemoved = removedMaxTtl + removedInactivity;
|
|
128
|
+
if (totalRemoved > 0) {
|
|
129
|
+
logger.info('Cleanup completed', {
|
|
130
|
+
removedMaxTtl,
|
|
131
|
+
removedInactivity,
|
|
132
|
+
remaining: this.store.size
|
|
133
|
+
});
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
/**
|
|
137
|
+
* Get store statistics
|
|
138
|
+
*/
|
|
139
|
+
getStats() {
|
|
140
|
+
const now = Date.now();
|
|
141
|
+
const sessions = Array.from(this.store.entries()).map(([keyId, session]) => ({
|
|
142
|
+
keyId: keyId.substring(0, 8) + '...',
|
|
143
|
+
ageMinutes: Math.round((now - session.createdAt) / (1000 * 60)),
|
|
144
|
+
inactivityMinutes: Math.round((now - session.lastAccessedAt) / (1000 * 60)),
|
|
145
|
+
}));
|
|
146
|
+
return {
|
|
147
|
+
size: this.store.size,
|
|
148
|
+
config: {
|
|
149
|
+
maxTtlHours: Math.round(this.maxTtlMs / (1000 * 60 * 60)),
|
|
150
|
+
inactivityMinutes: Math.round(this.inactivityTtlMs / (1000 * 60)),
|
|
151
|
+
},
|
|
152
|
+
sessions,
|
|
153
|
+
};
|
|
154
|
+
}
|
|
155
|
+
/**
|
|
156
|
+
* Stop cleanup interval (for graceful shutdown)
|
|
157
|
+
*/
|
|
158
|
+
destroy() {
|
|
159
|
+
if (this.cleanupInterval) {
|
|
160
|
+
clearInterval(this.cleanupInterval);
|
|
161
|
+
this.cleanupInterval = null;
|
|
162
|
+
}
|
|
163
|
+
logger.info('SessionStore destroyed');
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
exports.SessionStore = SessionStore;
|
|
167
|
+
// Singleton instance
|
|
168
|
+
exports.sessionStore = new SessionStore();
|
|
169
|
+
//# sourceMappingURL=session-store.js.map
|
|
@@ -2,6 +2,8 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.SignalHandler = void 0;
|
|
4
4
|
const logger_1 = require("../lib/logger");
|
|
5
|
+
const webhooks_1 = require("../bot-config/webhooks");
|
|
6
|
+
const types_1 = require("./utils/types");
|
|
5
7
|
// Optional: bot-config only available in bot server mode, not MCP terminal
|
|
6
8
|
let reloadConfigFromHailer = null;
|
|
7
9
|
let setActiveWorkspace = null;
|
|
@@ -169,18 +171,15 @@ class SignalHandler {
|
|
|
169
171
|
prevPhase: data.prevPhase || data.meta?.prevPhase
|
|
170
172
|
});
|
|
171
173
|
// Handle Agent Directory phase changes for bot enable/disable
|
|
172
|
-
//
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
// logger.error('Failed to handle activity phase change', err);
|
|
182
|
-
// });
|
|
183
|
-
// }
|
|
174
|
+
// Socket signals as primary path, webhook as backup
|
|
175
|
+
if (processId && phase && activityIdRaw) {
|
|
176
|
+
const activityIds = Array.isArray(activityIdRaw)
|
|
177
|
+
? activityIdRaw
|
|
178
|
+
: [activityIdRaw];
|
|
179
|
+
(0, webhooks_1.handleActivityPhaseChange)(processId, activityIds, phase).catch(err => {
|
|
180
|
+
logger.error('Failed to handle activity phase change', err);
|
|
181
|
+
});
|
|
182
|
+
}
|
|
184
183
|
}
|
|
185
184
|
handleActivityCreated(signal) {
|
|
186
185
|
const data = signal.data;
|
|
@@ -241,6 +240,7 @@ class SignalHandler {
|
|
|
241
240
|
// Refresh cache by fetching fresh data - API requires array of keys to fetch
|
|
242
241
|
// IMPORTANT: Include 'processes' to get updated workflow list (e.g., after template install)
|
|
243
242
|
const init = await this.client.socket.request('v2.core.init', [['users', 'network', 'networks', 'processes']]);
|
|
243
|
+
(0, types_1.normalizeInitProcesses)(init);
|
|
244
244
|
// Update workspace cache with fresh data
|
|
245
245
|
if (init.processes) {
|
|
246
246
|
this.workspaceCache.rawInit.processes = init.processes;
|
|
@@ -10,7 +10,6 @@
|
|
|
10
10
|
* - Enables Claude's strict mode validation with actual workspace values
|
|
11
11
|
*/
|
|
12
12
|
import { z } from 'zod';
|
|
13
|
-
import { UserContext } from './UserContextCache';
|
|
14
13
|
import { McpResponse } from './utils/types';
|
|
15
14
|
/**
|
|
16
15
|
* Tool groups for access control
|
|
@@ -27,6 +26,12 @@ export declare enum ToolGroup {
|
|
|
27
26
|
NUCLEAR = "nuclear",
|
|
28
27
|
BOT_INTERNAL = "bot_internal"
|
|
29
28
|
}
|
|
29
|
+
/**
|
|
30
|
+
* Context type for tool execution
|
|
31
|
+
* - 'hailer': Requires Hailer authentication via UserContextCache (default)
|
|
32
|
+
* - 'none': No authentication needed (e.g., Weaviate tools with their own auth)
|
|
33
|
+
*/
|
|
34
|
+
export type ToolContextType = 'hailer' | 'none';
|
|
30
35
|
/**
|
|
31
36
|
* Tool definition interface
|
|
32
37
|
*/
|
|
@@ -35,7 +40,11 @@ export interface Tool<TSchema extends z.ZodType = z.ZodType> {
|
|
|
35
40
|
group: ToolGroup;
|
|
36
41
|
description: string;
|
|
37
42
|
schema: TSchema;
|
|
38
|
-
|
|
43
|
+
/** What authentication context this tool needs. Defaults to 'hailer'. */
|
|
44
|
+
contextType?: ToolContextType;
|
|
45
|
+
/** Context is UserContext for Hailer tools, VipunenContext for contextType:'none' tools.
|
|
46
|
+
* Type safety is enforced at the mcp-server dispatch boundary, not here. */
|
|
47
|
+
execute: (args: z.infer<TSchema>, context: any) => Promise<McpResponse>;
|
|
39
48
|
}
|
|
40
49
|
/**
|
|
41
50
|
* Tool definition for MCP protocol (JSON-RPC)
|
|
@@ -56,10 +65,10 @@ export interface ToolDefinition {
|
|
|
56
65
|
*/
|
|
57
66
|
export declare class ToolRegistry {
|
|
58
67
|
private tools;
|
|
68
|
+
private _lazyGuard?;
|
|
59
69
|
private enableNuclearTools;
|
|
60
70
|
private workspaceSchemas;
|
|
61
71
|
private workspaceSchemasLoaded;
|
|
62
|
-
private static readonly TOOL_TO_SCHEMA_MAP;
|
|
63
72
|
constructor(options?: {
|
|
64
73
|
enableNuclearTools?: boolean;
|
|
65
74
|
});
|
|
@@ -80,6 +89,10 @@ export declare class ToolRegistry {
|
|
|
80
89
|
* Add a tool to the registry
|
|
81
90
|
*/
|
|
82
91
|
addTool(tool: Tool): void;
|
|
92
|
+
/**
|
|
93
|
+
* Get tool definitions filtered by contextType — single-pass, no secondary lookups
|
|
94
|
+
*/
|
|
95
|
+
getToolDefinitionsByContextType(contextType: ToolContextType): ToolDefinition[];
|
|
83
96
|
/**
|
|
84
97
|
* Get tool definitions with optional filtering
|
|
85
98
|
*
|
|
@@ -108,7 +121,7 @@ export declare class ToolRegistry {
|
|
|
108
121
|
/**
|
|
109
122
|
* Execute tool with validation
|
|
110
123
|
*/
|
|
111
|
-
executeTool(name: string, args: any, context:
|
|
124
|
+
executeTool(name: string, args: any, context: any): Promise<any>;
|
|
112
125
|
/**
|
|
113
126
|
* Pre-transform install_workflow args to fix common LLM mistakes BEFORE validation
|
|
114
127
|
*/
|