@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.
Files changed (233) hide show
  1. package/.claude/.session-checked +1 -0
  2. package/.claude/agents/agent-ada-skill-builder.md +10 -2
  3. package/.claude/agents/agent-alejandro-function-fields.md +104 -37
  4. package/.claude/agents/agent-bjorn-config-audit.md +41 -21
  5. package/.claude/agents/agent-builder-agent-creator.md +13 -3
  6. package/.claude/agents/agent-code-simplifier.md +53 -0
  7. package/.claude/agents/agent-dmitri-activity-crud.md +126 -11
  8. package/.claude/agents/agent-giuseppe-app-builder.md +212 -22
  9. package/.claude/agents/agent-gunther-mcp-tools.md +7 -36
  10. package/.claude/agents/agent-helga-workflow-config.md +75 -10
  11. package/.claude/agents/agent-igor-activity-mover-automation.md +125 -0
  12. package/.claude/agents/agent-ingrid-doc-templates.md +164 -36
  13. package/.claude/agents/agent-ivan-monolith.md +154 -0
  14. package/.claude/agents/agent-kenji-data-reader.md +15 -8
  15. package/.claude/agents/agent-lars-code-inspector.md +56 -8
  16. package/.claude/agents/agent-marco-mockup-builder.md +110 -0
  17. package/.claude/agents/agent-marcus-api-documenter.md +323 -0
  18. package/.claude/agents/agent-marketplace-publisher.md +232 -72
  19. package/.claude/agents/agent-marketplace-reviewer.md +255 -79
  20. package/.claude/agents/agent-permissions-handler.md +208 -0
  21. package/.claude/agents/agent-simple-writer.md +48 -0
  22. package/.claude/agents/agent-svetlana-code-review.md +127 -14
  23. package/.claude/agents/agent-tanya-test-runner.md +333 -0
  24. package/.claude/agents/agent-ui-designer.md +100 -0
  25. package/.claude/agents/agent-viktor-sql-insights.md +19 -6
  26. package/.claude/agents/agent-web-search.md +55 -0
  27. package/.claude/agents/agent-yevgeni-discussions.md +7 -1
  28. package/.claude/agents/agent-zara-zapier.md +159 -0
  29. package/.claude/commands/app-squad.md +135 -0
  30. package/.claude/commands/audit-squad.md +158 -0
  31. package/.claude/commands/autoplan.md +563 -0
  32. package/.claude/commands/cleanup-squad.md +98 -0
  33. package/.claude/commands/config-squad.md +106 -0
  34. package/.claude/commands/crud-squad.md +87 -0
  35. package/.claude/commands/data-squad.md +97 -0
  36. package/.claude/commands/debug-squad.md +303 -0
  37. package/.claude/commands/doc-squad.md +65 -0
  38. package/.claude/commands/handoff.md +137 -0
  39. package/.claude/commands/health.md +49 -0
  40. package/.claude/commands/help.md +2 -1
  41. package/.claude/commands/help:agents.md +96 -16
  42. package/.claude/commands/help:commands.md +55 -11
  43. package/.claude/commands/help:faq.md +16 -1
  44. package/.claude/commands/help:skills.md +93 -0
  45. package/.claude/commands/hotfix-squad.md +112 -0
  46. package/.claude/commands/integration-squad.md +82 -0
  47. package/.claude/commands/janitor-squad.md +167 -0
  48. package/.claude/commands/learn-auto.md +120 -0
  49. package/.claude/commands/learn.md +120 -0
  50. package/.claude/commands/mcp-list.md +27 -0
  51. package/.claude/commands/onboard-squad.md +140 -0
  52. package/.claude/commands/plan-workspace.md +732 -0
  53. package/.claude/commands/prd.md +131 -0
  54. package/.claude/commands/project-status.md +82 -0
  55. package/.claude/commands/publish.md +138 -0
  56. package/.claude/commands/recap.md +69 -0
  57. package/.claude/commands/restore.md +64 -0
  58. package/.claude/commands/review-squad.md +152 -0
  59. package/.claude/commands/save.md +24 -0
  60. package/.claude/commands/stats.md +19 -0
  61. package/.claude/commands/swarm.md +210 -0
  62. package/.claude/commands/tool-builder.md +3 -1
  63. package/.claude/commands/ws-pull.md +1 -1
  64. package/.claude/commands/yolo-off.md +17 -0
  65. package/.claude/commands/yolo.md +82 -0
  66. package/.claude/hooks/_shared-memory.cjs +305 -0
  67. package/.claude/hooks/_utils.cjs +134 -0
  68. package/.claude/hooks/agent-failure-detector.cjs +164 -79
  69. package/.claude/hooks/agent-usage-logger.cjs +204 -0
  70. package/.claude/hooks/app-edit-guard.cjs +20 -4
  71. package/.claude/hooks/auto-learn.cjs +316 -0
  72. package/.claude/hooks/bash-guard.cjs +282 -0
  73. package/.claude/hooks/builder-mode-manager.cjs +183 -54
  74. package/.claude/hooks/bulk-activity-guard.cjs +283 -0
  75. package/.claude/hooks/context-watchdog.cjs +292 -0
  76. package/.claude/hooks/delegation-reminder.cjs +478 -0
  77. package/.claude/hooks/design-system-lint.cjs +283 -0
  78. package/.claude/hooks/post-scaffold-hook.cjs +16 -3
  79. package/.claude/hooks/prompt-guard.cjs +366 -0
  80. package/.claude/hooks/publish-template-guard.cjs +16 -0
  81. package/.claude/hooks/session-start.cjs +35 -0
  82. package/.claude/hooks/shared-memory-writer.cjs +147 -0
  83. package/.claude/hooks/skill-injector.cjs +140 -0
  84. package/.claude/hooks/skill-usage-logger.cjs +258 -0
  85. package/.claude/hooks/src-edit-guard.cjs +16 -1
  86. package/.claude/hooks/sync-marketplace-agents.cjs +53 -8
  87. package/.claude/scripts/yolo-toggle.cjs +142 -0
  88. package/.claude/settings.json +141 -14
  89. package/.claude/skills/SDK-activity-patterns/SKILL.md +428 -0
  90. package/.claude/skills/SDK-document-templates/SKILL.md +1033 -0
  91. package/.claude/skills/SDK-function-fields/SKILL.md +542 -0
  92. package/.claude/skills/SDK-generate-skill/SKILL.md +92 -0
  93. package/.claude/skills/SDK-init-skill/SKILL.md +127 -0
  94. package/.claude/skills/SDK-insight-queries/SKILL.md +787 -0
  95. package/.claude/skills/SDK-ws-config-skill/SKILL.md +1139 -0
  96. package/.claude/skills/agent-structure/SKILL.md +98 -0
  97. package/.claude/skills/api-documentation-patterns/SKILL.md +474 -0
  98. package/.claude/skills/chrome-mcp-reference/SKILL.md +370 -0
  99. package/.claude/skills/delegation-routing/SKILL.md +202 -0
  100. package/.claude/skills/frontend-design/SKILL.md +254 -0
  101. package/.claude/skills/hailer-activity-mover/SKILL.md +213 -0
  102. package/.claude/skills/hailer-api-client/SKILL.md +518 -0
  103. package/.claude/skills/hailer-app-builder/SKILL.md +939 -11
  104. package/.claude/skills/hailer-apps-pictures/SKILL.md +269 -0
  105. package/.claude/skills/hailer-design-system/SKILL.md +235 -0
  106. package/.claude/skills/hailer-monolith-automations/SKILL.md +686 -0
  107. package/.claude/skills/hailer-permissions-system/SKILL.md +121 -0
  108. package/.claude/skills/hailer-project-protocol/SKILL.md +488 -0
  109. package/.claude/skills/hailer-rest-api/SKILL.md +61 -0
  110. package/.claude/skills/hailer-rest-api/hailer-activities.md +184 -0
  111. package/.claude/skills/hailer-rest-api/hailer-admin.md +473 -0
  112. package/.claude/skills/hailer-rest-api/hailer-calendar.md +256 -0
  113. package/.claude/skills/hailer-rest-api/hailer-feed.md +249 -0
  114. package/.claude/skills/hailer-rest-api/hailer-insights.md +195 -0
  115. package/.claude/skills/hailer-rest-api/hailer-messaging.md +276 -0
  116. package/.claude/skills/hailer-rest-api/hailer-workflows.md +283 -0
  117. package/.claude/skills/insight-join-patterns/SKILL.md +3 -0
  118. package/.claude/skills/integration-patterns/SKILL.md +421 -0
  119. package/.claude/skills/json-only-output/SKILL.md +52 -12
  120. package/.claude/skills/lsp-setup/SKILL.md +160 -0
  121. package/.claude/skills/mcp-direct-tools/SKILL.md +153 -0
  122. package/.claude/skills/optional-parameters/SKILL.md +32 -23
  123. package/.claude/skills/publish-hailer-app/SKILL.md +76 -12
  124. package/.claude/skills/testing-patterns/SKILL.md +630 -0
  125. package/.claude/skills/tool-builder/SKILL.md +250 -0
  126. package/.claude/skills/tool-parameter-usage/SKILL.md +59 -45
  127. package/.claude/skills/tool-response-verification/SKILL.md +82 -48
  128. package/.claude/skills/zapier-hailer-patterns/SKILL.md +581 -0
  129. package/.env.example +26 -7
  130. package/CLAUDE.md +290 -224
  131. package/dist/CLAUDE.md +370 -0
  132. package/dist/app.d.ts +1 -1
  133. package/dist/app.js +101 -101
  134. package/dist/bot/bot-config.d.ts +26 -0
  135. package/dist/bot/bot-config.js +135 -0
  136. package/dist/bot/bot-manager.d.ts +40 -0
  137. package/dist/bot/bot-manager.js +137 -0
  138. package/dist/bot/bot.d.ts +127 -0
  139. package/dist/bot/bot.js +1328 -0
  140. package/dist/bot/operation-logger.d.ts +28 -0
  141. package/dist/bot/operation-logger.js +132 -0
  142. package/dist/bot/services/conversation-manager.d.ts +60 -0
  143. package/dist/bot/services/conversation-manager.js +246 -0
  144. package/dist/bot/services/index.d.ts +9 -0
  145. package/dist/bot/services/index.js +18 -0
  146. package/dist/bot/services/message-classifier.d.ts +42 -0
  147. package/dist/bot/services/message-classifier.js +228 -0
  148. package/dist/bot/services/message-formatter.d.ts +88 -0
  149. package/dist/bot/services/message-formatter.js +411 -0
  150. package/dist/bot/services/session-logger.d.ts +162 -0
  151. package/dist/bot/services/session-logger.js +724 -0
  152. package/dist/bot/services/token-billing.d.ts +78 -0
  153. package/dist/bot/services/token-billing.js +233 -0
  154. package/dist/bot/services/types.d.ts +169 -0
  155. package/dist/bot/services/types.js +12 -0
  156. package/dist/bot/services/typing-indicator.d.ts +23 -0
  157. package/dist/bot/services/typing-indicator.js +60 -0
  158. package/dist/bot/services/workspace-schema-cache.d.ts +122 -0
  159. package/dist/bot/services/workspace-schema-cache.js +506 -0
  160. package/dist/bot/tool-executor.d.ts +28 -0
  161. package/dist/bot/tool-executor.js +48 -0
  162. package/dist/bot/workspace-overview.d.ts +12 -0
  163. package/dist/bot/workspace-overview.js +94 -0
  164. package/dist/cli.d.ts +1 -8
  165. package/dist/cli.js +1 -253
  166. package/dist/config.d.ts +96 -3
  167. package/dist/config.js +148 -37
  168. package/dist/core.d.ts +5 -0
  169. package/dist/core.js +61 -8
  170. package/dist/lib/discussion-lock.d.ts +42 -0
  171. package/dist/lib/discussion-lock.js +110 -0
  172. package/dist/lib/logger.d.ts +0 -1
  173. package/dist/lib/logger.js +39 -23
  174. package/dist/lib/request-logger.d.ts +77 -0
  175. package/dist/lib/request-logger.js +147 -0
  176. package/dist/mcp/UserContextCache.js +16 -13
  177. package/dist/mcp/hailer-clients.js +18 -17
  178. package/dist/mcp/signal-handler.js +29 -13
  179. package/dist/mcp/tool-registry.d.ts +4 -15
  180. package/dist/mcp/tool-registry.js +94 -32
  181. package/dist/mcp/tools/activity.js +28 -69
  182. package/dist/mcp/tools/app-core.js +9 -4
  183. package/dist/mcp/tools/app-marketplace.js +22 -12
  184. package/dist/mcp/tools/app-member.js +5 -2
  185. package/dist/mcp/tools/app-scaffold.js +32 -18
  186. package/dist/mcp/tools/bot-config/constants.d.ts +23 -0
  187. package/dist/mcp/tools/bot-config/constants.js +94 -0
  188. package/dist/mcp/tools/bot-config/core.d.ts +253 -0
  189. package/dist/mcp/tools/bot-config/core.js +2456 -0
  190. package/dist/mcp/tools/bot-config/index.d.ts +10 -0
  191. package/dist/mcp/tools/bot-config/index.js +59 -0
  192. package/dist/mcp/tools/bot-config/tools.d.ts +7 -0
  193. package/dist/mcp/tools/bot-config/tools.js +15 -0
  194. package/dist/mcp/tools/bot-config/types.d.ts +50 -0
  195. package/dist/mcp/tools/bot-config/types.js +6 -0
  196. package/dist/mcp/tools/discussion.js +107 -77
  197. package/dist/mcp/tools/document.d.ts +11 -0
  198. package/dist/mcp/tools/document.js +741 -0
  199. package/dist/mcp/tools/file.js +5 -2
  200. package/dist/mcp/tools/insight.js +36 -12
  201. package/dist/mcp/tools/investigate.d.ts +9 -0
  202. package/dist/mcp/tools/investigate.js +254 -0
  203. package/dist/mcp/tools/user.d.ts +2 -4
  204. package/dist/mcp/tools/user.js +9 -50
  205. package/dist/mcp/tools/workflow.d.ts +1 -0
  206. package/dist/mcp/tools/workflow.js +164 -52
  207. package/dist/mcp/utils/hailer-api-client.js +26 -17
  208. package/dist/mcp/webhook-handler.d.ts +64 -3
  209. package/dist/mcp/webhook-handler.js +219 -9
  210. package/dist/mcp-server.d.ts +4 -0
  211. package/dist/mcp-server.js +237 -25
  212. package/dist/plugins/bug-fixer/index.d.ts +2 -0
  213. package/dist/plugins/bug-fixer/index.js +18 -0
  214. package/dist/plugins/bug-fixer/tools.d.ts +45 -0
  215. package/dist/plugins/bug-fixer/tools.js +1096 -0
  216. package/package.json +10 -10
  217. package/scripts/test-hal-tools.ts +154 -0
  218. package/.claude/agents/agent-nora-name-functions.md +0 -123
  219. package/.claude/assistant-knowledge.md +0 -23
  220. package/.claude/commands/install-plugin.md +0 -261
  221. package/.claude/commands/list-plugins.md +0 -42
  222. package/.claude/commands/marketplace-setup.md +0 -33
  223. package/.claude/commands/publish-plugin.md +0 -55
  224. package/.claude/commands/uninstall-plugin.md +0 -87
  225. package/.claude/hooks/interactive-mode.cjs +0 -87
  226. package/.claude/hooks/mcp-server-guard.cjs +0 -108
  227. package/.claude/skills/marketplace-publishing.md +0 -155
  228. package/dist/bot/chat-bot.d.ts +0 -31
  229. package/dist/bot/chat-bot.js +0 -357
  230. package/dist/mcp/tools/metrics.d.ts +0 -13
  231. package/dist/mcp/tools/metrics.js +0 -546
  232. package/dist/stdio-server.d.ts +0 -14
  233. package/dist/stdio-server.js +0 -114
