@hailer/mcp 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (163) hide show
  1. package/.claude/commands/tool-builder.md +37 -0
  2. package/.claude/commands/ws-pull.md +44 -0
  3. package/.claude/settings.json +8 -0
  4. package/.claude/settings.local.json +49 -0
  5. package/.claude/skills/activity-api/SKILL.md +96 -0
  6. package/.claude/skills/activity-api/references/activity-endpoints.md +845 -0
  7. package/.claude/skills/add-app-member-skill/SKILL.md +977 -0
  8. package/.claude/skills/agent-building/SKILL.md +243 -0
  9. package/.claude/skills/agent-building/references/architecture-patterns.md +446 -0
  10. package/.claude/skills/agent-building/references/code-examples.md +587 -0
  11. package/.claude/skills/agent-building/references/implementation-guide.md +619 -0
  12. package/.claude/skills/app-api/SKILL.md +219 -0
  13. package/.claude/skills/app-api/references/app-endpoints.md +759 -0
  14. package/.claude/skills/building-hailer-apps-skill/SKILL.md +548 -0
  15. package/.claude/skills/create-app-skill/SKILL.md +1101 -0
  16. package/.claude/skills/create-insight-skill/SKILL.md +1317 -0
  17. package/.claude/skills/get-insight-data-skill/SKILL.md +1053 -0
  18. package/.claude/skills/hailer-api/SKILL.md +283 -0
  19. package/.claude/skills/hailer-api/references/activities.md +620 -0
  20. package/.claude/skills/hailer-api/references/authentication.md +216 -0
  21. package/.claude/skills/hailer-api/references/datasets.md +437 -0
  22. package/.claude/skills/hailer-api/references/files.md +301 -0
  23. package/.claude/skills/hailer-api/references/insights.md +469 -0
  24. package/.claude/skills/hailer-api/references/workflows.md +720 -0
  25. package/.claude/skills/hailer-api/references/workspaces-users.md +445 -0
  26. package/.claude/skills/insight-api/SKILL.md +185 -0
  27. package/.claude/skills/insight-api/references/insight-endpoints.md +514 -0
  28. package/.claude/skills/install-workflow-skill/SKILL.md +1056 -0
  29. package/.claude/skills/list-apps-skill/SKILL.md +1010 -0
  30. package/.claude/skills/list-workflows-minimal-skill/SKILL.md +992 -0
  31. package/.claude/skills/local-first-skill/SKILL.md +570 -0
  32. package/.claude/skills/mcp-tools/SKILL.md +419 -0
  33. package/.claude/skills/mcp-tools/references/api-endpoints.md +499 -0
  34. package/.claude/skills/mcp-tools/references/data-structures.md +554 -0
  35. package/.claude/skills/mcp-tools/references/implementation-patterns.md +717 -0
  36. package/.claude/skills/preview-insight-skill/SKILL.md +1290 -0
  37. package/.claude/skills/publish-hailer-app-skill/SKILL.md +453 -0
  38. package/.claude/skills/remove-app-member-skill/SKILL.md +671 -0
  39. package/.claude/skills/remove-app-skill/SKILL.md +985 -0
  40. package/.claude/skills/remove-insight-skill/SKILL.md +1011 -0
  41. package/.claude/skills/remove-workflow-skill/SKILL.md +920 -0
  42. package/.claude/skills/scaffold-hailer-app-skill/SKILL.md +1034 -0
  43. package/.claude/skills/skill-testing/README.md +137 -0
  44. package/.claude/skills/skill-testing/SKILL.md +348 -0
  45. package/.claude/skills/skill-testing/references/test-patterns.md +705 -0
  46. package/.claude/skills/skill-testing/references/testing-guide.md +603 -0
  47. package/.claude/skills/skill-testing/references/validation-checklist.md +537 -0
  48. package/.claude/skills/tool-builder/SKILL.md +328 -0
  49. package/.claude/skills/update-app-skill/SKILL.md +970 -0
  50. package/.claude/skills/update-workflow-field-skill/SKILL.md +1098 -0
  51. package/.env.example +81 -0
  52. package/.mcp.json +13 -0
  53. package/README.md +297 -0
  54. package/dist/app.d.ts +4 -0
  55. package/dist/app.js +74 -0
  56. package/dist/cli.d.ts +3 -0
  57. package/dist/cli.js +5 -0
  58. package/dist/client/adaptive-documentation-bot.d.ts +108 -0
  59. package/dist/client/adaptive-documentation-bot.js +475 -0
  60. package/dist/client/adaptive-documentation-types.d.ts +66 -0
  61. package/dist/client/adaptive-documentation-types.js +9 -0
  62. package/dist/client/agent-activity-bot.d.ts +51 -0
  63. package/dist/client/agent-activity-bot.js +166 -0
  64. package/dist/client/agent-tracker.d.ts +499 -0
  65. package/dist/client/agent-tracker.js +659 -0
  66. package/dist/client/description-updater.d.ts +56 -0
  67. package/dist/client/description-updater.js +259 -0
  68. package/dist/client/log-parser.d.ts +72 -0
  69. package/dist/client/log-parser.js +387 -0
  70. package/dist/client/mcp-client.d.ts +50 -0
  71. package/dist/client/mcp-client.js +532 -0
  72. package/dist/client/message-processor.d.ts +35 -0
  73. package/dist/client/message-processor.js +352 -0
  74. package/dist/client/multi-bot-manager.d.ts +24 -0
  75. package/dist/client/multi-bot-manager.js +74 -0
  76. package/dist/client/providers/anthropic-provider.d.ts +19 -0
  77. package/dist/client/providers/anthropic-provider.js +631 -0
  78. package/dist/client/providers/llm-provider.d.ts +47 -0
  79. package/dist/client/providers/llm-provider.js +367 -0
  80. package/dist/client/providers/openai-provider.d.ts +23 -0
  81. package/dist/client/providers/openai-provider.js +621 -0
  82. package/dist/client/simple-llm-caller.d.ts +19 -0
  83. package/dist/client/simple-llm-caller.js +100 -0
  84. package/dist/client/skill-generator.d.ts +81 -0
  85. package/dist/client/skill-generator.js +386 -0
  86. package/dist/client/test-adaptive-bot.d.ts +9 -0
  87. package/dist/client/test-adaptive-bot.js +82 -0
  88. package/dist/client/token-pricing.d.ts +38 -0
  89. package/dist/client/token-pricing.js +127 -0
  90. package/dist/client/token-tracker.d.ts +232 -0
  91. package/dist/client/token-tracker.js +457 -0
  92. package/dist/client/token-usage-bot.d.ts +53 -0
  93. package/dist/client/token-usage-bot.js +153 -0
  94. package/dist/client/tool-executor.d.ts +69 -0
  95. package/dist/client/tool-executor.js +159 -0
  96. package/dist/client/tool-schema-loader.d.ts +60 -0
  97. package/dist/client/tool-schema-loader.js +178 -0
  98. package/dist/client/types.d.ts +69 -0
  99. package/dist/client/types.js +7 -0
  100. package/dist/config.d.ts +162 -0
  101. package/dist/config.js +296 -0
  102. package/dist/core.d.ts +26 -0
  103. package/dist/core.js +147 -0
  104. package/dist/lib/context-manager.d.ts +111 -0
  105. package/dist/lib/context-manager.js +431 -0
  106. package/dist/lib/logger.d.ts +74 -0
  107. package/dist/lib/logger.js +277 -0
  108. package/dist/lib/materialize.d.ts +3 -0
  109. package/dist/lib/materialize.js +101 -0
  110. package/dist/lib/normalizedName.d.ts +7 -0
  111. package/dist/lib/normalizedName.js +48 -0
  112. package/dist/lib/prompt-length-manager.d.ts +81 -0
  113. package/dist/lib/prompt-length-manager.js +457 -0
  114. package/dist/lib/terminal-prompt.d.ts +9 -0
  115. package/dist/lib/terminal-prompt.js +108 -0
  116. package/dist/mcp/UserContextCache.d.ts +56 -0
  117. package/dist/mcp/UserContextCache.js +163 -0
  118. package/dist/mcp/auth.d.ts +2 -0
  119. package/dist/mcp/auth.js +29 -0
  120. package/dist/mcp/hailer-clients.d.ts +42 -0
  121. package/dist/mcp/hailer-clients.js +246 -0
  122. package/dist/mcp/signal-handler.d.ts +45 -0
  123. package/dist/mcp/signal-handler.js +317 -0
  124. package/dist/mcp/tool-registry.d.ts +100 -0
  125. package/dist/mcp/tool-registry.js +306 -0
  126. package/dist/mcp/tools/activity.d.ts +15 -0
  127. package/dist/mcp/tools/activity.js +955 -0
  128. package/dist/mcp/tools/app.d.ts +20 -0
  129. package/dist/mcp/tools/app.js +1488 -0
  130. package/dist/mcp/tools/discussion.d.ts +19 -0
  131. package/dist/mcp/tools/discussion.js +950 -0
  132. package/dist/mcp/tools/file.d.ts +15 -0
  133. package/dist/mcp/tools/file.js +119 -0
  134. package/dist/mcp/tools/insight.d.ts +17 -0
  135. package/dist/mcp/tools/insight.js +806 -0
  136. package/dist/mcp/tools/skill.d.ts +10 -0
  137. package/dist/mcp/tools/skill.js +279 -0
  138. package/dist/mcp/tools/user.d.ts +10 -0
  139. package/dist/mcp/tools/user.js +108 -0
  140. package/dist/mcp/tools/workflow-template.d.ts +19 -0
  141. package/dist/mcp/tools/workflow-template.js +822 -0
  142. package/dist/mcp/tools/workflow.d.ts +18 -0
  143. package/dist/mcp/tools/workflow.js +1362 -0
  144. package/dist/mcp/utils/api-errors.d.ts +45 -0
  145. package/dist/mcp/utils/api-errors.js +160 -0
  146. package/dist/mcp/utils/data-transformers.d.ts +102 -0
  147. package/dist/mcp/utils/data-transformers.js +194 -0
  148. package/dist/mcp/utils/file-upload.d.ts +33 -0
  149. package/dist/mcp/utils/file-upload.js +148 -0
  150. package/dist/mcp/utils/hailer-api-client.d.ts +120 -0
  151. package/dist/mcp/utils/hailer-api-client.js +323 -0
  152. package/dist/mcp/utils/index.d.ts +13 -0
  153. package/dist/mcp/utils/index.js +39 -0
  154. package/dist/mcp/utils/logger.d.ts +42 -0
  155. package/dist/mcp/utils/logger.js +103 -0
  156. package/dist/mcp/utils/types.d.ts +286 -0
  157. package/dist/mcp/utils/types.js +7 -0
  158. package/dist/mcp/workspace-cache.d.ts +42 -0
  159. package/dist/mcp/workspace-cache.js +97 -0
  160. package/dist/mcp-server.d.ts +42 -0
  161. package/dist/mcp-server.js +280 -0
  162. package/package.json +56 -0
  163. package/tsconfig.json +23 -0
