@hailer/mcp 0.0.1

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 (163) hide show
  1. package/.claude/commands/tool-builder.md +37 -0
  2. package/.claude/commands/ws-pull.md +44 -0
  3. package/.claude/settings.json +8 -0
  4. package/.claude/settings.local.json +49 -0
  5. package/.claude/skills/activity-api/SKILL.md +96 -0
  6. package/.claude/skills/activity-api/references/activity-endpoints.md +845 -0
  7. package/.claude/skills/add-app-member-skill/SKILL.md +977 -0
  8. package/.claude/skills/agent-building/SKILL.md +243 -0
  9. package/.claude/skills/agent-building/references/architecture-patterns.md +446 -0
  10. package/.claude/skills/agent-building/references/code-examples.md +587 -0
  11. package/.claude/skills/agent-building/references/implementation-guide.md +619 -0
  12. package/.claude/skills/app-api/SKILL.md +219 -0
  13. package/.claude/skills/app-api/references/app-endpoints.md +759 -0
  14. package/.claude/skills/building-hailer-apps-skill/SKILL.md +548 -0
  15. package/.claude/skills/create-app-skill/SKILL.md +1101 -0
  16. package/.claude/skills/create-insight-skill/SKILL.md +1317 -0
  17. package/.claude/skills/get-insight-data-skill/SKILL.md +1053 -0
  18. package/.claude/skills/hailer-api/SKILL.md +283 -0
  19. package/.claude/skills/hailer-api/references/activities.md +620 -0
  20. package/.claude/skills/hailer-api/references/authentication.md +216 -0
  21. package/.claude/skills/hailer-api/references/datasets.md +437 -0
  22. package/.claude/skills/hailer-api/references/files.md +301 -0
  23. package/.claude/skills/hailer-api/references/insights.md +469 -0
  24. package/.claude/skills/hailer-api/references/workflows.md +720 -0
  25. package/.claude/skills/hailer-api/references/workspaces-users.md +445 -0
  26. package/.claude/skills/insight-api/SKILL.md +185 -0
  27. package/.claude/skills/insight-api/references/insight-endpoints.md +514 -0
  28. package/.claude/skills/install-workflow-skill/SKILL.md +1056 -0
  29. package/.claude/skills/list-apps-skill/SKILL.md +1010 -0
  30. package/.claude/skills/list-workflows-minimal-skill/SKILL.md +992 -0
  31. package/.claude/skills/local-first-skill/SKILL.md +570 -0
  32. package/.claude/skills/mcp-tools/SKILL.md +419 -0
  33. package/.claude/skills/mcp-tools/references/api-endpoints.md +499 -0
  34. package/.claude/skills/mcp-tools/references/data-structures.md +554 -0
  35. package/.claude/skills/mcp-tools/references/implementation-patterns.md +717 -0
  36. package/.claude/skills/preview-insight-skill/SKILL.md +1290 -0
  37. package/.claude/skills/publish-hailer-app-skill/SKILL.md +453 -0
  38. package/.claude/skills/remove-app-member-skill/SKILL.md +671 -0
  39. package/.claude/skills/remove-app-skill/SKILL.md +985 -0
  40. package/.claude/skills/remove-insight-skill/SKILL.md +1011 -0
  41. package/.claude/skills/remove-workflow-skill/SKILL.md +920 -0
  42. package/.claude/skills/scaffold-hailer-app-skill/SKILL.md +1034 -0
  43. package/.claude/skills/skill-testing/README.md +137 -0
  44. package/.claude/skills/skill-testing/SKILL.md +348 -0
  45. package/.claude/skills/skill-testing/references/test-patterns.md +705 -0
  46. package/.claude/skills/skill-testing/references/testing-guide.md +603 -0
  47. package/.claude/skills/skill-testing/references/validation-checklist.md +537 -0
  48. package/.claude/skills/tool-builder/SKILL.md +328 -0
  49. package/.claude/skills/update-app-skill/SKILL.md +970 -0
  50. package/.claude/skills/update-workflow-field-skill/SKILL.md +1098 -0
  51. package/.env.example +81 -0
  52. package/.mcp.json +13 -0
  53. package/README.md +297 -0
  54. package/dist/app.d.ts +4 -0
  55. package/dist/app.js +74 -0
  56. package/dist/cli.d.ts +3 -0
  57. package/dist/cli.js +5 -0
  58. package/dist/client/adaptive-documentation-bot.d.ts +108 -0
  59. package/dist/client/adaptive-documentation-bot.js +475 -0
  60. package/dist/client/adaptive-documentation-types.d.ts +66 -0
  61. package/dist/client/adaptive-documentation-types.js +9 -0
  62. package/dist/client/agent-activity-bot.d.ts +51 -0
  63. package/dist/client/agent-activity-bot.js +166 -0
  64. package/dist/client/agent-tracker.d.ts +499 -0
  65. package/dist/client/agent-tracker.js +659 -0
  66. package/dist/client/description-updater.d.ts +56 -0
  67. package/dist/client/description-updater.js +259 -0
  68. package/dist/client/log-parser.d.ts +72 -0
  69. package/dist/client/log-parser.js +387 -0
  70. package/dist/client/mcp-client.d.ts +50 -0
  71. package/dist/client/mcp-client.js +532 -0
  72. package/dist/client/message-processor.d.ts +35 -0
  73. package/dist/client/message-processor.js +352 -0
  74. package/dist/client/multi-bot-manager.d.ts +24 -0
  75. package/dist/client/multi-bot-manager.js +74 -0
  76. package/dist/client/providers/anthropic-provider.d.ts +19 -0
  77. package/dist/client/providers/anthropic-provider.js +631 -0
  78. package/dist/client/providers/llm-provider.d.ts +47 -0
  79. package/dist/client/providers/llm-provider.js +367 -0
  80. package/dist/client/providers/openai-provider.d.ts +23 -0
  81. package/dist/client/providers/openai-provider.js +621 -0
  82. package/dist/client/simple-llm-caller.d.ts +19 -0
  83. package/dist/client/simple-llm-caller.js +100 -0
  84. package/dist/client/skill-generator.d.ts +81 -0
  85. package/dist/client/skill-generator.js +386 -0
  86. package/dist/client/test-adaptive-bot.d.ts +9 -0
  87. package/dist/client/test-adaptive-bot.js +82 -0
  88. package/dist/client/token-pricing.d.ts +38 -0
  89. package/dist/client/token-pricing.js +127 -0
  90. package/dist/client/token-tracker.d.ts +232 -0
  91. package/dist/client/token-tracker.js +457 -0
  92. package/dist/client/token-usage-bot.d.ts +53 -0
  93. package/dist/client/token-usage-bot.js +153 -0
  94. package/dist/client/tool-executor.d.ts +69 -0
  95. package/dist/client/tool-executor.js +159 -0
  96. package/dist/client/tool-schema-loader.d.ts +60 -0
  97. package/dist/client/tool-schema-loader.js +178 -0
  98. package/dist/client/types.d.ts +69 -0
  99. package/dist/client/types.js +7 -0
  100. package/dist/config.d.ts +162 -0
  101. package/dist/config.js +296 -0
  102. package/dist/core.d.ts +26 -0
  103. package/dist/core.js +147 -0
  104. package/dist/lib/context-manager.d.ts +111 -0
  105. package/dist/lib/context-manager.js +431 -0
  106. package/dist/lib/logger.d.ts +74 -0
  107. package/dist/lib/logger.js +277 -0
  108. package/dist/lib/materialize.d.ts +3 -0
  109. package/dist/lib/materialize.js +101 -0
  110. package/dist/lib/normalizedName.d.ts +7 -0
  111. package/dist/lib/normalizedName.js +48 -0
  112. package/dist/lib/prompt-length-manager.d.ts +81 -0
  113. package/dist/lib/prompt-length-manager.js +457 -0
  114. package/dist/lib/terminal-prompt.d.ts +9 -0
  115. package/dist/lib/terminal-prompt.js +108 -0
  116. package/dist/mcp/UserContextCache.d.ts +56 -0
  117. package/dist/mcp/UserContextCache.js +163 -0
  118. package/dist/mcp/auth.d.ts +2 -0
  119. package/dist/mcp/auth.js +29 -0
  120. package/dist/mcp/hailer-clients.d.ts +42 -0
  121. package/dist/mcp/hailer-clients.js +246 -0
  122. package/dist/mcp/signal-handler.d.ts +45 -0
  123. package/dist/mcp/signal-handler.js +317 -0
  124. package/dist/mcp/tool-registry.d.ts +100 -0
  125. package/dist/mcp/tool-registry.js +306 -0
  126. package/dist/mcp/tools/activity.d.ts +15 -0
  127. package/dist/mcp/tools/activity.js +955 -0
  128. package/dist/mcp/tools/app.d.ts +20 -0
  129. package/dist/mcp/tools/app.js +1488 -0
  130. package/dist/mcp/tools/discussion.d.ts +19 -0
  131. package/dist/mcp/tools/discussion.js +950 -0
  132. package/dist/mcp/tools/file.d.ts +15 -0
  133. package/dist/mcp/tools/file.js +119 -0
  134. package/dist/mcp/tools/insight.d.ts +17 -0
  135. package/dist/mcp/tools/insight.js +806 -0
  136. package/dist/mcp/tools/skill.d.ts +10 -0
  137. package/dist/mcp/tools/skill.js +279 -0
  138. package/dist/mcp/tools/user.d.ts +10 -0
  139. package/dist/mcp/tools/user.js +108 -0
  140. package/dist/mcp/tools/workflow-template.d.ts +19 -0
  141. package/dist/mcp/tools/workflow-template.js +822 -0
  142. package/dist/mcp/tools/workflow.d.ts +18 -0
  143. package/dist/mcp/tools/workflow.js +1362 -0
  144. package/dist/mcp/utils/api-errors.d.ts +45 -0
  145. package/dist/mcp/utils/api-errors.js +160 -0
  146. package/dist/mcp/utils/data-transformers.d.ts +102 -0
  147. package/dist/mcp/utils/data-transformers.js +194 -0
  148. package/dist/mcp/utils/file-upload.d.ts +33 -0
  149. package/dist/mcp/utils/file-upload.js +148 -0
  150. package/dist/mcp/utils/hailer-api-client.d.ts +120 -0
  151. package/dist/mcp/utils/hailer-api-client.js +323 -0
  152. package/dist/mcp/utils/index.d.ts +13 -0
  153. package/dist/mcp/utils/index.js +39 -0
  154. package/dist/mcp/utils/logger.d.ts +42 -0
  155. package/dist/mcp/utils/logger.js +103 -0
  156. package/dist/mcp/utils/types.d.ts +286 -0
  157. package/dist/mcp/utils/types.js +7 -0
  158. package/dist/mcp/workspace-cache.d.ts +42 -0
  159. package/dist/mcp/workspace-cache.js +97 -0
  160. package/dist/mcp-server.d.ts +42 -0
  161. package/dist/mcp-server.js +280 -0
  162. package/package.json +56 -0
  163. package/tsconfig.json +23 -0
