@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
package/dist/core.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Core class for Hailer MCP Server
|
|
3
3
|
* Pure orchestrator - manages application lifecycle and service coordination
|
|
4
|
+
* Separated from Express server implementation for better architecture
|
|
4
5
|
*/
|
|
5
6
|
import { Tool } from './mcp/tool-registry';
|
|
6
7
|
export declare class Core {
|
|
@@ -8,6 +9,8 @@ export declare class Core {
|
|
|
8
9
|
private appConfig;
|
|
9
10
|
private toolRegistry;
|
|
10
11
|
private mcpServer?;
|
|
12
|
+
private botManager?;
|
|
13
|
+
private shutdownRegistered;
|
|
11
14
|
constructor();
|
|
12
15
|
/**
|
|
13
16
|
* Public API for external tool registration
|
|
@@ -16,6 +19,8 @@ export declare class Core {
|
|
|
16
19
|
addTool(tool: Tool): void;
|
|
17
20
|
start(): Promise<void>;
|
|
18
21
|
private startMCPServer;
|
|
22
|
+
private startBotClient;
|
|
23
|
+
getDaemonStatus(): any;
|
|
19
24
|
stop(): Promise<void>;
|
|
20
25
|
setupGracefulShutdown(): void;
|
|
21
26
|
}
|
package/dist/core.js
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
/**
|
|
3
3
|
* Core class for Hailer MCP Server
|
|
4
4
|
* Pure orchestrator - manages application lifecycle and service coordination
|
|
5
|
+
* Separated from Express server implementation for better architecture
|
|
5
6
|
*/
|
|
6
7
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
8
|
exports.Core = void 0;
|
|
@@ -9,11 +10,15 @@ const logger_1 = require("./lib/logger");
|
|
|
9
10
|
const config_1 = require("./config");
|
|
10
11
|
const mcp_server_1 = require("./mcp-server");
|
|
11
12
|
const tool_registry_1 = require("./mcp/tool-registry");
|
|
13
|
+
const bot_manager_1 = require("./bot/bot-manager");
|
|
14
|
+
const webhook_handler_1 = require("./mcp/webhook-handler");
|
|
12
15
|
class Core {
|
|
13
16
|
logger;
|
|
14
17
|
appConfig;
|
|
15
18
|
toolRegistry;
|
|
16
19
|
mcpServer;
|
|
20
|
+
botManager;
|
|
21
|
+
shutdownRegistered = false;
|
|
17
22
|
constructor() {
|
|
18
23
|
// Initialize logger first
|
|
19
24
|
this.logger = (0, logger_1.createLogger)({
|
|
@@ -26,9 +31,10 @@ class Core {
|
|
|
26
31
|
});
|
|
27
32
|
// Use unified application configuration
|
|
28
33
|
this.appConfig = (0, config_1.createApplicationConfig)();
|
|
29
|
-
this.logger.
|
|
34
|
+
this.logger.debug('Core orchestrator initialized', {
|
|
30
35
|
nodeEnv: process.env.NODE_ENV,
|
|
31
36
|
enableMcpServer: this.appConfig.server.enableMcpServer,
|
|
37
|
+
enableClient: this.appConfig.server.enableClient,
|
|
32
38
|
enableNuclearTools: config_1.environment.ENABLE_NUCLEAR_TOOLS
|
|
33
39
|
});
|
|
34
40
|
}
|
|
@@ -40,9 +46,9 @@ class Core {
|
|
|
40
46
|
this.toolRegistry.addTool(tool);
|
|
41
47
|
}
|
|
42
48
|
async start() {
|
|
43
|
-
this.logger.
|
|
49
|
+
this.logger.debug('Starting Hailer MCP application');
|
|
44
50
|
try {
|
|
45
|
-
// Start MCP Server
|
|
51
|
+
// Start MCP Server FIRST (daemon/client needs it for tool schemas)
|
|
46
52
|
if (this.appConfig.server.enableMcpServer) {
|
|
47
53
|
const hasAccounts = Object.keys(this.appConfig.hailerAccounts).length > 0;
|
|
48
54
|
if (!hasAccounts) {
|
|
@@ -53,6 +59,10 @@ class Core {
|
|
|
53
59
|
await this.startMCPServer();
|
|
54
60
|
}
|
|
55
61
|
}
|
|
62
|
+
// Start bot client ONLY if MCP_CLIENT_ENABLED=true
|
|
63
|
+
if (this.appConfig.server.enableClient) {
|
|
64
|
+
await this.startBotClient();
|
|
65
|
+
}
|
|
56
66
|
this.setupGracefulShutdown();
|
|
57
67
|
this.logger.info('All configured services started successfully');
|
|
58
68
|
}
|
|
@@ -62,21 +72,53 @@ class Core {
|
|
|
62
72
|
}
|
|
63
73
|
}
|
|
64
74
|
async startMCPServer() {
|
|
65
|
-
|
|
75
|
+
// Server configuration is provided by unified config
|
|
76
|
+
this.logger.debug('Starting MCP Server service');
|
|
66
77
|
this.mcpServer = new mcp_server_1.MCPServerService({
|
|
67
78
|
port: this.appConfig.server.port,
|
|
68
79
|
corsOrigins: this.appConfig.server.corsOrigins,
|
|
69
|
-
toolRegistry: this.toolRegistry
|
|
80
|
+
toolRegistry: this.toolRegistry,
|
|
81
|
+
getDaemonStatus: () => this.getDaemonStatus() // Pass callback for daemon monitoring
|
|
70
82
|
});
|
|
71
83
|
await this.mcpServer.start();
|
|
72
|
-
this.logger.
|
|
84
|
+
this.logger.debug('MCP Server service started');
|
|
85
|
+
}
|
|
86
|
+
async startBotClient() {
|
|
87
|
+
const anthropicApiKey = process.env.ANTHROPIC_API_KEY;
|
|
88
|
+
if (!anthropicApiKey) {
|
|
89
|
+
this.logger.warn('ANTHROPIC_API_KEY not set - bot client disabled');
|
|
90
|
+
return;
|
|
91
|
+
}
|
|
92
|
+
this.logger.debug('Starting Bot Manager');
|
|
93
|
+
this.botManager = new bot_manager_1.BotManager(this.toolRegistry, anthropicApiKey);
|
|
94
|
+
await this.botManager.startAll();
|
|
95
|
+
// Wire up webhook hot reload — bot starts/stops when toggled in Agent Directory
|
|
96
|
+
const botManager = this.botManager;
|
|
97
|
+
(0, webhook_handler_1.onBotUpdate)(async (workspaceId, bot, action) => {
|
|
98
|
+
try {
|
|
99
|
+
await botManager.handleBotUpdate(workspaceId, bot, action);
|
|
100
|
+
}
|
|
101
|
+
catch (err) {
|
|
102
|
+
this.logger.error('Bot hot-reload failed', err);
|
|
103
|
+
}
|
|
104
|
+
});
|
|
105
|
+
this.logger.debug('Bot Manager started', { botCount: this.botManager.getBotCount() });
|
|
106
|
+
}
|
|
107
|
+
getDaemonStatus() {
|
|
108
|
+
if (!this.botManager)
|
|
109
|
+
return {};
|
|
110
|
+
return this.botManager.getStatus();
|
|
73
111
|
}
|
|
74
112
|
async stop() {
|
|
75
|
-
this.logger.
|
|
113
|
+
this.logger.debug('Stopping Hailer MCP application');
|
|
76
114
|
try {
|
|
115
|
+
if (this.botManager) {
|
|
116
|
+
await this.botManager.stopAll();
|
|
117
|
+
this.logger.debug('Bot Manager stopped');
|
|
118
|
+
}
|
|
77
119
|
if (this.mcpServer) {
|
|
78
120
|
await this.mcpServer.stop();
|
|
79
|
-
this.logger.
|
|
121
|
+
this.logger.debug('MCP Server stopped');
|
|
80
122
|
}
|
|
81
123
|
this.logger.info('Application stopped gracefully');
|
|
82
124
|
}
|
|
@@ -87,6 +129,9 @@ class Core {
|
|
|
87
129
|
}
|
|
88
130
|
// Graceful shutdown handling
|
|
89
131
|
setupGracefulShutdown() {
|
|
132
|
+
if (this.shutdownRegistered)
|
|
133
|
+
return;
|
|
134
|
+
this.shutdownRegistered = true;
|
|
90
135
|
const shutdown = async (signal) => {
|
|
91
136
|
this.logger.info(`Received ${signal}, shutting down gracefully`);
|
|
92
137
|
try {
|
|
@@ -100,6 +145,14 @@ class Core {
|
|
|
100
145
|
};
|
|
101
146
|
process.on('SIGTERM', () => shutdown('SIGTERM'));
|
|
102
147
|
process.on('SIGINT', () => shutdown('SIGINT'));
|
|
148
|
+
process.on('unhandledRejection', (reason) => {
|
|
149
|
+
this.logger.error('Unhandled rejection', reason);
|
|
150
|
+
this.stop().finally(() => process.exit(1));
|
|
151
|
+
});
|
|
152
|
+
process.on('uncaughtException', (error) => {
|
|
153
|
+
this.logger.error('Uncaught exception', error);
|
|
154
|
+
this.stop().finally(() => process.exit(1));
|
|
155
|
+
});
|
|
103
156
|
this.logger.debug('Graceful shutdown handlers registered');
|
|
104
157
|
}
|
|
105
158
|
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Discussion Lock Registry
|
|
3
|
+
*
|
|
4
|
+
* Prevents multiple bots from responding to the same discussion.
|
|
5
|
+
* When a specialist bot (like Giuseppe) is handling a discussion,
|
|
6
|
+
* it acquires a lock. Other bots (like Orchestrator) check the lock
|
|
7
|
+
* before responding.
|
|
8
|
+
*/
|
|
9
|
+
/**
|
|
10
|
+
* Acquire a lock on a discussion
|
|
11
|
+
* @param discussionId - The discussion to lock
|
|
12
|
+
* @param botName - Name of the bot acquiring the lock (for logging)
|
|
13
|
+
* @param ttlMs - Lock duration in milliseconds (default: 5 minutes)
|
|
14
|
+
* @returns true if lock acquired, false if already locked by another bot
|
|
15
|
+
*/
|
|
16
|
+
export declare function acquireDiscussionLock(discussionId: string, botName: string, ttlMs?: number): boolean;
|
|
17
|
+
/**
|
|
18
|
+
* Release a lock on a discussion
|
|
19
|
+
* @param discussionId - The discussion to unlock
|
|
20
|
+
* @param botName - Name of the bot releasing (must match acquirer)
|
|
21
|
+
*/
|
|
22
|
+
export declare function releaseDiscussionLock(discussionId: string, botName: string): void;
|
|
23
|
+
/**
|
|
24
|
+
* Check if a discussion is locked by another bot
|
|
25
|
+
* @param discussionId - The discussion to check
|
|
26
|
+
* @param myBotName - Name of the checking bot (own locks don't block)
|
|
27
|
+
* @returns true if locked by ANOTHER bot, false if free or own lock
|
|
28
|
+
*/
|
|
29
|
+
export declare function isDiscussionLocked(discussionId: string, myBotName: string): boolean;
|
|
30
|
+
/**
|
|
31
|
+
* Clean up expired locks (call periodically)
|
|
32
|
+
*/
|
|
33
|
+
export declare function cleanupExpiredLocks(): number;
|
|
34
|
+
/**
|
|
35
|
+
* Get current lock status (for debugging)
|
|
36
|
+
*/
|
|
37
|
+
export declare function getLockStatus(): Map<string, {
|
|
38
|
+
botName: string;
|
|
39
|
+
acquiredAt: number;
|
|
40
|
+
expiresAt: number;
|
|
41
|
+
}>;
|
|
42
|
+
//# sourceMappingURL=discussion-lock.d.ts.map
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Discussion Lock Registry
|
|
4
|
+
*
|
|
5
|
+
* Prevents multiple bots from responding to the same discussion.
|
|
6
|
+
* When a specialist bot (like Giuseppe) is handling a discussion,
|
|
7
|
+
* it acquires a lock. Other bots (like Orchestrator) check the lock
|
|
8
|
+
* before responding.
|
|
9
|
+
*/
|
|
10
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
11
|
+
exports.acquireDiscussionLock = acquireDiscussionLock;
|
|
12
|
+
exports.releaseDiscussionLock = releaseDiscussionLock;
|
|
13
|
+
exports.isDiscussionLocked = isDiscussionLocked;
|
|
14
|
+
exports.cleanupExpiredLocks = cleanupExpiredLocks;
|
|
15
|
+
exports.getLockStatus = getLockStatus;
|
|
16
|
+
const logger_1 = require("./logger");
|
|
17
|
+
const logger = (0, logger_1.createLogger)({ component: 'discussion-lock' });
|
|
18
|
+
// Singleton map of discussionId -> { botName, acquiredAt, expiresAt }
|
|
19
|
+
const locks = new Map();
|
|
20
|
+
// Default lock TTL: 5 minutes (allows for LLM processing time)
|
|
21
|
+
const DEFAULT_LOCK_TTL_MS = 5 * 60 * 1000;
|
|
22
|
+
/**
|
|
23
|
+
* Acquire a lock on a discussion
|
|
24
|
+
* @param discussionId - The discussion to lock
|
|
25
|
+
* @param botName - Name of the bot acquiring the lock (for logging)
|
|
26
|
+
* @param ttlMs - Lock duration in milliseconds (default: 5 minutes)
|
|
27
|
+
* @returns true if lock acquired, false if already locked by another bot
|
|
28
|
+
*/
|
|
29
|
+
function acquireDiscussionLock(discussionId, botName, ttlMs = DEFAULT_LOCK_TTL_MS) {
|
|
30
|
+
const now = Date.now();
|
|
31
|
+
const existing = locks.get(discussionId);
|
|
32
|
+
// Check if existing lock is still valid
|
|
33
|
+
if (existing && existing.expiresAt > now) {
|
|
34
|
+
if (existing.botName === botName) {
|
|
35
|
+
// Same bot - extend the lock
|
|
36
|
+
existing.expiresAt = now + ttlMs;
|
|
37
|
+
return true;
|
|
38
|
+
}
|
|
39
|
+
// Different bot has the lock
|
|
40
|
+
logger.debug('Discussion already locked', {
|
|
41
|
+
discussionId,
|
|
42
|
+
lockedBy: existing.botName,
|
|
43
|
+
requestedBy: botName
|
|
44
|
+
});
|
|
45
|
+
return false;
|
|
46
|
+
}
|
|
47
|
+
// Acquire lock
|
|
48
|
+
locks.set(discussionId, {
|
|
49
|
+
botName,
|
|
50
|
+
acquiredAt: now,
|
|
51
|
+
expiresAt: now + ttlMs
|
|
52
|
+
});
|
|
53
|
+
logger.debug('Discussion lock acquired', { discussionId, botName, ttlMs });
|
|
54
|
+
return true;
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Release a lock on a discussion
|
|
58
|
+
* @param discussionId - The discussion to unlock
|
|
59
|
+
* @param botName - Name of the bot releasing (must match acquirer)
|
|
60
|
+
*/
|
|
61
|
+
function releaseDiscussionLock(discussionId, botName) {
|
|
62
|
+
const existing = locks.get(discussionId);
|
|
63
|
+
if (existing && existing.botName === botName) {
|
|
64
|
+
locks.delete(discussionId);
|
|
65
|
+
logger.debug('Discussion lock released', { discussionId, botName });
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Check if a discussion is locked by another bot
|
|
70
|
+
* @param discussionId - The discussion to check
|
|
71
|
+
* @param myBotName - Name of the checking bot (own locks don't block)
|
|
72
|
+
* @returns true if locked by ANOTHER bot, false if free or own lock
|
|
73
|
+
*/
|
|
74
|
+
function isDiscussionLocked(discussionId, myBotName) {
|
|
75
|
+
const now = Date.now();
|
|
76
|
+
const existing = locks.get(discussionId);
|
|
77
|
+
// No lock or expired
|
|
78
|
+
if (!existing || existing.expiresAt <= now) {
|
|
79
|
+
return false;
|
|
80
|
+
}
|
|
81
|
+
// Own lock doesn't block
|
|
82
|
+
if (existing.botName === myBotName) {
|
|
83
|
+
return false;
|
|
84
|
+
}
|
|
85
|
+
return true;
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* Clean up expired locks (call periodically)
|
|
89
|
+
*/
|
|
90
|
+
function cleanupExpiredLocks() {
|
|
91
|
+
const now = Date.now();
|
|
92
|
+
let cleaned = 0;
|
|
93
|
+
for (const [discussionId, lock] of locks.entries()) {
|
|
94
|
+
if (lock.expiresAt <= now) {
|
|
95
|
+
locks.delete(discussionId);
|
|
96
|
+
cleaned++;
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
if (cleaned > 0) {
|
|
100
|
+
logger.debug('Cleaned up expired locks', { count: cleaned });
|
|
101
|
+
}
|
|
102
|
+
return cleaned;
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* Get current lock status (for debugging)
|
|
106
|
+
*/
|
|
107
|
+
function getLockStatus() {
|
|
108
|
+
return new Map(locks);
|
|
109
|
+
}
|
|
110
|
+
//# sourceMappingURL=discussion-lock.js.map
|
package/dist/lib/logger.d.ts
CHANGED
|
@@ -47,7 +47,6 @@ export declare class Logger {
|
|
|
47
47
|
private generateRequestId;
|
|
48
48
|
private logToOtel;
|
|
49
49
|
private log;
|
|
50
|
-
private getEmoji;
|
|
51
50
|
debug(message: string, context?: LogContext, tag?: LogTag): void;
|
|
52
51
|
info(message: string, context?: LogContext, tag?: LogTag): void;
|
|
53
52
|
warn(message: string, context?: LogContext, tag?: LogTag): void;
|
package/dist/lib/logger.js
CHANGED
|
@@ -15,6 +15,7 @@ const sdk_logs_1 = require("@opentelemetry/sdk-logs");
|
|
|
15
15
|
const exporter_logs_otlp_proto_1 = require("@opentelemetry/exporter-logs-otlp-proto");
|
|
16
16
|
const api_logs_1 = require("@opentelemetry/api-logs");
|
|
17
17
|
const resources_1 = require("@opentelemetry/resources");
|
|
18
|
+
const config_1 = require("../config");
|
|
18
19
|
var LogLevel;
|
|
19
20
|
(function (LogLevel) {
|
|
20
21
|
LogLevel[LogLevel["DEBUG"] = 0] = "DEBUG";
|
|
@@ -92,7 +93,7 @@ class Logger {
|
|
|
92
93
|
resource: new resources_1.Resource({ 'service.name': 'hailer-mcp-server' })
|
|
93
94
|
});
|
|
94
95
|
loggerProvider.addLogRecordProcessor(new sdk_logs_1.BatchLogRecordProcessor(logExporter));
|
|
95
|
-
this.otelLogger = loggerProvider.getLogger('hailer-mcp',
|
|
96
|
+
this.otelLogger = loggerProvider.getLogger('hailer-mcp', config_1.APP_VERSION);
|
|
96
97
|
}
|
|
97
98
|
catch (error) {
|
|
98
99
|
console.error('❌ Failed to initialize OTLP logger:', error);
|
|
@@ -130,31 +131,46 @@ class Logger {
|
|
|
130
131
|
if (!this.shouldLog(level))
|
|
131
132
|
return;
|
|
132
133
|
const fullContext = { ...this.context, ...context };
|
|
133
|
-
//
|
|
134
|
-
const emoji = this.getEmoji(level);
|
|
135
|
-
const levelName = LogLevel[level];
|
|
136
|
-
const contextStr = Object.keys(fullContext).length > 0
|
|
137
|
-
? ` [${Object.entries(fullContext)
|
|
138
|
-
.filter(([_, value]) => value !== undefined && value !== null)
|
|
139
|
-
.map(([key, value]) => `${key}=${value}`)
|
|
140
|
-
.join(', ')}]`
|
|
141
|
-
: '';
|
|
142
|
-
const consoleMessage = `${emoji} ${levelName}: [${tag}] ${message}${contextStr}`;
|
|
143
|
-
// IMPORTANT: All logs MUST go to stderr for MCP stdio transport compatibility
|
|
144
|
-
// stdout is reserved for JSON-RPC protocol messages
|
|
145
|
-
console.error(consoleMessage);
|
|
146
|
-
// Log to OTLP in production (console only in development)
|
|
134
|
+
// Log to OTLP in production
|
|
147
135
|
if (this.isProduction && this.otelLogger) {
|
|
148
136
|
this.logToOtel(level, message, tag, fullContext);
|
|
149
137
|
}
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
138
|
+
// Console output: compact single-line format with ANSI colors
|
|
139
|
+
// DEBUG lines are dim so INFO story lines pop out visually
|
|
140
|
+
const now = new Date();
|
|
141
|
+
const time = now.toTimeString().slice(0, 8);
|
|
142
|
+
const comp = fullContext.component || 'app';
|
|
143
|
+
// Build context suffix from non-standard keys (skip noise)
|
|
144
|
+
const skipKeys = new Set(['component', 'service', 'operation']);
|
|
145
|
+
const pairs = [];
|
|
146
|
+
for (const [k, v] of Object.entries(fullContext)) {
|
|
147
|
+
if (skipKeys.has(k) || v === undefined || v === null)
|
|
148
|
+
continue;
|
|
149
|
+
const raw = typeof v === 'object' ? JSON.stringify(v) : String(v);
|
|
150
|
+
// Truncate long values
|
|
151
|
+
const val = raw.length > 80 ? raw.slice(0, 80) + '...' : raw;
|
|
152
|
+
pairs.push(`${k}:${val}`);
|
|
153
|
+
}
|
|
154
|
+
const suffix = pairs.length > 0 ? ` | ${pairs.join(' ')}` : '';
|
|
155
|
+
// ANSI color codes
|
|
156
|
+
const DIM = '\x1b[2m';
|
|
157
|
+
const RESET = '\x1b[0m';
|
|
158
|
+
const YELLOW = '\x1b[33m';
|
|
159
|
+
const RED = '\x1b[31m';
|
|
160
|
+
const BOLD = '\x1b[1m';
|
|
161
|
+
const CYAN = '\x1b[36m';
|
|
162
|
+
const body = `[${comp}] ${message}${suffix}`;
|
|
163
|
+
if (level === LogLevel.DEBUG) {
|
|
164
|
+
console.log(`${DIM}${time} DEBUG ${body}${RESET}`);
|
|
165
|
+
}
|
|
166
|
+
else if (level === LogLevel.INFO) {
|
|
167
|
+
console.log(`${CYAN}${time}${RESET} ${BOLD}INFO ${RESET} ${body}`);
|
|
168
|
+
}
|
|
169
|
+
else if (level === LogLevel.WARN) {
|
|
170
|
+
console.warn(`${YELLOW}${time} WARN ${body}${RESET}`);
|
|
171
|
+
}
|
|
172
|
+
else {
|
|
173
|
+
console.error(`${RED}${time} ERROR ${body}${RESET}`);
|
|
158
174
|
}
|
|
159
175
|
}
|
|
160
176
|
// Core logging methods
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Request Logger - Combined request/response logging
|
|
3
|
+
*
|
|
4
|
+
* Bundles MSG, RESP, and TOOL events into one log entry emitted at the end of request processing.
|
|
5
|
+
* Provides cleaner logs and better correlation of request lifecycle.
|
|
6
|
+
*/
|
|
7
|
+
export interface ToolCallResult {
|
|
8
|
+
name: string;
|
|
9
|
+
status: 'success' | 'error' | 'warning';
|
|
10
|
+
duration?: string;
|
|
11
|
+
error?: string;
|
|
12
|
+
}
|
|
13
|
+
export interface RequestLogData {
|
|
14
|
+
workspaceName: string;
|
|
15
|
+
botName: string;
|
|
16
|
+
botId: string;
|
|
17
|
+
request: {
|
|
18
|
+
from: string;
|
|
19
|
+
discussion: string;
|
|
20
|
+
timestamp: string;
|
|
21
|
+
};
|
|
22
|
+
response?: {
|
|
23
|
+
duration: string;
|
|
24
|
+
tokens: number;
|
|
25
|
+
timestamp: string;
|
|
26
|
+
};
|
|
27
|
+
tools: ToolCallResult[];
|
|
28
|
+
errors: string[];
|
|
29
|
+
}
|
|
30
|
+
export declare class RequestLogger {
|
|
31
|
+
private data;
|
|
32
|
+
private startTime;
|
|
33
|
+
private currentToolStart;
|
|
34
|
+
private currentToolName;
|
|
35
|
+
constructor(workspaceName: string, botName: string, botId: string);
|
|
36
|
+
/**
|
|
37
|
+
* Called when message is received
|
|
38
|
+
*/
|
|
39
|
+
messageReceived(from: string, discussionId: string): void;
|
|
40
|
+
/**
|
|
41
|
+
* Called when tool execution starts
|
|
42
|
+
*/
|
|
43
|
+
toolStart(toolName: string): void;
|
|
44
|
+
/**
|
|
45
|
+
* Called when tool execution succeeds
|
|
46
|
+
*/
|
|
47
|
+
toolSuccess(toolName?: string): void;
|
|
48
|
+
/**
|
|
49
|
+
* Called when tool execution fails
|
|
50
|
+
*/
|
|
51
|
+
toolError(toolName: string, error: string): void;
|
|
52
|
+
/**
|
|
53
|
+
* Called when tool has validation warning
|
|
54
|
+
*/
|
|
55
|
+
toolWarning(toolName: string, warning: string): void;
|
|
56
|
+
/**
|
|
57
|
+
* Called when a tool is used (legacy - for backward compatibility)
|
|
58
|
+
* @deprecated Use toolStart/toolSuccess/toolError instead
|
|
59
|
+
*/
|
|
60
|
+
toolCall(toolName: string): void;
|
|
61
|
+
/**
|
|
62
|
+
* Called when an error occurs
|
|
63
|
+
*/
|
|
64
|
+
error(message: string): void;
|
|
65
|
+
/**
|
|
66
|
+
* Called when response is sent - emits the combined log
|
|
67
|
+
*/
|
|
68
|
+
responseSent(tokens: number): void;
|
|
69
|
+
/**
|
|
70
|
+
* Get current data (for debugging)
|
|
71
|
+
*/
|
|
72
|
+
getData(): RequestLogData;
|
|
73
|
+
private static currentInstance;
|
|
74
|
+
static setCurrent(logger: RequestLogger | null): void;
|
|
75
|
+
static getCurrent(): RequestLogger | null;
|
|
76
|
+
}
|
|
77
|
+
//# sourceMappingURL=request-logger.d.ts.map
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Request Logger - Combined request/response logging
|
|
4
|
+
*
|
|
5
|
+
* Bundles MSG, RESP, and TOOL events into one log entry emitted at the end of request processing.
|
|
6
|
+
* Provides cleaner logs and better correlation of request lifecycle.
|
|
7
|
+
*/
|
|
8
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
9
|
+
exports.RequestLogger = void 0;
|
|
10
|
+
const logger_1 = require("./logger");
|
|
11
|
+
const logger = (0, logger_1.createLogger)({ component: 'RequestLogger' });
|
|
12
|
+
class RequestLogger {
|
|
13
|
+
data;
|
|
14
|
+
startTime;
|
|
15
|
+
currentToolStart = 0;
|
|
16
|
+
currentToolName = '';
|
|
17
|
+
constructor(workspaceName, botName, botId) {
|
|
18
|
+
this.startTime = Date.now();
|
|
19
|
+
this.data = {
|
|
20
|
+
workspaceName,
|
|
21
|
+
botName,
|
|
22
|
+
botId,
|
|
23
|
+
request: {
|
|
24
|
+
from: '',
|
|
25
|
+
discussion: '',
|
|
26
|
+
timestamp: new Date().toISOString(),
|
|
27
|
+
},
|
|
28
|
+
tools: [],
|
|
29
|
+
errors: [],
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Called when message is received
|
|
34
|
+
*/
|
|
35
|
+
messageReceived(from, discussionId) {
|
|
36
|
+
this.data.request.from = from;
|
|
37
|
+
this.data.request.discussion = discussionId.substring(0, 8);
|
|
38
|
+
this.data.request.timestamp = new Date().toISOString();
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Called when tool execution starts
|
|
42
|
+
*/
|
|
43
|
+
toolStart(toolName) {
|
|
44
|
+
this.currentToolName = toolName;
|
|
45
|
+
this.currentToolStart = Date.now();
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Called when tool execution succeeds
|
|
49
|
+
*/
|
|
50
|
+
toolSuccess(toolName) {
|
|
51
|
+
const name = toolName || this.currentToolName;
|
|
52
|
+
const duration = this.currentToolStart ? ((Date.now() - this.currentToolStart) / 1000).toFixed(1) + 's' : undefined;
|
|
53
|
+
this.data.tools.push({
|
|
54
|
+
name,
|
|
55
|
+
status: 'success',
|
|
56
|
+
duration,
|
|
57
|
+
});
|
|
58
|
+
this.currentToolName = '';
|
|
59
|
+
this.currentToolStart = 0;
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Called when tool execution fails
|
|
63
|
+
*/
|
|
64
|
+
toolError(toolName, error) {
|
|
65
|
+
const duration = this.currentToolStart ? ((Date.now() - this.currentToolStart) / 1000).toFixed(1) + 's' : undefined;
|
|
66
|
+
this.data.tools.push({
|
|
67
|
+
name: toolName || this.currentToolName,
|
|
68
|
+
status: 'error',
|
|
69
|
+
error,
|
|
70
|
+
duration,
|
|
71
|
+
});
|
|
72
|
+
this.currentToolName = '';
|
|
73
|
+
this.currentToolStart = 0;
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Called when tool has validation warning
|
|
77
|
+
*/
|
|
78
|
+
toolWarning(toolName, warning) {
|
|
79
|
+
this.data.tools.push({
|
|
80
|
+
name: toolName,
|
|
81
|
+
status: 'warning',
|
|
82
|
+
error: warning,
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Called when a tool is used (legacy - for backward compatibility)
|
|
87
|
+
* @deprecated Use toolStart/toolSuccess/toolError instead
|
|
88
|
+
*/
|
|
89
|
+
toolCall(toolName) {
|
|
90
|
+
// Only add if not already tracking this tool
|
|
91
|
+
if (!this.data.tools.find(t => t.name === toolName)) {
|
|
92
|
+
this.data.tools.push({
|
|
93
|
+
name: toolName,
|
|
94
|
+
status: 'success',
|
|
95
|
+
});
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* Called when an error occurs
|
|
100
|
+
*/
|
|
101
|
+
error(message) {
|
|
102
|
+
this.data.errors.push(message);
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* Called when response is sent - emits the combined log
|
|
106
|
+
*/
|
|
107
|
+
responseSent(tokens) {
|
|
108
|
+
const duration = ((Date.now() - this.startTime) / 1000).toFixed(1);
|
|
109
|
+
this.data.response = {
|
|
110
|
+
duration: `${duration}s`,
|
|
111
|
+
tokens,
|
|
112
|
+
timestamp: new Date().toISOString(),
|
|
113
|
+
};
|
|
114
|
+
// Build clean output - only include fields that have data
|
|
115
|
+
const logData = {
|
|
116
|
+
marker: 'REQUEST',
|
|
117
|
+
workspaceName: this.data.workspaceName,
|
|
118
|
+
botName: this.data.botName,
|
|
119
|
+
botId: this.data.botId,
|
|
120
|
+
request: this.data.request,
|
|
121
|
+
response: this.data.response,
|
|
122
|
+
};
|
|
123
|
+
if (this.data.tools.length > 0) {
|
|
124
|
+
logData.tools = this.data.tools;
|
|
125
|
+
}
|
|
126
|
+
if (this.data.errors.length > 0) {
|
|
127
|
+
logData.errors = this.data.errors;
|
|
128
|
+
}
|
|
129
|
+
logger.info('Request complete', logData);
|
|
130
|
+
}
|
|
131
|
+
/**
|
|
132
|
+
* Get current data (for debugging)
|
|
133
|
+
*/
|
|
134
|
+
getData() {
|
|
135
|
+
return { ...this.data };
|
|
136
|
+
}
|
|
137
|
+
// Static instance for tool registry to access
|
|
138
|
+
static currentInstance = null;
|
|
139
|
+
static setCurrent(logger) {
|
|
140
|
+
RequestLogger.currentInstance = logger;
|
|
141
|
+
}
|
|
142
|
+
static getCurrent() {
|
|
143
|
+
return RequestLogger.currentInstance;
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
exports.RequestLogger = RequestLogger;
|
|
147
|
+
//# sourceMappingURL=request-logger.js.map
|