@@ -0,0 +1,1488 @@
1
+ "use strict";
2
+ /**
3
+ * App Tools - Clean Architecture Implementation
4
+ *
5
+ * Hailer app management tools:
6
+ * - Apps extend workspace functionality
7
+ * - Development apps (localhost URLs)
8
+ * - Published apps (auto-generated URLs)
9
+ *
10
+ * All 8 app management tools in one file for cohesion.
11
+ */
12
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
13
+ if (k2 === undefined) k2 = k;
14
+ var desc = Object.getOwnPropertyDescriptor(m, k);
15
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
16
+ desc = { enumerable: true, get: function() { return m[k]; } };
17
+ }
18
+ Object.defineProperty(o, k2, desc);
19
+ }) : (function(o, m, k, k2) {
20
+ if (k2 === undefined) k2 = k;
21
+ o[k2] = m[k];
22
+ }));
23
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
24
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
25
+ }) : function(o, v) {
26
+ o["default"] = v;
27
+ });
28
+ var __importStar = (this && this.__importStar) || (function () {
29
+ var ownKeys = function(o) {
30
+ ownKeys = Object.getOwnPropertyNames || function (o) {
31
+ var ar = [];
32
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
33
+ return ar;
34
+ };
35
+ return ownKeys(o);
36
+ };
37
+ return function (mod) {
38
+ if (mod && mod.__esModule) return mod;
39
+ var result = {};
40
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
41
+ __setModuleDefault(result, mod);
42
+ return result;
43
+ };
44
+ })();
45
+ Object.defineProperty(exports, "__esModule", { value: true });
46
+ exports.publishHailerAppTool = exports.scaffoldHailerAppTool = exports.removeAppMemberTool = exports.addAppMemberTool = exports.removeAppTool = exports.updateAppTool = exports.listAppsTool = exports.createAppTool = void 0;
47
+ const zod_1 = require("zod");
48
+ const tool_registry_1 = require("../tool-registry");
49
+ const workspace_cache_1 = require("../workspace-cache");
50
+ const logger_1 = require("../../lib/logger");
51
+ const config_1 = require("../../config");
52
+ const logger = (0, logger_1.createLogger)({ component: 'app-tools' });
53
+ // ============================================================================
54
+ // CREATE APP TOOL
55
+ // ============================================================================
56
+ const createAppDescription = `🧪 [PLAYGROUND] Create App - Create Hailer app entry in workspace
57
+
58
+ **What are Apps?**
59
+ Apps are custom web applications that extend Hailer workspace functionality. Think React/vanilla JS apps running within Hailer.
60
+
61
+ **App Types**:
62
+ - **Development Apps**: URL points to localhost (e.g., http://localhost:3000)
63
+ - **Published Apps**: URL empty or points to production
64
+
65
+ **Example 1 - Development App**:
66
+ \`\`\`javascript
67
+ create_app({
68
+ name: 'Local Development',
69
+ description: 'App pointing to local server',
70
+ url: 'http://localhost:3000'
71
+ })
72
+ \`\`\`
73
+
74
+ **Example 2 - Published App**:
75
+ \`\`\`javascript
76
+ create_app({
77
+ name: 'Task Manager',
78
+ description: 'Production task management app',
79
+ url: '' // Empty for auto URL
80
+ })
81
+ \`\`\`
82
+
83
+ **Properties**:
84
+ - \`name\` (required) - App display name
85
+ - \`description\` (optional) - App description
86
+ - \`url\` (optional) - App URL or empty for auto-generated
87
+ - \`image\` (optional) - Image/icon ID
88
+
89
+ **Requirements**:
90
+ - User must be workspace administrator
91
+ - For published apps, leave URL empty
92
+
93
+ **Tips**:
94
+ - Use development apps for local testing
95
+ - Published apps get automatic URLs from Hailer
96
+ - Use \`add_app_member\` to share with others`;
97
+ exports.createAppTool = {
98
+ name: 'create_app',
99
+ group: tool_registry_1.ToolGroup.PLAYGROUND,
100
+ description: createAppDescription,
101
+ schema: zod_1.z.object({
102
+ workspaceId: zod_1.z
103
+ .string()
104
+ .optional()
105
+ .describe("Optional workspace ID - defaults to current workspace"),
106
+ name: zod_1.z
107
+ .string()
108
+ .min(1)
109
+ .describe("App name (required)"),
110
+ description: zod_1.z
111
+ .string()
112
+ .optional()
113
+ .describe("App description"),
114
+ url: zod_1.z
115
+ .string()
116
+ .optional()
117
+ .describe("App URL (empty for published apps, localhost for dev)"),
118
+ image: zod_1.z
119
+ .string()
120
+ .optional()
121
+ .describe("Image/icon ID (24 characters)"),
122
+ config: zod_1.z
123
+ .record(zod_1.z.unknown())
124
+ .optional()
125
+ .describe("Optional app configuration"),
126
+ }),
127
+ async execute(args, context) {
128
+ logger.debug('Creating app', {
129
+ name: args.name,
130
+ workspaceId: args.workspaceId,
131
+ hasUrl: !!args.url,
132
+ apiKey: context.apiKey.substring(0, 8) + '...'
133
+ });
134
+ try {
135
+ if (!context.workspaceCache) {
136
+ return {
137
+ content: [{
138
+ type: "text",
139
+ text: "❌ Workspace cache not available",
140
+ }],
141
+ };
142
+ }
143
+ const workspaceId = args.workspaceId
144
+ ? (0, workspace_cache_1.resolveWorkspaceId)(context.workspaceCache, args.workspaceId)
145
+ : context.workspaceCache.currentWorkspace._id;
146
+ if (!workspaceId) {
147
+ return {
148
+ content: [{
149
+ type: "text",
150
+ text: `❌ Could not resolve workspace: ${args.workspaceId}`,
151
+ }],
152
+ };
153
+ }
154
+ logger.debug('Calling v3.app.create', {
155
+ workspaceId,
156
+ name: args.name
157
+ });
158
+ const appData = {
159
+ cid: workspaceId,
160
+ name: args.name
161
+ };
162
+ if (args.description)
163
+ appData.description = args.description;
164
+ if (args.url !== undefined)
165
+ appData.url = args.url;
166
+ if (args.image)
167
+ appData.image = args.image;
168
+ if (args.config)
169
+ appData.config = args.config;
170
+ const result = await context.hailer.request('v3.app.create', [appData]);
171
+ logger.debug('App creation successful', {
172
+ appId: result.appId || result._id
173
+ });
174
+ const appId = result.appId || result._id;
175
+ let responseText = `✅ **App Created Successfully**\n\n`;
176
+ responseText += `**App Name:** ${args.name}\n`;
177
+ responseText += `**App ID:** \`${appId}\`\n`;
178
+ responseText += `**Workspace:** ${workspaceId}\n`;
179
+ if (args.description) {
180
+ responseText += `**Description:** ${args.description}\n`;
181
+ }
182
+ if (args.url) {
183
+ responseText += `**URL:** ${args.url}\n`;
184
+ responseText += `**Type:** Development App (points to ${args.url})\n`;
185
+ }
186
+ else {
187
+ responseText += `**URL:** Auto-generated by Hailer\n`;
188
+ responseText += `**Type:** Published App\n`;
189
+ }
190
+ responseText += `\n💡 **Next Steps:**\n`;
191
+ responseText += `- Use \`list_apps\` to see all apps\n`;
192
+ responseText += `- Use \`add_app_member\` to share with users/teams\n`;
193
+ responseText += `- Use \`update_app\` to modify properties\n`;
194
+ if (!args.url) {
195
+ responseText += `\n📦 **Publishing:**\n`;
196
+ responseText += `1. Configure manifest.json with this appId: \`${appId}\`\n`;
197
+ responseText += `2. Run: \`EMAIL=your@email.com npm run publish-production\`\n`;
198
+ }
199
+ return {
200
+ content: [{
201
+ type: "text",
202
+ text: responseText,
203
+ }],
204
+ };
205
+ }
206
+ catch (error) {
207
+ logger.error("Error creating app", error);
208
+ let errorMessage = 'Unknown error occurred';
209
+ if (error instanceof Error) {
210
+ errorMessage = error.message;
211
+ }
212
+ else if (typeof error === 'object' && error !== null) {
213
+ try {
214
+ errorMessage = JSON.stringify(error, null, 2);
215
+ }
216
+ catch {
217
+ errorMessage = String(error);
218
+ }
219
+ }
220
+ else {
221
+ errorMessage = String(error);
222
+ }
223
+ if (errorMessage.toLowerCase().includes('permission')) {
224
+ return {
225
+ content: [{
226
+ type: "text",
227
+ text: `❌ **Permission Denied**\n\nYou don't have permission to create apps. Only workspace administrators can create apps.\n\n**Error:** ${errorMessage}`,
228
+ }],
229
+ };
230
+ }
231
+ return {
232
+ content: [{
233
+ type: "text",
234
+ text: `❌ **Error creating app**\n\n**Error:** ${errorMessage}\n\n**Common Issues:**\n- User must be workspace administrator\n- Invalid workspace ID\n- Image ID must be 24 characters if provided`,
235
+ }],
236
+ };
237
+ }
238
+ }
239
+ };
240
+ // ============================================================================
241
+ // LIST APPS TOOL
242
+ // ============================================================================
243
+ const listAppsDescription = `🧪 [PLAYGROUND] List Apps - View all apps in workspace
244
+
245
+ **What it does**:
246
+ Lists all Hailer apps in the current workspace that you have access to.
247
+
248
+ **Example**:
249
+ \`\`\`javascript
250
+ list_apps()
251
+ \`\`\`
252
+
253
+ **Shows**:
254
+ - App name and description
255
+ - App ID
256
+ - URL (localhost for dev, auto for published)
257
+ - Creator and timestamps
258
+ - Configuration
259
+
260
+ **Use Cases**:
261
+ - See all workspace apps
262
+ - Find app IDs for updates
263
+ - Check which apps are development vs published
264
+ - Audit app configuration`;
265
+ exports.listAppsTool = {
266
+ name: 'list_apps',
267
+ group: tool_registry_1.ToolGroup.PLAYGROUND,
268
+ description: listAppsDescription,
269
+ schema: zod_1.z.object({
270
+ workspaceId: zod_1.z
271
+ .string()
272
+ .optional()
273
+ .describe("Optional workspace ID - defaults to current workspace"),
274
+ }),
275
+ async execute(args, context) {
276
+ logger.debug('Listing apps', {
277
+ workspaceId: args.workspaceId,
278
+ apiKey: context.apiKey.substring(0, 8) + '...'
279
+ });
280
+ try {
281
+ if (!context.workspaceCache) {
282
+ return {
283
+ content: [{
284
+ type: "text",
285
+ text: "❌ Workspace cache not available",
286
+ }],
287
+ };
288
+ }
289
+ const workspaceId = args.workspaceId
290
+ ? (0, workspace_cache_1.resolveWorkspaceId)(context.workspaceCache, args.workspaceId)
291
+ : context.workspaceCache.currentWorkspace._id;
292
+ if (!workspaceId) {
293
+ return {
294
+ content: [{
295
+ type: "text",
296
+ text: `❌ Could not resolve workspace: ${args.workspaceId}`,
297
+ }],
298
+ };
299
+ }
300
+ logger.debug('Calling v3.app.list');
301
+ const result = await context.hailer.request('v3.app.list', [{}]);
302
+ logger.debug('List apps successful', {
303
+ appCount: result.apps?.length || 0
304
+ });
305
+ let responseText = `✅ **Apps Retrieved**\n\n`;
306
+ responseText += `**Workspace:** ${workspaceId}\n\n`;
307
+ if (!result.apps || result.apps.length === 0) {
308
+ responseText += `**No apps found** in this workspace.\n\n`;
309
+ responseText += `💡 Use \`create_app\` to create your first app.`;
310
+ return {
311
+ content: [{
312
+ type: "text",
313
+ text: responseText,
314
+ }],
315
+ };
316
+ }
317
+ const apps = result.apps;
318
+ responseText += `**Total Apps:** ${apps.length}\n\n`;
319
+ apps.forEach((app) => {
320
+ responseText += `### ${app.name || 'Unnamed App'}\n`;
321
+ responseText += `- **App ID:** \`${app._id}\`\n`;
322
+ if (app.description) {
323
+ responseText += `- **Description:** ${app.description}\n`;
324
+ }
325
+ if (app.url) {
326
+ responseText += `- **URL:** ${app.url}\n`;
327
+ responseText += `- **Type:** ${app.url.includes('localhost') ? 'Development' : 'Custom URL'}\n`;
328
+ }
329
+ else {
330
+ responseText += `- **URL:** Auto-generated (Published App)\n`;
331
+ responseText += `- **Type:** Published\n`;
332
+ }
333
+ if (app.created) {
334
+ responseText += `- **Created:** ${new Date(app.created * 1000).toLocaleString()}\n`;
335
+ }
336
+ if (app.config && Object.keys(app.config).length > 0) {
337
+ responseText += `- **Config:** Present\n`;
338
+ }
339
+ responseText += `\n`;
340
+ });
341
+ responseText += `💡 **Next Steps:**\n`;
342
+ responseText += `- Use \`update_app\` to modify an app\n`;
343
+ responseText += `- Use \`add_app_member\` to share apps\n`;
344
+ responseText += `- Use \`remove_app\` to delete apps`;
345
+ return {
346
+ content: [{
347
+ type: "text",
348
+ text: responseText,
349
+ }],
350
+ };
351
+ }
352
+ catch (error) {
353
+ logger.error("Error listing apps", error);
354
+ let errorMessage = 'Unknown error occurred';
355
+ if (error instanceof Error) {
356
+ errorMessage = error.message;
357
+ }
358
+ else if (typeof error === 'object' && error !== null) {
359
+ try {
360
+ errorMessage = JSON.stringify(error, null, 2);
361
+ }
362
+ catch {
363
+ errorMessage = String(error);
364
+ }
365
+ }
366
+ else {
367
+ errorMessage = String(error);
368
+ }
369
+ return {
370
+ content: [{
371
+ type: "text",
372
+ text: `❌ **Error listing apps**\n\n**Error:** ${errorMessage}\n\n**Common Issues:**\n- Workspace not accessible\n- Permission issues`,
373
+ }],
374
+ };
375
+ }
376
+ }
377
+ };
378
+ // ============================================================================
379
+ // UPDATE APP TOOL
380
+ // ============================================================================
381
+ const updateAppDescription = `🧪 [PLAYGROUND] Update App - Modify app properties
382
+
383
+ **What it does**:
384
+ Updates an existing app's properties (name, description, URL, etc.).
385
+
386
+ **Example - Update name and description**:
387
+ \`\`\`javascript
388
+ update_app({
389
+ appId: '<app-id>',
390
+ name: 'Updated App Name',
391
+ description: 'New description'
392
+ })
393
+ \`\`\`
394
+
395
+ **Example - Change URL (dev to prod)**:
396
+ \`\`\`javascript
397
+ update_app({
398
+ appId: '<app-id>',
399
+ url: '' // Empty for published
400
+ })
401
+ \`\`\`
402
+
403
+ **Updatable Properties**:
404
+ - \`name\` - App display name
405
+ - \`description\` - App description
406
+ - \`url\` - App URL
407
+ - \`image\` - App icon ID
408
+ - \`config\` - App configuration
409
+
410
+ **Requirements**:
411
+ - User must be app creator or workspace admin
412
+
413
+ **Tips**:
414
+ - Only specified properties are updated
415
+ - Use \`list_apps\` to get app IDs`;
416
+ exports.updateAppTool = {
417
+ name: 'update_app',
418
+ group: tool_registry_1.ToolGroup.PLAYGROUND,
419
+ description: updateAppDescription,
420
+ schema: zod_1.z.object({
421
+ appId: zod_1.z
422
+ .string()
423
+ .min(1)
424
+ .describe("App ID to update"),
425
+ name: zod_1.z
426
+ .string()
427
+ .optional()
428
+ .describe("New app name"),
429
+ description: zod_1.z
430
+ .string()
431
+ .optional()
432
+ .describe("New description"),
433
+ url: zod_1.z
434
+ .string()
435
+ .optional()
436
+ .describe("New URL"),
437
+ image: zod_1.z
438
+ .string()
439
+ .optional()
440
+ .describe("New image ID"),
441
+ config: zod_1.z
442
+ .record(zod_1.z.unknown())
443
+ .optional()
444
+ .describe("New configuration"),
445
+ }),
446
+ async execute(args, context) {
447
+ logger.debug('Updating app', {
448
+ appId: args.appId,
449
+ apiKey: context.apiKey.substring(0, 8) + '...'
450
+ });
451
+ try {
452
+ const updateData = {};
453
+ if (args.name !== undefined)
454
+ updateData.name = args.name;
455
+ if (args.description !== undefined)
456
+ updateData.description = args.description;
457
+ if (args.url !== undefined)
458
+ updateData.url = args.url;
459
+ if (args.image !== undefined)
460
+ updateData.image = args.image;
461
+ if (args.config !== undefined)
462
+ updateData.config = args.config;
463
+ logger.debug('Calling v3.app.update', {
464
+ appId: args.appId,
465
+ updates: Object.keys(updateData)
466
+ });
467
+ await context.hailer.request('v3.app.update', [
468
+ args.appId,
469
+ updateData
470
+ ]);
471
+ logger.debug('App update successful');
472
+ let responseText = `✅ **App Updated Successfully**\n\n`;
473
+ responseText += `**App ID:** \`${args.appId}\`\n\n`;
474
+ responseText += `**Updated Properties:**\n`;
475
+ const updatedFields = [];
476
+ if (args.name)
477
+ updatedFields.push(`name → "${args.name}"`);
478
+ if (args.description)
479
+ updatedFields.push(`description → "${args.description}"`);
480
+ if (args.url !== undefined)
481
+ updatedFields.push(`url → "${args.url || 'auto-generated'}"`);
482
+ if (args.image)
483
+ updatedFields.push(`image → "${args.image}"`);
484
+ if (args.config)
485
+ updatedFields.push(`config (updated)`);
486
+ updatedFields.forEach(field => {
487
+ responseText += `- ${field}\n`;
488
+ });
489
+ responseText += `\n💡 Use \`list_apps\` to verify changes.`;
490
+ return {
491
+ content: [{
492
+ type: "text",
493
+ text: responseText,
494
+ }],
495
+ };
496
+ }
497
+ catch (error) {
498
+ logger.error("Error updating app", error);
499
+ let errorMessage = 'Unknown error occurred';
500
+ if (error instanceof Error) {
501
+ errorMessage = error.message;
502
+ }
503
+ else if (typeof error === 'object' && error !== null) {
504
+ try {
505
+ errorMessage = JSON.stringify(error, null, 2);
506
+ }
507
+ catch {
508
+ errorMessage = String(error);
509
+ }
510
+ }
511
+ else {
512
+ errorMessage = String(error);
513
+ }
514
+ if (errorMessage.toLowerCase().includes('not found')) {
515
+ return {
516
+ content: [{
517
+ type: "text",
518
+ text: `❌ **App Not Found**\n\nThe specified app doesn't exist.\n\n**App ID:** \`${args.appId}\`\n\n💡 Use \`list_apps\` to see available apps.`,
519
+ }],
520
+ };
521
+ }
522
+ if (errorMessage.toLowerCase().includes('permission')) {
523
+ return {
524
+ content: [{
525
+ type: "text",
526
+ text: `❌ **Permission Denied**\n\nYou don't have permission to update this app. Only app creator or workspace admin can update apps.\n\n**Error:** ${errorMessage}`,
527
+ }],
528
+ };
529
+ }
530
+ return {
531
+ content: [{
532
+ type: "text",
533
+ text: `❌ **Error updating app**\n\n**Error:** ${errorMessage}\n\n**Common Issues:**\n- App ID invalid\n- Not app creator or admin\n- Invalid property values`,
534
+ }],
535
+ };
536
+ }
537
+ }
538
+ };
539
+ // ============================================================================
540
+ // REMOVE APP TOOL
541
+ // ============================================================================
542
+ const removeAppDescription = `🧪 [PLAYGROUND] Remove App - ⚠️ DANGER: Permanently deletes app entry from Hailer
543
+
544
+ ⚠️ **MANDATORY: GATHER COMPLETE CONTEXT BEFORE CALLING THIS TOOL**
545
+ **BEFORE calling this tool, you are REQUIRED to:**
546
+ 1. Load the skill: \`get_skill({ skillName: "remove-app-skill" })\`
547
+ 2. Fetch app details with \`list_apps\` to get:
548
+ - App name and ID
549
+ - Workspace ID and name
550
+ - App type (development/published)
551
+ - App configuration
552
+ 3. Show comprehensive confirmation message including:
553
+ - Workspace ID and name
554
+ - App ID and name
555
+ - What will be deleted (entry, permissions, configuration)
556
+ - What won't be deleted (published code remains)
557
+ - Clear irreversibility warning
558
+ 4. Wait for explicit user confirmation
559
+ **FAILURE TO GATHER AND SHOW THIS CONTEXT IS AN ERROR**
560
+
561
+ **Required**: appId
562
+ **Permission**: App creator or workspace administrator
563
+
564
+ **What gets deleted**:
565
+ - App entry (name, description, URL, metadata)
566
+ - App permissions
567
+ - App configuration
568
+
569
+ **What doesn't get deleted**:
570
+ - Published app code (remains on server)
571
+ - App data (if any)
572
+
573
+ **Example**:
574
+ \`\`\`javascript
575
+ remove_app({
576
+ appId: '<app-id>'
577
+ })
578
+ \`\`\`
579
+
580
+ **Tips**:
581
+ - Use \`list_apps\` to get app IDs
582
+ - Published app code must be removed separately
583
+ - Operation cannot be undone`;
584
+ exports.removeAppTool = {
585
+ name: 'remove_app',
586
+ group: tool_registry_1.ToolGroup.NUCLEAR,
587
+ description: removeAppDescription,
588
+ schema: zod_1.z.object({
589
+ appId: zod_1.z
590
+ .string()
591
+ .min(1)
592
+ .describe("App ID to remove"),
593
+ confirmed: zod_1.z
594
+ .boolean()
595
+ .optional()
596
+ .describe("First confirmation - must be true to proceed"),
597
+ secondConfirmed: zod_1.z
598
+ .boolean()
599
+ .optional()
600
+ .describe("Second confirmation - must be true to proceed (required for double-check safety)"),
601
+ }),
602
+ async execute(args, context) {
603
+ logger.debug('Removing app', {
604
+ appId: args.appId,
605
+ confirmed: args.confirmed,
606
+ secondConfirmed: args.secondConfirmed,
607
+ apiKey: context.apiKey.substring(0, 8) + '...'
608
+ });
609
+ try {
610
+ // Fetch app info and workspace info
611
+ const [appListResult, initData] = await Promise.all([
612
+ context.hailer.request('v3.app.list', [{}]),
613
+ context.hailer.request('v2.core.init', [["network"]])
614
+ ]);
615
+ const app = appListResult.apps?.find(a => a._id === args.appId);
616
+ const appName = app?.name || 'Unknown';
617
+ const workspaceId = initData.network?._id || 'Unknown';
618
+ const workspaceName = initData.network?.name || 'Unknown';
619
+ // SAFETY CHECK: Require double confirmation
620
+ if (!args.confirmed || !args.secondConfirmed) {
621
+ let warningText = `⚠️ **DESTRUCTIVE OPERATION - CONFIRMATION REQUIRED**\n\n`;
622
+ warningText += `You are about to **permanently delete** the following:\n\n`;
623
+ warningText += `**App:** ${appName}\n`;
624
+ warningText += `**App ID:** \`${args.appId}\`\n`;
625
+ warningText += `**Workspace:** ${workspaceName} (\`${workspaceId}\`)\n\n`;
626
+ warningText += `**⚠️ This will permanently delete:**\n`;
627
+ warningText += `- App entry (name, description, URL)\n`;
628
+ warningText += `- App permissions\n`;
629
+ warningText += `- App configuration\n\n`;
630
+ warningText += `**🚨 THIS CANNOT BE UNDONE! 🚨**\n\n`;
631
+ warningText += `**To proceed, you must:**\n`;
632
+ warningText += `1. Review the \`remove-app-skill\` (REQUIRED)\n`;
633
+ warningText += `2. Call this tool again with BOTH confirmations:\n\n`;
634
+ warningText += `\`\`\`javascript\n`;
635
+ warningText += `remove_app({\n`;
636
+ warningText += ` appId: "${args.appId}",\n`;
637
+ warningText += ` confirmed: true,\n`;
638
+ warningText += ` secondConfirmed: true\n`;
639
+ warningText += `})\n`;
640
+ warningText += `\`\`\`\n\n`;
641
+ warningText += `💡 **Before proceeding:**\n`;
642
+ warningText += `- Load \`remove-app-skill\` to review safety checklist\n`;
643
+ warningText += `- Verify with user that this is intentional\n`;
644
+ warningText += `- Note: Published app code remains on server`;
645
+ return {
646
+ content: [{
647
+ type: "text",
648
+ text: warningText,
649
+ }],
650
+ };
651
+ }
652
+ logger.debug('Calling v3.app.remove', {
653
+ appId: args.appId,
654
+ appName,
655
+ workspaceId,
656
+ workspaceName
657
+ });
658
+ await context.hailer.request('v3.app.remove', [args.appId]);
659
+ logger.debug('App removal successful', {
660
+ appId: args.appId,
661
+ appName
662
+ });
663
+ let responseText = `✅ **App Removed Successfully**\n\n`;
664
+ responseText += `**App:** ${appName}\n`;
665
+ responseText += `**App ID:** \`${args.appId}\`\n`;
666
+ responseText += `**Workspace:** ${workspaceName} (\`${workspaceId}\`)\n\n`;
667
+ responseText += `⚠️ **The app entry has been permanently deleted.**\n\n`;
668
+ responseText += `**What was deleted:**\n`;
669
+ responseText += `- App entry (name, description, URL)\n`;
670
+ responseText += `- App permissions\n`;
671
+ responseText += `- App configuration\n\n`;
672
+ responseText += `**Note:** Published app code remains on server (if applicable).\n\n`;
673
+ responseText += `💡 Use \`list_apps\` to see remaining apps.`;
674
+ return {
675
+ content: [{
676
+ type: "text",
677
+ text: responseText,
678
+ }],
679
+ };
680
+ }
681
+ catch (error) {
682
+ logger.error("Error removing app", error);
683
+ let errorMessage = 'Unknown error occurred';
684
+ if (error instanceof Error) {
685
+ errorMessage = error.message;
686
+ }
687
+ else if (typeof error === 'object' && error !== null) {
688
+ try {
689
+ errorMessage = JSON.stringify(error, null, 2);
690
+ }
691
+ catch {
692
+ errorMessage = String(error);
693
+ }
694
+ }
695
+ else {
696
+ errorMessage = String(error);
697
+ }
698
+ if (errorMessage.toLowerCase().includes('not found')) {
699
+ return {
700
+ content: [{
701
+ type: "text",
702
+ text: `❌ **App Not Found**\n\nThe specified app doesn't exist or has already been deleted.\n\n**App ID:** \`${args.appId}\`\n\n💡 Use \`list_apps\` to see available apps.`,
703
+ }],
704
+ };
705
+ }
706
+ if (errorMessage.toLowerCase().includes('permission')) {
707
+ return {
708
+ content: [{
709
+ type: "text",
710
+ text: `❌ **Permission Denied**\n\nYou don't have permission to remove this app. Only app creator or workspace admin can delete apps.\n\n**Error:** ${errorMessage}`,
711
+ }],
712
+ };
713
+ }
714
+ return {
715
+ content: [{
716
+ type: "text",
717
+ text: `❌ **Error removing app**\n\n**Error:** ${errorMessage}\n\n**Common Issues:**\n- App ID invalid\n- App already deleted\n- Not app creator or admin`,
718
+ }],
719
+ };
720
+ }
721
+ }
722
+ };
723
+ // ============================================================================
724
+ // ADD APP MEMBER TOOL
725
+ // ============================================================================
726
+ const addAppMemberDescription = `🧪 [PLAYGROUND] Add App Member - Share app with users/teams
727
+
728
+ **What it does**:
729
+ Grants permission for users, teams, or entire workspace to access an app.
730
+
731
+ **Member Formats**:
732
+ - \`network_<workspaceId>\` - Entire workspace
733
+ - \`team_<teamId>\` - Specific team
734
+ - \`user_<userId>\` - Individual user
735
+ - \`group_<groupId>\` - Custom group
736
+
737
+ **Example - Share with workspace**:
738
+ \`\`\`javascript
739
+ add_app_member({
740
+ appId: '<app-id>',
741
+ member: 'network_68446c045b30685f67c6fc8c'
742
+ })
743
+ \`\`\`
744
+
745
+ **Example - Share with team**:
746
+ \`\`\`javascript
747
+ add_app_member({
748
+ appId: '<app-id>',
749
+ member: 'team_<team-id>'
750
+ })
751
+ \`\`\`
752
+
753
+ **Example - Share with user**:
754
+ \`\`\`javascript
755
+ add_app_member({
756
+ appId: '<app-id>',
757
+ member: 'user_<user-id>'
758
+ })
759
+ \`\`\`
760
+
761
+ **Requirements**:
762
+ - User must be app creator or workspace admin
763
+
764
+ **Tips**:
765
+ - Default: Only creator and admins see app
766
+ - Use network_ to make app available to everyone
767
+ - Use team_ for team-specific apps`;
768
+ exports.addAppMemberTool = {
769
+ name: 'add_app_member',
770
+ group: tool_registry_1.ToolGroup.PLAYGROUND,
771
+ description: addAppMemberDescription,
772
+ schema: zod_1.z.object({
773
+ appId: zod_1.z
774
+ .string()
775
+ .min(1)
776
+ .describe("App ID"),
777
+ member: zod_1.z
778
+ .string()
779
+ .regex(/^(network_|team_|user_|group_)[a-zA-Z0-9]+$/, "Member must be network_*, team_*, user_*, or group_*")
780
+ .describe("Member identifier (network_<id>, team_<id>, user_<id>, or group_<id>)"),
781
+ }),
782
+ async execute(args, context) {
783
+ logger.debug('Adding app member', {
784
+ appId: args.appId,
785
+ member: args.member,
786
+ apiKey: context.apiKey.substring(0, 8) + '...'
787
+ });
788
+ try {
789
+ logger.debug('Calling v3.app.member.add', {
790
+ appId: args.appId,
791
+ member: args.member
792
+ });
793
+ await context.hailer.request('v3.app.member.add', [
794
+ args.appId,
795
+ args.member
796
+ ]);
797
+ logger.debug('App member added successfully');
798
+ const memberType = args.member.split('_')[0];
799
+ const memberTypeLabel = {
800
+ 'network': 'Workspace',
801
+ 'team': 'Team',
802
+ 'user': 'User',
803
+ 'group': 'Group'
804
+ };
805
+ let responseText = `✅ **App Member Added Successfully**\n\n`;
806
+ responseText += `**App ID:** \`${args.appId}\`\n`;
807
+ responseText += `**Member Type:** ${memberTypeLabel[memberType] || 'Member'}\n`;
808
+ responseText += `**Member ID:** \`${args.member}\`\n\n`;
809
+ if (memberType === 'network') {
810
+ responseText += `🌐 **App is now accessible to entire workspace!**\n`;
811
+ }
812
+ else if (memberType === 'team') {
813
+ responseText += `👥 **App is now accessible to all team members.**\n`;
814
+ }
815
+ else if (memberType === 'user') {
816
+ responseText += `👤 **App is now accessible to this user.**\n`;
817
+ }
818
+ else {
819
+ responseText += `🔑 **App is now accessible to this group.**\n`;
820
+ }
821
+ return {
822
+ content: [{
823
+ type: "text",
824
+ text: responseText,
825
+ }],
826
+ };
827
+ }
828
+ catch (error) {
829
+ logger.error("Error adding app member", error);
830
+ let errorMessage = 'Unknown error occurred';
831
+ if (error instanceof Error) {
832
+ errorMessage = error.message;
833
+ }
834
+ else if (typeof error === 'object' && error !== null) {
835
+ try {
836
+ errorMessage = JSON.stringify(error, null, 2);
837
+ }
838
+ catch {
839
+ errorMessage = String(error);
840
+ }
841
+ }
842
+ else {
843
+ errorMessage = String(error);
844
+ }
845
+ if (errorMessage.toLowerCase().includes('not found')) {
846
+ return {
847
+ content: [{
848
+ type: "text",
849
+ text: `❌ **App Not Found**\n\nThe specified app doesn't exist.\n\n**App ID:** \`${args.appId}\`\n\n💡 Use \`list_apps\` to see available apps.`,
850
+ }],
851
+ };
852
+ }
853
+ if (errorMessage.toLowerCase().includes('permission')) {
854
+ return {
855
+ content: [{
856
+ type: "text",
857
+ text: `❌ **Permission Denied**\n\nYou don't have permission to manage this app's members. Only app creator or workspace admin can add members.\n\n**Error:** ${errorMessage}`,
858
+ }],
859
+ };
860
+ }
861
+ return {
862
+ content: [{
863
+ type: "text",
864
+ text: `❌ **Error adding app member**\n\n**Error:** ${errorMessage}\n\n**Common Issues:**\n- App ID invalid\n- Member ID invalid\n- Not app creator or admin\n- Member format must be network_*, team_*, user_*, or group_*`,
865
+ }],
866
+ };
867
+ }
868
+ }
869
+ };
870
+ // ============================================================================
871
+ // REMOVE APP MEMBER TOOL
872
+ // ============================================================================
873
+ const removeAppMemberDescription = `🧪 [PLAYGROUND] Remove App Member - Revoke app access
874
+
875
+ **What it does**:
876
+ Revokes permission for users, teams, or workspace to access an app.
877
+
878
+ **Example - Remove workspace access**:
879
+ \`\`\`javascript
880
+ remove_app_member({
881
+ appId: '<app-id>',
882
+ member: 'network_68446c045b30685f67c6fc8c'
883
+ })
884
+ \`\`\`
885
+
886
+ **Example - Remove team access**:
887
+ \`\`\`javascript
888
+ remove_app_member({
889
+ appId: '<app-id>',
890
+ member: 'team_<team-id>'
891
+ })
892
+ \`\`\`
893
+
894
+ **Requirements**:
895
+ - User must be app creator or workspace admin
896
+
897
+ **Notes**:
898
+ - Creator and admins always retain access
899
+ - Removing workspace revokes access from all members
900
+
901
+ **Tips**:
902
+ - Use \`list_apps\` to get app IDs
903
+ - Member format same as add_app_member`;
904
+ exports.removeAppMemberTool = {
905
+ name: 'remove_app_member',
906
+ group: tool_registry_1.ToolGroup.PLAYGROUND,
907
+ description: removeAppMemberDescription,
908
+ schema: zod_1.z.object({
909
+ appId: zod_1.z
910
+ .string()
911
+ .min(1)
912
+ .describe("App ID"),
913
+ member: zod_1.z
914
+ .string()
915
+ .regex(/^(network_|team_|user_|group_)[a-zA-Z0-9]+$/, "Member must be network_*, team_*, user_*, or group_*")
916
+ .describe("Member identifier to remove"),
917
+ }),
918
+ async execute(args, context) {
919
+ logger.debug('Removing app member', {
920
+ appId: args.appId,
921
+ member: args.member,
922
+ apiKey: context.apiKey.substring(0, 8) + '...'
923
+ });
924
+ try {
925
+ logger.debug('Calling v3.app.member.remove', {
926
+ appId: args.appId,
927
+ member: args.member
928
+ });
929
+ await context.hailer.request('v3.app.member.remove', [
930
+ args.appId,
931
+ args.member
932
+ ]);
933
+ logger.debug('App member removed successfully');
934
+ const memberType = args.member.split('_')[0];
935
+ const memberTypeLabel = {
936
+ 'network': 'Workspace',
937
+ 'team': 'Team',
938
+ 'user': 'User',
939
+ 'group': 'Group'
940
+ };
941
+ let responseText = `✅ **App Member Removed Successfully**\n\n`;
942
+ responseText += `**App ID:** \`${args.appId}\`\n`;
943
+ responseText += `**Member Type:** ${memberTypeLabel[memberType] || 'Member'}\n`;
944
+ responseText += `**Member ID:** \`${args.member}\`\n\n`;
945
+ responseText += `🔒 **Access revoked for this ${(memberTypeLabel[memberType] || 'Member').toLowerCase()}.**\n\n`;
946
+ responseText += `**Note:** Creator and admins always retain access.`;
947
+ return {
948
+ content: [{
949
+ type: "text",
950
+ text: responseText,
951
+ }],
952
+ };
953
+ }
954
+ catch (error) {
955
+ logger.error("Error removing app member", error);
956
+ let errorMessage = 'Unknown error occurred';
957
+ if (error instanceof Error) {
958
+ errorMessage = error.message;
959
+ }
960
+ else if (typeof error === 'object' && error !== null) {
961
+ try {
962
+ errorMessage = JSON.stringify(error, null, 2);
963
+ }
964
+ catch {
965
+ errorMessage = String(error);
966
+ }
967
+ }
968
+ else {
969
+ errorMessage = String(error);
970
+ }
971
+ if (errorMessage.toLowerCase().includes('not found')) {
972
+ return {
973
+ content: [{
974
+ type: "text",
975
+ text: `❌ **App or Member Not Found**\n\nThe specified app or member doesn't exist.\n\n**App ID:** \`${args.appId}\`\n**Member:** \`${args.member}\`\n\n💡 Use \`list_apps\` to see available apps.`,
976
+ }],
977
+ };
978
+ }
979
+ if (errorMessage.toLowerCase().includes('permission')) {
980
+ return {
981
+ content: [{
982
+ type: "text",
983
+ text: `❌ **Permission Denied**\n\nYou don't have permission to manage this app's members. Only app creator or workspace admin can remove members.\n\n**Error:** ${errorMessage}`,
984
+ }],
985
+ };
986
+ }
987
+ return {
988
+ content: [{
989
+ type: "text",
990
+ text: `❌ **Error removing app member**\n\n**Error:** ${errorMessage}\n\n**Common Issues:**\n- App ID invalid\n- Member doesn't have access\n- Not app creator or admin`,
991
+ }],
992
+ };
993
+ }
994
+ }
995
+ };
996
+ // ============================================================================
997
+ // SCAFFOLD HAILER APP TOOL
998
+ // ============================================================================
999
+ const scaffoldHailerAppDescription = `Scaffold new Hailer app from template - ONE SHOT SETUP
1000
+
1001
+ ⚠️ **MANDATORY: YOU MUST LOAD SKILL FIRST**
1002
+ **BEFORE calling this tool, you are REQUIRED to:**
1003
+ 1. Load the skill: \`get_skill({ skillName: "scaffold-hailer-app-skill" })\`
1004
+ 2. Read the setup guide and understand the process
1005
+ 3. Review template options and troubleshooting tips
1006
+ **FAILURE TO LOAD THE SKILL FIRST IS AN ERROR**
1007
+
1008
+ **Required Parameters**:
1009
+ - projectName: Project folder name
1010
+ - template: react-ts (recommended), react-swc-ts, or vanilla
1011
+
1012
+ **Optional Parameters**:
1013
+ - description: App description for Hailer
1014
+ - autoCreateDevApp: (default: true) Automatically create dev app entry in Hailer
1015
+ - autoShareWithWorkspace: (default: true) Share app with entire workspace
1016
+ - autoStartDevServer: (default: true) Start dev server in background
1017
+
1018
+ **What This Does (One Shot)**:
1019
+ 1. ✅ Scaffolds project from template
1020
+ 2. ✅ Installs dependencies
1021
+ 3. ✅ Creates dev app entry in Hailer with correct URL
1022
+ 4. ✅ Shares app with workspace
1023
+ 5. ✅ Updates manifest.json with app ID
1024
+ 6. ✅ Starts dev server on port 3000
1025
+ 7. ✅ App ready to open in Hailer!
1026
+
1027
+ **Target Directory**:
1028
+ - Uses DEV_APPS_PATH from .env.local if set
1029
+ - Falls back to targetDirectory parameter
1030
+ - Falls back to current directory if neither set`;
1031
+ exports.scaffoldHailerAppTool = {
1032
+ name: 'scaffold_hailer_app',
1033
+ group: tool_registry_1.ToolGroup.PLAYGROUND,
1034
+ description: scaffoldHailerAppDescription,
1035
+ schema: zod_1.z.object({
1036
+ projectName: zod_1.z.string().min(1).describe("Project folder name"),
1037
+ template: zod_1.z.enum(['react-ts', 'react-swc-ts', 'vanilla']).describe("Template to use"),
1038
+ description: zod_1.z.string().optional().describe("App description for Hailer"),
1039
+ targetDirectory: zod_1.z.string().optional().describe("Target directory (defaults to DEV_APPS_PATH or current)"),
1040
+ installDependencies: zod_1.z.coerce.boolean().optional().default(true).describe("Run npm install after scaffolding"),
1041
+ autoCreateDevApp: zod_1.z.coerce.boolean().optional().default(true).describe("Automatically create dev app entry in Hailer"),
1042
+ autoShareWithWorkspace: zod_1.z.coerce.boolean().optional().default(true).describe("Share app with entire workspace"),
1043
+ autoStartDevServer: zod_1.z.coerce.boolean().optional().default(true).describe("Start dev server in background on port 3000")
1044
+ }),
1045
+ async execute(args, context) {
1046
+ const { execSync, spawn } = await Promise.resolve().then(() => __importStar(require('child_process')));
1047
+ const path = await Promise.resolve().then(() => __importStar(require('path')));
1048
+ const fs = await Promise.resolve().then(() => __importStar(require('fs')));
1049
+ try {
1050
+ const targetDir = args.targetDirectory || config_1.environment.DEV_APPS_PATH || process.cwd();
1051
+ const projectPath = path.join(targetDir, args.projectName);
1052
+ // Check if directory already exists
1053
+ if (fs.existsSync(projectPath)) {
1054
+ return {
1055
+ content: [{
1056
+ type: "text",
1057
+ text: `❌ **Directory Already Exists**\n\nThe directory \`${projectPath}\` already exists.\n\n**Options:**\n- Choose a different project name\n- Remove the existing directory\n- Use a different target directory`,
1058
+ }],
1059
+ };
1060
+ }
1061
+ let responseText = `🚀 **ONE-SHOT HAILER APP SETUP**\n\n`;
1062
+ responseText += `**Project:** ${args.projectName}\n`;
1063
+ responseText += `**Template:** ${args.template}\n`;
1064
+ responseText += `**Location:** ${projectPath}\n\n`;
1065
+ // Step 1: Scaffold project
1066
+ responseText += `⏳ Step 1/8: Creating project from template...\n`;
1067
+ try {
1068
+ const createCmd = `npm create @hailer/app@latest ${args.projectName} -- --template ${args.template}`;
1069
+ execSync(createCmd, {
1070
+ cwd: targetDir,
1071
+ stdio: 'pipe',
1072
+ encoding: 'utf-8',
1073
+ shell: '/bin/bash'
1074
+ });
1075
+ responseText += `✅ Project scaffolded\n\n`;
1076
+ }
1077
+ catch (error) {
1078
+ const errorMessage = error instanceof Error ? error.message : String(error);
1079
+ return {
1080
+ content: [{
1081
+ type: "text",
1082
+ text: `❌ **Error scaffolding project**\n\n**Error:** ${errorMessage}\n\n**Possible Issues:**\n- npm not available\n- Network issues\n- Insufficient permissions`,
1083
+ }],
1084
+ };
1085
+ }
1086
+ // Step 2: Install dependencies
1087
+ if (args.installDependencies !== false) {
1088
+ responseText += `⏳ Step 2/8: Installing dependencies...\n`;
1089
+ try {
1090
+ execSync('npm install', {
1091
+ cwd: projectPath,
1092
+ stdio: 'pipe',
1093
+ encoding: 'utf-8',
1094
+ shell: '/bin/bash'
1095
+ });
1096
+ responseText += `✅ Dependencies installed\n\n`;
1097
+ }
1098
+ catch (error) {
1099
+ const errorMessage = error instanceof Error ? error.message : String(error);
1100
+ responseText += `⚠️ Failed to install dependencies: ${errorMessage}\n\n`;
1101
+ }
1102
+ }
1103
+ else {
1104
+ responseText += `⏭️ Step 2/8: Skipped (installDependencies = false)\n\n`;
1105
+ }
1106
+ // Step 3: Configure CORS in vite.config.ts
1107
+ responseText += `⏳ Step 3/8: Configuring CORS for Hailer access...\n`;
1108
+ try {
1109
+ const viteConfigPath = path.join(projectPath, 'vite.config.ts');
1110
+ if (fs.existsSync(viteConfigPath)) {
1111
+ let viteConfig = fs.readFileSync(viteConfigPath, 'utf-8');
1112
+ // Check if CORS is already configured
1113
+ if (!viteConfig.includes('cors:')) {
1114
+ // Add CORS configuration to the server block
1115
+ // Matches: server: { port: 3000 } or server: { port: 3000, } with optional whitespace
1116
+ viteConfig = viteConfig.replace(/server:\s*{\s*port:\s*3000\s*,?\s*}/, `server: {
1117
+ port: 3000,
1118
+ cors: {
1119
+ origin: '*',
1120
+ credentials: true
1121
+ }
1122
+ }`);
1123
+ fs.writeFileSync(viteConfigPath, viteConfig);
1124
+ responseText += `✅ CORS configured in vite.config.ts\n\n`;
1125
+ }
1126
+ else {
1127
+ responseText += `✅ CORS already configured\n\n`;
1128
+ }
1129
+ }
1130
+ else {
1131
+ responseText += `⚠️ vite.config.ts not found, skipping CORS configuration\n\n`;
1132
+ }
1133
+ }
1134
+ catch (error) {
1135
+ const errorMessage = error instanceof Error ? error.message : String(error);
1136
+ responseText += `⚠️ Failed to configure CORS: ${errorMessage}\n\n`;
1137
+ }
1138
+ let appId;
1139
+ let workspaceId;
1140
+ // Step 4: Create dev app in Hailer
1141
+ if (args.autoCreateDevApp !== false) {
1142
+ responseText += `⏳ Step 4/8: Creating dev app entry in Hailer...\n`;
1143
+ try {
1144
+ if (!context.workspaceCache) {
1145
+ responseText += `⚠️ Workspace cache not available, skipping app creation\n\n`;
1146
+ }
1147
+ else {
1148
+ workspaceId = context.workspaceCache.currentWorkspace._id;
1149
+ const appData = {
1150
+ cid: workspaceId,
1151
+ name: args.projectName,
1152
+ url: 'http://localhost:3000'
1153
+ };
1154
+ if (args.description) {
1155
+ appData.description = args.description;
1156
+ }
1157
+ const result = await context.hailer.request('v3.app.create', [appData]);
1158
+ appId = result.appId || result._id;
1159
+ responseText += `✅ App created: ${appId}\n`;
1160
+ responseText += ` URL: http://localhost:3000\n\n`;
1161
+ }
1162
+ }
1163
+ catch (error) {
1164
+ const errorMessage = error instanceof Error ? error.message : String(error);
1165
+ responseText += `⚠️ Failed to create app in Hailer: ${errorMessage}\n\n`;
1166
+ }
1167
+ }
1168
+ else {
1169
+ responseText += `⏭️ Step 4/8: Skipped (autoCreateDevApp = false)\n\n`;
1170
+ }
1171
+ // Step 5: Share with workspace
1172
+ if (args.autoShareWithWorkspace !== false && appId && workspaceId) {
1173
+ responseText += `⏳ Step 5/8: Sharing app with workspace...\n`;
1174
+ try {
1175
+ await context.hailer.request('v3.app.member.add', [
1176
+ appId,
1177
+ `network_${workspaceId}`
1178
+ ]);
1179
+ responseText += `✅ App shared with entire workspace\n\n`;
1180
+ }
1181
+ catch (error) {
1182
+ const errorMessage = error instanceof Error ? error.message : String(error);
1183
+ responseText += `⚠️ Failed to share app: ${errorMessage}\n\n`;
1184
+ }
1185
+ }
1186
+ else {
1187
+ responseText += `⏭️ Step 5/8: Skipped (no app ID or autoShareWithWorkspace = false)\n\n`;
1188
+ }
1189
+ // Step 6: Update manifest.json with app ID
1190
+ if (appId) {
1191
+ responseText += `⏳ Step 6/8: Updating manifest.json with app ID...\n`;
1192
+ try {
1193
+ const manifestPath = path.join(projectPath, 'public', 'manifest.json');
1194
+ if (fs.existsSync(manifestPath)) {
1195
+ const manifestContent = fs.readFileSync(manifestPath, 'utf-8');
1196
+ const manifest = JSON.parse(manifestContent);
1197
+ manifest.appId = appId;
1198
+ fs.writeFileSync(manifestPath, JSON.stringify(manifest, null, 2));
1199
+ responseText += `✅ manifest.json updated with appId\n\n`;
1200
+ }
1201
+ else {
1202
+ responseText += `⚠️ manifest.json not found at ${manifestPath}\n\n`;
1203
+ }
1204
+ }
1205
+ catch (error) {
1206
+ const errorMessage = error instanceof Error ? error.message : String(error);
1207
+ responseText += `⚠️ Failed to update manifest: ${errorMessage}\n\n`;
1208
+ }
1209
+ }
1210
+ else {
1211
+ responseText += `⏭️ Step 6/8: Skipped (no app ID)\n\n`;
1212
+ }
1213
+ // Step 7: Start dev server
1214
+ if (args.autoStartDevServer !== false) {
1215
+ responseText += `⏳ Step 7/8: Starting dev server on port 3000...\n`;
1216
+ try {
1217
+ // Start dev server in background
1218
+ const devServer = spawn('npm', ['run', 'dev'], {
1219
+ cwd: projectPath,
1220
+ detached: true,
1221
+ stdio: 'ignore',
1222
+ shell: true
1223
+ });
1224
+ devServer.unref();
1225
+ responseText += `✅ Dev server started in background\n`;
1226
+ responseText += ` PID: ${devServer.pid}\n`;
1227
+ responseText += ` URL: http://localhost:3000\n\n`;
1228
+ }
1229
+ catch (error) {
1230
+ const errorMessage = error instanceof Error ? error.message : String(error);
1231
+ responseText += `⚠️ Failed to start dev server: ${errorMessage}\n`;
1232
+ responseText += ` Start manually: cd ${args.projectName} && npm run dev\n\n`;
1233
+ }
1234
+ }
1235
+ else {
1236
+ responseText += `⏭️ Step 7/8: Skipped (autoStartDevServer = false)\n\n`;
1237
+ }
1238
+ // Step 8: Complete
1239
+ responseText += `✅ **Step 8/8: Setup Complete!**\n\n`;
1240
+ // Final summary
1241
+ responseText += `## 🎉 Your Hailer App is Ready!\n\n`;
1242
+ responseText += `**What was done:**\n`;
1243
+ responseText += `- ✅ Project scaffolded from ${args.template} template\n`;
1244
+ if (args.installDependencies !== false)
1245
+ responseText += `- ✅ Dependencies installed\n`;
1246
+ responseText += `- ✅ CORS configured for Hailer access\n`;
1247
+ if (appId)
1248
+ responseText += `- ✅ Dev app entry created in Hailer (ID: \`${appId}\`)\n`;
1249
+ if (args.autoShareWithWorkspace !== false && appId)
1250
+ responseText += `- ✅ App shared with entire workspace\n`;
1251
+ if (appId)
1252
+ responseText += `- ✅ manifest.json configured with app ID\n`;
1253
+ if (args.autoStartDevServer !== false)
1254
+ responseText += `- ✅ Dev server started on http://localhost:3000\n`;
1255
+ responseText += `\n## 🚀 Next Steps\n\n`;
1256
+ responseText += `1. **Open the app in Hailer** - Look for "${args.projectName}" in your apps menu\n`;
1257
+ responseText += `2. **Start coding** - Files in \`${projectPath}/src\` will hot-reload\n`;
1258
+ responseText += `3. **View logs** - Check dev server output if needed\n\n`;
1259
+ responseText += `## 📂 Project Location\n\n`;
1260
+ responseText += `\`\`\`\n${projectPath}\n\`\`\`\n\n`;
1261
+ if (appId) {
1262
+ responseText += `## 🔗 App Info\n\n`;
1263
+ responseText += `- **App ID:** \`${appId}\`\n`;
1264
+ responseText += `- **Dev URL:** http://localhost:3000\n`;
1265
+ responseText += `- **Shared with:** Entire workspace\n`;
1266
+ }
1267
+ return {
1268
+ content: [{
1269
+ type: "text",
1270
+ text: responseText,
1271
+ }],
1272
+ };
1273
+ }
1274
+ catch (error) {
1275
+ const errorMessage = error instanceof Error ? error.message : String(error);
1276
+ return {
1277
+ content: [{
1278
+ type: "text",
1279
+ text: `❌ **Error in one-shot setup**\n\n**Error:** ${errorMessage}\n\n**Common Issues:**\n- Node.js not installed or version < 18\n- npm not available\n- Insufficient permissions\n- Hailer API connection issues`,
1280
+ }],
1281
+ };
1282
+ }
1283
+ }
1284
+ };
1285
+ // ============================================================================
1286
+ // PUBLISH HAILER APP TOOL
1287
+ // ============================================================================
1288
+ const publishHailerAppDescription = `Publish Hailer app to production - Builds and uploads to Hailer hosting
1289
+
1290
+ ⚠️ **MANDATORY: YOU MUST LOAD SKILL FIRST**
1291
+ **BEFORE calling this tool, you are REQUIRED to:**
1292
+ 1. Load the skill: \`get_skill({ skillName: "publish-hailer-app-skill" })\`
1293
+ 2. Read the complete workflow and prerequisites
1294
+ 3. Review troubleshooting tips and common issues
1295
+ **FAILURE TO LOAD THE SKILL FIRST IS AN ERROR**
1296
+
1297
+ **Required Parameters**:
1298
+ - email: Hailer user email
1299
+ - password: User password
1300
+
1301
+ **Project Directory**:
1302
+ - Uses DEV_APPS_PATH from .env.local if set
1303
+ - Falls back to projectDirectory parameter
1304
+ - Falls back to current directory if neither set
1305
+
1306
+ **Prerequisites**: Published app entry exists (create_app with empty URL), manifest.json has appId
1307
+ **Process**: Builds bundle → authenticates → uploads files`;
1308
+ exports.publishHailerAppTool = {
1309
+ name: 'publish_hailer_app',
1310
+ group: tool_registry_1.ToolGroup.PLAYGROUND,
1311
+ description: publishHailerAppDescription,
1312
+ schema: zod_1.z.object({
1313
+ email: zod_1.z.string().email().describe("Hailer user email for authentication"),
1314
+ password: zod_1.z.string().min(1).describe("Hailer user password"),
1315
+ projectDirectory: zod_1.z.string().optional().describe("Path to app project (defaults to current directory)"),
1316
+ appId: zod_1.z.string().optional().describe("App ID to publish to (reads from manifest.json if not provided)")
1317
+ }),
1318
+ async execute(args, _context) {
1319
+ const { execSync } = await Promise.resolve().then(() => __importStar(require('child_process')));
1320
+ const path = await Promise.resolve().then(() => __importStar(require('path')));
1321
+ const fs = await Promise.resolve().then(() => __importStar(require('fs')));
1322
+ try {
1323
+ const projectDir = args.projectDirectory || config_1.environment.DEV_APPS_PATH || process.cwd();
1324
+ // Check if directory exists
1325
+ if (!fs.existsSync(projectDir)) {
1326
+ return {
1327
+ content: [{
1328
+ type: "text",
1329
+ text: `❌ **Directory Not Found**\n\nThe directory \`${projectDir}\` does not exist.\n\n**Check:**\n- Project directory path is correct\n- You're in the right location`,
1330
+ }],
1331
+ };
1332
+ }
1333
+ // Check if package.json exists
1334
+ const packageJsonPath = path.join(projectDir, 'package.json');
1335
+ if (!fs.existsSync(packageJsonPath)) {
1336
+ return {
1337
+ content: [{
1338
+ type: "text",
1339
+ text: `❌ **Not a Hailer App Project**\n\nNo package.json found in \`${projectDir}\`\n\n**This doesn't appear to be a Hailer app project.**\n\nMake sure you're in the correct directory.`,
1340
+ }],
1341
+ };
1342
+ }
1343
+ // Read manifest.json to get/verify appId
1344
+ const manifestPath = path.join(projectDir, 'public', 'manifest.json');
1345
+ let appId = args.appId;
1346
+ let appName = 'Unknown';
1347
+ if (fs.existsSync(manifestPath)) {
1348
+ try {
1349
+ const manifestContent = fs.readFileSync(manifestPath, 'utf-8');
1350
+ const manifest = JSON.parse(manifestContent);
1351
+ if (!appId) {
1352
+ appId = manifest.appId;
1353
+ }
1354
+ appName = manifest.name || appName;
1355
+ if (!appId) {
1356
+ return {
1357
+ content: [{
1358
+ type: "text",
1359
+ text: `❌ **App ID Not Configured**\n\nNo appId found in \`manifest.json\` and none provided.\n\n**Steps to fix:**\n1. Get your published app ID from Hailer\n2. Edit \`public/manifest.json\`\n3. Set \`"appId": "your-app-id-here"\`\n\nOr provide appId parameter when calling this tool.`,
1360
+ }],
1361
+ };
1362
+ }
1363
+ }
1364
+ catch (error) {
1365
+ const errorMessage = error instanceof Error ? error.message : String(error);
1366
+ return {
1367
+ content: [{
1368
+ type: "text",
1369
+ text: `❌ **Invalid manifest.json**\n\nFailed to parse \`public/manifest.json\`: ${errorMessage}\n\n**Check:**\n- manifest.json is valid JSON\n- appId field is set correctly`,
1370
+ }],
1371
+ };
1372
+ }
1373
+ }
1374
+ else if (!appId) {
1375
+ return {
1376
+ content: [{
1377
+ type: "text",
1378
+ text: `❌ **Manifest Not Found**\n\nNo \`public/manifest.json\` found and no appId provided.\n\n**Steps to fix:**\n1. Ensure \`public/manifest.json\` exists\n2. Set appId in manifest\n\nOr provide appId parameter when calling this tool.`,
1379
+ }],
1380
+ };
1381
+ }
1382
+ let responseText = `🚀 **Publishing Hailer App**\n\n`;
1383
+ responseText += `**App Name:** ${appName}\n`;
1384
+ responseText += `**App ID:** \`${appId}\`\n`;
1385
+ responseText += `**Project:** ${projectDir}\n\n`;
1386
+ // Check if publish-production script exists
1387
+ try {
1388
+ const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf-8'));
1389
+ if (!packageJson.scripts?.['publish-production']) {
1390
+ return {
1391
+ content: [{
1392
+ type: "text",
1393
+ text: `❌ **Publish Script Not Found**\n\nNo \`publish-production\` script found in package.json.\n\n**This may not be a Hailer app created with @hailer/create-app.**\n\nHailer apps should have:\n\`\`\`json\n"scripts": {\n "publish-production": "...",\n ...\n}\n\`\`\``,
1394
+ }],
1395
+ };
1396
+ }
1397
+ }
1398
+ catch (error) {
1399
+ const errorMessage = error instanceof Error ? error.message : String(error);
1400
+ return {
1401
+ content: [{
1402
+ type: "text",
1403
+ text: `❌ **Invalid package.json**\n\n${errorMessage}`,
1404
+ }],
1405
+ };
1406
+ }
1407
+ // Run publish command with email and password
1408
+ responseText += `⏳ Building and publishing app...\n\n`;
1409
+ try {
1410
+ const publishCmd = `EMAIL=${args.email} npm run publish-production`;
1411
+ // Execute with password via stdin
1412
+ const result = execSync(publishCmd, {
1413
+ cwd: projectDir,
1414
+ input: args.password + '\n',
1415
+ encoding: 'utf-8',
1416
+ stdio: ['pipe', 'pipe', 'pipe']
1417
+ });
1418
+ responseText += `✅ **App Published Successfully!**\n\n`;
1419
+ // Try to parse output for useful info
1420
+ if (result) {
1421
+ responseText += `\`\`\`\n${result.trim()}\n\`\`\`\n\n`;
1422
+ }
1423
+ }
1424
+ catch (error) {
1425
+ const err = error;
1426
+ const errorOutput = err.stderr || err.stdout || err.message || String(error);
1427
+ // Check for common errors
1428
+ if (errorOutput.includes('Authentication failed') || errorOutput.includes('Invalid credentials')) {
1429
+ return {
1430
+ content: [{
1431
+ type: "text",
1432
+ text: `❌ **Authentication Failed**\n\nInvalid email or password.\n\n**Check:**\n- Email is correct\n- Password is correct\n- Account has access to this workspace`,
1433
+ }],
1434
+ };
1435
+ }
1436
+ if (errorOutput.includes('Permission denied') || errorOutput.includes('not authorized')) {
1437
+ return {
1438
+ content: [{
1439
+ type: "text",
1440
+ text: `❌ **Permission Denied**\n\nYou don't have permission to publish this app.\n\n**Requirements:**\n- Must be app creator or workspace admin\n- Must have access to the workspace`,
1441
+ }],
1442
+ };
1443
+ }
1444
+ if (errorOutput.includes('App not found') || errorOutput.includes('Invalid app')) {
1445
+ return {
1446
+ content: [{
1447
+ type: "text",
1448
+ text: `❌ **App Not Found**\n\nApp ID \`${appId}\` not found in Hailer.\n\n**Steps to fix:**\n1. Verify app exists: use \`list_apps\` tool\n2. Check appId in manifest.json is correct\n3. Ensure you created a published app entry (with empty URL)`,
1449
+ }],
1450
+ };
1451
+ }
1452
+ return {
1453
+ content: [{
1454
+ type: "text",
1455
+ text: `❌ **Publish Failed**\n\n\`\`\`\n${errorOutput}\n\`\`\`\n\n**Common Issues:**\n- Build errors (check app code)\n- Network connectivity issues\n- Invalid appId in manifest.json\n- Missing dependencies (run npm install)`,
1456
+ }],
1457
+ };
1458
+ }
1459
+ responseText += `## 📋 Next Steps\n\n`;
1460
+ responseText += `1. **Open published app in Hailer** (not the dev version)\n`;
1461
+ responseText += `2. **Verify functionality** - test all features work\n`;
1462
+ responseText += `3. **Share with users** - use \`add_app_member\` tool:\n`;
1463
+ responseText += ` \`\`\`javascript\n`;
1464
+ responseText += ` add_app_member({\n`;
1465
+ responseText += ` appId: "${appId}",\n`;
1466
+ responseText += ` member: "network_<workspace-id>" // or team_*, user_*\n`;
1467
+ responseText += ` })\n`;
1468
+ responseText += ` \`\`\`\n\n`;
1469
+ responseText += `**Note:** Published files have replaced the previous version of this app.`;
1470
+ return {
1471
+ content: [{
1472
+ type: "text",
1473
+ text: responseText,
1474
+ }],
1475
+ };
1476
+ }
1477
+ catch (error) {
1478
+ const errorMessage = error instanceof Error ? error.message : String(error);
1479
+ return {
1480
+ content: [{
1481
+ type: "text",
1482
+ text: `❌ **Error publishing Hailer app**\n\n**Error:** ${errorMessage}\n\n**Common Issues:**\n- Not in a Hailer app directory\n- Missing package.json or manifest.json\n- Network connectivity issues\n- Build failures`,
1483
+ }],
1484
+ };
1485
+ }
1486
+ }
1487
+ };
1488
+ //# sourceMappingURL=app.js.map