@hailer/mcp 0.0.6 → 0.1.0

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 (120) hide show
  1. package/.claude/agents/ada.md +127 -0
  2. package/.claude/agents/agent-builder.md +151 -0
  3. package/.claude/agents/alejandro.md +66 -0
  4. package/.claude/agents/bjorn.md +305 -0
  5. package/.claude/agents/dmitri.md +61 -0
  6. package/.claude/agents/giuseppe.md +66 -0
  7. package/.claude/agents/gunther.md +355 -0
  8. package/.claude/agents/helga.md +68 -0
  9. package/.claude/agents/kenji.md +58 -0
  10. package/.claude/agents/svetlana.md +394 -0
  11. package/.claude/agents/viktor.md +63 -0
  12. package/.claude/agents/yevgeni.md +60 -0
  13. package/.claude/hooks/agent-failure-detector.cjs +286 -0
  14. package/.claude/hooks/app-edit-guard.cjs +462 -0
  15. package/.claude/hooks/interactive-mode.cjs +59 -0
  16. package/.claude/hooks/mcp-server-guard.cjs +92 -0
  17. package/.claude/hooks/post-scaffold-hook.cjs +31 -0
  18. package/.claude/hooks/src-edit-guard.cjs +208 -0
  19. package/.claude/settings.json +47 -2
  20. package/.claude/skills/insight-join-patterns/SKILL.md +209 -0
  21. package/.env.example +13 -1
  22. package/CLAUDE.md +134 -0
  23. package/dist/app.js +4 -3
  24. package/dist/cli.js +0 -0
  25. package/dist/client/adaptive-documentation-bot.d.ts +0 -2
  26. package/dist/client/adaptive-documentation-bot.js +5 -16
  27. package/dist/client/message-processor.js +5 -0
  28. package/dist/client/providers/anthropic-provider.js +21 -7
  29. package/dist/mcp/UserContextCache.d.ts +14 -0
  30. package/dist/mcp/UserContextCache.js +49 -24
  31. package/dist/mcp/auth.d.ts +7 -0
  32. package/dist/mcp/auth.js +13 -5
  33. package/dist/mcp/hailer-clients.d.ts +5 -2
  34. package/dist/mcp/signal-handler.d.ts +28 -2
  35. package/dist/mcp/signal-handler.js +4 -2
  36. package/dist/mcp/tool-registry.d.ts +55 -2
  37. package/dist/mcp/tool-registry.js +197 -2
  38. package/dist/mcp/tools/app-core.d.ts +15 -0
  39. package/dist/mcp/tools/app-core.js +609 -0
  40. package/dist/mcp/tools/app-marketplace.d.ts +21 -0
  41. package/dist/mcp/tools/app-marketplace.js +1284 -0
  42. package/dist/mcp/tools/app-member.d.ts +11 -0
  43. package/dist/mcp/tools/app-member.js +258 -0
  44. package/dist/mcp/tools/app-scaffold.d.ts +11 -0
  45. package/dist/mcp/tools/app-scaffold.js +743 -0
  46. package/dist/mcp/tools/app.d.ts +13 -22
  47. package/dist/mcp/tools/app.js +17 -2466
  48. package/dist/mcp/tools/file.js +6 -6
  49. package/dist/mcp/tools/insight.d.ts +1 -0
  50. package/dist/mcp/tools/insight.js +203 -64
  51. package/dist/mcp/tools/user.js +3 -9
  52. package/dist/mcp/tools/workflow.js +49 -38
  53. package/dist/mcp/utils/hailer-api-client.js +4 -13
  54. package/dist/mcp/utils/tool-helpers.d.ts +102 -0
  55. package/dist/mcp/utils/tool-helpers.js +179 -0
  56. package/dist/mcp/utils/types.d.ts +6 -0
  57. package/dist/mcp/workspace-cache.d.ts +5 -5
  58. package/dist/mcp/workspace-cache.js +4 -3
  59. package/package.json +1 -1
  60. package/.claude/hooks/PreToolUse.sh +0 -52
  61. package/.claude/hooks/prompt-skill-loader.cjs +0 -553
  62. package/.claude/hooks/skill-loader.cjs +0 -142
  63. package/.claude/settings.local.json +0 -49
  64. package/.claude/skills/MCP-add-app-member-skill/SKILL.md +0 -977
  65. package/.claude/skills/MCP-build-data-app-skill/SKILL.md +0 -372
  66. package/.claude/skills/MCP-create-app-skill/SKILL.md +0 -1101
  67. package/.claude/skills/MCP-create-insight-skill/SKILL.md +0 -1317
  68. package/.claude/skills/MCP-get-insight-data-skill/SKILL.md +0 -1053
  69. package/.claude/skills/MCP-insight-api/SKILL.md +0 -185
  70. package/.claude/skills/MCP-insight-api/references/insight-endpoints.md +0 -514
  71. package/.claude/skills/MCP-install-workflow-skill/SKILL.md +0 -1056
  72. package/.claude/skills/MCP-list-apps-skill/SKILL.md +0 -1010
  73. package/.claude/skills/MCP-list-workflows-minimal-skill/SKILL.md +0 -992
  74. package/.claude/skills/MCP-local-first-skill/SKILL.md +0 -570
  75. package/.claude/skills/MCP-populate-workflow-data-skill/SKILL.md +0 -395
  76. package/.claude/skills/MCP-preview-insight-skill/SKILL.md +0 -1290
  77. package/.claude/skills/MCP-publish-hailer-app-skill/SKILL.md +0 -453
  78. package/.claude/skills/MCP-publish-template-skill/SKILL.md +0 -278
  79. package/.claude/skills/MCP-remove-app-member-skill/SKILL.md +0 -671
  80. package/.claude/skills/MCP-remove-app-skill/SKILL.md +0 -985
  81. package/.claude/skills/MCP-remove-insight-skill/SKILL.md +0 -1011
  82. package/.claude/skills/MCP-remove-workflow-skill/SKILL.md +0 -920
  83. package/.claude/skills/MCP-scaffold-hailer-app-skill/SKILL.md +0 -1314
  84. package/.claude/skills/MCP-update-app-skill/SKILL.md +0 -970
  85. package/.claude/skills/MCP-update-workflow-field-skill/SKILL.md +0 -1098
  86. package/.claude/skills/SDK-create-function-field-skill/SKILL.md +0 -313
  87. package/.claude/skills/SDK-generate-skill/SKILL.md +0 -223
  88. package/.claude/skills/SDK-init-skill/SKILL.md +0 -177
  89. package/.claude/skills/SDK-workspace-setup-skill/SKILL.md +0 -605
  90. package/.claude/skills/SDK-ws-config-skill/SKILL.md +0 -435
  91. package/.claude/skills/activity-api/SKILL.md +0 -96
  92. package/.claude/skills/activity-api/references/activity-endpoints.md +0 -845
  93. package/.claude/skills/agent-building/SKILL.md +0 -243
  94. package/.claude/skills/agent-building/references/architecture-patterns.md +0 -446
  95. package/.claude/skills/agent-building/references/code-examples.md +0 -587
  96. package/.claude/skills/agent-building/references/implementation-guide.md +0 -619
  97. package/.claude/skills/app-api/SKILL.md +0 -219
  98. package/.claude/skills/app-api/references/app-endpoints.md +0 -759
  99. package/.claude/skills/building-hailer-apps-skill/SKILL.md +0 -813
  100. package/.claude/skills/hailer-api/SKILL.md +0 -283
  101. package/.claude/skills/hailer-api/references/activities.md +0 -620
  102. package/.claude/skills/hailer-api/references/authentication.md +0 -216
  103. package/.claude/skills/hailer-api/references/datasets.md +0 -437
  104. package/.claude/skills/hailer-api/references/files.md +0 -301
  105. package/.claude/skills/hailer-api/references/insights.md +0 -469
  106. package/.claude/skills/hailer-api/references/workflows.md +0 -720
  107. package/.claude/skills/hailer-api/references/workspaces-users.md +0 -445
  108. package/.claude/skills/hailer-app-builder/SKILL.md +0 -340
  109. package/.claude/skills/mcp-tools/SKILL.md +0 -419
  110. package/.claude/skills/mcp-tools/references/api-endpoints.md +0 -499
  111. package/.claude/skills/mcp-tools/references/data-structures.md +0 -554
  112. package/.claude/skills/mcp-tools/references/implementation-patterns.md +0 -717
  113. package/.claude/skills/skill-testing/README.md +0 -137
  114. package/.claude/skills/skill-testing/SKILL.md +0 -348
  115. package/.claude/skills/skill-testing/references/test-patterns.md +0 -705
  116. package/.claude/skills/skill-testing/references/testing-guide.md +0 -603
  117. package/.claude/skills/skill-testing/references/validation-checklist.md +0 -537
  118. package/.claude/skills/spawn-app-builder/SKILL.md +0 -366
  119. package/.claude/skills/tool-builder/SKILL.md +0 -328
  120. package/tsconfig.json +0 -23
