@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
|
@@ -0,0 +1,228 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Message Classifier Service
|
|
4
|
+
*
|
|
5
|
+
* Handles incoming message extraction and classification:
|
|
6
|
+
* - Extracts message content from Hailer signals
|
|
7
|
+
* - Classifies message priority (high/normal)
|
|
8
|
+
* - Detects mentions, replies, and DMs
|
|
9
|
+
*/
|
|
10
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
11
|
+
exports.MessageClassifier = void 0;
|
|
12
|
+
class MessageClassifier {
|
|
13
|
+
botUserId;
|
|
14
|
+
botConnection;
|
|
15
|
+
logger;
|
|
16
|
+
// Pre-compiled mention pattern for performance
|
|
17
|
+
mentionPattern;
|
|
18
|
+
constructor(botUserId, botConnection, logger) {
|
|
19
|
+
this.botUserId = botUserId;
|
|
20
|
+
this.botConnection = botConnection;
|
|
21
|
+
this.logger = logger;
|
|
22
|
+
// Compile mention pattern once
|
|
23
|
+
this.mentionPattern = new RegExp(`\\[hailerTag\\|[^\\]]+\\]\\(${this.botUserId}\\)`, "i");
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Extract and classify incoming message from signal
|
|
27
|
+
*/
|
|
28
|
+
async extractIncomingMessage(signal) {
|
|
29
|
+
const { discussion, msg_id, uid } = signal.data;
|
|
30
|
+
// Skip our own messages
|
|
31
|
+
if (uid === this.botUserId) {
|
|
32
|
+
return null;
|
|
33
|
+
}
|
|
34
|
+
// Validate uid before using it downstream
|
|
35
|
+
if (!uid || typeof uid !== 'string') {
|
|
36
|
+
return null;
|
|
37
|
+
}
|
|
38
|
+
// Fetch the actual message content
|
|
39
|
+
let messageContent = "";
|
|
40
|
+
let senderName = "Unknown";
|
|
41
|
+
let fileAttachments = [];
|
|
42
|
+
let messages = [];
|
|
43
|
+
try {
|
|
44
|
+
const response = await this.botConnection.client.socket.request("v3.discussion.message.latest", [discussion]);
|
|
45
|
+
messages = response?.messages || [];
|
|
46
|
+
let targetMessage = messages.find((msg) => msg._id === msg_id);
|
|
47
|
+
if (!targetMessage) {
|
|
48
|
+
this.logger.warn("Target message not in latest batch", { discussionId: discussion, messageId: msg_id });
|
|
49
|
+
// Retry once after a short delay — the message may not have been committed to DB yet
|
|
50
|
+
await new Promise(r => setTimeout(r, 500));
|
|
51
|
+
const retryResponse = await this.botConnection.client.socket.request("v3.discussion.message.latest", [discussion]);
|
|
52
|
+
const retryMessages = retryResponse?.messages || [];
|
|
53
|
+
targetMessage = retryMessages.find((msg) => msg._id === msg_id);
|
|
54
|
+
if (!targetMessage) {
|
|
55
|
+
this.logger.error("Target message not found after retry", { discussionId: discussion, messageId: msg_id });
|
|
56
|
+
return null;
|
|
57
|
+
}
|
|
58
|
+
// Update messages array for downstream use (reply detection, etc.)
|
|
59
|
+
messages = retryMessages;
|
|
60
|
+
}
|
|
61
|
+
messageContent = targetMessage.msg || targetMessage.content || "";
|
|
62
|
+
// Extract file attachments if present
|
|
63
|
+
if (targetMessage.files && Array.isArray(targetMessage.files) && targetMessage.files.length > 0) {
|
|
64
|
+
fileAttachments = targetMessage.files.map((file) => ({
|
|
65
|
+
fileId: file._id,
|
|
66
|
+
filename: file.filename || file.name || "unknown",
|
|
67
|
+
size: file.size,
|
|
68
|
+
mime: file.mime || file.type,
|
|
69
|
+
}));
|
|
70
|
+
this.logger.debug("File attachments detected", {
|
|
71
|
+
messageId: msg_id,
|
|
72
|
+
fileCount: fileAttachments.length,
|
|
73
|
+
fileIds: fileAttachments.map(f => f.fileId).join(","),
|
|
74
|
+
});
|
|
75
|
+
}
|
|
76
|
+
// Get sender name: try workspace cache first, then message field
|
|
77
|
+
const cachedUser = this.botConnection.workspaceCache?.usersById[uid];
|
|
78
|
+
const cachedName = cachedUser?.fullName ?? `${cachedUser?.firstname || ''} ${cachedUser?.lastname || ''}`.trim();
|
|
79
|
+
senderName = cachedName || targetMessage.userName || "Unknown";
|
|
80
|
+
// Skip system messages
|
|
81
|
+
if (targetMessage.type && targetMessage.type !== "user") {
|
|
82
|
+
return null;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
catch (error) {
|
|
86
|
+
this.logger.warn("Could not fetch message content", { error });
|
|
87
|
+
return null;
|
|
88
|
+
}
|
|
89
|
+
// Load discussion metadata (used for DM check, activity link, and workspace ID)
|
|
90
|
+
let linkedActivityId;
|
|
91
|
+
let linkedActivityName;
|
|
92
|
+
let discussionWorkspaceId;
|
|
93
|
+
let discData = null;
|
|
94
|
+
try {
|
|
95
|
+
const discussionResponse = await this.botConnection.client.socket.request("messenger.load_discussions", [[discussion]]);
|
|
96
|
+
if (discussionResponse && Object.hasOwn(discussionResponse, discussion)) {
|
|
97
|
+
discData = discussionResponse[discussion];
|
|
98
|
+
linkedActivityId = discData.linked_activity;
|
|
99
|
+
linkedActivityName = discData.name; // Discussion name is usually the activity name
|
|
100
|
+
discussionWorkspaceId = discData.cid; // Workspace ID (cid = company ID in Hailer)
|
|
101
|
+
this.logger.debug("Discussion metadata loaded", {
|
|
102
|
+
discussionId: discussion,
|
|
103
|
+
linkedActivityId: linkedActivityId || "none",
|
|
104
|
+
linkedActivityName: linkedActivityName || "none",
|
|
105
|
+
hasLinkedActivity: !!linkedActivityId,
|
|
106
|
+
cid: discussionWorkspaceId || "not in response",
|
|
107
|
+
discDataKeys: Object.keys(discData).join(","),
|
|
108
|
+
});
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
catch (error) {
|
|
112
|
+
this.logger.debug("Failed to load discussion metadata", {
|
|
113
|
+
discussionId: discussion,
|
|
114
|
+
error: error instanceof Error ? error.message : String(error),
|
|
115
|
+
});
|
|
116
|
+
}
|
|
117
|
+
// Classify priority (reuse already-fetched messages and discussion data to avoid double API calls)
|
|
118
|
+
const isMention = this.checkMention(messageContent);
|
|
119
|
+
const isReplyToBot = this.checkReplyInMessages(messages, msg_id);
|
|
120
|
+
const isDirectMessage = discData
|
|
121
|
+
? this.checkDirectMessageFromData(discData, uid)
|
|
122
|
+
: await this.checkDirectMessage(discussion, uid);
|
|
123
|
+
let priority = "normal";
|
|
124
|
+
let priorityReason = "General chat message";
|
|
125
|
+
if (isDirectMessage) {
|
|
126
|
+
priority = "high";
|
|
127
|
+
priorityReason = "Direct message (1:1 conversation)";
|
|
128
|
+
}
|
|
129
|
+
else if (isMention) {
|
|
130
|
+
priority = "high";
|
|
131
|
+
priorityReason = "Bot mentioned in message";
|
|
132
|
+
}
|
|
133
|
+
else if (isReplyToBot) {
|
|
134
|
+
priority = "high";
|
|
135
|
+
priorityReason = "Reply to bot's message";
|
|
136
|
+
}
|
|
137
|
+
// Extract workspaceId - prefer discussion metadata (accurate), fallback to signal
|
|
138
|
+
// Discussion metadata contains authoritative workspace ID from Hailer
|
|
139
|
+
const workspaceId = discussionWorkspaceId || signal.workspaceId;
|
|
140
|
+
if (!workspaceId) {
|
|
141
|
+
this.logger.warn("Cannot determine workspace - rejecting message for isolation safety", {
|
|
142
|
+
discussionId: discussion,
|
|
143
|
+
messageId: msg_id,
|
|
144
|
+
discussionWorkspaceId: discussionWorkspaceId || "none",
|
|
145
|
+
signalWorkspaceId: signal.workspaceId || "none",
|
|
146
|
+
});
|
|
147
|
+
return null;
|
|
148
|
+
}
|
|
149
|
+
// Debug log workspace context (normal in multi-tenant setup)
|
|
150
|
+
if (discussionWorkspaceId) {
|
|
151
|
+
this.logger.debug("Message workspace context", {
|
|
152
|
+
discussionId: discussion,
|
|
153
|
+
workspaceId: discussionWorkspaceId,
|
|
154
|
+
});
|
|
155
|
+
}
|
|
156
|
+
return {
|
|
157
|
+
id: msg_id,
|
|
158
|
+
discussionId: discussion,
|
|
159
|
+
workspaceId,
|
|
160
|
+
discussionName: linkedActivityName,
|
|
161
|
+
linkedActivityId,
|
|
162
|
+
linkedActivityName,
|
|
163
|
+
senderId: uid,
|
|
164
|
+
senderName,
|
|
165
|
+
content: messageContent,
|
|
166
|
+
timestamp: signal.timestamp,
|
|
167
|
+
priority,
|
|
168
|
+
priorityReason,
|
|
169
|
+
isReplyToBot,
|
|
170
|
+
isMention,
|
|
171
|
+
isDirectMessage,
|
|
172
|
+
fileAttachments: fileAttachments.length > 0 ? fileAttachments : undefined,
|
|
173
|
+
};
|
|
174
|
+
}
|
|
175
|
+
/**
|
|
176
|
+
* Check if message mentions this bot
|
|
177
|
+
* Uses pre-compiled regex pattern for performance
|
|
178
|
+
*/
|
|
179
|
+
checkMention(content) {
|
|
180
|
+
return this.mentionPattern.test(content);
|
|
181
|
+
}
|
|
182
|
+
/**
|
|
183
|
+
* Check if message is a reply to one of our messages using pre-fetched messages.
|
|
184
|
+
* Avoids a redundant API call by reusing the messages already fetched in extractIncomingMessage.
|
|
185
|
+
*/
|
|
186
|
+
checkReplyInMessages(messages, messageId) {
|
|
187
|
+
const targetMessage = messages.find((msg) => msg._id === messageId);
|
|
188
|
+
if (targetMessage?.replyTo) {
|
|
189
|
+
const repliedToMessage = messages.find((msg) => msg._id === targetMessage.replyTo);
|
|
190
|
+
return repliedToMessage?.uid === this.botUserId;
|
|
191
|
+
}
|
|
192
|
+
return false;
|
|
193
|
+
}
|
|
194
|
+
/**
|
|
195
|
+
* Check if this is a 1:1 DM with the bot using pre-loaded discussion data.
|
|
196
|
+
* Avoids a redundant API call by reusing discussion data already fetched in extractIncomingMessage.
|
|
197
|
+
*/
|
|
198
|
+
checkDirectMessageFromData(discData, senderId) {
|
|
199
|
+
const participants = discData.participants || [];
|
|
200
|
+
if (participants.length === 2) {
|
|
201
|
+
return participants.includes(this.botUserId) && participants.includes(senderId);
|
|
202
|
+
}
|
|
203
|
+
return false;
|
|
204
|
+
}
|
|
205
|
+
/**
|
|
206
|
+
* Check if this is a 1:1 DM with the bot (fallback - fetches discussion from API)
|
|
207
|
+
*/
|
|
208
|
+
async checkDirectMessage(discussionId, senderId) {
|
|
209
|
+
try {
|
|
210
|
+
const response = await this.botConnection.client.socket.request("messenger.load_discussions", [[discussionId]]);
|
|
211
|
+
if (response && response[discussionId]) {
|
|
212
|
+
const discussion = response[discussionId];
|
|
213
|
+
const participants = discussion.participants || [];
|
|
214
|
+
// 1:1 = exactly 2 participants: sender and bot
|
|
215
|
+
if (participants.length === 2) {
|
|
216
|
+
return participants.includes(this.botUserId) &&
|
|
217
|
+
participants.includes(senderId);
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
catch {
|
|
222
|
+
// Ignore errors
|
|
223
|
+
}
|
|
224
|
+
return false;
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
exports.MessageClassifier = MessageClassifier;
|
|
228
|
+
//# sourceMappingURL=message-classifier.js.map
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Message Formatter Service
|
|
3
|
+
*
|
|
4
|
+
* Handles formatting of messages for Hailer:
|
|
5
|
+
* - Converting @mentions and #activity tags to Hailer tags
|
|
6
|
+
* - Resolving user/activity IDs via API
|
|
7
|
+
* - Extracting tag links for messenger.send
|
|
8
|
+
*/
|
|
9
|
+
import { Logger } from "../../lib/logger";
|
|
10
|
+
import { BotConnection, McpToolCallback } from "./types";
|
|
11
|
+
export declare class MessageFormatterService {
|
|
12
|
+
private botConnection;
|
|
13
|
+
private logger;
|
|
14
|
+
private callMcpTool;
|
|
15
|
+
constructor(botConnection: BotConnection, logger: Logger, callMcpTool: McpToolCallback);
|
|
16
|
+
/**
|
|
17
|
+
* Sanitize display name to prevent tag injection attacks
|
|
18
|
+
* Removes/escapes characters that could break the tag format
|
|
19
|
+
*/
|
|
20
|
+
private sanitizeDisplayName;
|
|
21
|
+
/**
|
|
22
|
+
* Validate that targetId is a valid MongoDB ObjectId format
|
|
23
|
+
*/
|
|
24
|
+
private isValidTargetId;
|
|
25
|
+
/**
|
|
26
|
+
* Format a Hailer tag for mentioning a user or activity
|
|
27
|
+
* Hailer requires ZWNBSP (U+FEFF) around the tag
|
|
28
|
+
*/
|
|
29
|
+
private formatHailerTag;
|
|
30
|
+
/**
|
|
31
|
+
* Look up user by ID and create a Hailer tag
|
|
32
|
+
*/
|
|
33
|
+
private createUserTagById;
|
|
34
|
+
/**
|
|
35
|
+
* Look up user by name and create a Hailer tag
|
|
36
|
+
*/
|
|
37
|
+
private createUserTagByName;
|
|
38
|
+
/**
|
|
39
|
+
* Convert @mentions and #activity tags in response to Hailer tags
|
|
40
|
+
* Supports:
|
|
41
|
+
* - @userId (24-char hex MongoDB ID) -> user tag
|
|
42
|
+
* - @"Full Name" (quoted name lookup) -> user tag
|
|
43
|
+
* - @FirstName (single word name lookup) -> user tag
|
|
44
|
+
* - #activityId (24-char hex) -> activity tag
|
|
45
|
+
* - #"Activity Name" (quoted) -> activity tag (requires lookup)
|
|
46
|
+
*/
|
|
47
|
+
convertMentionsToTags(content: string): string;
|
|
48
|
+
/**
|
|
49
|
+
* Resolve user tags - look up names for IDs via API when not in cache
|
|
50
|
+
* Handles @userId (24-char hex) format
|
|
51
|
+
*/
|
|
52
|
+
resolveUserTags(content: string): Promise<string>;
|
|
53
|
+
/**
|
|
54
|
+
* Resolve activity tags - look up names for IDs and IDs for names
|
|
55
|
+
* Handles both #activityId and #"Activity Name" formats
|
|
56
|
+
*/
|
|
57
|
+
resolveActivityTags(content: string): Promise<string>;
|
|
58
|
+
/**
|
|
59
|
+
* Convert Hailer URLs to Hailer tags
|
|
60
|
+
* Handles:
|
|
61
|
+
* - https://app.hailer.com/#/activities/{activityId}
|
|
62
|
+
* - https://app.hailer.com/#/discussions/{discussionId}
|
|
63
|
+
*/
|
|
64
|
+
resolveHailerUrls(content: string): Promise<string>;
|
|
65
|
+
/**
|
|
66
|
+
* Extract link metadata from hailerTag formatted content
|
|
67
|
+
* Returns array of links for the messenger.send API
|
|
68
|
+
*/
|
|
69
|
+
extractTagLinks(content: string): Array<{
|
|
70
|
+
target: string;
|
|
71
|
+
targetType: string;
|
|
72
|
+
type: string;
|
|
73
|
+
}>;
|
|
74
|
+
/**
|
|
75
|
+
* Format incoming message for LLM consumption
|
|
76
|
+
*/
|
|
77
|
+
formatIncomingMessage(message: {
|
|
78
|
+
discussionId: string;
|
|
79
|
+
linkedActivityId?: string;
|
|
80
|
+
senderName: string;
|
|
81
|
+
senderId: string;
|
|
82
|
+
timestamp: number;
|
|
83
|
+
priority: string;
|
|
84
|
+
priorityReason: string;
|
|
85
|
+
content: string;
|
|
86
|
+
}): string;
|
|
87
|
+
}
|
|
88
|
+
//# sourceMappingURL=message-formatter.d.ts.map
|