@@ -0,0 +1,28 @@
1
+ /**
2
+ * OperationLogger - Centralized inline logging for bot operations.
3
+ *
4
+ * Produces structured single-line log entries for message flow,
5
+ * balance checks, routing, LLM calls, tool calls, and responses.
6
+ */
7
+ export declare class OperationLogger {
8
+ messageIn(discussionId: string, from: string, content: string): void;
9
+ balanceCheck(discussionId: string, workspaceId: string, balance: number, status: string): void;
10
+ route(discussionId: string, classification: string, model: string, content: string): void;
11
+ llmCall(discussionId: string, model: string, inTokens: number, outTokens: number, cacheHitPct: number, durationSec: number): void;
12
+ toolCall(discussionId: string, toolName: string, summary: string, durationSec: number, status: 'OK' | 'FAIL', errorPreview?: string): void;
13
+ permDenied(discussionId: string, toolName: string, workflowId: string, userId: string): void;
14
+ permFiltered(discussionId: string, toolName: string, before: number, after: number): void;
15
+ messageOut(discussionId: string, charCount: number, tagCount: number): void;
16
+ engage(discussionId: string, trigger: string): void;
17
+ disengage(discussionId: string, nonResponses: number): void;
18
+ coalesce(discussionId: string, count: number): void;
19
+ interrupt(discussionId: string, reason: string): void;
20
+ contextInject(discussionId: string, count: number): void;
21
+ progress(discussionId: string): void;
22
+ }
23
+ /**
24
+ * Generate a human-readable summary from a tool result.
25
+ * Used by bot.ts executeTools() to produce concise TOOL CALL log summaries.
26
+ */
27
+ export declare function summarizeToolResult(toolName: string, resultText: string): string;
28
+ //# sourceMappingURL=operation-logger.d.ts.map
@@ -0,0 +1,132 @@
1
+ "use strict";
2
+ /**
3
+ * OperationLogger - Centralized inline logging for bot operations.
4
+ *
5
+ * Produces structured single-line log entries for message flow,
6
+ * balance checks, routing, LLM calls, tool calls, and responses.
7
+ */
8
+ Object.defineProperty(exports, "__esModule", { value: true });
9
+ exports.OperationLogger = void 0;
10
+ exports.summarizeToolResult = summarizeToolResult;
11
+ const logger_1 = require("../lib/logger");
12
+ const logger = (0, logger_1.createLogger)({ component: 'ops' });
13
+ /** Shorten discussion ID to first 8 chars */
14
+ function did(discussionId) {
15
+ return `d:${discussionId.slice(0, 8)}..`;
16
+ }
17
+ /** Shorten model name for log readability */
18
+ function shortModel(model) {
19
+ if (model.includes('sonnet-4-5'))
20
+ return 'sonnet-4.5';
21
+ if (model.includes('haiku-4-5'))
22
+ return 'haiku-4.5';
23
+ if (model.includes('sonnet'))
24
+ return 'sonnet';
25
+ if (model.includes('haiku'))
26
+ return 'haiku';
27
+ return model;
28
+ }
29
+ /** Truncate string to maxLen chars, collapsing newlines */
30
+ function trunc(s, maxLen = 80) {
31
+ const clean = s.replace(/\n/g, ' ').trim();
32
+ return clean.length > maxLen ? clean.slice(0, maxLen) + '...' : clean;
33
+ }
34
+ class OperationLogger {
35
+ messageIn(discussionId, from, content) {
36
+ logger.info(`MSG IN | ${did(discussionId)} | from:${from} | "${trunc(content, 60)}"`);
37
+ }
38
+ balanceCheck(discussionId, workspaceId, balance, status) {
39
+ logger.info(`BALANCE | ${did(discussionId)} | ws:${workspaceId.slice(0, 8)}.. | ${balance} tokens | ${status}`);
40
+ }
41
+ route(discussionId, classification, model, content) {
42
+ logger.info(`ROUTE | ${did(discussionId)} | ${classification} -> ${shortModel(model)} | "${trunc(content, 60)}"`);
43
+ }
44
+ llmCall(discussionId, model, inTokens, outTokens, cacheHitPct, durationSec) {
45
+ logger.info(`LLM CALL | ${did(discussionId)} | ${shortModel(model)} | ${inTokens} in / ${outTokens} out | cache: ${cacheHitPct}% | ${durationSec.toFixed(1)}s`);
46
+ }
47
+ toolCall(discussionId, toolName, summary, durationSec, status, errorPreview) {
48
+ let line = `TOOL CALL | ${did(discussionId)} | ${toolName} | ${summary} | ${durationSec.toFixed(1)}s | ${status}`;
49
+ if (errorPreview)
50
+ line += ` | "${trunc(errorPreview)}"`;
51
+ logger.info(line);
52
+ }
53
+ permDenied(discussionId, toolName, workflowId, userId) {
54
+ logger.warn(`PERM DENY | ${did(discussionId)} | ${toolName} | wf:${workflowId.slice(0, 8)}.. | user:${userId.slice(0, 8)}..`);
55
+ }
56
+ permFiltered(discussionId, toolName, before, after) {
57
+ logger.info(`PERM FILT | ${did(discussionId)} | ${toolName} | ${before} -> ${after} workflows`);
58
+ }
59
+ messageOut(discussionId, charCount, tagCount) {
60
+ logger.info(`MSG OUT | ${did(discussionId)} | ${charCount} chars | ${tagCount} tags`);
61
+ }
62
+ engage(discussionId, trigger) {
63
+ logger.info(`ENGAGE | ${did(discussionId)} | ${trigger}`);
64
+ }
65
+ disengage(discussionId, nonResponses) {
66
+ logger.info(`DISENGAGE | ${did(discussionId)} | ${nonResponses} non-responses`);
67
+ }
68
+ coalesce(discussionId, count) {
69
+ logger.info(`COALESCE | ${did(discussionId)} | ${count} messages`);
70
+ }
71
+ interrupt(discussionId, reason) {
72
+ logger.info(`INTERRUPT | ${did(discussionId)} | ${reason}`);
73
+ }
74
+ contextInject(discussionId, count) {
75
+ logger.info(`CTX INJ | ${did(discussionId)} | ${count} messages`);
76
+ }
77
+ progress(discussionId) {
78
+ logger.info(`PROGRESS | ${did(discussionId)}`);
79
+ }
80
+ }
81
+ exports.OperationLogger = OperationLogger;
82
+ /**
83
+ * Generate a human-readable summary from a tool result.
84
+ * Used by bot.ts executeTools() to produce concise TOOL CALL log summaries.
85
+ */
86
+ function summarizeToolResult(toolName, resultText) {
87
+ try {
88
+ const json = JSON.parse(resultText);
89
+ // create_activity
90
+ if (toolName === 'create_activity') {
91
+ if (json.created_ids)
92
+ return `${json.created_ids.length} activit${json.created_ids.length === 1 ? 'y' : 'ies'}`;
93
+ if (json.name)
94
+ return `1 activity: ${trunc(json.name, 40)}`;
95
+ }
96
+ // list_activities
97
+ if (toolName === 'list_activities') {
98
+ const count = json.stats?.total ?? json.activities?.length ?? json.length;
99
+ if (count !== undefined)
100
+ return `${count} results`;
101
+ }
102
+ // list_workflows / list_workflows_minimal
103
+ if (toolName.includes('list_workflows')) {
104
+ const count = json.workflows?.length ?? json.length;
105
+ if (count !== undefined)
106
+ return `${count} workflows`;
107
+ }
108
+ // get_workflow_schema
109
+ if (toolName === 'get_workflow_schema') {
110
+ const count = json.fields?.length ?? Object.keys(json.fields || {}).length;
111
+ if (count)
112
+ return `${count} fields`;
113
+ }
114
+ // count_activities
115
+ if (toolName === 'count_activities') {
116
+ if (json.total !== undefined)
117
+ return `${json.total} activities`;
118
+ }
119
+ // search_workspace_users
120
+ if (toolName === 'search_workspace_users') {
121
+ const count = json.users?.length ?? json.length;
122
+ if (count !== undefined)
123
+ return `${count} users`;
124
+ }
125
+ }
126
+ catch {
127
+ // Not JSON, fall through
128
+ }
129
+ // Fallback: first 80 chars of result text
130
+ return trunc(resultText);
131
+ }
132
+ //# sourceMappingURL=operation-logger.js.map
@@ -0,0 +1,60 @@
1
+ /**
2
+ * Conversation Manager Service
3
+ *
4
+ * Manages per-discussion conversation state:
5
+ * - LRU cache of conversation histories
6
+ * - Context size management with summarization
7
+ * - Conversation state access
8
+ */
9
+ import Anthropic from "@anthropic-ai/sdk";
10
+ import { Logger } from "../../lib/logger";
11
+ /** Conversation message using Anthropic's MessageParam type */
12
+ export type ConversationMessage = Anthropic.MessageParam;
13
+ export declare class ConversationManager {
14
+ private maxConversations;
15
+ private maxContextMessages;
16
+ private logger;
17
+ private conversationsByDiscussion;
18
+ constructor(maxConversations: number, maxContextMessages: number, logger: Logger);
19
+ /**
20
+ * Get or create conversation history for a specific discussion
21
+ * Each discussion has its own isolated context to prevent bloat
22
+ * Uses LRU eviction when map exceeds maxConversations
23
+ */
24
+ getConversation(discussionId: string): ConversationMessage[];
25
+ /**
26
+ * Add a message to a conversation
27
+ */
28
+ addMessage(discussionId: string, message: ConversationMessage): void;
29
+ /**
30
+ * Manage conversation context size - truncate if too large
31
+ * Generates a programmatic summary of dropped messages before truncating
32
+ */
33
+ manageContextSize(discussionId: string): void;
34
+ /**
35
+ * Build a compact programmatic summary of dropped messages (no LLM call)
36
+ */
37
+ private summarizeDroppedMessages;
38
+ /**
39
+ * Get conversation state for debugging
40
+ */
41
+ getState(currentDiscussionId?: string): {
42
+ discussionCount: number;
43
+ currentMessageCount: number;
44
+ };
45
+ /**
46
+ * Get full conversation for a discussion (for debugging)
47
+ */
48
+ getFullConversation(discussionId?: string): ConversationMessage[];
49
+ /**
50
+ * Clear all conversations
51
+ */
52
+ clear(): void;
53
+ /**
54
+ * Prepare conversation for API call with Anthropic prompt caching
55
+ * Adds cache_control to the last assistant message to cache conversation history
56
+ * Returns a COPY - does not modify the original conversation
57
+ */
58
+ prepareForCaching(conversation: ConversationMessage[]): ConversationMessage[];
59
+ }
60
+ //# sourceMappingURL=conversation-manager.d.ts.map
@@ -0,0 +1,246 @@
1
+ "use strict";
2
+ /**
3
+ * Conversation Manager Service
4
+ *
5
+ * Manages per-discussion conversation state:
6
+ * - LRU cache of conversation histories
7
+ * - Context size management with summarization
8
+ * - Conversation state access
9
+ */
10
+ Object.defineProperty(exports, "__esModule", { value: true });
11
+ exports.ConversationManager = void 0;
12
+ class ConversationManager {
13
+ maxConversations;
14
+ maxContextMessages;
15
+ logger;
16
+ conversationsByDiscussion = new Map();
17
+ constructor(maxConversations, maxContextMessages, logger) {
18
+ this.maxConversations = maxConversations;
19
+ this.maxContextMessages = maxContextMessages;
20
+ this.logger = logger;
21
+ }
22
+ /**
23
+ * Get or create conversation history for a specific discussion
24
+ * Each discussion has its own isolated context to prevent bloat
25
+ * Uses LRU eviction when map exceeds maxConversations
26
+ */
27
+ getConversation(discussionId) {
28
+ let conversation = this.conversationsByDiscussion.get(discussionId);
29
+ if (conversation) {
30
+ // Move to end for LRU (delete and re-add to update insertion order)
31
+ this.conversationsByDiscussion.delete(discussionId);
32
+ this.conversationsByDiscussion.set(discussionId, conversation);
33
+ return conversation;
34
+ }
35
+ // Evict oldest conversations if at capacity
36
+ if (this.conversationsByDiscussion.size >= this.maxConversations) {
37
+ const toEvict = this.conversationsByDiscussion.size - this.maxConversations + 1;
38
+ const keys = [...this.conversationsByDiscussion.keys()].slice(0, toEvict);
39
+ for (const key of keys) {
40
+ this.conversationsByDiscussion.delete(key);
41
+ }
42
+ this.logger.debug("Evicted old conversations", { evicted: toEvict, remaining: this.conversationsByDiscussion.size });
43
+ }
44
+ conversation = [];
45
+ this.conversationsByDiscussion.set(discussionId, conversation);
46
+ this.logger.debug("Created new conversation context", { discussionId });
47
+ return conversation;
48
+ }
49
+ /**
50
+ * Add a message to a conversation
51
+ */
52
+ addMessage(discussionId, message) {
53
+ const conversation = this.getConversation(discussionId);
54
+ conversation.push(message);
55
+ }
56
+ /**
57
+ * Manage conversation context size - truncate if too large
58
+ * Generates a programmatic summary of dropped messages before truncating
59
+ */
60
+ manageContextSize(discussionId) {
61
+ const conversation = this.getConversation(discussionId);
62
+ if (conversation.length > this.maxContextMessages) {
63
+ const originalCount = conversation.length;
64
+ const keepCount = Math.floor(this.maxContextMessages * 0.6);
65
+ const dropped = conversation.slice(0, -keepCount);
66
+ const toKeep = conversation.slice(-keepCount);
67
+ // Build summary of what's being dropped
68
+ const summary = this.summarizeDroppedMessages(dropped);
69
+ // Merge or prepend summary to preserve user/assistant alternation
70
+ let result;
71
+ if (toKeep.length > 0 && toKeep[0].role === "user") {
72
+ // First kept message is user — merge summary into it to avoid consecutive user messages
73
+ const first = toKeep[0];
74
+ if (typeof first.content === "string") {
75
+ toKeep[0] = { role: "user", content: `${summary}\n\n${first.content}` };
76
+ }
77
+ else if (Array.isArray(first.content)) {
78
+ toKeep[0] = {
79
+ role: "user",
80
+ content: [{ type: "text", text: summary }, ...first.content],
81
+ };
82
+ }
83
+ result = toKeep;
84
+ }
85
+ else {
86
+ // First kept message is assistant — safe to prepend user summary
87
+ result = [{ role: "user", content: summary }, ...toKeep];
88
+ }
89
+ this.conversationsByDiscussion.set(discussionId, result);
90
+ this.logger.debug("Context truncated with summary", {
91
+ discussionId,
92
+ originalCount,
93
+ newCount: result.length,
94
+ dropped: dropped.length,
95
+ });
96
+ }
97
+ }
98
+ /**
99
+ * Build a compact programmatic summary of dropped messages (no LLM call)
100
+ */
101
+ summarizeDroppedMessages(dropped) {
102
+ const senders = new Set();
103
+ const tools = new Set();
104
+ const userSnippets = [];
105
+ for (const msg of dropped) {
106
+ if (msg.role === "user") {
107
+ const content = typeof msg.content === "string"
108
+ ? msg.content
109
+ : Array.isArray(msg.content)
110
+ ? msg.content
111
+ .filter((b) => b.type === "text")
112
+ .map((b) => b.text)
113
+ .join(" ")
114
+ : "";
115
+ // Extract sender from <incoming from="Name">
116
+ const fromMatch = content.match(/from="([^"]+)"/);
117
+ if (fromMatch)
118
+ senders.add(fromMatch[1]);
119
+ if (content && !content.startsWith("<context")) {
120
+ userSnippets.push(content.slice(0, 100));
121
+ }
122
+ }
123
+ else if (msg.role === "assistant" && Array.isArray(msg.content)) {
124
+ for (const block of msg.content) {
125
+ if (block.type === "tool_use") {
126
+ tools.add(block.name);
127
+ }
128
+ }
129
+ }
130
+ }
131
+ const parts = [
132
+ `Prior conversation (${dropped.length} messages truncated):`,
133
+ ];
134
+ if (senders.size > 0)
135
+ parts.push(`- Participants: ${[...senders].join(", ")}`);
136
+ if (tools.size > 0)
137
+ parts.push(`- Tools used: ${[...tools].join(", ")}`);
138
+ if (userSnippets.length > 0) {
139
+ parts.push(`- First topic: ${userSnippets[0]}...`);
140
+ if (userSnippets.length > 1) {
141
+ parts.push(`- Last topic: ${userSnippets[userSnippets.length - 1]}...`);
142
+ }
143
+ }
144
+ return `<context type="truncated-history">\n${parts.join("\n")}\n</context>`;
145
+ }
146
+ /**
147
+ * Get conversation state for debugging
148
+ */
149
+ getState(currentDiscussionId) {
150
+ const currentConvo = currentDiscussionId
151
+ ? this.conversationsByDiscussion.get(currentDiscussionId)
152
+ : null;
153
+ return {
154
+ discussionCount: this.conversationsByDiscussion.size,
155
+ currentMessageCount: currentConvo?.length ?? 0,
156
+ };
157
+ }
158
+ /**
159
+ * Get full conversation for a discussion (for debugging)
160
+ */
161
+ getFullConversation(discussionId) {
162
+ if (!discussionId) {
163
+ // Return first conversation if no ID specified
164
+ const first = this.conversationsByDiscussion.values().next().value;
165
+ return first || [];
166
+ }
167
+ return this.conversationsByDiscussion.get(discussionId) || [];
168
+ }
169
+ /**
170
+ * Clear all conversations
171
+ */
172
+ clear() {
173
+ this.conversationsByDiscussion.clear();
174
+ }
175
+ /**
176
+ * Prepare conversation for API call with Anthropic prompt caching
177
+ * Adds cache_control to the last assistant message to cache conversation history
178
+ * Returns a COPY - does not modify the original conversation
179
+ */
180
+ prepareForCaching(conversation) {
181
+ // Sanitize: remove any messages with empty content (prevents API 400 errors)
182
+ for (let i = conversation.length - 1; i >= 0; i--) {
183
+ const msg = conversation[i];
184
+ const content = msg.content;
185
+ const isEmpty = !content || (Array.isArray(content) && content.length === 0) ||
186
+ (typeof content === 'string' && content.trim() === '');
187
+ if (isEmpty) {
188
+ this.logger.warn('Removed empty content message from conversation', {
189
+ index: i, role: msg.role, contentType: typeof content,
190
+ });
191
+ conversation.splice(i, 1);
192
+ }
193
+ }
194
+ if (conversation.length < 2) {
195
+ // Need at least one exchange to cache
196
+ return conversation;
197
+ }
198
+ // Find the last assistant message (should be second-to-last, before new user message)
199
+ let lastAssistantIndex = -1;
200
+ for (let i = conversation.length - 1; i >= 0; i--) {
201
+ if (conversation[i].role === "assistant") {
202
+ lastAssistantIndex = i;
203
+ break;
204
+ }
205
+ }
206
+ if (lastAssistantIndex === -1) {
207
+ // No assistant message found
208
+ return conversation;
209
+ }
210
+ // Shallow copy with targeted cache_control modification
211
+ const cached = conversation.map((msg, index) => {
212
+ if (index !== lastAssistantIndex) {
213
+ return msg;
214
+ }
215
+ // This is the last assistant message - add cache_control
216
+ const content = msg.content;
217
+ if (typeof content === "string") {
218
+ // Convert string to block format with cache_control
219
+ return {
220
+ role: msg.role,
221
+ content: [
222
+ {
223
+ type: "text",
224
+ text: content,
225
+ cache_control: { type: "ephemeral" },
226
+ },
227
+ ],
228
+ };
229
+ }
230
+ if (Array.isArray(content) && content.length > 0) {
231
+ // Add cache_control to the last block
232
+ const newContent = content.map((block, blockIndex) => {
233
+ if (blockIndex === content.length - 1) {
234
+ return { ...block, cache_control: { type: "ephemeral" } };
235
+ }
236
+ return block;
237
+ });
238
+ return { role: msg.role, content: newContent };
239
+ }
240
+ return msg;
241
+ });
242
+ return cached;
243
+ }
244
+ }
245
+ exports.ConversationManager = ConversationManager;
246
+ //# sourceMappingURL=conversation-manager.js.map
@@ -0,0 +1,9 @@
1
+ export { ConversationManager } from './conversation-manager';
2
+ export { MessageClassifier } from './message-classifier';
3
+ export { MessageFormatterService } from './message-formatter';
4
+ export { TypingIndicatorService } from './typing-indicator';
5
+ export { TokenBillingService } from './token-billing';
6
+ export { SessionLoggerService } from './session-logger';
7
+ export { WorkspaceSchemaCacheService } from './workspace-schema-cache';
8
+ export type { BotConnection, McpToolCallback } from './types';
9
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1,18 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.WorkspaceSchemaCacheService = exports.SessionLoggerService = exports.TokenBillingService = exports.TypingIndicatorService = exports.MessageFormatterService = exports.MessageClassifier = exports.ConversationManager = void 0;
4
+ var conversation_manager_1 = require("./conversation-manager");
5
+ Object.defineProperty(exports, "ConversationManager", { enumerable: true, get: function () { return conversation_manager_1.ConversationManager; } });
6
+ var message_classifier_1 = require("./message-classifier");
7
+ Object.defineProperty(exports, "MessageClassifier", { enumerable: true, get: function () { return message_classifier_1.MessageClassifier; } });
8
+ var message_formatter_1 = require("./message-formatter");
9
+ Object.defineProperty(exports, "MessageFormatterService", { enumerable: true, get: function () { return message_formatter_1.MessageFormatterService; } });
10
+ var typing_indicator_1 = require("./typing-indicator");
11
+ Object.defineProperty(exports, "TypingIndicatorService", { enumerable: true, get: function () { return typing_indicator_1.TypingIndicatorService; } });
12
+ var token_billing_1 = require("./token-billing");
13
+ Object.defineProperty(exports, "TokenBillingService", { enumerable: true, get: function () { return token_billing_1.TokenBillingService; } });
14
+ var session_logger_1 = require("./session-logger");
15
+ Object.defineProperty(exports, "SessionLoggerService", { enumerable: true, get: function () { return session_logger_1.SessionLoggerService; } });
16
+ var workspace_schema_cache_1 = require("./workspace-schema-cache");
17
+ Object.defineProperty(exports, "WorkspaceSchemaCacheService", { enumerable: true, get: function () { return workspace_schema_cache_1.WorkspaceSchemaCacheService; } });
18
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1,42 @@
1
+ /**
2
+ * Message Classifier Service
3
+ *
4
+ * Handles incoming message extraction and classification:
5
+ * - Extracts message content from Hailer signals
6
+ * - Classifies message priority (high/normal)
7
+ * - Detects mentions, replies, and DMs
8
+ */
9
+ import { Logger } from "../../lib/logger";
10
+ import { HailerSignal } from "../../mcp/signal-handler";
11
+ import { BotConnection, IncomingMessage, HailerMessage } from "./types";
12
+ export declare class MessageClassifier {
13
+ private botUserId;
14
+ private botConnection;
15
+ private logger;
16
+ private mentionPattern;
17
+ constructor(botUserId: string, botConnection: BotConnection, logger: Logger);
18
+ /**
19
+ * Extract and classify incoming message from signal
20
+ */
21
+ extractIncomingMessage(signal: HailerSignal): Promise<IncomingMessage | null>;
22
+ /**
23
+ * Check if message mentions this bot
24
+ * Uses pre-compiled regex pattern for performance
25
+ */
26
+ checkMention(content: string): boolean;
27
+ /**
28
+ * Check if message is a reply to one of our messages using pre-fetched messages.
29
+ * Avoids a redundant API call by reusing the messages already fetched in extractIncomingMessage.
30
+ */
31
+ checkReplyInMessages(messages: HailerMessage[], messageId: string): boolean;
32
+ /**
33
+ * Check if this is a 1:1 DM with the bot using pre-loaded discussion data.
34
+ * Avoids a redundant API call by reusing discussion data already fetched in extractIncomingMessage.
35
+ */
36
+ checkDirectMessageFromData(discData: any, senderId: string): boolean;
37
+ /**
38
+ * Check if this is a 1:1 DM with the bot (fallback - fetches discussion from API)
39
+ */
40
+ checkDirectMessage(discussionId: string, senderId: string): Promise<boolean>;
41
+ }
42
+ //# sourceMappingURL=message-classifier.d.ts.map