@@ -0,0 +1,1284 @@
1
+ "use strict";
2
+ /**
3
+ * App Tools - Marketplace & Templates
4
+ *
5
+ * App marketplace and template management tools:
6
+ * - List, create, get, and install templates
7
+ * - Publish templates to marketplace
8
+ * - Publish apps to marketplace
9
+ * - Install marketplace apps
10
+ * - Get product info and manifests
11
+ */
12
+ Object.defineProperty(exports, "__esModule", { value: true });
13
+ exports.installMarketplaceAppTool = exports.publishAppTool = exports.getProductManifestTool = exports.getProductTool = exports.publishTemplateTool = exports.getTemplateTool = exports.installTemplateTool = exports.createTemplateTool = exports.listTemplatesTool = void 0;
14
+ const zod_1 = require("zod");
15
+ const tool_registry_1 = require("../tool-registry");
16
+ const logger_1 = require("../../lib/logger");
17
+ const tool_helpers_1 = require("../utils/tool-helpers");
18
+ const logger = (0, logger_1.createLogger)({ component: 'app-marketplace' });
19
+ const listTemplatesDescription = `🏪 [PLAYGROUND] List Templates - View marketplace templates available
20
+
21
+ **What it does**:
22
+ Lists all workflow templates available in the Hailer marketplace.
23
+
24
+ **Example**:
25
+ \`\`\`javascript
26
+ list_templates()
27
+ \`\`\`
28
+
29
+ **Shows**:
30
+ - Template name and description
31
+ - Template ID
32
+ - Creator info
33
+ - Installation status
34
+
35
+ **Use Cases**:
36
+ - Discover available templates
37
+ - Find template IDs for installation
38
+ - Browse marketplace offerings
39
+
40
+ **Note**: Products created with \`create_template\` are workspace-specific and won't appear here until published to the public marketplace.`;
41
+ exports.listTemplatesTool = {
42
+ name: 'list_templates',
43
+ group: tool_registry_1.ToolGroup.PLAYGROUND,
44
+ description: listTemplatesDescription,
45
+ schema: zod_1.z.object({
46
+ workspaceId: zod_1.z
47
+ .string()
48
+ .optional()
49
+ .describe("Optional workspace ID - defaults to current workspace"),
50
+ publicOnly: zod_1.z
51
+ .boolean()
52
+ .optional()
53
+ .default(false)
54
+ .describe("If true, show only public marketplace templates. If false (default), show private/workspace templates."),
55
+ }),
56
+ async execute(args, context) {
57
+ const showPublic = args.publicOnly ?? false;
58
+ logger.debug('Listing marketplace templates', {
59
+ workspaceId: args.workspaceId,
60
+ publicOnly: showPublic,
61
+ apiKey: context.apiKey.substring(0, 8) + '...'
62
+ });
63
+ try {
64
+ const workspaceId = (0, tool_helpers_1.getResolvedWorkspaceId)(args, context);
65
+ if (!workspaceId) {
66
+ return (0, tool_helpers_1.missingWorkspaceCacheResponse)();
67
+ }
68
+ logger.debug('Calling v3.product.list', { workspaceId, public: showPublic });
69
+ // v3.product.list endpoint with public flag
70
+ const result = await context.hailer.request('v3.product.list', [
71
+ { cid: workspaceId, public: showPublic },
72
+ {} // pagination options
73
+ ]);
74
+ logger.debug('Template list response', {
75
+ result: JSON.stringify(result)
76
+ });
77
+ const templateType = showPublic ? 'Public Marketplace' : 'Private/Workspace';
78
+ let responseText = `✅ **${templateType} Templates**\n\n`;
79
+ responseText += `**Workspace:** ${workspaceId}\n`;
80
+ responseText += `**Filter:** ${showPublic ? 'Public only' : 'Private/workspace'}\n\n`;
81
+ // Handle response: {products: [], totalCount: 0}
82
+ const products = result?.products || [];
83
+ const totalCount = result?.totalCount || 0;
84
+ if (products.length === 0) {
85
+ responseText += `**No ${showPublic ? 'public' : 'private'} templates found.**\n\n`;
86
+ if (showPublic) {
87
+ responseText += `💡 Try \`list_templates()\` without \`publicOnly: true\` to see private workspace templates.\n`;
88
+ }
89
+ else {
90
+ responseText += `💡 Use \`create_template\` to create a new template.\n`;
91
+ }
92
+ return {
93
+ content: [{
94
+ type: "text",
95
+ text: responseText,
96
+ }],
97
+ };
98
+ }
99
+ const templates = products;
100
+ responseText += `**Total Templates:** ${templates.length}\n\n`;
101
+ templates.forEach((template, index) => {
102
+ responseText += `### ${index + 1}. ${template.name || 'Unnamed Template'}\n`;
103
+ responseText += `- **ID:** \`${template._id || template.id || 'N/A'}\`\n`;
104
+ if (template.description) {
105
+ responseText += `- **Description:** ${template.description}\n`;
106
+ }
107
+ if (template.creator) {
108
+ responseText += `- **Creator:** ${template.creator}\n`;
109
+ }
110
+ if (template.version) {
111
+ responseText += `- **Version:** ${template.version}\n`;
112
+ }
113
+ if (template.icon) {
114
+ responseText += `- **Icon:** \`${template.icon}\`\n`;
115
+ }
116
+ if (template.images && template.images.length > 0) {
117
+ responseText += `- **Images:** ${template.images.map((img) => `\`${img}\``).join(', ')}\n`;
118
+ }
119
+ responseText += `\n`;
120
+ });
121
+ responseText += `💡 **Next Steps:**\n`;
122
+ responseText += `- Use \`install_template\` to install a template\n`;
123
+ responseText += `- Use \`get_template\` to see template details`;
124
+ return {
125
+ content: [{
126
+ type: "text",
127
+ text: responseText,
128
+ }],
129
+ };
130
+ }
131
+ catch (error) {
132
+ logger.error("Error listing templates", error);
133
+ const errorMessage = (0, tool_helpers_1.extractErrorMessage)(error);
134
+ return {
135
+ content: [{
136
+ type: "text",
137
+ text: `❌ **Error listing templates**\n\n**Error:** ${errorMessage}\n\n**Common Issues:**\n- API endpoint not available\n- Permission issues`,
138
+ }],
139
+ };
140
+ }
141
+ }
142
+ };
143
+ // ============================================================================
144
+ // CREATE TEMPLATE TOOL (MARKETPLACE)
145
+ // ============================================================================
146
+ const createTemplateDescription = `🏪 [PLAYGROUND] Create Template - Add template to marketplace
147
+
148
+ **What it does**:
149
+ Creates a new workflow template in the Hailer marketplace.
150
+
151
+ **Example**:
152
+ \`\`\`javascript
153
+ create_template({
154
+ name: 'Project Management',
155
+ description: 'Template for managing projects',
156
+ workflowId: '<source-workflow-id>'
157
+ })
158
+ \`\`\`
159
+
160
+ **Parameters**:
161
+ - \`name\` (required) - Template name
162
+ - \`description\` (optional) - Template description
163
+ - \`workflowId\` (optional) - Source workflow to create template from
164
+
165
+ **Requirements**:
166
+ - User must be workspace administrator
167
+
168
+ **Tips**:
169
+ - Create template from existing workflow
170
+ - Use descriptive names for discoverability`;
171
+ exports.createTemplateTool = {
172
+ name: 'create_template',
173
+ group: tool_registry_1.ToolGroup.PLAYGROUND,
174
+ description: createTemplateDescription,
175
+ schema: zod_1.z.object({
176
+ name: zod_1.z
177
+ .string()
178
+ .min(1)
179
+ .describe("Template name (required)"),
180
+ description: zod_1.z
181
+ .string()
182
+ .optional()
183
+ .describe("Template description"),
184
+ workflowId: zod_1.z
185
+ .string()
186
+ .optional()
187
+ .describe("Source workflow ID to create template from"),
188
+ }),
189
+ async execute(args, context) {
190
+ logger.debug('Creating marketplace template', {
191
+ name: args.name,
192
+ hasWorkflowId: !!args.workflowId,
193
+ apiKey: context.apiKey.substring(0, 8) + '...'
194
+ });
195
+ try {
196
+ const workspaceId = (0, tool_helpers_1.getResolvedWorkspaceId)({}, context);
197
+ if (!workspaceId) {
198
+ return (0, tool_helpers_1.missingWorkspaceCacheResponse)();
199
+ }
200
+ // v2.network.product.create - creates a product entry (only accepts name)
201
+ const templateData = {
202
+ name: args.name
203
+ };
204
+ logger.debug('Calling v2.network.product.create', {
205
+ workspaceId,
206
+ templateData
207
+ });
208
+ const result = await context.hailer.request('v2.network.product.create', [templateData]);
209
+ logger.debug('Template creation response', {
210
+ result: JSON.stringify(result)
211
+ });
212
+ const templateId = result?.productId || result?._id || result?.id;
213
+ let responseText = `✅ **Template Created Successfully**\n\n`;
214
+ responseText += `**Template Name:** ${args.name}\n`;
215
+ responseText += `**Template ID:** \`${templateId || 'See response'}\`\n`;
216
+ responseText += `**Workspace:** ${workspaceId}\n`;
217
+ responseText += `\n💡 **Next Steps:**\n`;
218
+ responseText += `- Use Hailer marketplace UI to add workflows and description\n`;
219
+ responseText += `- Share the template ID with others to install\n`;
220
+ if (args.description || args.workflowId) {
221
+ responseText += `\n⚠️ **Note:** The \`v3.app.product.create\` API only accepts \`name\`.\n`;
222
+ responseText += `Description and workflow attachment must be done via Hailer UI.\n`;
223
+ }
224
+ return {
225
+ content: [{
226
+ type: "text",
227
+ text: responseText,
228
+ }],
229
+ };
230
+ }
231
+ catch (error) {
232
+ logger.error("Error creating template", error);
233
+ const errorMessage = (0, tool_helpers_1.extractErrorMessage)(error);
234
+ if (errorMessage.toLowerCase().includes('permission')) {
235
+ return {
236
+ content: [{
237
+ type: "text",
238
+ text: `❌ **Permission Denied**\n\nYou don't have permission to create templates. Only workspace administrators can create templates.\n\n**Error:** ${errorMessage}`,
239
+ }],
240
+ };
241
+ }
242
+ return {
243
+ content: [{
244
+ type: "text",
245
+ text: `❌ **Error creating template**\n\n**Error:** ${errorMessage}\n\n**Common Issues:**\n- User must be workspace administrator\n- Invalid workflow ID`,
246
+ }],
247
+ };
248
+ }
249
+ }
250
+ };
251
+ // ============================================================================
252
+ // INSTALL TEMPLATE TOOL (MARKETPLACE)
253
+ // ============================================================================
254
+ const installTemplateDescription = `🏪 [PLAYGROUND] Install Template - Install marketplace template to workspace
255
+
256
+ **What it does**:
257
+ Installs a template from the Hailer marketplace into your workspace.
258
+
259
+ **Example**:
260
+ \`\`\`javascript
261
+ install_template({
262
+ templateId: '<template-id>'
263
+ })
264
+ \`\`\`
265
+
266
+ **Parameters**:
267
+ - \`templateId\` (required) - Template/Product ID from marketplace
268
+
269
+ **Requirements**:
270
+ - User must be workspace administrator
271
+
272
+ **Tips**:
273
+ - Use \`list_templates\` to find template IDs
274
+ - Template creates new workflow(s) in workspace`;
275
+ exports.installTemplateTool = {
276
+ name: 'install_template',
277
+ group: tool_registry_1.ToolGroup.PLAYGROUND,
278
+ description: installTemplateDescription,
279
+ schema: zod_1.z.object({
280
+ templateId: zod_1.z
281
+ .string()
282
+ .min(1)
283
+ .describe("Template/Product ID to install"),
284
+ workspaceId: zod_1.z
285
+ .string()
286
+ .optional()
287
+ .describe("Target workspace ID (defaults to current)"),
288
+ }),
289
+ async execute(args, context) {
290
+ logger.debug('Installing marketplace template', {
291
+ templateId: args.templateId,
292
+ workspaceId: args.workspaceId,
293
+ apiKey: context.apiKey.substring(0, 8) + '...'
294
+ });
295
+ try {
296
+ const workspaceId = (0, tool_helpers_1.getResolvedWorkspaceId)(args, context);
297
+ if (!workspaceId) {
298
+ return (0, tool_helpers_1.missingWorkspaceCacheResponse)();
299
+ }
300
+ logger.debug('Calling v2.network.product.install', {
301
+ templateId: args.templateId,
302
+ workspaceId
303
+ });
304
+ const result = await context.hailer.request('v2.network.product.install', [
305
+ args.templateId,
306
+ workspaceId
307
+ ]);
308
+ logger.debug('Template installation response', {
309
+ result: JSON.stringify(result)
310
+ });
311
+ const appId = result?.appId || result?._id;
312
+ let responseText = `✅ **Template Installed Successfully**\n\n`;
313
+ responseText += `**Template ID:** \`${args.templateId}\`\n`;
314
+ responseText += `**Workspace:** ${workspaceId}\n`;
315
+ if (appId) {
316
+ responseText += `**App ID:** \`${appId}\`\n`;
317
+ }
318
+ responseText += `\n💡 **Next Steps:**\n`;
319
+ responseText += `- Use \`list_workflows\` to see new workflow(s)\n`;
320
+ responseText += `- Use \`list_apps\` to see new app(s)\n`;
321
+ return {
322
+ content: [{
323
+ type: "text",
324
+ text: responseText,
325
+ }],
326
+ };
327
+ }
328
+ catch (error) {
329
+ logger.error("Error installing template", error);
330
+ const errorMessage = (0, tool_helpers_1.extractErrorMessage)(error);
331
+ if (errorMessage.toLowerCase().includes('not found')) {
332
+ return {
333
+ content: [{
334
+ type: "text",
335
+ text: `❌ **Template Not Found**\n\nTemplate ID \`${args.templateId}\` not found in marketplace.\n\n**Check:**\n- Template ID is correct\n- Template is published and available\n\n💡 Use \`list_templates\` to see available templates.`,
336
+ }],
337
+ };
338
+ }
339
+ if (errorMessage.toLowerCase().includes('permission')) {
340
+ return {
341
+ content: [{
342
+ type: "text",
343
+ text: `❌ **Permission Denied**\n\nYou don't have permission to install templates. Only workspace administrators can install templates.\n\n**Error:** ${errorMessage}`,
344
+ }],
345
+ };
346
+ }
347
+ if (errorMessage.toLowerCase().includes('already installed')) {
348
+ return {
349
+ content: [{
350
+ type: "text",
351
+ text: `⚠️ **Template Already Installed**\n\nThis template is already installed in the workspace.\n\n**Template ID:** \`${args.templateId}\`\n\n💡 Use \`list_apps\` to see installed apps.`,
352
+ }],
353
+ };
354
+ }
355
+ // Include debug info for troubleshooting
356
+ const debugInfo = {
357
+ endpoint: 'v2.network.product.install',
358
+ requestData: [args.templateId, args.workspaceId || 'current-workspace']
359
+ };
360
+ return {
361
+ content: [{
362
+ type: "text",
363
+ text: `❌ **Error installing template**\n\n**Error:** ${errorMessage}\n\n**Debug Info:**\n\`\`\`json\n${JSON.stringify(debugInfo, null, 2)}\n\`\`\`\n\n**Common Issues:**\n- Invalid template ID\n- Template not found\n- Permission denied\n- Already installed`,
364
+ }],
365
+ };
366
+ }
367
+ }
368
+ };
369
+ // ============================================================================
370
+ // GET TEMPLATE TOOL (MARKETPLACE)
371
+ // ============================================================================
372
+ const getTemplateDescription = `🏪 [PLAYGROUND] Get Template - View template details from marketplace
373
+
374
+ **What it does**:
375
+ Retrieves detailed information about a specific marketplace template.
376
+
377
+ **Example**:
378
+ \`\`\`javascript
379
+ get_template({
380
+ templateId: '<template-id>'
381
+ })
382
+ \`\`\`
383
+
384
+ **Shows**:
385
+ - Template name and description
386
+ - Template version
387
+ - Included workflows
388
+ - Manifest information
389
+
390
+ **Use Cases**:
391
+ - Preview template before installing
392
+ - Check template version
393
+ - View template structure`;
394
+ exports.getTemplateTool = {
395
+ name: 'get_template',
396
+ group: tool_registry_1.ToolGroup.PLAYGROUND,
397
+ description: getTemplateDescription,
398
+ schema: zod_1.z.object({
399
+ templateId: zod_1.z
400
+ .string()
401
+ .min(1)
402
+ .describe("Template/Product ID to get details for"),
403
+ }),
404
+ async execute(args, context) {
405
+ logger.debug('Getting marketplace template', {
406
+ templateId: args.templateId,
407
+ apiKey: context.apiKey.substring(0, 8) + '...'
408
+ });
409
+ try {
410
+ logger.debug('Calling v2.network.product.get', {
411
+ templateId: args.templateId
412
+ });
413
+ const result = await context.hailer.request('v2.network.product.get', [args.templateId]);
414
+ logger.debug('Template get response', {
415
+ result: JSON.stringify(result)
416
+ });
417
+ const product = result?.product || result;
418
+ let responseText = `✅ **Template Details**\n\n`;
419
+ responseText += `**Template ID:** \`${args.templateId}\`\n`;
420
+ if (product?.name) {
421
+ responseText += `**Name:** ${product.name}\n`;
422
+ }
423
+ if (product?.description) {
424
+ responseText += `**Description:** ${product.description}\n`;
425
+ }
426
+ if (product?.version) {
427
+ responseText += `**Version:** ${product.version}\n`;
428
+ }
429
+ // Also try to get manifest
430
+ try {
431
+ const manifest = await context.hailer.request('v2.network.product.getManifest', [args.templateId]);
432
+ logger.debug('Template manifest response', {
433
+ manifest: JSON.stringify(manifest)
434
+ });
435
+ if (manifest) {
436
+ responseText += `\n**Manifest:**\n\`\`\`json\n${JSON.stringify(manifest, null, 2)}\n\`\`\`\n`;
437
+ }
438
+ }
439
+ catch (manifestError) {
440
+ logger.debug('Could not fetch manifest', { error: manifestError });
441
+ }
442
+ // Check if installed (needs productId and workspaceId)
443
+ try {
444
+ if (context.workspaceCache) {
445
+ const workspaceId = context.workspaceCache.currentWorkspace._id;
446
+ const installed = await context.hailer.request('v2.network.product.isProductInstalled', [
447
+ args.templateId,
448
+ workspaceId
449
+ ]);
450
+ logger.debug('Template installation check', {
451
+ installed: JSON.stringify(installed)
452
+ });
453
+ if (installed?.installed) {
454
+ responseText += `\n✅ **Status:** Installed in current workspace\n`;
455
+ if (installed.appId) {
456
+ responseText += `**App ID:** \`${installed.appId}\`\n`;
457
+ }
458
+ }
459
+ else {
460
+ responseText += `\n⚪ **Status:** Not installed in current workspace\n`;
461
+ }
462
+ }
463
+ }
464
+ catch (installCheckError) {
465
+ logger.debug('Could not check installation status', { error: installCheckError });
466
+ }
467
+ responseText += `\n💡 **Next Steps:**\n`;
468
+ responseText += `- Use \`install_template\` to install this template\n`;
469
+ responseText += `- Use \`list_templates\` to see other templates`;
470
+ return {
471
+ content: [{
472
+ type: "text",
473
+ text: responseText,
474
+ }],
475
+ };
476
+ }
477
+ catch (error) {
478
+ logger.error("Error getting template", error);
479
+ const errorMessage = (0, tool_helpers_1.extractErrorMessage)(error);
480
+ if (errorMessage.toLowerCase().includes('not found')) {
481
+ return {
482
+ content: [{
483
+ type: "text",
484
+ text: `❌ **Template Not Found**\n\nTemplate ID \`${args.templateId}\` not found in marketplace.\n\n**Check:**\n- Template ID is correct\n- Template exists and is published\n\n💡 Use \`list_templates\` to see available templates.`,
485
+ }],
486
+ };
487
+ }
488
+ return {
489
+ content: [{
490
+ type: "text",
491
+ text: `❌ **Error getting template**\n\n**Error:** ${errorMessage}\n\n**Common Issues:**\n- Invalid template ID\n- Template not found`,
492
+ }],
493
+ };
494
+ }
495
+ }
496
+ };
497
+ // ============================================================================
498
+ // PUBLISH TEMPLATE TOOL (MARKETPLACE)
499
+ // ============================================================================
500
+ const publishTemplateDescription = `🏪 [PLAYGROUND] Publish Template - Publish workspace to marketplace
501
+
502
+ **What it does**:
503
+ Publishes the current workspace as a template to the Hailer marketplace, making it installable by other workspaces.
504
+
505
+ **Example - New Template**:
506
+ \`\`\`javascript
507
+ publish_template({
508
+ title: 'Football Manager',
509
+ description: 'Complete football club management workspace',
510
+ version: '1.0.0',
511
+ versionDescription: 'Initial release with Players, Matches, Training workflows',
512
+ publisher: 'Hailer Oy',
513
+ iconFileId: '692d3e66e98c7bab4af7f0a1'
514
+ })
515
+ \`\`\`
516
+
517
+ **Example - Update Existing Template**:
518
+ \`\`\`javascript
519
+ publish_template({
520
+ productId: '692d46bfca77093f10b0c09a', // Existing product ID
521
+ title: 'Football Manager',
522
+ description: 'Updated description',
523
+ version: '1.1.0',
524
+ versionDescription: 'Fixed icon and added new features',
525
+ publisher: 'Hailer Oy',
526
+ iconFileId: '692d47adf9383bd1a9e26d78'
527
+ })
528
+ \`\`\`
529
+
530
+ **Required Parameters** (gather ALL before calling):
531
+ - \`title\` - Template name (max 64 chars)
532
+ - \`description\` - Template description (max 4096 chars)
533
+ - \`version\` - Version string (e.g. "1.0.0")
534
+ - \`versionDescription\` - Release notes for this version
535
+ - \`publisher\` - Publishing company/person name
536
+ - \`iconFileId\` - Icon file ID (upload with \`upload_files\` first)
537
+
538
+ **Optional Parameters**:
539
+ - \`productId\` - Existing product ID to UPDATE (omit to create new)
540
+ - \`imageFileIds\` - Array of preview image file IDs
541
+ - \`externalUrl\` - External website URL
542
+
543
+ **IMPORTANT**: A PreToolUse hook will BLOCK this call if required fields are missing.
544
+ Gather ALL information from user BEFORE calling this tool.
545
+
546
+ **Workflow**:
547
+ 1. Ask user for template details (name, description, version, etc.)
548
+ 2. Ask user for icon (URL, path, or existing fileId)
549
+ 3. Upload icon with \`upload_files\`
550
+ 4. Call \`publish_template\` with ALL fields
551
+ 5. To UPDATE: include \`productId\` from previous publish
552
+
553
+ **What Gets Published**:
554
+ - The ENTIRE current workspace is published as a template
555
+ - All workflows, fields, phases are included
556
+
557
+ **After Publishing**:
558
+ - Template appears in \`list_templates()\`
559
+ - Other workspaces can install with \`install_template()\``;
560
+ exports.publishTemplateTool = {
561
+ name: 'publish_template',
562
+ group: tool_registry_1.ToolGroup.PLAYGROUND,
563
+ description: publishTemplateDescription,
564
+ schema: zod_1.z.object({
565
+ productId: zod_1.z
566
+ .string()
567
+ .length(24)
568
+ .optional()
569
+ .describe("Existing product ID to UPDATE (omit to create new template)"),
570
+ title: zod_1.z
571
+ .string()
572
+ .min(1)
573
+ .max(64)
574
+ .describe("Template name (max 64 chars)"),
575
+ description: zod_1.z
576
+ .string()
577
+ .min(1)
578
+ .max(4096)
579
+ .describe("Template description (max 4096 chars)"),
580
+ version: zod_1.z
581
+ .string()
582
+ .min(1)
583
+ .describe("Version string (e.g. '1.0.0')"),
584
+ versionDescription: zod_1.z
585
+ .string()
586
+ .min(1)
587
+ .describe("Release notes for this version"),
588
+ publisher: zod_1.z
589
+ .string()
590
+ .min(1)
591
+ .describe("Publishing company or person name"),
592
+ iconFileId: zod_1.z
593
+ .string()
594
+ .length(24)
595
+ .describe("Icon file ID (24 chars). Upload with upload_files first"),
596
+ imageFileIds: zod_1.z
597
+ .array(zod_1.z.string().length(24))
598
+ .optional()
599
+ .describe("Optional array of preview image file IDs"),
600
+ externalUrl: zod_1.z
601
+ .string()
602
+ .url()
603
+ .optional()
604
+ .describe("Optional external website URL"),
605
+ }),
606
+ async execute(args, context) {
607
+ const isUpdate = !!args.productId;
608
+ logger.debug(`${isUpdate ? 'Updating' : 'Publishing'} template to marketplace`, {
609
+ title: args.title,
610
+ version: args.version,
611
+ productId: args.productId,
612
+ apiKey: context.apiKey.substring(0, 8) + '...'
613
+ });
614
+ try {
615
+ const workspaceId = (0, tool_helpers_1.getResolvedWorkspaceId)({}, context);
616
+ if (!workspaceId) {
617
+ return (0, tool_helpers_1.missingWorkspaceCacheResponse)();
618
+ }
619
+ let productId = args.productId;
620
+ // Only create new manifest if not updating existing template
621
+ if (!isUpdate) {
622
+ // Note: versionDescription is required and cannot be empty
623
+ const publishData = {
624
+ workspaceId,
625
+ version: args.version,
626
+ versionDescription: args.versionDescription,
627
+ title: args.title,
628
+ description: args.description
629
+ };
630
+ logger.debug('Calling v2.network.product.publishTemplate', {
631
+ publishData
632
+ });
633
+ // Step 1: Create the template manifest
634
+ const publishResult = await context.hailer.request('v2.network.product.publishTemplate', [publishData]);
635
+ logger.debug('Publish template response', {
636
+ result: JSON.stringify(publishResult)
637
+ });
638
+ productId = publishResult?.productId || publishResult?._id || publishResult?.id;
639
+ if (!productId) {
640
+ return {
641
+ content: [{
642
+ type: "text",
643
+ text: `❌ **Error**: publishTemplate succeeded but no product ID returned.\n\n**Response:**\n\`\`\`json\n${JSON.stringify(publishResult, null, 2)}\n\`\`\``,
644
+ }],
645
+ };
646
+ }
647
+ }
648
+ // Step 2: Create or Update the product in marketplace
649
+ let productData;
650
+ let apiMethod;
651
+ let apiArgs;
652
+ if (isUpdate) {
653
+ // Update only allows specific fields
654
+ productData = {
655
+ name: args.title,
656
+ description: args.description,
657
+ publisher: args.publisher,
658
+ icon: args.iconFileId,
659
+ images: args.imageFileIds || [args.iconFileId]
660
+ };
661
+ if (args.externalUrl) {
662
+ productData.externalUrl = args.externalUrl;
663
+ }
664
+ apiMethod = 'v3.product.update';
665
+ apiArgs = [productId, productData];
666
+ }
667
+ else {
668
+ // Create requires full data
669
+ productData = {
670
+ cid: workspaceId,
671
+ targetId: productId,
672
+ name: args.title,
673
+ description: args.description,
674
+ type: 'template',
675
+ publisher: args.publisher,
676
+ icon: args.iconFileId,
677
+ images: args.imageFileIds || [args.iconFileId]
678
+ };
679
+ if (args.externalUrl) {
680
+ productData.externalUrl = args.externalUrl;
681
+ }
682
+ apiMethod = 'v3.product.create';
683
+ apiArgs = [productData];
684
+ }
685
+ logger.debug(`Calling ${apiMethod}`, { productId, workspaceId, iconFileId: args.iconFileId });
686
+ const apiResult = await context.hailer.request(apiMethod, apiArgs);
687
+ logger.debug(`${apiMethod} response`, {
688
+ result: JSON.stringify(apiResult)
689
+ });
690
+ // Get the final product ID from the v3 API response (this is the correct marketplace ID)
691
+ const finalProductId = apiResult?._id || apiResult?.id || productId;
692
+ let responseText = `✅ **Template ${isUpdate ? 'Updated' : 'Published'} Successfully**\n\n`;
693
+ responseText += `**Title:** ${args.title}\n`;
694
+ responseText += `**Publisher:** ${args.publisher}\n`;
695
+ responseText += `**Version:** ${args.version}\n`;
696
+ responseText += `**Workspace:** ${workspaceId}\n`;
697
+ responseText += `**Product ID:** \`${finalProductId}\`\n`;
698
+ responseText += `**Release Notes:** ${args.versionDescription}\n`;
699
+ responseText += `\n💡 **Next Steps:**\n`;
700
+ responseText += `- Use \`list_templates()\` to see it in the marketplace\n`;
701
+ responseText += `- Share the product ID with other workspaces\n`;
702
+ responseText += `- They can install with \`install_template({ templateId: "${finalProductId}" })\`\n`;
703
+ return {
704
+ content: [{
705
+ type: "text",
706
+ text: responseText,
707
+ }],
708
+ };
709
+ }
710
+ catch (error) {
711
+ logger.error("Error publishing template", error);
712
+ const errorMessage = (0, tool_helpers_1.extractErrorMessage)(error);
713
+ if (errorMessage.toLowerCase().includes('permission')) {
714
+ return {
715
+ content: [{
716
+ type: "text",
717
+ text: `❌ **Permission Denied**\n\nYou don't have permission to publish templates. Only workspace administrators can publish.\n\n**Error:** ${errorMessage}`,
718
+ }],
719
+ };
720
+ }
721
+ // Always include debug info for troubleshooting
722
+ const debugWorkspaceId = context.workspaceCache?.currentWorkspace._id || 'unknown';
723
+ const debugInfo = {
724
+ endpoint: 'v2.network.product.publishTemplate',
725
+ requestData: {
726
+ workspaceId: debugWorkspaceId,
727
+ version: args.version,
728
+ versionDescription: args.versionDescription,
729
+ title: args.title,
730
+ description: args.description
731
+ }
732
+ };
733
+ return {
734
+ content: [{
735
+ type: "text",
736
+ text: `❌ **Error publishing template**\n\n**Error:** ${errorMessage}\n\n**Debug Info:**\n\`\`\`json\n${JSON.stringify(debugInfo, null, 2)}\n\`\`\`\n\n**Common Issues:**\n- Product may need to exist first (use create_template)\n- Version format may be incorrect\n- Workflow may not be attached to product`,
737
+ }],
738
+ };
739
+ }
740
+ }
741
+ };
742
+ // =============================================================================
743
+ // GET PRODUCT (v3) TOOL
744
+ // =============================================================================
745
+ const getProductDescription = `🏪 [PLAYGROUND] Get Product - Get detailed product info from marketplace (v3 API)
746
+
747
+ **What it does**:
748
+ Retrieves detailed information about a marketplace product using v3 API.
749
+
750
+ **Example**:
751
+ \`\`\`javascript
752
+ get_product({
753
+ productId: '692994df55996e1201963cd7'
754
+ })
755
+ \`\`\`
756
+
757
+ **Returns**: Product details including versions, workflows, and configuration`;
758
+ exports.getProductTool = {
759
+ name: 'get_product',
760
+ group: tool_registry_1.ToolGroup.PLAYGROUND,
761
+ description: getProductDescription,
762
+ schema: zod_1.z.object({
763
+ productId: zod_1.z
764
+ .string()
765
+ .length(24)
766
+ .describe("Product ID to get details for (24 characters)"),
767
+ }),
768
+ async execute(args, context) {
769
+ logger.debug('Getting product details (v3)', {
770
+ productId: args.productId,
771
+ apiKey: context.apiKey.substring(0, 8) + '...'
772
+ });
773
+ try {
774
+ logger.debug('Calling v3.app.product.get', {
775
+ productId: args.productId
776
+ });
777
+ const result = await context.hailer.request('v3.app.product.get', [args.productId]);
778
+ logger.debug('Product get response', {
779
+ result: JSON.stringify(result)
780
+ });
781
+ const product = result;
782
+ let responseText = `✅ **Product Details (v3)**\n\n`;
783
+ responseText += `**Product ID:** \`${args.productId}\`\n`;
784
+ if (product?.name) {
785
+ responseText += `**Name:** ${product.name}\n`;
786
+ }
787
+ if (product?.description) {
788
+ responseText += `**Description:** ${product.description}\n`;
789
+ }
790
+ if (product?.type) {
791
+ responseText += `**Type:** ${product.type}\n`;
792
+ }
793
+ if (product?.versions?.length) {
794
+ responseText += `**Versions:** ${product.versions.length}\n`;
795
+ }
796
+ return {
797
+ content: [{
798
+ type: "text",
799
+ text: responseText,
800
+ }],
801
+ };
802
+ }
803
+ catch (error) {
804
+ logger.error("Error getting product", error);
805
+ const errorMessage = (0, tool_helpers_1.extractErrorMessage)(error);
806
+ return {
807
+ content: [{
808
+ type: "text",
809
+ text: `❌ **Error getting product**\n\n**Error:** ${errorMessage}`,
810
+ }],
811
+ };
812
+ }
813
+ }
814
+ };
815
+ // =============================================================================
816
+ // GET PRODUCT MANIFEST (v3) TOOL
817
+ // =============================================================================
818
+ const getProductManifestDescription = `🏪 [PLAYGROUND] Get Product Manifest - Get manifest/version info from marketplace product
819
+
820
+ **What it does**:
821
+ Retrieves the manifest for a marketplace product, which may include version and workflow information.
822
+
823
+ **Example**:
824
+ \`\`\`javascript
825
+ get_product_manifest({
826
+ productId: '692994df55996e1201963cd7'
827
+ })
828
+ \`\`\`
829
+
830
+ **Returns**: Product manifest with version details`;
831
+ exports.getProductManifestTool = {
832
+ name: 'get_product_manifest',
833
+ group: tool_registry_1.ToolGroup.PLAYGROUND,
834
+ description: getProductManifestDescription,
835
+ schema: zod_1.z.object({
836
+ productId: zod_1.z
837
+ .string()
838
+ .length(24)
839
+ .describe("Product ID to get manifest for (24 characters)"),
840
+ }),
841
+ async execute(args, context) {
842
+ logger.debug('Getting product manifest (v3)', {
843
+ productId: args.productId,
844
+ apiKey: context.apiKey.substring(0, 8) + '...'
845
+ });
846
+ try {
847
+ logger.debug('Calling v3.app.product.getManifest', {
848
+ productId: args.productId
849
+ });
850
+ const result = await context.hailer.request('v3.app.product.getManifest', [args.productId]);
851
+ logger.debug('Product manifest response', {
852
+ result: JSON.stringify(result)
853
+ });
854
+ const manifest = result;
855
+ let responseText = `✅ **Product Manifest (v3)**\n\n`;
856
+ responseText += `**Product ID:** \`${args.productId}\`\n`;
857
+ if (manifest?.version) {
858
+ responseText += `**Version:** ${manifest.version}\n`;
859
+ }
860
+ if (manifest?.workflows?.length) {
861
+ responseText += `**Workflows:** ${manifest.workflows.length}\n`;
862
+ }
863
+ return {
864
+ content: [{
865
+ type: "text",
866
+ text: responseText,
867
+ }],
868
+ };
869
+ }
870
+ catch (error) {
871
+ logger.error("Error getting product manifest", error);
872
+ const errorMessage = (0, tool_helpers_1.extractErrorMessage)(error);
873
+ return {
874
+ content: [{
875
+ type: "text",
876
+ text: `❌ **Error getting product manifest**\n\n**Error:** ${errorMessage}`,
877
+ }],
878
+ };
879
+ }
880
+ }
881
+ };
882
+ // =============================================================================
883
+ // PUBLISH APP TO MARKETPLACE TOOL
884
+ // =============================================================================
885
+ const publishAppDescription = `🏪 [PLAYGROUND] Publish App - Publish app to Hailer marketplace
886
+
887
+ **What it does**:
888
+ Publishes an existing app to the Hailer marketplace, making it installable by other workspaces.
889
+
890
+ **IMPORTANT**: This is different from \`publish_hailer_app\` which deploys code to Hailer hosting.
891
+ This tool creates a **marketplace listing** so other workspaces can discover and install your app.
892
+
893
+ **Example - New Marketplace Listing**:
894
+ \`\`\`javascript
895
+ publish_app({
896
+ appId: '692d3e66e98c7bab4af7f0a1',
897
+ versionId: '692d3e66e98c7bab4af7f0a3', // From publish_hailer_app response
898
+ title: 'Task Manager Pro',
899
+ description: 'Advanced task management with Kanban boards',
900
+ version: '1.0.0',
901
+ versionDescription: 'Initial release with drag-drop support',
902
+ publisher: 'Hailer Oy',
903
+ iconFileId: '692d3e66e98c7bab4af7f0a2'
904
+ })
905
+ \`\`\`
906
+
907
+ **Example - Update Existing Listing**:
908
+ \`\`\`javascript
909
+ publish_app({
910
+ appId: '692d3e66e98c7bab4af7f0a1',
911
+ versionId: '692d3e66e98c7bab4af7f0a3',
912
+ productId: '692d46bfca77093f10b0c09a', // Existing product ID
913
+ title: 'Task Manager Pro',
914
+ description: 'Updated description',
915
+ version: '1.1.0',
916
+ versionDescription: 'Added dark mode support',
917
+ publisher: 'Hailer Oy',
918
+ iconFileId: '692d47adf9383bd1a9e26d78'
919
+ })
920
+ \`\`\`
921
+
922
+ **Required Parameters** (gather ALL before calling):
923
+ - \`appId\` - App ID to publish (must be a published app, not dev)
924
+ - \`versionId\` - Version ID from \`publish_hailer_app\` response (the targetId for marketplace)
925
+ - \`title\` - Marketplace listing name (max 64 chars)
926
+ - \`description\` - Full description (max 4096 chars)
927
+ - \`version\` - Version string (e.g. "1.0.0")
928
+ - \`versionDescription\` - Release notes for this version
929
+ - \`publisher\` - Publishing company/person name
930
+ - \`iconFileId\` - Icon file ID (upload with \`upload_files\` first)
931
+
932
+ **Optional Parameters**:
933
+ - \`productId\` - Existing product ID to UPDATE (omit to create new)
934
+ - \`imageFileIds\` - Array of preview image file IDs
935
+ - \`externalUrl\` - External documentation URL
936
+
937
+ **Workflow**:
938
+ 1. Create and publish app with \`publish_hailer_app\` (deploys code, returns versionId)
939
+ 2. Upload icon with \`upload_files\`
940
+ 3. Call \`publish_app\` with versionId to create marketplace listing
941
+ 4. Other workspaces can install with \`install_marketplace_app\`
942
+
943
+ **After Publishing**:
944
+ - App appears in marketplace
945
+ - Share the product ID with other workspaces
946
+ - They install with \`install_marketplace_app({ productId: "..." })\``;
947
+ exports.publishAppTool = {
948
+ name: 'publish_app',
949
+ group: tool_registry_1.ToolGroup.PLAYGROUND,
950
+ description: publishAppDescription,
951
+ schema: zod_1.z.object({
952
+ appId: zod_1.z
953
+ .string()
954
+ .length(24)
955
+ .describe("App ID to publish (24 characters)"),
956
+ versionId: zod_1.z
957
+ .string()
958
+ .length(24)
959
+ .optional()
960
+ .describe("Optional version ID. If not provided, uses appId as targetId."),
961
+ productId: zod_1.z
962
+ .string()
963
+ .length(24)
964
+ .optional()
965
+ .describe("Existing product ID to UPDATE (omit to create new listing)"),
966
+ title: zod_1.z
967
+ .string()
968
+ .min(1)
969
+ .max(64)
970
+ .describe("Marketplace listing name (max 64 chars)"),
971
+ description: zod_1.z
972
+ .string()
973
+ .min(1)
974
+ .max(4096)
975
+ .describe("Full description (max 4096 chars)"),
976
+ version: zod_1.z
977
+ .string()
978
+ .min(1)
979
+ .describe("Version string (e.g. '1.0.0')"),
980
+ versionDescription: zod_1.z
981
+ .string()
982
+ .min(1)
983
+ .describe("Release notes for this version"),
984
+ publisher: zod_1.z
985
+ .string()
986
+ .min(1)
987
+ .describe("Publishing company or person name"),
988
+ iconFileId: zod_1.z
989
+ .string()
990
+ .length(24)
991
+ .describe("Icon file ID (24 chars). Upload with upload_files first"),
992
+ imageFileIds: zod_1.z
993
+ .array(zod_1.z.string().length(24))
994
+ .optional()
995
+ .describe("Optional array of preview image file IDs"),
996
+ externalUrl: zod_1.z
997
+ .string()
998
+ .url()
999
+ .optional()
1000
+ .describe("Optional external documentation URL"),
1001
+ }),
1002
+ async execute(args, context) {
1003
+ const isUpdate = !!args.productId;
1004
+ logger.debug(`${isUpdate ? 'Updating' : 'Publishing'} app to marketplace`, {
1005
+ appId: args.appId,
1006
+ title: args.title,
1007
+ version: args.version,
1008
+ productId: args.productId,
1009
+ apiKey: context.apiKey.substring(0, 8) + '...'
1010
+ });
1011
+ try {
1012
+ const workspaceId = (0, tool_helpers_1.getResolvedWorkspaceId)({}, context);
1013
+ if (!workspaceId) {
1014
+ return (0, tool_helpers_1.missingWorkspaceCacheResponse)();
1015
+ }
1016
+ // Verify app exists and get details
1017
+ logger.debug('Fetching app details', { appId: args.appId });
1018
+ const appResult = await context.hailer.request('v3.app.list', [{}]);
1019
+ const apps = appResult?.apps || appResult?.details?.apps || (Array.isArray(appResult) ? appResult : []);
1020
+ const app = Array.isArray(apps) ? apps.find((a) => a._id === args.appId) : null;
1021
+ if (!app) {
1022
+ return {
1023
+ content: [{
1024
+ type: "text",
1025
+ text: `❌ **App Not Found**\n\nApp ID \`${args.appId}\` was not found in the current workspace.\n\n**Tips:**\n- Use \`list_apps()\` to see available apps\n- Ensure the app exists and you have access`,
1026
+ }],
1027
+ };
1028
+ }
1029
+ // Warn if app is a dev app (has localhost URL)
1030
+ if (app.url && app.url.includes('localhost')) {
1031
+ return {
1032
+ content: [{
1033
+ type: "text",
1034
+ text: `⚠️ **Cannot Publish Development App**\n\nApp "${app.name}" is a development app (URL: ${app.url}).\n\n**To publish to marketplace:**\n1. First publish the app code with \`publish_hailer_app\`\n2. Or create a production app with empty URL\n3. Then call \`publish_app\` again`,
1035
+ }],
1036
+ };
1037
+ }
1038
+ let productId = args.productId;
1039
+ let targetId = args.versionId;
1040
+ // Step 1: If no versionId provided and not updating, create app version manifest
1041
+ if (!targetId && !productId) {
1042
+ const publishData = {
1043
+ appId: args.appId,
1044
+ workspaceId,
1045
+ version: args.version,
1046
+ versionDescription: args.versionDescription,
1047
+ title: args.title,
1048
+ description: args.description
1049
+ };
1050
+ logger.debug('Calling v2.network.product.publishAppVersion', { publishData });
1051
+ try {
1052
+ const publishResult = await context.hailer.request('v2.network.product.publishAppVersion', [publishData]);
1053
+ logger.debug('publishAppVersion response', { result: JSON.stringify(publishResult) });
1054
+ targetId = publishResult?.productId || publishResult?._id || publishResult?.id;
1055
+ }
1056
+ catch (err) {
1057
+ logger.debug('v2.network.product.publishAppVersion failed', {
1058
+ error: err instanceof Error ? err.message : String(err)
1059
+ });
1060
+ // If publishAppVersion doesn't exist, the error will be caught below
1061
+ }
1062
+ if (!targetId) {
1063
+ return {
1064
+ content: [{
1065
+ type: "text",
1066
+ text: `❌ **Error**: Could not create app version for marketplace.\n\n**Note:** The app marketplace publishing API may not be available. Make sure the app has been published with \`publish_hailer_app\` first.\n\nYou can share the app directly with \`add_app_member\` instead.`,
1067
+ }],
1068
+ };
1069
+ }
1070
+ }
1071
+ // Step 2: Create or Update the product in marketplace
1072
+ let productData;
1073
+ let apiMethod;
1074
+ let apiArgs;
1075
+ if (isUpdate && productId) {
1076
+ // Update only allows specific fields
1077
+ productData = {
1078
+ name: args.title,
1079
+ description: args.description,
1080
+ publisher: args.publisher,
1081
+ icon: args.iconFileId,
1082
+ images: args.imageFileIds || [args.iconFileId]
1083
+ };
1084
+ if (args.externalUrl) {
1085
+ productData.externalUrl = args.externalUrl;
1086
+ }
1087
+ apiMethod = 'v3.product.update';
1088
+ apiArgs = [productId, productData];
1089
+ }
1090
+ else {
1091
+ // Create requires full data - targetId comes from versionId param or publishAppVersion call
1092
+ productData = {
1093
+ cid: workspaceId,
1094
+ targetId, // Version ID from publishAppVersion or provided versionId
1095
+ name: args.title,
1096
+ description: args.description,
1097
+ type: 'app',
1098
+ publisher: args.publisher,
1099
+ icon: args.iconFileId,
1100
+ images: args.imageFileIds || [args.iconFileId]
1101
+ };
1102
+ if (args.externalUrl) {
1103
+ productData.externalUrl = args.externalUrl;
1104
+ }
1105
+ apiMethod = 'v3.product.create';
1106
+ apiArgs = [productData];
1107
+ }
1108
+ logger.debug(`Calling ${apiMethod}`, { productId, workspaceId, appId: args.appId, targetId, iconFileId: args.iconFileId });
1109
+ const apiResult = await context.hailer.request(apiMethod, apiArgs);
1110
+ logger.debug(`${apiMethod} response`, {
1111
+ result: JSON.stringify(apiResult)
1112
+ });
1113
+ // Get the final product ID from the v3 API response
1114
+ const finalProductId = apiResult?._id || apiResult?.id || productId;
1115
+ let responseText = `✅ **App ${isUpdate ? 'Updated' : 'Published'} to Marketplace**\n\n`;
1116
+ responseText += `**App:** ${app.name} (\`${args.appId}\`)\n`;
1117
+ responseText += `**Title:** ${args.title}\n`;
1118
+ responseText += `**Publisher:** ${args.publisher}\n`;
1119
+ responseText += `**Version:** ${args.version}\n`;
1120
+ responseText += `**Product ID:** \`${finalProductId}\`\n`;
1121
+ responseText += `**Release Notes:** ${args.versionDescription}\n`;
1122
+ responseText += `\n💡 **Next Steps:**\n`;
1123
+ responseText += `- Share the product ID with other workspaces\n`;
1124
+ responseText += `- They can install with \`install_marketplace_app({ productId: "${finalProductId}" })\`\n`;
1125
+ responseText += `- To update, include \`productId: "${finalProductId}"\` in next publish\n`;
1126
+ return {
1127
+ content: [{
1128
+ type: "text",
1129
+ text: responseText,
1130
+ }],
1131
+ };
1132
+ }
1133
+ catch (error) {
1134
+ logger.error("Error publishing app to marketplace", error);
1135
+ const errorMessage = (0, tool_helpers_1.extractErrorMessage)(error);
1136
+ if (errorMessage.toLowerCase().includes('permission')) {
1137
+ return {
1138
+ content: [{
1139
+ type: "text",
1140
+ text: `❌ **Permission Denied**\n\nYou don't have permission to publish apps to marketplace. Only workspace administrators can publish.\n\n**Error:** ${errorMessage}`,
1141
+ }],
1142
+ };
1143
+ }
1144
+ return {
1145
+ content: [{
1146
+ type: "text",
1147
+ text: `❌ **Error publishing app to marketplace**\n\n**Error:** ${errorMessage}\n\n**Common Issues:**\n- App must be a production app (not dev/localhost)\n- Must be workspace administrator\n- Icon file must be uploaded first\n- Invalid version format`,
1148
+ }],
1149
+ };
1150
+ }
1151
+ }
1152
+ };
1153
+ // =============================================================================
1154
+ // INSTALL MARKETPLACE APP TOOL
1155
+ // =============================================================================
1156
+ const installMarketplaceAppDescription = `🏪 [PLAYGROUND] Install Marketplace App - Install app from Hailer marketplace
1157
+
1158
+ **What it does**:
1159
+ Installs an app from the Hailer marketplace into your workspace.
1160
+
1161
+ **Example**:
1162
+ \`\`\`javascript
1163
+ install_marketplace_app({
1164
+ productId: '692d46bfca77093f10b0c09a'
1165
+ })
1166
+ \`\`\`
1167
+
1168
+ **Parameters**:
1169
+ - \`productId\` (required) - Marketplace product ID
1170
+
1171
+ **Requirements**:
1172
+ - User must be workspace administrator
1173
+
1174
+ **Tips**:
1175
+ - Get product ID from app publisher or marketplace
1176
+ - Use \`get_product\` to preview app details before installing
1177
+ - Installed app appears in workspace app list`;
1178
+ exports.installMarketplaceAppTool = {
1179
+ name: 'install_marketplace_app',
1180
+ group: tool_registry_1.ToolGroup.PLAYGROUND,
1181
+ description: installMarketplaceAppDescription,
1182
+ schema: zod_1.z.object({
1183
+ productId: zod_1.z
1184
+ .string()
1185
+ .length(24)
1186
+ .describe("Marketplace product ID to install (24 characters)"),
1187
+ workspaceId: zod_1.z
1188
+ .string()
1189
+ .optional()
1190
+ .describe("Target workspace ID (defaults to current)"),
1191
+ }),
1192
+ async execute(args, context) {
1193
+ logger.debug('Installing marketplace app', {
1194
+ productId: args.productId,
1195
+ apiKey: context.apiKey.substring(0, 8) + '...'
1196
+ });
1197
+ try {
1198
+ const workspaceId = (0, tool_helpers_1.getResolvedWorkspaceId)(args, context);
1199
+ if (!workspaceId) {
1200
+ return (0, tool_helpers_1.missingWorkspaceCacheResponse)();
1201
+ }
1202
+ // Check if already installed
1203
+ logger.debug('Checking if product is already installed', { productId: args.productId, workspaceId });
1204
+ try {
1205
+ const isInstalledResult = await context.hailer.request('v3.app.product.isProductInstalled', [args.productId, workspaceId]);
1206
+ if (isInstalledResult?.installed) {
1207
+ return {
1208
+ content: [{
1209
+ type: "text",
1210
+ text: `ℹ️ **App Already Installed**\n\nThis app is already installed in your workspace.\n\n**App ID:** \`${isInstalledResult.appId || 'unknown'}\`\n\n**Tips:**\n- Use \`list_apps()\` to see installed apps\n- Use \`get_product({ productId: "${args.productId}" })\` to view product details`,
1211
+ }],
1212
+ };
1213
+ }
1214
+ }
1215
+ catch (checkError) {
1216
+ // Ignore check errors and proceed with installation
1217
+ logger.debug('Could not check installation status, proceeding', {
1218
+ error: checkError instanceof Error ? checkError.message : String(checkError)
1219
+ });
1220
+ }
1221
+ // Get product details first
1222
+ logger.debug('Fetching product details', { productId: args.productId });
1223
+ let productName = 'Unknown';
1224
+ try {
1225
+ const productResult = await context.hailer.request('v3.app.product.get', [args.productId]);
1226
+ productName = productResult?.name || productResult?.title || 'Unknown';
1227
+ }
1228
+ catch (productError) {
1229
+ logger.debug('Could not fetch product details', {
1230
+ error: productError instanceof Error ? productError.message : String(productError)
1231
+ });
1232
+ }
1233
+ // Install the app
1234
+ logger.debug('Calling v3.app.product.install', { productId: args.productId, workspaceId });
1235
+ const installResult = await context.hailer.request('v3.app.product.install', [args.productId, workspaceId]);
1236
+ logger.debug('Install result', { result: JSON.stringify(installResult) });
1237
+ const installedAppId = installResult?.appId || installResult?.details?.appId || installResult?._id;
1238
+ let responseText = `✅ **App Installed Successfully**\n\n`;
1239
+ responseText += `**Product:** ${productName}\n`;
1240
+ responseText += `**Product ID:** \`${args.productId}\`\n`;
1241
+ if (installedAppId) {
1242
+ responseText += `**Installed App ID:** \`${installedAppId}\`\n`;
1243
+ }
1244
+ responseText += `**Workspace:** \`${workspaceId}\`\n`;
1245
+ responseText += `\n💡 **Next Steps:**\n`;
1246
+ responseText += `- Use \`list_apps()\` to see the installed app\n`;
1247
+ responseText += `- Use \`add_app_member\` to share with workspace members\n`;
1248
+ responseText += `- Open the app from Hailer workspace menu\n`;
1249
+ return {
1250
+ content: [{
1251
+ type: "text",
1252
+ text: responseText,
1253
+ }],
1254
+ };
1255
+ }
1256
+ catch (error) {
1257
+ logger.error("Error installing marketplace app", error);
1258
+ const errorMessage = (0, tool_helpers_1.extractErrorMessage)(error);
1259
+ if (errorMessage.toLowerCase().includes('permission')) {
1260
+ return {
1261
+ content: [{
1262
+ type: "text",
1263
+ text: `❌ **Permission Denied**\n\nYou don't have permission to install apps. Only workspace administrators can install marketplace apps.\n\n**Error:** ${errorMessage}`,
1264
+ }],
1265
+ };
1266
+ }
1267
+ if (errorMessage.toLowerCase().includes('not found')) {
1268
+ return {
1269
+ content: [{
1270
+ type: "text",
1271
+ text: `❌ **Product Not Found**\n\nThe marketplace product \`${args.productId}\` was not found.\n\n**Tips:**\n- Verify the product ID is correct\n- Use \`get_product\` to check if the product exists\n\n**Error:** ${errorMessage}`,
1272
+ }],
1273
+ };
1274
+ }
1275
+ return {
1276
+ content: [{
1277
+ type: "text",
1278
+ text: `❌ **Error installing marketplace app**\n\n**Error:** ${errorMessage}\n\n**Common Issues:**\n- Invalid product ID\n- Product not found in marketplace\n- Insufficient permissions`,
1279
+ }],
1280
+ };
1281
+ }
1282
+ }
1283
+ };
1284
+ //# sourceMappingURL=app-marketplace.js.map