@hailer/mcp 0.2.3 โ 0.2.5
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/agents/agent-marketplace-publisher.md +120 -0
- package/.claude/agents/agent-marketplace-reviewer.md +133 -0
- package/.claude/commands/help.md +28 -0
- package/.claude/commands/help:agents.md +71 -0
- package/.claude/commands/help:commands.md +39 -0
- package/.claude/commands/help:faq.md +69 -0
- package/.claude/commands/help:plugins.md +50 -0
- package/.claude/commands/help:tools.md +75 -0
- package/.claude/commands/install-plugin.md +261 -0
- package/.claude/commands/list-plugins.md +42 -0
- package/.claude/commands/marketplace-setup.md +33 -0
- package/.claude/commands/publish-plugin.md +55 -0
- package/.claude/commands/uninstall-plugin.md +87 -0
- package/.claude/hooks/interactive-mode.cjs +5 -3
- package/.claude/skills/marketplace-publishing.md +155 -0
- package/CHANGELOG.md +89 -0
- package/CLAUDE.md +83 -36
- package/dist/app.js +13 -1
- package/dist/config.d.ts +1 -0
- package/dist/config.js +3 -0
- package/dist/core.d.ts +3 -4
- package/dist/core.js +23 -65
- package/dist/mcp/tools/app-marketplace.js +10 -32
- package/dist/mcp/tools/bug-fixer-tools.d.ts +22 -0
- package/dist/mcp/tools/bug-fixer-tools.js +447 -31
- package/dist/mcp/tools/file.d.ts +5 -1
- package/dist/mcp/tools/file.js +122 -4
- package/dist/mcp/utils/hailer-api-client.d.ts +13 -0
- package/dist/mcp/utils/hailer-api-client.js +64 -0
- package/package.json +1 -1
- package/mcp-system-prompt.txt +0 -127
package/dist/mcp/tools/file.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
/**
|
|
3
|
-
*
|
|
3
|
+
* File Tools - Clean Architecture Implementation
|
|
4
4
|
*
|
|
5
5
|
* Demonstrates the new tool architecture pattern:
|
|
6
6
|
* - Direct Tool<TSchema> interface implementation
|
|
@@ -8,12 +8,47 @@
|
|
|
8
8
|
* - No static class wrapper needed
|
|
9
9
|
* - Type-safe with Zod schema inference
|
|
10
10
|
*/
|
|
11
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
12
|
+
if (k2 === undefined) k2 = k;
|
|
13
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
14
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
15
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
16
|
+
}
|
|
17
|
+
Object.defineProperty(o, k2, desc);
|
|
18
|
+
}) : (function(o, m, k, k2) {
|
|
19
|
+
if (k2 === undefined) k2 = k;
|
|
20
|
+
o[k2] = m[k];
|
|
21
|
+
}));
|
|
22
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
23
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
24
|
+
}) : function(o, v) {
|
|
25
|
+
o["default"] = v;
|
|
26
|
+
});
|
|
27
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
28
|
+
var ownKeys = function(o) {
|
|
29
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
30
|
+
var ar = [];
|
|
31
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
32
|
+
return ar;
|
|
33
|
+
};
|
|
34
|
+
return ownKeys(o);
|
|
35
|
+
};
|
|
36
|
+
return function (mod) {
|
|
37
|
+
if (mod && mod.__esModule) return mod;
|
|
38
|
+
var result = {};
|
|
39
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
40
|
+
__setModuleDefault(result, mod);
|
|
41
|
+
return result;
|
|
42
|
+
};
|
|
43
|
+
})();
|
|
11
44
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
-
exports.uploadFilesTool = void 0;
|
|
45
|
+
exports.downloadFileTool = exports.uploadFilesTool = void 0;
|
|
13
46
|
const zod_1 = require("zod");
|
|
14
47
|
const tool_registry_1 = require("../tool-registry");
|
|
15
48
|
const logger_1 = require("../../lib/logger");
|
|
16
|
-
const
|
|
49
|
+
const fs = __importStar(require("fs"));
|
|
50
|
+
const path = __importStar(require("path"));
|
|
51
|
+
const logger = (0, logger_1.createLogger)({ component: 'file-tools' });
|
|
17
52
|
/**
|
|
18
53
|
* Tool description - extracted for clarity
|
|
19
54
|
*/
|
|
@@ -25,7 +60,7 @@ Max 100MB per file. Returns file IDs for activities.`;
|
|
|
25
60
|
*/
|
|
26
61
|
exports.uploadFilesTool = {
|
|
27
62
|
name: 'upload_files',
|
|
28
|
-
group: tool_registry_1.ToolGroup.
|
|
63
|
+
group: tool_registry_1.ToolGroup.WRITE,
|
|
29
64
|
description: uploadFilesDescription,
|
|
30
65
|
schema: zod_1.z.object({
|
|
31
66
|
files: zod_1.z.union([
|
|
@@ -116,4 +151,87 @@ exports.uploadFilesTool = {
|
|
|
116
151
|
}
|
|
117
152
|
}
|
|
118
153
|
};
|
|
154
|
+
/**
|
|
155
|
+
* Download File Tool Description
|
|
156
|
+
*/
|
|
157
|
+
const downloadFileDescription = `๐งช [PLAYGROUND] Download file: \`{ "fileId": "abc123" }\` or save to disk: \`{ "fileId": "abc123", "savePath": "/path/to/save.pdf" }\`.
|
|
158
|
+
|
|
159
|
+
Returns file metadata and content (text for text files, base64 for binary).`;
|
|
160
|
+
/**
|
|
161
|
+
* Download File Tool - Clean implementation
|
|
162
|
+
*/
|
|
163
|
+
exports.downloadFileTool = {
|
|
164
|
+
name: 'download_file',
|
|
165
|
+
group: tool_registry_1.ToolGroup.READ,
|
|
166
|
+
description: downloadFileDescription,
|
|
167
|
+
schema: zod_1.z.object({
|
|
168
|
+
fileId: zod_1.z.string().describe("File ID to download"),
|
|
169
|
+
savePath: zod_1.z.string().optional().describe("Optional: local path to save file to disk")
|
|
170
|
+
}),
|
|
171
|
+
async execute(args, context) {
|
|
172
|
+
const { fileId, savePath } = args;
|
|
173
|
+
logger.debug('Downloading file', { fileId, savePath });
|
|
174
|
+
try {
|
|
175
|
+
const result = await context.hailer.downloadFile(fileId);
|
|
176
|
+
// If savePath provided, write to disk
|
|
177
|
+
if (savePath) {
|
|
178
|
+
try {
|
|
179
|
+
const dir = path.dirname(savePath);
|
|
180
|
+
if (!fs.existsSync(dir)) {
|
|
181
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
182
|
+
}
|
|
183
|
+
const buffer = result.encoding === 'base64'
|
|
184
|
+
? Buffer.from(result.content, 'base64')
|
|
185
|
+
: Buffer.from(result.content, 'utf8');
|
|
186
|
+
fs.writeFileSync(savePath, buffer);
|
|
187
|
+
return {
|
|
188
|
+
content: [{
|
|
189
|
+
type: "text",
|
|
190
|
+
text: `๐ฅ File downloaded and saved\n\n` +
|
|
191
|
+
`**File:** ${result.filename}\n` +
|
|
192
|
+
`**Type:** ${result.contentType}\n` +
|
|
193
|
+
`**Size:** ${(result.size / 1024).toFixed(2)} KB\n` +
|
|
194
|
+
`**Saved to:** ${savePath}\n` +
|
|
195
|
+
`**File ID:** ${result.fileId}`
|
|
196
|
+
}]
|
|
197
|
+
};
|
|
198
|
+
}
|
|
199
|
+
catch (error) {
|
|
200
|
+
return {
|
|
201
|
+
content: [{
|
|
202
|
+
type: "text",
|
|
203
|
+
text: `โ Failed to save file: ${error instanceof Error ? error.message : String(error)}`
|
|
204
|
+
}]
|
|
205
|
+
};
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
// Otherwise return content in response
|
|
209
|
+
const sizeKB = (result.size / 1024).toFixed(2);
|
|
210
|
+
const contentPreview = result.encoding === 'utf8'
|
|
211
|
+
? (result.content.length > 1000 ? result.content.substring(0, 1000) + '...' : result.content)
|
|
212
|
+
: `[Binary content - ${sizeKB} KB base64 encoded]`;
|
|
213
|
+
return {
|
|
214
|
+
content: [{
|
|
215
|
+
type: "text",
|
|
216
|
+
text: `๐ฅ File downloaded\n\n` +
|
|
217
|
+
`**File:** ${result.filename}\n` +
|
|
218
|
+
`**Type:** ${result.contentType}\n` +
|
|
219
|
+
`**Size:** ${sizeKB} KB\n` +
|
|
220
|
+
`**Encoding:** ${result.encoding}\n` +
|
|
221
|
+
`**File ID:** ${result.fileId}\n\n` +
|
|
222
|
+
`**Content:**\n\`\`\`\n${contentPreview}\n\`\`\``
|
|
223
|
+
}]
|
|
224
|
+
};
|
|
225
|
+
}
|
|
226
|
+
catch (error) {
|
|
227
|
+
logger.error('Download failed', error);
|
|
228
|
+
return {
|
|
229
|
+
content: [{
|
|
230
|
+
type: "text",
|
|
231
|
+
text: `โ Download failed: ${error instanceof Error ? error.message : String(error)}`
|
|
232
|
+
}]
|
|
233
|
+
};
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
};
|
|
119
237
|
//# sourceMappingURL=file.js.map
|
|
@@ -151,6 +151,19 @@ export declare class HailerApiClient {
|
|
|
151
151
|
* Upload a file from URL or filesystem path
|
|
152
152
|
*/
|
|
153
153
|
uploadFile(fileSpec: FileSpec): Promise<UploadResult>;
|
|
154
|
+
/**
|
|
155
|
+
* Download a file by file ID
|
|
156
|
+
* @param fileId - The file ID to download
|
|
157
|
+
* @returns File metadata and content (base64 for binary, text for text files)
|
|
158
|
+
*/
|
|
159
|
+
downloadFile(fileId: string): Promise<{
|
|
160
|
+
fileId: string;
|
|
161
|
+
filename: string;
|
|
162
|
+
contentType: string;
|
|
163
|
+
size: number;
|
|
164
|
+
content: string;
|
|
165
|
+
encoding: 'utf8' | 'base64';
|
|
166
|
+
}>;
|
|
154
167
|
/**
|
|
155
168
|
* Helper method to create MCP tool responses
|
|
156
169
|
*/
|
|
@@ -437,6 +437,70 @@ class HailerApiClient {
|
|
|
437
437
|
async uploadFile(fileSpec) {
|
|
438
438
|
return await (0, file_upload_1.uploadSingleFile)(fileSpec, this.clients);
|
|
439
439
|
}
|
|
440
|
+
/**
|
|
441
|
+
* Download a file by file ID
|
|
442
|
+
* @param fileId - The file ID to download
|
|
443
|
+
* @returns File metadata and content (base64 for binary, text for text files)
|
|
444
|
+
*/
|
|
445
|
+
async downloadFile(fileId) {
|
|
446
|
+
const url = `${this.clients.socket.host}/file/${fileId}`;
|
|
447
|
+
this.logger.debug('Downloading file', { fileId, url });
|
|
448
|
+
try {
|
|
449
|
+
const response = await fetch(url, {
|
|
450
|
+
method: 'GET',
|
|
451
|
+
headers: {
|
|
452
|
+
'hlrkey': this.clients.sessionKey,
|
|
453
|
+
},
|
|
454
|
+
});
|
|
455
|
+
if (!response.ok) {
|
|
456
|
+
throw new Error(`File download failed: ${response.status} ${response.statusText}`);
|
|
457
|
+
}
|
|
458
|
+
const contentType = response.headers.get('content-type') || 'application/octet-stream';
|
|
459
|
+
const contentDisposition = response.headers.get('content-disposition') || '';
|
|
460
|
+
// Extract filename from content-disposition header
|
|
461
|
+
let filename = fileId;
|
|
462
|
+
const filenameMatch = contentDisposition.match(/filename[^;=\n]*=((['"]).*?\2|[^;\n]*)/);
|
|
463
|
+
if (filenameMatch && filenameMatch[1]) {
|
|
464
|
+
filename = filenameMatch[1].replace(/['"]/g, '');
|
|
465
|
+
}
|
|
466
|
+
// Determine if content is text or binary
|
|
467
|
+
const isText = contentType.startsWith('text/') ||
|
|
468
|
+
contentType.includes('json') ||
|
|
469
|
+
contentType.includes('xml') ||
|
|
470
|
+
contentType.includes('javascript');
|
|
471
|
+
const buffer = await response.arrayBuffer();
|
|
472
|
+
const size = buffer.byteLength;
|
|
473
|
+
let content;
|
|
474
|
+
let encoding;
|
|
475
|
+
if (isText) {
|
|
476
|
+
content = new TextDecoder('utf-8').decode(buffer);
|
|
477
|
+
encoding = 'utf8';
|
|
478
|
+
}
|
|
479
|
+
else {
|
|
480
|
+
content = Buffer.from(buffer).toString('base64');
|
|
481
|
+
encoding = 'base64';
|
|
482
|
+
}
|
|
483
|
+
this.logger.debug('File downloaded successfully', {
|
|
484
|
+
fileId,
|
|
485
|
+
filename,
|
|
486
|
+
contentType,
|
|
487
|
+
size,
|
|
488
|
+
encoding
|
|
489
|
+
});
|
|
490
|
+
return {
|
|
491
|
+
fileId,
|
|
492
|
+
filename,
|
|
493
|
+
contentType,
|
|
494
|
+
size,
|
|
495
|
+
content,
|
|
496
|
+
encoding
|
|
497
|
+
};
|
|
498
|
+
}
|
|
499
|
+
catch (error) {
|
|
500
|
+
this.logger.error('File download failed', error, { fileId });
|
|
501
|
+
throw error;
|
|
502
|
+
}
|
|
503
|
+
}
|
|
440
504
|
/**
|
|
441
505
|
* Helper method to create MCP tool responses
|
|
442
506
|
*/
|
package/package.json
CHANGED
package/mcp-system-prompt.txt
DELETED
|
@@ -1,127 +0,0 @@
|
|
|
1
|
-
You are the MCP Assistant for Hailer MCP Server. Help users understand what MCP agents can do and guide them to the right agent for their task.
|
|
2
|
-
|
|
3
|
-
# What is Hailer MCP?
|
|
4
|
-
|
|
5
|
-
Hailer MCP is a Model Context Protocol server that connects Claude Code to Hailer workspaces. It provides 34+ tools for managing workflows, activities, insights, apps, and discussions.
|
|
6
|
-
|
|
7
|
-
Hailer is a SaaS platform for business process management with:
|
|
8
|
-
- Workspaces (organizations)
|
|
9
|
-
- Workflows (kanban-style process boards with phases)
|
|
10
|
-
- Activities (data records within workflows)
|
|
11
|
-
- Discussions (chat threads attached to activities)
|
|
12
|
-
- Insights (SQL-like reports over workflow data)
|
|
13
|
-
- Apps (custom React applications)
|
|
14
|
-
|
|
15
|
-
# Available Agents
|
|
16
|
-
|
|
17
|
-
## Fast Agents (haiku model)
|
|
18
|
-
|
|
19
|
-
### kenji - Data Reader
|
|
20
|
-
- Reads schema, fields, phases from local workspace/ files
|
|
21
|
-
- Falls back to API for activity data and counts
|
|
22
|
-
- Use for: "What fields does X have?", "List workflows", "Show phases"
|
|
23
|
-
|
|
24
|
-
### dmitri - Data Writer
|
|
25
|
-
- Creates and updates activities (single or bulk)
|
|
26
|
-
- Use for: "Create customer", "Update 50 records", "Move to phase"
|
|
27
|
-
- Needs: workflow_id, phase_id, field values from kenji first
|
|
28
|
-
|
|
29
|
-
### yevgeni - Discussion Handler
|
|
30
|
-
- Reads/posts messages, manages discussion membership
|
|
31
|
-
- Use for: "Post message", "Read chat history", "Invite user to discussion"
|
|
32
|
-
|
|
33
|
-
### bjorn - Config Auditor
|
|
34
|
-
- Audits CLAUDE.md, agents, hooks, settings.json
|
|
35
|
-
- Use for: "Check if config is correct", "Find orphaned files"
|
|
36
|
-
|
|
37
|
-
## Reasoning Agents (sonnet model)
|
|
38
|
-
|
|
39
|
-
### helga - Workspace Config
|
|
40
|
-
- Manages workflows, fields, phases via TypeScript SDK files
|
|
41
|
-
- Use for: "Add field to workflow", "Create new workflow", "Rename phase"
|
|
42
|
-
- Returns commands for orchestrator to run (npm run push)
|
|
43
|
-
|
|
44
|
-
### viktor - SQL Insights
|
|
45
|
-
- Creates SQL-like reports over workflow data
|
|
46
|
-
- Use for: "Report of high priority tasks", "Sales by month", "Join customers with orders"
|
|
47
|
-
- Always previews before creating
|
|
48
|
-
|
|
49
|
-
### giuseppe - App Builder
|
|
50
|
-
- Builds Hailer apps with React/TypeScript/Chakra
|
|
51
|
-
- Use for: "Build dashboard showing customers", "Create kanban app"
|
|
52
|
-
- Needs: workflow_id, phase_id, field_ids from kenji first
|
|
53
|
-
|
|
54
|
-
### alejandro - Function Fields
|
|
55
|
-
- Creates calculated/formula fields in workflows
|
|
56
|
-
- Use for: "Add Total Cost = qty * price", "Concatenate first + last name"
|
|
57
|
-
- Always tests formulas before enabling
|
|
58
|
-
|
|
59
|
-
### gunther - MCP Tool Builder
|
|
60
|
-
- Creates new MCP tools for the server itself
|
|
61
|
-
- Use for: "Add tool to count activities", "Create new API endpoint"
|
|
62
|
-
|
|
63
|
-
### svetlana - Code Reviewer
|
|
64
|
-
- Reviews code for bugs, security, best practices (READ-ONLY)
|
|
65
|
-
- Use for: "Review my changes", "Check for security issues"
|
|
66
|
-
|
|
67
|
-
### ada - Skill Creator
|
|
68
|
-
- Creates skills when agents fail repeatedly
|
|
69
|
-
- Use for: "Viktor keeps getting JOINs wrong", "Document this pattern"
|
|
70
|
-
|
|
71
|
-
### ingrid - Document Templates
|
|
72
|
-
- Creates PDF/CSV document templates
|
|
73
|
-
- Use for: "Create invoice template", "Add report template"
|
|
74
|
-
|
|
75
|
-
### agent-builder - Agent Creator
|
|
76
|
-
- Creates new lean agents (<50 lines)
|
|
77
|
-
- Use for: "I need an agent for X"
|
|
78
|
-
|
|
79
|
-
# How Agents Work
|
|
80
|
-
|
|
81
|
-
1. User asks the orchestrator (main Claude)
|
|
82
|
-
2. Orchestrator delegates to appropriate agent
|
|
83
|
-
3. Agent returns JSON with result
|
|
84
|
-
4. Orchestrator interprets and reports back
|
|
85
|
-
|
|
86
|
-
Agents output JSON only:
|
|
87
|
-
{ "status": "success|error", "result": {...}, "summary": "..." }
|
|
88
|
-
|
|
89
|
-
# Common Workflows
|
|
90
|
-
|
|
91
|
-
## Read data
|
|
92
|
-
kenji โ list workflows, get schema, get fields
|
|
93
|
-
|
|
94
|
-
## Create/update data
|
|
95
|
-
kenji (get IDs) โ dmitri (create/update)
|
|
96
|
-
|
|
97
|
-
## Build report
|
|
98
|
-
kenji (get schema) โ viktor (create insight)
|
|
99
|
-
|
|
100
|
-
## Build app
|
|
101
|
-
kenji (get IDs) โ giuseppe (scaffold + build)
|
|
102
|
-
|
|
103
|
-
## Configure workspace
|
|
104
|
-
helga (edit files) โ orchestrator runs push commands
|
|
105
|
-
|
|
106
|
-
# Current Version: 0.0.5
|
|
107
|
-
|
|
108
|
-
Recent changes:
|
|
109
|
-
- Hailer app builder improvements
|
|
110
|
-
- Marketplace template publishing
|
|
111
|
-
- Safety hooks for destructive operations
|
|
112
|
-
- 34+ MCP tools available
|
|
113
|
-
|
|
114
|
-
# Limitations
|
|
115
|
-
|
|
116
|
-
- Agents run via Claude Code CLI, not standalone
|
|
117
|
-
- Workspace-scoped (cannot access external systems)
|
|
118
|
-
- Orchestrator must provide IDs to write agents
|
|
119
|
-
- Some operations require npm run commands
|
|
120
|
-
|
|
121
|
-
# Guidelines
|
|
122
|
-
|
|
123
|
-
- Be concise (1-3 sentences per response)
|
|
124
|
-
- Match user's language
|
|
125
|
-
- If unsure which agent, ask clarifying question
|
|
126
|
-
- You guide users, you cannot execute actions yourself
|
|
127
|
-
- Recommend kenji first for any data lookup
|