@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.
- package/.claude/commands/tool-builder.md +37 -0
- package/.claude/commands/ws-pull.md +44 -0
- package/.claude/settings.json +8 -0
- package/.claude/settings.local.json +49 -0
- package/.claude/skills/activity-api/SKILL.md +96 -0
- package/.claude/skills/activity-api/references/activity-endpoints.md +845 -0
- package/.claude/skills/add-app-member-skill/SKILL.md +977 -0
- package/.claude/skills/agent-building/SKILL.md +243 -0
- package/.claude/skills/agent-building/references/architecture-patterns.md +446 -0
- package/.claude/skills/agent-building/references/code-examples.md +587 -0
- package/.claude/skills/agent-building/references/implementation-guide.md +619 -0
- package/.claude/skills/app-api/SKILL.md +219 -0
- package/.claude/skills/app-api/references/app-endpoints.md +759 -0
- package/.claude/skills/building-hailer-apps-skill/SKILL.md +548 -0
- package/.claude/skills/create-app-skill/SKILL.md +1101 -0
- package/.claude/skills/create-insight-skill/SKILL.md +1317 -0
- package/.claude/skills/get-insight-data-skill/SKILL.md +1053 -0
- package/.claude/skills/hailer-api/SKILL.md +283 -0
- package/.claude/skills/hailer-api/references/activities.md +620 -0
- package/.claude/skills/hailer-api/references/authentication.md +216 -0
- package/.claude/skills/hailer-api/references/datasets.md +437 -0
- package/.claude/skills/hailer-api/references/files.md +301 -0
- package/.claude/skills/hailer-api/references/insights.md +469 -0
- package/.claude/skills/hailer-api/references/workflows.md +720 -0
- package/.claude/skills/hailer-api/references/workspaces-users.md +445 -0
- package/.claude/skills/insight-api/SKILL.md +185 -0
- package/.claude/skills/insight-api/references/insight-endpoints.md +514 -0
- package/.claude/skills/install-workflow-skill/SKILL.md +1056 -0
- package/.claude/skills/list-apps-skill/SKILL.md +1010 -0
- package/.claude/skills/list-workflows-minimal-skill/SKILL.md +992 -0
- package/.claude/skills/local-first-skill/SKILL.md +570 -0
- package/.claude/skills/mcp-tools/SKILL.md +419 -0
- package/.claude/skills/mcp-tools/references/api-endpoints.md +499 -0
- package/.claude/skills/mcp-tools/references/data-structures.md +554 -0
- package/.claude/skills/mcp-tools/references/implementation-patterns.md +717 -0
- package/.claude/skills/preview-insight-skill/SKILL.md +1290 -0
- package/.claude/skills/publish-hailer-app-skill/SKILL.md +453 -0
- package/.claude/skills/remove-app-member-skill/SKILL.md +671 -0
- package/.claude/skills/remove-app-skill/SKILL.md +985 -0
- package/.claude/skills/remove-insight-skill/SKILL.md +1011 -0
- package/.claude/skills/remove-workflow-skill/SKILL.md +920 -0
- package/.claude/skills/scaffold-hailer-app-skill/SKILL.md +1034 -0
- package/.claude/skills/skill-testing/README.md +137 -0
- package/.claude/skills/skill-testing/SKILL.md +348 -0
- package/.claude/skills/skill-testing/references/test-patterns.md +705 -0
- package/.claude/skills/skill-testing/references/testing-guide.md +603 -0
- package/.claude/skills/skill-testing/references/validation-checklist.md +537 -0
- package/.claude/skills/tool-builder/SKILL.md +328 -0
- package/.claude/skills/update-app-skill/SKILL.md +970 -0
- package/.claude/skills/update-workflow-field-skill/SKILL.md +1098 -0
- package/.env.example +81 -0
- package/.mcp.json +13 -0
- package/README.md +297 -0
- package/dist/app.d.ts +4 -0
- package/dist/app.js +74 -0
- package/dist/cli.d.ts +3 -0
- package/dist/cli.js +5 -0
- package/dist/client/adaptive-documentation-bot.d.ts +108 -0
- package/dist/client/adaptive-documentation-bot.js +475 -0
- package/dist/client/adaptive-documentation-types.d.ts +66 -0
- package/dist/client/adaptive-documentation-types.js +9 -0
- package/dist/client/agent-activity-bot.d.ts +51 -0
- package/dist/client/agent-activity-bot.js +166 -0
- package/dist/client/agent-tracker.d.ts +499 -0
- package/dist/client/agent-tracker.js +659 -0
- package/dist/client/description-updater.d.ts +56 -0
- package/dist/client/description-updater.js +259 -0
- package/dist/client/log-parser.d.ts +72 -0
- package/dist/client/log-parser.js +387 -0
- package/dist/client/mcp-client.d.ts +50 -0
- package/dist/client/mcp-client.js +532 -0
- package/dist/client/message-processor.d.ts +35 -0
- package/dist/client/message-processor.js +352 -0
- package/dist/client/multi-bot-manager.d.ts +24 -0
- package/dist/client/multi-bot-manager.js +74 -0
- package/dist/client/providers/anthropic-provider.d.ts +19 -0
- package/dist/client/providers/anthropic-provider.js +631 -0
- package/dist/client/providers/llm-provider.d.ts +47 -0
- package/dist/client/providers/llm-provider.js +367 -0
- package/dist/client/providers/openai-provider.d.ts +23 -0
- package/dist/client/providers/openai-provider.js +621 -0
- package/dist/client/simple-llm-caller.d.ts +19 -0
- package/dist/client/simple-llm-caller.js +100 -0
- package/dist/client/skill-generator.d.ts +81 -0
- package/dist/client/skill-generator.js +386 -0
- package/dist/client/test-adaptive-bot.d.ts +9 -0
- package/dist/client/test-adaptive-bot.js +82 -0
- package/dist/client/token-pricing.d.ts +38 -0
- package/dist/client/token-pricing.js +127 -0
- package/dist/client/token-tracker.d.ts +232 -0
- package/dist/client/token-tracker.js +457 -0
- package/dist/client/token-usage-bot.d.ts +53 -0
- package/dist/client/token-usage-bot.js +153 -0
- package/dist/client/tool-executor.d.ts +69 -0
- package/dist/client/tool-executor.js +159 -0
- package/dist/client/tool-schema-loader.d.ts +60 -0
- package/dist/client/tool-schema-loader.js +178 -0
- package/dist/client/types.d.ts +69 -0
- package/dist/client/types.js +7 -0
- package/dist/config.d.ts +162 -0
- package/dist/config.js +296 -0
- package/dist/core.d.ts +26 -0
- package/dist/core.js +147 -0
- package/dist/lib/context-manager.d.ts +111 -0
- package/dist/lib/context-manager.js +431 -0
- package/dist/lib/logger.d.ts +74 -0
- package/dist/lib/logger.js +277 -0
- package/dist/lib/materialize.d.ts +3 -0
- package/dist/lib/materialize.js +101 -0
- package/dist/lib/normalizedName.d.ts +7 -0
- package/dist/lib/normalizedName.js +48 -0
- package/dist/lib/prompt-length-manager.d.ts +81 -0
- package/dist/lib/prompt-length-manager.js +457 -0
- package/dist/lib/terminal-prompt.d.ts +9 -0
- package/dist/lib/terminal-prompt.js +108 -0
- package/dist/mcp/UserContextCache.d.ts +56 -0
- package/dist/mcp/UserContextCache.js +163 -0
- package/dist/mcp/auth.d.ts +2 -0
- package/dist/mcp/auth.js +29 -0
- package/dist/mcp/hailer-clients.d.ts +42 -0
- package/dist/mcp/hailer-clients.js +246 -0
- package/dist/mcp/signal-handler.d.ts +45 -0
- package/dist/mcp/signal-handler.js +317 -0
- package/dist/mcp/tool-registry.d.ts +100 -0
- package/dist/mcp/tool-registry.js +306 -0
- package/dist/mcp/tools/activity.d.ts +15 -0
- package/dist/mcp/tools/activity.js +955 -0
- package/dist/mcp/tools/app.d.ts +20 -0
- package/dist/mcp/tools/app.js +1488 -0
- package/dist/mcp/tools/discussion.d.ts +19 -0
- package/dist/mcp/tools/discussion.js +950 -0
- package/dist/mcp/tools/file.d.ts +15 -0
- package/dist/mcp/tools/file.js +119 -0
- package/dist/mcp/tools/insight.d.ts +17 -0
- package/dist/mcp/tools/insight.js +806 -0
- package/dist/mcp/tools/skill.d.ts +10 -0
- package/dist/mcp/tools/skill.js +279 -0
- package/dist/mcp/tools/user.d.ts +10 -0
- package/dist/mcp/tools/user.js +108 -0
- package/dist/mcp/tools/workflow-template.d.ts +19 -0
- package/dist/mcp/tools/workflow-template.js +822 -0
- package/dist/mcp/tools/workflow.d.ts +18 -0
- package/dist/mcp/tools/workflow.js +1362 -0
- package/dist/mcp/utils/api-errors.d.ts +45 -0
- package/dist/mcp/utils/api-errors.js +160 -0
- package/dist/mcp/utils/data-transformers.d.ts +102 -0
- package/dist/mcp/utils/data-transformers.js +194 -0
- package/dist/mcp/utils/file-upload.d.ts +33 -0
- package/dist/mcp/utils/file-upload.js +148 -0
- package/dist/mcp/utils/hailer-api-client.d.ts +120 -0
- package/dist/mcp/utils/hailer-api-client.js +323 -0
- package/dist/mcp/utils/index.d.ts +13 -0
- package/dist/mcp/utils/index.js +39 -0
- package/dist/mcp/utils/logger.d.ts +42 -0
- package/dist/mcp/utils/logger.js +103 -0
- package/dist/mcp/utils/types.d.ts +286 -0
- package/dist/mcp/utils/types.js +7 -0
- package/dist/mcp/workspace-cache.d.ts +42 -0
- package/dist/mcp/workspace-cache.js +97 -0
- package/dist/mcp-server.d.ts +42 -0
- package/dist/mcp-server.js +280 -0
- package/package.json +56 -0
- package/tsconfig.json +23 -0
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Hailer API Client
|
|
3
|
+
* Provides separate socket and REST API methods for flexible endpoint usage
|
|
4
|
+
*/
|
|
5
|
+
import { HailerClient } from '../hailer-clients';
|
|
6
|
+
import { LogContext } from '../../lib/logger';
|
|
7
|
+
import { FileSpec, UploadResult } from './file-upload';
|
|
8
|
+
export interface RestCallConfig {
|
|
9
|
+
operation: string;
|
|
10
|
+
endpoint: string;
|
|
11
|
+
body?: any;
|
|
12
|
+
method?: string;
|
|
13
|
+
timeout?: number;
|
|
14
|
+
context?: LogContext;
|
|
15
|
+
}
|
|
16
|
+
export declare class HailerApiClient {
|
|
17
|
+
private clients;
|
|
18
|
+
private logger;
|
|
19
|
+
constructor(clients: HailerClient);
|
|
20
|
+
/**
|
|
21
|
+
* Makes a socket API call - thin wrapper around clients.socket.request
|
|
22
|
+
*/
|
|
23
|
+
request<T>(method: string, args?: any[]): Promise<T>;
|
|
24
|
+
/**
|
|
25
|
+
* Makes a REST API call
|
|
26
|
+
*/
|
|
27
|
+
callRest<T>(config: RestCallConfig): Promise<T>;
|
|
28
|
+
/**
|
|
29
|
+
* Get workflow schema - uses Socket API to get field definitions
|
|
30
|
+
*/
|
|
31
|
+
getWorkflowSchema(workflowId: string, phaseId: string): Promise<any>;
|
|
32
|
+
/**
|
|
33
|
+
* Fetch activity list - uses v3 Socket API with enhanced pagination and filtering
|
|
34
|
+
*/
|
|
35
|
+
fetchActivityList(workflowId: string, phaseId?: string, limit?: number, options?: {
|
|
36
|
+
page?: number;
|
|
37
|
+
search?: string;
|
|
38
|
+
sortBy?: string;
|
|
39
|
+
sortOrder?: string;
|
|
40
|
+
includeStats?: boolean;
|
|
41
|
+
returnFlat?: boolean;
|
|
42
|
+
filters?: any;
|
|
43
|
+
}): Promise<any>;
|
|
44
|
+
/**
|
|
45
|
+
* Create activities - uses Socket API
|
|
46
|
+
*/
|
|
47
|
+
createActivities(workflowId: string, activities: any[], options?: any): Promise<any>;
|
|
48
|
+
/**
|
|
49
|
+
* Update activities - uses Socket API
|
|
50
|
+
*/
|
|
51
|
+
updateActivities(updates: any[], options?: any): Promise<any>;
|
|
52
|
+
/**
|
|
53
|
+
* Fetch discussion messages - uses Socket API, load messages from specified discussion
|
|
54
|
+
* @param discussionId - The discussion ID to fetch messages from
|
|
55
|
+
* @param limit - Number of messages to fetch (client-side limiting if API doesn't support it)
|
|
56
|
+
*/
|
|
57
|
+
fetchDiscussionMessages(discussionId: string, limit?: number): Promise<any>;
|
|
58
|
+
/**
|
|
59
|
+
* Fetch previous discussion messages - uses Socket API for pagination
|
|
60
|
+
* @param oldestMessageId - The ID of the oldest message from previous fetch
|
|
61
|
+
* @param batches - Number of previous batches to fetch (default: 1)
|
|
62
|
+
*/
|
|
63
|
+
fetchPreviousDiscussionMessages(oldestMessageId: string, batches?: number): Promise<any>;
|
|
64
|
+
/**
|
|
65
|
+
* Fetch activity by ID - uses Socket API
|
|
66
|
+
*/
|
|
67
|
+
fetchActivityById(activityId: string): Promise<any>;
|
|
68
|
+
/**
|
|
69
|
+
* Send discussion message - uses Socket API
|
|
70
|
+
*/
|
|
71
|
+
sendDiscussionMessage(discussionId: string, content: string, fileIds?: string[]): Promise<any>;
|
|
72
|
+
/**
|
|
73
|
+
* Join an activity's discussion by following the activity - uses Socket API
|
|
74
|
+
* This is the recommended way to join activity discussions.
|
|
75
|
+
* Returns true if now following, false if was already following and toggled off.
|
|
76
|
+
*/
|
|
77
|
+
joinActivityDiscussion(activityId: string): Promise<boolean>;
|
|
78
|
+
/**
|
|
79
|
+
* Leave an activity's discussion by unfollowing the activity - uses Socket API
|
|
80
|
+
* Returns true if successfully unfollowed, false if was already not following.
|
|
81
|
+
*/
|
|
82
|
+
leaveActivityDiscussion(activityId: string): Promise<boolean>;
|
|
83
|
+
/**
|
|
84
|
+
* Leave a discussion directly - uses Socket API
|
|
85
|
+
* This works for any discussion type. For activity discussions, prefer leaveActivityDiscussion().
|
|
86
|
+
*/
|
|
87
|
+
leaveDiscussion(discussionId: string): Promise<void>;
|
|
88
|
+
/**
|
|
89
|
+
* Join a discussion directly - uses Socket API
|
|
90
|
+
* Note: There's no generic join endpoint. For activity discussions, use joinActivityDiscussion().
|
|
91
|
+
* For other discussion types, you may need to use invite mechanisms.
|
|
92
|
+
* This method attempts to fetch the discussion to check if user needs to join.
|
|
93
|
+
*/
|
|
94
|
+
joinDiscussion(discussionId: string): Promise<{
|
|
95
|
+
success: boolean;
|
|
96
|
+
message: string;
|
|
97
|
+
method?: string;
|
|
98
|
+
}>;
|
|
99
|
+
/**
|
|
100
|
+
* Fetch workspace initialization data - uses Socket API
|
|
101
|
+
*/
|
|
102
|
+
fetchInit(): Promise<any>;
|
|
103
|
+
/**
|
|
104
|
+
* Global search across workspace - uses Socket API
|
|
105
|
+
*/
|
|
106
|
+
globalSearch(query: string, sections?: string[]): Promise<any>;
|
|
107
|
+
/**
|
|
108
|
+
* Upload a file from URL or filesystem path
|
|
109
|
+
*/
|
|
110
|
+
uploadFile(fileSpec: FileSpec): Promise<UploadResult>;
|
|
111
|
+
/**
|
|
112
|
+
* Helper method to create MCP tool responses
|
|
113
|
+
*/
|
|
114
|
+
createMcpResponse(data: any, operation: string, summary?: string): any;
|
|
115
|
+
/**
|
|
116
|
+
* Helper method to create MCP error responses
|
|
117
|
+
*/
|
|
118
|
+
createMcpError(error: unknown, operation: string): any;
|
|
119
|
+
}
|
|
120
|
+
//# sourceMappingURL=hailer-api-client.d.ts.map
|
|
@@ -0,0 +1,323 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Hailer API Client
|
|
4
|
+
* Provides separate socket and REST API methods for flexible endpoint usage
|
|
5
|
+
*/
|
|
6
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
+
exports.HailerApiClient = void 0;
|
|
8
|
+
const logger_1 = require("../../lib/logger");
|
|
9
|
+
const api_errors_1 = require("./api-errors");
|
|
10
|
+
const file_upload_1 = require("./file-upload");
|
|
11
|
+
class HailerApiClient {
|
|
12
|
+
clients;
|
|
13
|
+
logger = (0, logger_1.createLogger)({ component: 'HailerApiClient' });
|
|
14
|
+
constructor(clients) {
|
|
15
|
+
this.clients = clients;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Makes a socket API call - thin wrapper around clients.socket.request
|
|
19
|
+
*/
|
|
20
|
+
async request(method, args) {
|
|
21
|
+
if (!this.clients.socket) {
|
|
22
|
+
throw new Error(`Socket client not available for method: ${method}`);
|
|
23
|
+
}
|
|
24
|
+
this.logger.debug('Socket API call', { method, args });
|
|
25
|
+
try {
|
|
26
|
+
const result = await this.clients.socket.request(method, args || []);
|
|
27
|
+
this.logger.debug('Socket API success', { method });
|
|
28
|
+
return result;
|
|
29
|
+
}
|
|
30
|
+
catch (error) {
|
|
31
|
+
// Log with detailed context for debugging
|
|
32
|
+
this.logger.error('Socket API error', error, {
|
|
33
|
+
method,
|
|
34
|
+
args: JSON.stringify(args || []),
|
|
35
|
+
apiBaseUrl: this.clients.socket.host
|
|
36
|
+
});
|
|
37
|
+
throw error;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Makes a REST API call
|
|
42
|
+
*/
|
|
43
|
+
async callRest(config) {
|
|
44
|
+
const url = `${this.clients.socket.host}${config.endpoint}`;
|
|
45
|
+
return await (0, api_errors_1.makeApiCall)(url, {
|
|
46
|
+
operation: config.operation,
|
|
47
|
+
endpoint: config.endpoint,
|
|
48
|
+
method: config.method || 'POST',
|
|
49
|
+
body: config.body,
|
|
50
|
+
timeout: config.timeout,
|
|
51
|
+
context: config.context,
|
|
52
|
+
headers: {
|
|
53
|
+
'hlrkey': this.clients.sessionKey,
|
|
54
|
+
},
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Get workflow schema - uses Socket API to get field definitions
|
|
59
|
+
*/
|
|
60
|
+
async getWorkflowSchema(workflowId, phaseId) {
|
|
61
|
+
return await this.request('v3.activity.template.create', [workflowId, phaseId]);
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Fetch activity list - uses v3 Socket API with enhanced pagination and filtering
|
|
65
|
+
*/
|
|
66
|
+
async fetchActivityList(workflowId, phaseId, limit = 50, options) {
|
|
67
|
+
// V3 API uses processId and phaseId (not process/phase)
|
|
68
|
+
const workflowFilter = { processId: workflowId };
|
|
69
|
+
if (phaseId)
|
|
70
|
+
workflowFilter.phaseId = phaseId;
|
|
71
|
+
const requestOptions = {
|
|
72
|
+
filters: options?.filters,
|
|
73
|
+
limit,
|
|
74
|
+
search: options?.search || null,
|
|
75
|
+
page: options?.page ? options.page + 1 : 1, // v3 uses 1-based page numbering
|
|
76
|
+
sortBy: options?.sortBy || "updated",
|
|
77
|
+
sortOrder: options?.sortOrder || "desc",
|
|
78
|
+
includeStats: options?.includeStats !== undefined ? options?.includeStats : true,
|
|
79
|
+
returnFlat: options?.returnFlat !== undefined ? options?.returnFlat : true,
|
|
80
|
+
};
|
|
81
|
+
this.logger.debug('📋 V3 Activity List API Call', {
|
|
82
|
+
endpoint: 'v3.activity.list',
|
|
83
|
+
workflowId,
|
|
84
|
+
phaseId,
|
|
85
|
+
limit,
|
|
86
|
+
hasFilters: !!options?.filters,
|
|
87
|
+
filterCount: options?.filters?.and?.length || 0,
|
|
88
|
+
});
|
|
89
|
+
// Use Format B (simple array) - confirmed working
|
|
90
|
+
return await this.request('v3.activity.list', [workflowFilter, requestOptions]);
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* Create activities - uses Socket API
|
|
94
|
+
*/
|
|
95
|
+
async createActivities(workflowId, activities, options) {
|
|
96
|
+
console.log('🏭 CREATE ACTIVITIES API CALL');
|
|
97
|
+
console.log('📋 Workflow ID:', workflowId);
|
|
98
|
+
console.log('📊 Activities Count:', activities.length);
|
|
99
|
+
console.log('🎯 Activities Array:', JSON.stringify(activities, null, 2));
|
|
100
|
+
console.log('⚙️ Options:', JSON.stringify(options || {}, null, 2));
|
|
101
|
+
this.logger.debug('createActivities called with:', {
|
|
102
|
+
workflowId,
|
|
103
|
+
activities: JSON.stringify(activities),
|
|
104
|
+
options: JSON.stringify(options || {})
|
|
105
|
+
});
|
|
106
|
+
console.log('🔌 Calling socket API: v3.activity.createMany');
|
|
107
|
+
try {
|
|
108
|
+
const result = await this.request('v3.activity.createMany', [workflowId, activities, options || {}]);
|
|
109
|
+
console.log('✅ CREATE ACTIVITIES SUCCESS');
|
|
110
|
+
return result;
|
|
111
|
+
}
|
|
112
|
+
catch (error) {
|
|
113
|
+
console.error('❌ CREATE ACTIVITIES FAILED');
|
|
114
|
+
throw error;
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
/**
|
|
118
|
+
* Update activities - uses Socket API
|
|
119
|
+
*/
|
|
120
|
+
async updateActivities(updates, options) {
|
|
121
|
+
const args = options ? [updates, options] : [updates];
|
|
122
|
+
return await this.request('v3.activity.updateMany', args);
|
|
123
|
+
}
|
|
124
|
+
/**
|
|
125
|
+
* Fetch discussion messages - uses Socket API, load messages from specified discussion
|
|
126
|
+
* @param discussionId - The discussion ID to fetch messages from
|
|
127
|
+
* @param limit - Number of messages to fetch (client-side limiting if API doesn't support it)
|
|
128
|
+
*/
|
|
129
|
+
async fetchDiscussionMessages(discussionId, limit = 50) {
|
|
130
|
+
const result = await this.request('v3.discussion.message.latest', [discussionId]);
|
|
131
|
+
// If API returned messages and we need to limit them, slice the array
|
|
132
|
+
if (result?.messages && Array.isArray(result.messages) && result.messages.length > limit) {
|
|
133
|
+
return {
|
|
134
|
+
...result,
|
|
135
|
+
messages: result.messages.slice(0, limit),
|
|
136
|
+
// Add metadata to indicate truncation
|
|
137
|
+
truncated: true,
|
|
138
|
+
originalCount: result.messages.length,
|
|
139
|
+
requestedLimit: limit
|
|
140
|
+
};
|
|
141
|
+
}
|
|
142
|
+
return result;
|
|
143
|
+
}
|
|
144
|
+
/**
|
|
145
|
+
* Fetch previous discussion messages - uses Socket API for pagination
|
|
146
|
+
* @param oldestMessageId - The ID of the oldest message from previous fetch
|
|
147
|
+
* @param batches - Number of previous batches to fetch (default: 1)
|
|
148
|
+
*/
|
|
149
|
+
async fetchPreviousDiscussionMessages(oldestMessageId, batches = 1) {
|
|
150
|
+
const allMessages = [];
|
|
151
|
+
let currentMessageId = oldestMessageId;
|
|
152
|
+
let totalFetched = 0;
|
|
153
|
+
this.logger.debug('Starting previous message fetch', {
|
|
154
|
+
oldestMessageId,
|
|
155
|
+
batches,
|
|
156
|
+
totalRequests: batches
|
|
157
|
+
});
|
|
158
|
+
for (let i = 0; i < batches; i++) {
|
|
159
|
+
try {
|
|
160
|
+
this.logger.debug(`Fetching batch ${i + 1}/${batches}`, {
|
|
161
|
+
currentMessageId,
|
|
162
|
+
batchNumber: i + 1
|
|
163
|
+
});
|
|
164
|
+
const result = await this.request('v3.discussion.message.previous', [currentMessageId]);
|
|
165
|
+
this.logger.debug(`Batch ${i + 1} API response`, {
|
|
166
|
+
hasMessages: !!(result?.messages),
|
|
167
|
+
messageCount: result?.messages?.length || 0,
|
|
168
|
+
resultKeys: Object.keys(result || {})
|
|
169
|
+
});
|
|
170
|
+
if (result?.messages && Array.isArray(result.messages) && result.messages.length > 0) {
|
|
171
|
+
allMessages.push(...result.messages);
|
|
172
|
+
totalFetched += result.messages.length;
|
|
173
|
+
// Update currentMessageId to the oldest message from this batch for next iteration
|
|
174
|
+
const oldestInBatch = result.messages[result.messages.length - 1];
|
|
175
|
+
currentMessageId = oldestInBatch._id;
|
|
176
|
+
this.logger.debug(`Batch ${i + 1}/${batches} fetched successfully`, {
|
|
177
|
+
messagesInBatch: result.messages.length,
|
|
178
|
+
totalSoFar: totalFetched,
|
|
179
|
+
nextMessageId: currentMessageId
|
|
180
|
+
});
|
|
181
|
+
}
|
|
182
|
+
else {
|
|
183
|
+
// No more messages available
|
|
184
|
+
this.logger.debug(`No more messages available at batch ${i + 1}`, {
|
|
185
|
+
totalFetched,
|
|
186
|
+
completedBatches: i,
|
|
187
|
+
resultStructure: result
|
|
188
|
+
});
|
|
189
|
+
break;
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
catch (error) {
|
|
193
|
+
this.logger.error(`Error fetching batch ${i + 1}`, {
|
|
194
|
+
error: error,
|
|
195
|
+
currentMessageId,
|
|
196
|
+
batchNumber: i + 1
|
|
197
|
+
});
|
|
198
|
+
break;
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
const finalResult = {
|
|
202
|
+
messages: allMessages,
|
|
203
|
+
totalFetched,
|
|
204
|
+
batchesCompleted: Math.min(batches, Math.ceil(totalFetched / 50)),
|
|
205
|
+
oldestMessageId: allMessages.length > 0 ? allMessages[allMessages.length - 1]._id : oldestMessageId,
|
|
206
|
+
hasMore: totalFetched > 0 // Assume there might be more if we got any messages
|
|
207
|
+
};
|
|
208
|
+
this.logger.debug('Previous message fetch completed', finalResult);
|
|
209
|
+
return finalResult;
|
|
210
|
+
}
|
|
211
|
+
/**
|
|
212
|
+
* Fetch activity by ID - uses Socket API
|
|
213
|
+
*/
|
|
214
|
+
async fetchActivityById(activityId) {
|
|
215
|
+
return await this.request('activities.load', [activityId]);
|
|
216
|
+
}
|
|
217
|
+
/**
|
|
218
|
+
* Send discussion message - uses Socket API
|
|
219
|
+
*/
|
|
220
|
+
async sendDiscussionMessage(discussionId, content, fileIds) {
|
|
221
|
+
const messageData = { msg: content };
|
|
222
|
+
if (fileIds && fileIds.length > 0) {
|
|
223
|
+
messageData.files = fileIds;
|
|
224
|
+
}
|
|
225
|
+
return await this.request('messenger.send', [messageData, discussionId]);
|
|
226
|
+
}
|
|
227
|
+
/**
|
|
228
|
+
* Join an activity's discussion by following the activity - uses Socket API
|
|
229
|
+
* This is the recommended way to join activity discussions.
|
|
230
|
+
* Returns true if now following, false if was already following and toggled off.
|
|
231
|
+
*/
|
|
232
|
+
async joinActivityDiscussion(activityId) {
|
|
233
|
+
// activities.follow toggles the state, but we need to check current state first
|
|
234
|
+
const activity = await this.fetchActivityById(activityId);
|
|
235
|
+
// If not already following, call activities.follow to join
|
|
236
|
+
const result = await this.request('activities.follow', [activityId]);
|
|
237
|
+
return result; // true if now following, false if unfollowed
|
|
238
|
+
}
|
|
239
|
+
/**
|
|
240
|
+
* Leave an activity's discussion by unfollowing the activity - uses Socket API
|
|
241
|
+
* Returns true if successfully unfollowed, false if was already not following.
|
|
242
|
+
*/
|
|
243
|
+
async leaveActivityDiscussion(activityId) {
|
|
244
|
+
// activities.follow toggles the state
|
|
245
|
+
const activity = await this.fetchActivityById(activityId);
|
|
246
|
+
// If already following, call activities.follow to unfollow
|
|
247
|
+
const result = await this.request('activities.follow', [activityId]);
|
|
248
|
+
return !result; // Inverse: true if now unfollowed, false if followed
|
|
249
|
+
}
|
|
250
|
+
/**
|
|
251
|
+
* Leave a discussion directly - uses Socket API
|
|
252
|
+
* This works for any discussion type. For activity discussions, prefer leaveActivityDiscussion().
|
|
253
|
+
*/
|
|
254
|
+
async leaveDiscussion(discussionId) {
|
|
255
|
+
return await this.request('messenger.leave_discussion', [discussionId]);
|
|
256
|
+
}
|
|
257
|
+
/**
|
|
258
|
+
* Join a discussion directly - uses Socket API
|
|
259
|
+
* Note: There's no generic join endpoint. For activity discussions, use joinActivityDiscussion().
|
|
260
|
+
* For other discussion types, you may need to use invite mechanisms.
|
|
261
|
+
* This method attempts to fetch the discussion to check if user needs to join.
|
|
262
|
+
*/
|
|
263
|
+
async joinDiscussion(discussionId) {
|
|
264
|
+
// Try to fetch messages to check if already a member
|
|
265
|
+
try {
|
|
266
|
+
await this.request('v3.discussion.message.latest', [discussionId]);
|
|
267
|
+
return {
|
|
268
|
+
success: true,
|
|
269
|
+
message: 'Already a member of this discussion or successfully accessed it',
|
|
270
|
+
method: 'direct_access'
|
|
271
|
+
};
|
|
272
|
+
}
|
|
273
|
+
catch (error) {
|
|
274
|
+
// Check if error indicates permission/access issue
|
|
275
|
+
const errorMsg = error?.message || String(error);
|
|
276
|
+
if (errorMsg.toLowerCase().includes('permission') ||
|
|
277
|
+
errorMsg.toLowerCase().includes('access') ||
|
|
278
|
+
errorMsg.toLowerCase().includes('not found')) {
|
|
279
|
+
// This is likely an activity discussion - we need the activity ID
|
|
280
|
+
throw new Error('Cannot join this discussion directly. If this is an activity discussion, ' +
|
|
281
|
+
'please use join_activity_discussion tool with the activity ID instead. ' +
|
|
282
|
+
'For other discussion types, you may need an invitation.');
|
|
283
|
+
}
|
|
284
|
+
throw error;
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
/**
|
|
288
|
+
* Fetch workspace initialization data - uses Socket API
|
|
289
|
+
*/
|
|
290
|
+
async fetchInit() {
|
|
291
|
+
return await this.request('v2.core.init', [{}]);
|
|
292
|
+
}
|
|
293
|
+
/**
|
|
294
|
+
* Global search across workspace - uses Socket API
|
|
295
|
+
*/
|
|
296
|
+
async globalSearch(query, sections) {
|
|
297
|
+
const searchOptions = { search: query };
|
|
298
|
+
if (sections) {
|
|
299
|
+
searchOptions.sections = sections;
|
|
300
|
+
}
|
|
301
|
+
return await this.request('v2.search.global', [searchOptions]);
|
|
302
|
+
}
|
|
303
|
+
/**
|
|
304
|
+
* Upload a file from URL or filesystem path
|
|
305
|
+
*/
|
|
306
|
+
async uploadFile(fileSpec) {
|
|
307
|
+
return await (0, file_upload_1.uploadSingleFile)(fileSpec, this.clients);
|
|
308
|
+
}
|
|
309
|
+
/**
|
|
310
|
+
* Helper method to create MCP tool responses
|
|
311
|
+
*/
|
|
312
|
+
createMcpResponse(data, operation, summary) {
|
|
313
|
+
return (0, api_errors_1.createSuccessResponse)(data, operation, summary);
|
|
314
|
+
}
|
|
315
|
+
/**
|
|
316
|
+
* Helper method to create MCP error responses
|
|
317
|
+
*/
|
|
318
|
+
createMcpError(error, operation) {
|
|
319
|
+
return (0, api_errors_1.createErrorResponse)(error, operation);
|
|
320
|
+
}
|
|
321
|
+
}
|
|
322
|
+
exports.HailerApiClient = HailerApiClient;
|
|
323
|
+
//# sourceMappingURL=hailer-api-client.js.map
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Utility exports for Hailer MCP Server
|
|
3
|
+
* Provides centralized access to all utility functions and types
|
|
4
|
+
*/
|
|
5
|
+
export { createLogger, getDefaultLogger as logger, LogLevel, LogTag } from '../../lib/logger';
|
|
6
|
+
export type { LogContext } from '../../lib/logger';
|
|
7
|
+
export { HailerApiError, makeApiCall, handleApiResponse, createErrorResponse, createSuccessResponse } from './api-errors';
|
|
8
|
+
export type { ApiCallOptions } from './api-errors';
|
|
9
|
+
export { HailerApiClient } from './hailer-api-client';
|
|
10
|
+
export type { RestCallConfig } from './hailer-api-client';
|
|
11
|
+
export { transformActivity, transformActivities, transformFields, transformFieldValue, findFieldByKey, transformWorkflow, transformPhases, transformWorkflowFields, formatTimestamp, formatUserName, getFirstPhaseId, formatActivityListResponse, transformActivityForSearch, } from './data-transformers';
|
|
12
|
+
export type * from './types';
|
|
13
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Utility exports for Hailer MCP Server
|
|
4
|
+
* Provides centralized access to all utility functions and types
|
|
5
|
+
*/
|
|
6
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
+
exports.transformActivityForSearch = exports.formatActivityListResponse = exports.getFirstPhaseId = exports.formatUserName = exports.formatTimestamp = exports.transformWorkflowFields = exports.transformPhases = exports.transformWorkflow = exports.findFieldByKey = exports.transformFieldValue = exports.transformFields = exports.transformActivities = exports.transformActivity = exports.HailerApiClient = exports.createSuccessResponse = exports.createErrorResponse = exports.handleApiResponse = exports.makeApiCall = exports.HailerApiError = exports.LogTag = exports.LogLevel = exports.logger = exports.createLogger = void 0;
|
|
8
|
+
// Logging utilities
|
|
9
|
+
var logger_1 = require("../../lib/logger");
|
|
10
|
+
Object.defineProperty(exports, "createLogger", { enumerable: true, get: function () { return logger_1.createLogger; } });
|
|
11
|
+
Object.defineProperty(exports, "logger", { enumerable: true, get: function () { return logger_1.getDefaultLogger; } });
|
|
12
|
+
Object.defineProperty(exports, "LogLevel", { enumerable: true, get: function () { return logger_1.LogLevel; } });
|
|
13
|
+
Object.defineProperty(exports, "LogTag", { enumerable: true, get: function () { return logger_1.LogTag; } });
|
|
14
|
+
// Error handling utilities
|
|
15
|
+
var api_errors_1 = require("./api-errors");
|
|
16
|
+
Object.defineProperty(exports, "HailerApiError", { enumerable: true, get: function () { return api_errors_1.HailerApiError; } });
|
|
17
|
+
Object.defineProperty(exports, "makeApiCall", { enumerable: true, get: function () { return api_errors_1.makeApiCall; } });
|
|
18
|
+
Object.defineProperty(exports, "handleApiResponse", { enumerable: true, get: function () { return api_errors_1.handleApiResponse; } });
|
|
19
|
+
Object.defineProperty(exports, "createErrorResponse", { enumerable: true, get: function () { return api_errors_1.createErrorResponse; } });
|
|
20
|
+
Object.defineProperty(exports, "createSuccessResponse", { enumerable: true, get: function () { return api_errors_1.createSuccessResponse; } });
|
|
21
|
+
// API client
|
|
22
|
+
var hailer_api_client_1 = require("./hailer-api-client");
|
|
23
|
+
Object.defineProperty(exports, "HailerApiClient", { enumerable: true, get: function () { return hailer_api_client_1.HailerApiClient; } });
|
|
24
|
+
// Data transformers
|
|
25
|
+
var data_transformers_1 = require("./data-transformers");
|
|
26
|
+
Object.defineProperty(exports, "transformActivity", { enumerable: true, get: function () { return data_transformers_1.transformActivity; } });
|
|
27
|
+
Object.defineProperty(exports, "transformActivities", { enumerable: true, get: function () { return data_transformers_1.transformActivities; } });
|
|
28
|
+
Object.defineProperty(exports, "transformFields", { enumerable: true, get: function () { return data_transformers_1.transformFields; } });
|
|
29
|
+
Object.defineProperty(exports, "transformFieldValue", { enumerable: true, get: function () { return data_transformers_1.transformFieldValue; } });
|
|
30
|
+
Object.defineProperty(exports, "findFieldByKey", { enumerable: true, get: function () { return data_transformers_1.findFieldByKey; } });
|
|
31
|
+
Object.defineProperty(exports, "transformWorkflow", { enumerable: true, get: function () { return data_transformers_1.transformWorkflow; } });
|
|
32
|
+
Object.defineProperty(exports, "transformPhases", { enumerable: true, get: function () { return data_transformers_1.transformPhases; } });
|
|
33
|
+
Object.defineProperty(exports, "transformWorkflowFields", { enumerable: true, get: function () { return data_transformers_1.transformWorkflowFields; } });
|
|
34
|
+
Object.defineProperty(exports, "formatTimestamp", { enumerable: true, get: function () { return data_transformers_1.formatTimestamp; } });
|
|
35
|
+
Object.defineProperty(exports, "formatUserName", { enumerable: true, get: function () { return data_transformers_1.formatUserName; } });
|
|
36
|
+
Object.defineProperty(exports, "getFirstPhaseId", { enumerable: true, get: function () { return data_transformers_1.getFirstPhaseId; } });
|
|
37
|
+
Object.defineProperty(exports, "formatActivityListResponse", { enumerable: true, get: function () { return data_transformers_1.formatActivityListResponse; } });
|
|
38
|
+
Object.defineProperty(exports, "transformActivityForSearch", { enumerable: true, get: function () { return data_transformers_1.transformActivityForSearch; } });
|
|
39
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Structured logging utility for Hailer MCP Server
|
|
3
|
+
* Provides consistent logging across the application with configurable levels
|
|
4
|
+
*/
|
|
5
|
+
export declare enum LogLevel {
|
|
6
|
+
DEBUG = 0,
|
|
7
|
+
INFO = 1,
|
|
8
|
+
WARN = 2,
|
|
9
|
+
ERROR = 3
|
|
10
|
+
}
|
|
11
|
+
export interface LogContext {
|
|
12
|
+
operation?: string;
|
|
13
|
+
endpoint?: string;
|
|
14
|
+
activityId?: string;
|
|
15
|
+
workflowId?: string;
|
|
16
|
+
discussionId?: string;
|
|
17
|
+
userId?: string;
|
|
18
|
+
duration?: number;
|
|
19
|
+
[key: string]: any;
|
|
20
|
+
}
|
|
21
|
+
declare class Logger {
|
|
22
|
+
private level;
|
|
23
|
+
private context;
|
|
24
|
+
setLevel(level: LogLevel): void;
|
|
25
|
+
setContext(context: LogContext): Logger;
|
|
26
|
+
private withContext;
|
|
27
|
+
private shouldLog;
|
|
28
|
+
private formatMessage;
|
|
29
|
+
private getEmoji;
|
|
30
|
+
debug(message: string, context?: LogContext): void;
|
|
31
|
+
info(message: string, context?: LogContext): void;
|
|
32
|
+
warn(message: string, context?: LogContext): void;
|
|
33
|
+
error(message: string, error?: Error | unknown, context?: LogContext): void;
|
|
34
|
+
apiCall(operation: string, endpoint: string, params?: any): void;
|
|
35
|
+
apiSuccess(operation: string, endpoint: string, duration?: number): void;
|
|
36
|
+
apiError(operation: string, endpoint: string, error: Error | unknown, duration?: number): void;
|
|
37
|
+
socketFallback(operation: string, reason: string): void;
|
|
38
|
+
}
|
|
39
|
+
export declare const logger: Logger;
|
|
40
|
+
export declare function createLogger(context: LogContext): Logger;
|
|
41
|
+
export {};
|
|
42
|
+
//# sourceMappingURL=logger.d.ts.map
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Structured logging utility for Hailer MCP Server
|
|
4
|
+
* Provides consistent logging across the application with configurable levels
|
|
5
|
+
*/
|
|
6
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
+
exports.logger = exports.LogLevel = void 0;
|
|
8
|
+
exports.createLogger = createLogger;
|
|
9
|
+
var LogLevel;
|
|
10
|
+
(function (LogLevel) {
|
|
11
|
+
LogLevel[LogLevel["DEBUG"] = 0] = "DEBUG";
|
|
12
|
+
LogLevel[LogLevel["INFO"] = 1] = "INFO";
|
|
13
|
+
LogLevel[LogLevel["WARN"] = 2] = "WARN";
|
|
14
|
+
LogLevel[LogLevel["ERROR"] = 3] = "ERROR";
|
|
15
|
+
})(LogLevel || (exports.LogLevel = LogLevel = {}));
|
|
16
|
+
class Logger {
|
|
17
|
+
level = LogLevel.DEBUG;
|
|
18
|
+
context = {};
|
|
19
|
+
setLevel(level) {
|
|
20
|
+
this.level = level;
|
|
21
|
+
}
|
|
22
|
+
setContext(context) {
|
|
23
|
+
return new Logger().withContext({ ...this.context, ...context });
|
|
24
|
+
}
|
|
25
|
+
withContext(context) {
|
|
26
|
+
const newLogger = new Logger();
|
|
27
|
+
newLogger.level = this.level;
|
|
28
|
+
newLogger.context = context;
|
|
29
|
+
return newLogger;
|
|
30
|
+
}
|
|
31
|
+
shouldLog(level) {
|
|
32
|
+
return level >= this.level;
|
|
33
|
+
}
|
|
34
|
+
formatMessage(level, message, context) {
|
|
35
|
+
const emoji = this.getEmoji(level);
|
|
36
|
+
const levelName = LogLevel[level];
|
|
37
|
+
const fullContext = { ...this.context, ...context };
|
|
38
|
+
let contextStr = '';
|
|
39
|
+
if (Object.keys(fullContext).length > 0) {
|
|
40
|
+
const contextParts = Object.entries(fullContext)
|
|
41
|
+
.filter(([_, value]) => value !== undefined && value !== null)
|
|
42
|
+
.map(([key, value]) => `${key}=${value}`);
|
|
43
|
+
if (contextParts.length > 0) {
|
|
44
|
+
contextStr = ` [${contextParts.join(', ')}]`;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
return `${emoji} ${levelName}: ${message}${contextStr}`;
|
|
48
|
+
}
|
|
49
|
+
getEmoji(level) {
|
|
50
|
+
switch (level) {
|
|
51
|
+
case LogLevel.DEBUG: return '🔍';
|
|
52
|
+
case LogLevel.INFO: return '📡';
|
|
53
|
+
case LogLevel.WARN: return '⚠️';
|
|
54
|
+
case LogLevel.ERROR: return '❌';
|
|
55
|
+
default: return '📝';
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
debug(message, context) {
|
|
59
|
+
if (this.shouldLog(LogLevel.DEBUG)) {
|
|
60
|
+
console.log(this.formatMessage(LogLevel.DEBUG, message, context));
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
info(message, context) {
|
|
64
|
+
if (this.shouldLog(LogLevel.INFO)) {
|
|
65
|
+
console.log(this.formatMessage(LogLevel.INFO, message, context));
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
warn(message, context) {
|
|
69
|
+
if (this.shouldLog(LogLevel.WARN)) {
|
|
70
|
+
console.warn(this.formatMessage(LogLevel.WARN, message, context));
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
error(message, error, context) {
|
|
74
|
+
if (this.shouldLog(LogLevel.ERROR)) {
|
|
75
|
+
const errorMsg = error instanceof Error ? error.message : String(error);
|
|
76
|
+
const fullMessage = error ? `${message}: ${errorMsg}` : message;
|
|
77
|
+
console.error(this.formatMessage(LogLevel.ERROR, fullMessage, context));
|
|
78
|
+
if (error instanceof Error && error.stack) {
|
|
79
|
+
console.error(error.stack);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
// Convenience methods for common operations
|
|
84
|
+
apiCall(operation, endpoint, params) {
|
|
85
|
+
this.debug(`API call: ${operation}`, { operation, endpoint, params: params ? JSON.stringify(params) : undefined });
|
|
86
|
+
}
|
|
87
|
+
apiSuccess(operation, endpoint, duration) {
|
|
88
|
+
this.info(`API success: ${operation}`, { operation, endpoint, duration });
|
|
89
|
+
}
|
|
90
|
+
apiError(operation, endpoint, error, duration) {
|
|
91
|
+
this.error(`API error: ${operation}`, error, { operation, endpoint, duration });
|
|
92
|
+
}
|
|
93
|
+
socketFallback(operation, reason) {
|
|
94
|
+
this.warn(`Socket fallback: ${operation} - ${reason}`, { operation });
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
// Export singleton instance
|
|
98
|
+
exports.logger = new Logger();
|
|
99
|
+
// Export factory function for creating loggers with specific context
|
|
100
|
+
function createLogger(context) {
|
|
101
|
+
return exports.logger.setContext(context);
|
|
102
|
+
}
|
|
103
|
+
//# sourceMappingURL=logger.js.map
|