@@ -0,0 +1,457 @@
1
+ "use strict";
2
+ /**
3
+ * Prompt Length Manager
4
+ * Handles prompt length validation, truncation, and debugging
5
+ */
6
+ Object.defineProperty(exports, "__esModule", { value: true });
7
+ exports.promptLengthManager = exports.PromptLengthManager = exports.DEFAULT_TRUNCATION_CONFIG = void 0;
8
+ const logger_1 = require("./logger");
9
+ exports.DEFAULT_TRUNCATION_CONFIG = {
10
+ // Claude 4 optimized limits (leaving room for response)
11
+ maxTotalTokens: 150_000, // 150k tokens for Claude 4
12
+ maxUserMessagesTokens: 20_000, // 20k tokens for user messages
13
+ // Character limits (fallback: 1 token ā‰ˆ 4 characters)
14
+ maxTotalCharacters: 600_000, // ~150k tokens
15
+ maxUserMessagesCharacters: 80_000, // ~20k tokens
16
+ // Provider context windows (in tokens)
17
+ anthropicContextWindow: 200_000, // Claude Sonnet 4
18
+ openaiContextWindow: 128_000, // GPT-4 Turbo
19
+ // New smart truncation strategy
20
+ preserveSystemPrompt: true, // Never truncate system prompts
21
+ preserveUserMessages: true, // Preserve up to 20k tokens
22
+ preserveAssistantResponses: true, // Preserve when possible
23
+ truncateToolResponsesFirst: true, // Tool responses are most expendable
24
+ };
25
+ class PromptLengthManager {
26
+ logger;
27
+ config;
28
+ constructor(config = {}) {
29
+ this.config = { ...exports.DEFAULT_TRUNCATION_CONFIG, ...config };
30
+ this.logger = (0, logger_1.createLogger)({ component: "PromptLengthManager" });
31
+ }
32
+ /**
33
+ * Estimate token count from character count
34
+ * Rough approximation: 1 token ā‰ˆ 4 characters for English text
35
+ */
36
+ estimateTokens(text) {
37
+ return Math.ceil(text.length / 4);
38
+ }
39
+ /**
40
+ * Count exact characters and estimate tokens for a text
41
+ */
42
+ analyzeText(text) {
43
+ const characters = text.length;
44
+ const estimatedTokens = this.estimateTokens(text);
45
+ return { characters, estimatedTokens };
46
+ }
47
+ /**
48
+ * Truncate text intelligently, preserving structure when possible
49
+ */
50
+ truncateText(text, maxLength, source) {
51
+ if (text.length <= maxLength) {
52
+ return { text, truncated: false };
53
+ }
54
+ // Try to truncate at natural boundaries (paragraphs, sentences)
55
+ const truncated = text.substring(0, maxLength);
56
+ // Find last complete sentence or paragraph
57
+ const lastParagraph = truncated.lastIndexOf('\n\n');
58
+ const lastSentence = truncated.lastIndexOf('. ');
59
+ let cutPoint = maxLength;
60
+ let truncationMethod = 'hard_cutoff';
61
+ if (lastParagraph > maxLength * 0.7) {
62
+ cutPoint = lastParagraph;
63
+ truncationMethod = 'paragraph_boundary';
64
+ }
65
+ else if (lastSentence > maxLength * 0.8) {
66
+ cutPoint = lastSentence + 1;
67
+ truncationMethod = 'sentence_boundary';
68
+ }
69
+ const finalText = text.substring(0, cutPoint) + '\n\n[... Content truncated ...]';
70
+ const removedContent = text.substring(cutPoint);
71
+ this.logger.warn(`Truncated ${source}`, {
72
+ originalLength: text.length,
73
+ truncatedLength: finalText.length,
74
+ truncatedAt: cutPoint,
75
+ truncationMethod,
76
+ removedCharacters: removedContent.length,
77
+ reductionPercent: Math.round((1 - finalText.length / text.length) * 100),
78
+ source,
79
+ removedContentPreview: removedContent.substring(0, 200) + (removedContent.length > 200 ? '...' : ''),
80
+ originalContentPreview: text.substring(0, 200) + (text.length > 200 ? '...' : '')
81
+ });
82
+ return {
83
+ text: finalText,
84
+ truncated: true,
85
+ truncatedAt: cutPoint,
86
+ truncationMethod,
87
+ originalContent: text
88
+ };
89
+ }
90
+ /**
91
+ * Analyze prompt components and build analysis
92
+ */
93
+ analyzePrompt(components) {
94
+ let totalCharacters = 0;
95
+ let totalTokens = 0;
96
+ const warnings = [];
97
+ const processedComponents = [];
98
+ for (const component of components) {
99
+ const analysis = this.analyzeText(component.content);
100
+ totalCharacters += analysis.characters;
101
+ totalTokens += analysis.estimatedTokens;
102
+ processedComponents.push({
103
+ ...component,
104
+ originalLength: analysis.characters,
105
+ });
106
+ // TRUNCATION WARNINGS TEMPORARILY DISABLED FOR TESTING
107
+ /* COMMENTED OUT - RE-ENABLE BY UNCOMMENTING THIS BLOCK
108
+ // Check component token limits under new system
109
+ const componentTokens = this.estimateTokens(component.content);
110
+
111
+ if (component.type === 'user' && componentTokens > this.config.maxUserMessagesTokens) {
112
+ warnings.push(`User message (${componentTokens} tokens) exceeds user message limit (${this.config.maxUserMessagesTokens} tokens)`);
113
+ }
114
+
115
+ // Note: No individual limits for system prompts or tool responses under new logic
116
+ */ // END OF COMMENTED OUT WARNING LOGIC
117
+ }
118
+ // TOTAL TOKEN LIMIT WARNINGS TEMPORARILY DISABLED FOR TESTING
119
+ /* COMMENTED OUT - RE-ENABLE BY UNCOMMENTING THIS BLOCK
120
+ // Check total token limits (primary check under new system)
121
+ if (totalTokens > this.config.maxTotalTokens) {
122
+ warnings.push(`Total prompt (${totalTokens} tokens) exceeds Claude 4 limit (${this.config.maxTotalTokens} tokens)`);
123
+ }
124
+ */ // END OF COMMENTED OUT WARNING LOGIC
125
+ return {
126
+ totalCharacters,
127
+ estimatedTokens: totalTokens,
128
+ components: processedComponents,
129
+ truncationApplied: false,
130
+ warnings,
131
+ };
132
+ }
133
+ /**
134
+ * No longer truncate individual tool responses - only when total prompt exceeds limits
135
+ * This method now just passes through content unchanged and logs for monitoring
136
+ * TEMPORARILY DISABLED - Even monitoring/logging is disabled
137
+ */
138
+ truncateToolResponse(content, toolName) {
139
+ // TRUNCATION AND MONITORING TEMPORARILY DISABLED FOR TESTING
140
+ return content; // Pass through unchanged with no logging
141
+ /* COMMENTED OUT - RE-ENABLE BY UNCOMMENTING THIS BLOCK
142
+ this.logger.debug(`Tool response processed (no individual limits)`, {
143
+ toolName,
144
+ length: content.length,
145
+ estimatedTokens: this.estimateTokens(content),
146
+ note: "Individual tool limits removed - truncation only happens at total prompt level"
147
+ });
148
+
149
+ return content; // Pass through unchanged
150
+ */ // END OF COMMENTED OUT MONITORING LOGIC
151
+ }
152
+ /**
153
+ * Apply smart token-based truncation optimized for Claude 4
154
+ * TEMPORARILY DISABLED - All truncation logic commented out for testing
155
+ */
156
+ truncatePrompt(analysis) {
157
+ // TRUNCATION TEMPORARILY DISABLED FOR TESTING
158
+ this.logger.info("Truncation is temporarily disabled - returning prompt unchanged", {
159
+ originalTokens: analysis.estimatedTokens,
160
+ originalChars: analysis.totalCharacters,
161
+ tokenLimit: this.config.maxTotalTokens,
162
+ status: "DISABLED"
163
+ });
164
+ return analysis;
165
+ /* COMMENTED OUT - RE-ENABLE BY UNCOMMENTING THIS BLOCK
166
+ if (analysis.estimatedTokens <= this.config.maxTotalTokens) {
167
+ return analysis; // No truncation needed
168
+ }
169
+
170
+ const targetTokenReduction = analysis.estimatedTokens - this.config.maxTotalTokens;
171
+
172
+ this.logger.warn("Applying Claude 4 optimized prompt truncation", {
173
+ originalTokens: analysis.estimatedTokens,
174
+ originalChars: analysis.totalCharacters,
175
+ tokenLimit: this.config.maxTotalTokens,
176
+ targetTokenReduction,
177
+ truncationStrategy: "claude_4_smart_preservation"
178
+ });
179
+
180
+ // Track unknown component types for debugging
181
+ const knownTypes = new Set(['system', 'user', 'assistant', 'tool_result', 'tool_call']);
182
+ const unknownComponents = analysis.components.filter(c => !knownTypes.has(c.type));
183
+ if (unknownComponents.length > 0) {
184
+ this.logger.info("Unknown prompt component types detected", {
185
+ unknownTypes: unknownComponents.map(c => ({ type: c.type, source: c.source, length: c.content.length })),
186
+ count: unknownComponents.length
187
+ });
188
+ }
189
+
190
+ // Separate components by type for smart preservation
191
+ const systemComponents = analysis.components.filter(c => c.type === 'system');
192
+ const userComponents = analysis.components.filter(c => c.type === 'user');
193
+ const assistantComponents = analysis.components.filter(c => c.type === 'assistant' || c.type === 'tool_call');
194
+ const toolComponents = analysis.components.filter(c => c.type === 'tool_result');
195
+ const otherComponents = analysis.components.filter(c => !knownTypes.has(c.type));
196
+
197
+ // Calculate current token usage by component type
198
+ const systemTokens = systemComponents.reduce((sum, c) => sum + this.estimateTokens(c.content), 0);
199
+ const userTokens = userComponents.reduce((sum, c) => sum + this.estimateTokens(c.content), 0);
200
+ const assistantTokens = assistantComponents.reduce((sum, c) => sum + this.estimateTokens(c.content), 0);
201
+ const toolTokens = toolComponents.reduce((sum, c) => sum + this.estimateTokens(c.content), 0);
202
+ const otherTokens = otherComponents.reduce((sum, c) => sum + this.estimateTokens(c.content), 0);
203
+
204
+ this.logger.info("Component token breakdown", {
205
+ system: `${systemTokens} tokens (${systemComponents.length} components) - PRESERVED`,
206
+ user: `${userTokens} tokens (${userComponents.length} components) - PRESERVE UP TO 20k`,
207
+ assistant: `${assistantTokens} tokens (${assistantComponents.length} components) - PRESERVE WHEN POSSIBLE`,
208
+ tool_result: `${toolTokens} tokens (${toolComponents.length} components) - TRUNCATE FIRST`,
209
+ other: `${otherTokens} tokens (${otherComponents.length} components) - UNKNOWN TYPE`
210
+ });
211
+
212
+ const truncatedComponents: PromptComponent[] = [];
213
+ let tokensUsed = 0;
214
+ let tokensReduced = 0;
215
+
216
+ // Step 1: Always preserve system prompts (100%)
217
+ systemComponents.forEach(component => {
218
+ truncatedComponents.push({ ...component });
219
+ tokensUsed += this.estimateTokens(component.content);
220
+ });
221
+
222
+ // Step 2: Preserve user messages up to 20k tokens
223
+ let userTokensUsed = 0;
224
+ userComponents.forEach(component => {
225
+ const componentTokens = this.estimateTokens(component.content);
226
+ if (userTokensUsed + componentTokens <= this.config.maxUserMessagesTokens) {
227
+ // Keep this user message fully
228
+ truncatedComponents.push({ ...component });
229
+ tokensUsed += componentTokens;
230
+ userTokensUsed += componentTokens;
231
+ } else if (userTokensUsed < this.config.maxUserMessagesTokens) {
232
+ // Partial truncation to fit within user message limit
233
+ const allowedTokens = this.config.maxUserMessagesTokens - userTokensUsed;
234
+ const allowedChars = Math.floor(allowedTokens * 4); // Approximate conversion
235
+
236
+ const result = this.truncateText(component.content, allowedChars, component.source || 'user_message');
237
+ truncatedComponents.push({
238
+ ...component,
239
+ content: result.text,
240
+ truncated: result.truncated,
241
+ originalContent: result.originalContent,
242
+ truncatedAt: result.truncatedAt,
243
+ truncationReason: `User message truncated to fit within ${this.config.maxUserMessagesTokens} token limit for user messages`
244
+ });
245
+
246
+ const actualTokens = this.estimateTokens(result.text);
247
+ tokensUsed += actualTokens;
248
+ userTokensUsed += actualTokens;
249
+ tokensReduced += componentTokens - actualTokens;
250
+
251
+ if (result.truncated) {
252
+ this.logger.warn("User message truncated to fit limit", {
253
+ componentSource: component.source,
254
+ originalTokens: componentTokens,
255
+ truncatedTokens: actualTokens,
256
+ userTokenLimit: this.config.maxUserMessagesTokens
257
+ });
258
+ }
259
+ }
260
+ // Skip user messages that don't fit in the 20k limit
261
+ });
262
+
263
+ // Step 3: Add assistant responses if we have room
264
+ assistantComponents.forEach(component => {
265
+ const componentTokens = this.estimateTokens(component.content);
266
+ if (tokensUsed + componentTokens <= this.config.maxTotalTokens - targetTokenReduction) {
267
+ truncatedComponents.push({ ...component });
268
+ tokensUsed += componentTokens;
269
+ }
270
+ // Skip assistant messages if no room
271
+ });
272
+
273
+ // Step 4: Add tool responses with truncation if needed
274
+ const remainingTokenBudget = this.config.maxTotalTokens - tokensUsed;
275
+ let toolBudgetUsed = 0;
276
+
277
+ toolComponents.forEach(component => {
278
+ const componentTokens = this.estimateTokens(component.content);
279
+
280
+ if (toolBudgetUsed + componentTokens <= remainingTokenBudget) {
281
+ // Tool response fits fully
282
+ truncatedComponents.push({ ...component });
283
+ tokensUsed += componentTokens;
284
+ toolBudgetUsed += componentTokens;
285
+ } else if (toolBudgetUsed < remainingTokenBudget) {
286
+ // Partial truncation of tool response
287
+ const allowedTokens = remainingTokenBudget - toolBudgetUsed;
288
+ const allowedChars = Math.floor(allowedTokens * 4);
289
+
290
+ const result = this.truncateText(component.content, allowedChars, component.source || 'tool_result');
291
+ truncatedComponents.push({
292
+ ...component,
293
+ content: result.text,
294
+ truncated: result.truncated,
295
+ originalContent: result.originalContent,
296
+ truncatedAt: result.truncatedAt,
297
+ truncationReason: `Tool response truncated to fit within ${this.config.maxTotalTokens} token total limit`
298
+ });
299
+
300
+ const actualTokens = this.estimateTokens(result.text);
301
+ tokensUsed += actualTokens;
302
+ toolBudgetUsed += actualTokens;
303
+ tokensReduced += componentTokens - actualTokens;
304
+
305
+ if (result.truncated) {
306
+ this.logger.warn("Tool response truncated", {
307
+ toolSource: component.source,
308
+ originalTokens: componentTokens,
309
+ truncatedTokens: actualTokens,
310
+ originalLength: component.content.length,
311
+ truncatedLength: result.text.length,
312
+ truncationMethod: result.truncationMethod,
313
+ truncatedAt: result.truncatedAt
314
+ });
315
+ }
316
+ }
317
+ // Skip tool responses that don't fit
318
+ });
319
+
320
+ // Step 5: Handle unknown component types
321
+ otherComponents.forEach(component => {
322
+ this.logger.warn("Unknown component type in prompt", {
323
+ type: component.type,
324
+ source: component.source,
325
+ length: component.content.length,
326
+ tokens: this.estimateTokens(component.content),
327
+ note: "Added to debug page for analysis"
328
+ });
329
+
330
+ // Add to debug but don't include in prompt for now
331
+ truncatedComponents.push({
332
+ ...component,
333
+ truncationReason: `Unknown component type '${component.type}' - review on debug page`
334
+ });
335
+ });
336
+
337
+ const finalTokens = this.estimateTokens(truncatedComponents.map(c => c.content).join(''));
338
+
339
+ return {
340
+ totalCharacters: truncatedComponents.reduce((sum, c) => sum + c.content.length, 0),
341
+ estimatedTokens: finalTokens,
342
+ components: truncatedComponents,
343
+ truncationApplied: tokensReduced > 0,
344
+ warnings: [
345
+ ...analysis.warnings,
346
+ `Applied Claude 4 smart truncation: reduced by ${tokensReduced} tokens (${Math.round(tokensReduced / analysis.estimatedTokens * 100)}%)`,
347
+ `Preservation strategy: System (100%) → User (up to 20k tokens) → Assistant → Tools`,
348
+ `Final prompt: ${finalTokens.toLocaleString()} tokens (limit: ${this.config.maxTotalTokens.toLocaleString()})`
349
+ ],
350
+ };
351
+ */ // END OF COMMENTED OUT TRUNCATION LOGIC
352
+ }
353
+ /**
354
+ * Check if a provider-specific error indicates prompt too long
355
+ */
356
+ isPromptTooLongError(error, provider) {
357
+ const errorMessage = error.message.toLowerCase();
358
+ if (provider === 'anthropic') {
359
+ return errorMessage.includes('prompt too long') ||
360
+ errorMessage.includes('maximum context length') ||
361
+ errorMessage.includes('context_length_exceeded') ||
362
+ errorMessage.includes('token limit exceeded');
363
+ }
364
+ if (provider === 'openai') {
365
+ return errorMessage.includes('maximum context length') ||
366
+ errorMessage.includes('context_length_exceeded') ||
367
+ errorMessage.includes('token limit exceeded') ||
368
+ errorMessage.includes('reduce the length');
369
+ }
370
+ return false;
371
+ }
372
+ /**
373
+ * Log comprehensive debug information about prompt structure
374
+ */
375
+ logPromptDebugInfo(analysis, provider, botId) {
376
+ const debugData = {
377
+ provider,
378
+ botId,
379
+ summary: {
380
+ totalCharacters: analysis.totalCharacters,
381
+ estimatedTokens: analysis.estimatedTokens,
382
+ componentCount: analysis.components.length,
383
+ truncationApplied: analysis.truncationApplied,
384
+ warningCount: analysis.warnings.length,
385
+ },
386
+ breakdown: analysis.components.map(comp => ({
387
+ type: comp.type,
388
+ source: comp.source,
389
+ currentLength: comp.content.length,
390
+ originalLength: comp.originalLength || comp.content.length,
391
+ truncated: comp.truncated,
392
+ reductionPercent: comp.originalLength ?
393
+ Math.round((1 - comp.content.length / comp.originalLength) * 100) : 0,
394
+ estimatedTokens: this.estimateTokens(comp.content),
395
+ // First 100 chars as preview (for debugging)
396
+ preview: comp.content.substring(0, 100) + (comp.content.length > 100 ? '...' : ''),
397
+ })),
398
+ warnings: analysis.warnings,
399
+ };
400
+ this.logger.info("Prompt debug analysis", debugData);
401
+ // Enhanced truncation logging
402
+ const truncatedComponents = analysis.components.filter(c => c.truncated);
403
+ if (truncatedComponents.length > 0) {
404
+ this.logger.warn("Component truncation summary", {
405
+ truncatedCount: truncatedComponents.length,
406
+ totalComponents: analysis.components.length,
407
+ truncations: truncatedComponents.map(comp => ({
408
+ type: comp.type,
409
+ source: comp.source,
410
+ originalChars: comp.originalLength,
411
+ truncatedChars: comp.content.length,
412
+ savedChars: (comp.originalLength || comp.content.length) - comp.content.length,
413
+ reductionPercent: comp.originalLength ?
414
+ Math.round((1 - comp.content.length / comp.originalLength) * 100) : 0,
415
+ }))
416
+ });
417
+ }
418
+ // Log full prompt to separate file if it was truncated or has warnings
419
+ if (analysis.truncationApplied || analysis.warnings.length > 0) {
420
+ this.logger.warn("Prompt required attention", {
421
+ reason: analysis.truncationApplied ? 'truncation' : 'warnings',
422
+ fullPrompt: analysis.components.map(c => `=== ${c.type.toUpperCase()} (${c.source || 'unknown'}) ===\n${c.content}`).join('\n\n'),
423
+ });
424
+ }
425
+ }
426
+ /**
427
+ * Generate a quick truncation summary for debugging
428
+ */
429
+ generateTruncationSummary(analysis) {
430
+ const totalOriginal = analysis.components.reduce((sum, comp) => sum + (comp.originalLength || comp.content.length), 0);
431
+ const totalCurrent = analysis.totalCharacters;
432
+ const totalSaved = totalOriginal - totalCurrent;
433
+ const overallReduction = totalOriginal > 0 ? Math.round((totalSaved / totalOriginal) * 100) : 0;
434
+ const truncatedComponents = analysis.components.filter(c => c.truncated);
435
+ let summary = `Prompt Summary: ${totalCurrent.toLocaleString()} chars (${analysis.estimatedTokens.toLocaleString()} tokens)`;
436
+ if (totalSaved > 0) {
437
+ summary += `\nTruncation Applied: Saved ${totalSaved.toLocaleString()} chars (${overallReduction}% reduction)`;
438
+ summary += `\nTruncated Components: ${truncatedComponents.length}/${analysis.components.length}`;
439
+ if (truncatedComponents.length > 0) {
440
+ summary += `\nBreakdown:`;
441
+ truncatedComponents.forEach(comp => {
442
+ const saved = (comp.originalLength || comp.content.length) - comp.content.length;
443
+ const percent = comp.originalLength ? Math.round((saved / comp.originalLength) * 100) : 0;
444
+ summary += `\n - ${comp.type} (${comp.source}): ${saved.toLocaleString()} chars saved (${percent}%)`;
445
+ });
446
+ }
447
+ }
448
+ else {
449
+ summary += `\nNo truncation applied`;
450
+ }
451
+ return summary;
452
+ }
453
+ }
454
+ exports.PromptLengthManager = PromptLengthManager;
455
+ // Export a default instance
456
+ exports.promptLengthManager = new PromptLengthManager();
457
+ //# sourceMappingURL=prompt-length-manager.js.map
@@ -0,0 +1,9 @@
1
+ export interface TerminalPrompts {
2
+ email: string;
3
+ password: string;
4
+ }
5
+ /**
6
+ * Prompts user for email and password in terminal
7
+ */
8
+ export declare function promptForCredentials(): Promise<TerminalPrompts>;
9
+ //# sourceMappingURL=terminal-prompt.d.ts.map
@@ -0,0 +1,108 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.promptForCredentials = promptForCredentials;
37
+ const readline = __importStar(require("readline"));
38
+ const logger_1 = require("./logger");
39
+ const logger = (0, logger_1.createLogger)({ component: 'terminal-prompt' });
40
+ /**
41
+ * Prompts user for email and password in terminal
42
+ */
43
+ function promptForCredentials() {
44
+ return new Promise((resolve, reject) => {
45
+ const rl = readline.createInterface({
46
+ input: process.stdin,
47
+ output: process.stdout
48
+ });
49
+ logger.info('Prompting for Hailer credentials in Claude Code mode');
50
+ console.log(`\nšŸ” Please enter bot's or your own Hailer credentials. The Claude Code will use the account to access production data on Hailer.`);
51
+ rl.question('Email: ', (email) => {
52
+ if (!email.trim()) {
53
+ logger.error('Email validation failed: empty email provided');
54
+ console.log('āŒ Email cannot be empty');
55
+ rl.close();
56
+ reject(new Error('Email cannot be empty'));
57
+ return;
58
+ }
59
+ // Use a simple approach - just hide the password completely during input
60
+ rl.close();
61
+ process.stdout.write('Password: ');
62
+ // Disable echo temporarily
63
+ if (process.stdin.setRawMode) {
64
+ process.stdin.setRawMode(true);
65
+ }
66
+ process.stdin.resume();
67
+ process.stdin.setEncoding('utf8');
68
+ let password = '';
69
+ const cleanup = () => {
70
+ if (process.stdin.setRawMode) {
71
+ process.stdin.setRawMode(false);
72
+ }
73
+ process.stdin.pause();
74
+ };
75
+ process.stdin.on('data', function onData(char) {
76
+ const byte = char.charCodeAt(0);
77
+ if (byte === 3) { // Ctrl-C
78
+ cleanup();
79
+ process.stdin.removeListener('data', onData);
80
+ reject(new Error('Password input cancelled'));
81
+ return;
82
+ }
83
+ if (byte === 13 || byte === 10) { // Enter
84
+ cleanup();
85
+ process.stdin.removeListener('data', onData);
86
+ resolve({
87
+ email: email.trim(),
88
+ password: password.trim()
89
+ });
90
+ return;
91
+ }
92
+ if (byte === 127 || byte === 8) { // Backspace
93
+ if (password.length > 0) {
94
+ password = password.slice(0, -1);
95
+ process.stdout.write('\b \b'); // Move back, write space, move back again
96
+ }
97
+ return;
98
+ }
99
+ // Add character to password and show asterisk
100
+ if (byte >= 32) {
101
+ password += char;
102
+ process.stdout.write('*');
103
+ }
104
+ });
105
+ });
106
+ });
107
+ }
108
+ //# sourceMappingURL=terminal-prompt.js.map
@@ -0,0 +1,56 @@
1
+ import { HailerClient } from './hailer-clients';
2
+ import { WorkspaceCache } from './workspace-cache';
3
+ import { HailerV2CoreInitResponse, HailerApiClient } from './utils/index';
4
+ export interface UserContext {
5
+ client: HailerClient;
6
+ hailer: HailerApiClient;
7
+ init: HailerV2CoreInitResponse;
8
+ workspaceCache: WorkspaceCache;
9
+ apiKey: string;
10
+ createdAt: number;
11
+ }
12
+ /**
13
+ * Cache for user-specific data (client connections, init data, workspace cache)
14
+ *
15
+ * Replaces per-user ClassBasedToolManager instances with efficient caching:
16
+ * - Reuses shared connection pool from hailer-clients.ts
17
+ * - Caches user-specific data (init, workspaceCache) separately from tool logic
18
+ * - Used by both MCP Server and Client for consistent user context
19
+ */
20
+ export declare class UserContextCache {
21
+ private static cache;
22
+ /** Life of each cache unit. */
23
+ private static readonly DEFAULT_TTL_MS;
24
+ /**
25
+ * Get or create user context (client, init, workspaceCache) for an API key
26
+ * This data is user-specific and should be cached per user
27
+ *
28
+ * @param apiKey - Hailer API key for authentication
29
+ * @param forceRefresh - If true, bypasses cache and creates fresh context (useful for testing or after permission changes)
30
+ * @param ttlMs - Custom TTL in milliseconds, defaults to 15 minutes
31
+ */
32
+ static getContext(apiKey: string, forceRefresh?: boolean, ttlMs?: number): Promise<UserContext>;
33
+ /**
34
+ * Clear cache entry for specific API key (for cleanup/testing)
35
+ */
36
+ static clearContext(apiKey: string): void;
37
+ /**
38
+ * Clear all cached contexts (for cleanup/testing)
39
+ */
40
+ static clearAll(): void;
41
+ /**
42
+ * Get cache statistics (for monitoring and debugging)
43
+ *
44
+ * @returns Cache stats including size, API keys, and age information
45
+ */
46
+ static getCacheStats(): {
47
+ size: number;
48
+ apiKeys: string[];
49
+ entries: Array<{
50
+ apiKey: string;
51
+ ageMinutes: number;
52
+ isExpired: boolean;
53
+ }>;
54
+ };
55
+ }
56
+ //# sourceMappingURL=UserContextCache.d.ts.map