@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,806 @@
1
+ "use strict";
2
+ /**
3
+ * Insight Tools - Clean Architecture Implementation
4
+ *
5
+ * SQL-like insights over Hailer workflows:
6
+ * - Workflows = Tables
7
+ * - Activities = Rows
8
+ * - Fields = Columns
9
+ *
10
+ * All 4 insight management tools in one file for cohesion.
11
+ */
12
+ Object.defineProperty(exports, "__esModule", { value: true });
13
+ exports.listInsightsTool = exports.removeInsightTool = exports.getInsightDataTool = exports.previewInsightTool = exports.createInsightTool = void 0;
14
+ const zod_1 = require("zod");
15
+ const tool_registry_1 = require("../tool-registry");
16
+ const workspace_cache_1 = require("../workspace-cache");
17
+ const logger_1 = require("../../lib/logger");
18
+ const logger = (0, logger_1.createLogger)({ component: 'insight-tools' });
19
+ // ============================================================================
20
+ // SHARED TYPES & SCHEMAS
21
+ // ============================================================================
22
+ /**
23
+ * Field definition schema - either meta field or custom fieldId
24
+ */
25
+ const fieldSchema = zod_1.z.object({
26
+ name: zod_1.z.string().describe("Column name in SQL query"),
27
+ }).and(zod_1.z.union([
28
+ zod_1.z.object({
29
+ meta: zod_1.z.enum([
30
+ '_id',
31
+ 'uid',
32
+ 'team',
33
+ 'createdBy',
34
+ 'name',
35
+ 'created',
36
+ 'updated',
37
+ 'phaseId',
38
+ 'phaseName',
39
+ 'phaseLastMove',
40
+ 'workflowId',
41
+ 'workflowName',
42
+ 'priority'
43
+ ]).describe("Built-in activity property"),
44
+ }),
45
+ zod_1.z.object({
46
+ fieldId: zod_1.z.string().describe("Custom field ID from workflow"),
47
+ }),
48
+ ]));
49
+ /**
50
+ * Source definition schema - workflow as SQL table
51
+ */
52
+ const sourceSchema = zod_1.z.object({
53
+ name: zod_1.z.string().describe("Table alias for SQL query"),
54
+ workflowId: zod_1.z.string().describe("Workflow ID to query"),
55
+ fields: zod_1.z.array(fieldSchema).min(1).describe("Field mappings for SQL columns"),
56
+ });
57
+ // ============================================================================
58
+ // CREATE INSIGHT TOOL
59
+ // ============================================================================
60
+ const createInsightDescription = `๐Ÿงช [PLAYGROUND] Create SQL-like insights (workflows = tables, activities = rows, fields = columns)
61
+
62
+ โš ๏ธ **MANDATORY: YOU MUST LOAD SKILL FIRST**
63
+ **BEFORE calling this tool, you are REQUIRED to:**
64
+ 1. Load the skill: \`get_skill({ skillName: "create-insight-skill" })\`
65
+ 2. Read the query examples, JOIN patterns, and aggregation examples
66
+ 3. Test your SQL with \`preview_insight\` first
67
+ **FAILURE TO LOAD THE SKILL FIRST IS AN ERROR**
68
+
69
+ **Required Parameters**:
70
+ - name: Insight name
71
+ - sources: Array with name (table alias), workflowId, fields (meta or fieldId)
72
+ - query: Standard SQL (SELECT, JOIN, WHERE, GROUP BY, ORDER BY, LIMIT)
73
+
74
+ **Meta Fields**: _id, uid, team, createdBy, name, created, updated, phaseId, phaseName, phaseLastMove, workflowId, workflowName, priority
75
+ **SQL Support**: All standard SQL features including JOINs and aggregations`;
76
+ exports.createInsightTool = {
77
+ name: 'create_insight',
78
+ group: tool_registry_1.ToolGroup.PLAYGROUND,
79
+ description: createInsightDescription,
80
+ schema: zod_1.z.object({
81
+ workspaceId: zod_1.z
82
+ .string()
83
+ .optional()
84
+ .describe("Optional workspace ID or name - defaults to current workspace"),
85
+ name: zod_1.z
86
+ .string()
87
+ .min(1)
88
+ .describe("Insight name"),
89
+ public: zod_1.z
90
+ .boolean()
91
+ .optional()
92
+ .default(false)
93
+ .describe("Whether insight is publicly accessible (default: false)"),
94
+ sources: zod_1.z
95
+ .array(sourceSchema)
96
+ .min(1)
97
+ .describe("Workflow sources (like SQL table references)"),
98
+ query: zod_1.z
99
+ .string()
100
+ .min(1)
101
+ .describe("SQL query (SELECT, JOIN, WHERE, GROUP BY, ORDER BY, etc.)"),
102
+ }),
103
+ async execute(args, context) {
104
+ logger.debug('Creating insight', {
105
+ name: args.name,
106
+ workspaceId: args.workspaceId,
107
+ sourcesCount: args.sources.length,
108
+ apiKey: context.apiKey.substring(0, 8) + '...'
109
+ });
110
+ try {
111
+ if (!context.workspaceCache) {
112
+ return {
113
+ content: [{
114
+ type: "text",
115
+ text: "โŒ Workspace cache not available",
116
+ }],
117
+ };
118
+ }
119
+ // Resolve workspace ID
120
+ const workspaceId = args.workspaceId
121
+ ? (0, workspace_cache_1.resolveWorkspaceId)(context.workspaceCache, args.workspaceId)
122
+ : context.workspaceCache.currentWorkspace._id;
123
+ if (!workspaceId) {
124
+ return {
125
+ content: [{
126
+ type: "text",
127
+ text: `โŒ Could not resolve workspace: ${args.workspaceId}`,
128
+ }],
129
+ };
130
+ }
131
+ logger.debug('Calling v3.insight.create', {
132
+ workspaceId,
133
+ name: args.name,
134
+ sourcesCount: args.sources.length
135
+ });
136
+ // Build insight payload
137
+ const insightData = {
138
+ name: args.name,
139
+ public: args.public || false,
140
+ sources: args.sources,
141
+ query: args.query,
142
+ };
143
+ // Call v3.insight.create endpoint
144
+ const result = await context.hailer.request('v3.insight.create', [workspaceId, insightData]);
145
+ logger.debug('Insight creation successful', {
146
+ insightId: result.insightId || result._id,
147
+ result: JSON.stringify(result)
148
+ });
149
+ const insightId = result.insightId || result._id;
150
+ const discussionId = result.discussionId || result.discussion;
151
+ // Automatically join the insight's discussion
152
+ if (discussionId) {
153
+ try {
154
+ logger.debug('Automatically joining insight discussion', { discussionId });
155
+ await context.hailer.joinDiscussion(discussionId);
156
+ logger.debug('Successfully joined insight discussion', { discussionId });
157
+ }
158
+ catch (joinError) {
159
+ logger.warn('Failed to join insight discussion (non-fatal)', {
160
+ discussionId,
161
+ error: joinError instanceof Error ? joinError.message : String(joinError)
162
+ });
163
+ }
164
+ }
165
+ else {
166
+ logger.debug('No discussion ID in response, skipping auto-join');
167
+ }
168
+ // Build success response
169
+ let responseText = `โœ… **Insight Created Successfully**\n\n`;
170
+ responseText += `**Insight Name:** ${args.name}\n`;
171
+ responseText += `**Insight ID:** \`${insightId}\`\n`;
172
+ responseText += `**Workspace:** ${workspaceId}\n`;
173
+ responseText += `**Public:** ${args.public ? 'Yes' : 'No'}\n`;
174
+ responseText += `**Sources:** ${args.sources.length} workflow(s)\n`;
175
+ if (discussionId) {
176
+ responseText += `**Discussion:** Automatically joined โœ“\n`;
177
+ }
178
+ responseText += `\n`;
179
+ // Show sources
180
+ responseText += `**Query Sources:**\n`;
181
+ args.sources.forEach((source) => {
182
+ responseText += `- \`${source.name}\` โ†’ Workflow: \`${source.workflowId}\` (${source.fields.length} fields)\n`;
183
+ });
184
+ responseText += `\n**SQL Query:**\n\`\`\`sql\n${args.query}\n\`\`\`\n\n`;
185
+ responseText += `๐Ÿ’ก **Next Steps:**\n`;
186
+ responseText += `- Use \`get_insight_data\` to execute the query and see results\n`;
187
+ responseText += `- Use \`list_insights\` to see all insights in workspace\n`;
188
+ responseText += `- Use \`update_insight\` to modify the insight\n`;
189
+ responseText += `- Use \`preview_insight\` to test query changes before saving\n\n`;
190
+ if (args.public) {
191
+ responseText += `๐ŸŒ **Public Insight:** This insight can be accessed without authentication.\n`;
192
+ }
193
+ return {
194
+ content: [{
195
+ type: "text",
196
+ text: responseText,
197
+ }],
198
+ };
199
+ }
200
+ catch (error) {
201
+ logger.error("Error creating insight", error);
202
+ let errorMessage = 'Unknown error occurred';
203
+ let errorDetails = '';
204
+ if (error instanceof Error) {
205
+ errorMessage = error.message;
206
+ if (error.stack) {
207
+ errorDetails = `\n\n**Stack trace:**\n\`\`\`\n${error.stack}\n\`\`\``;
208
+ }
209
+ }
210
+ else if (typeof error === 'object' && error !== null) {
211
+ try {
212
+ errorMessage = JSON.stringify(error, null, 2);
213
+ }
214
+ catch {
215
+ errorMessage = String(error);
216
+ }
217
+ }
218
+ else {
219
+ errorMessage = String(error);
220
+ }
221
+ // Handle SQL syntax errors
222
+ if (errorMessage.toLowerCase().includes('sql') || errorMessage.toLowerCase().includes('syntax')) {
223
+ return {
224
+ content: [{
225
+ type: "text",
226
+ text: `โŒ **SQL Query Error**\n\nThere's a problem with your SQL query.\n\n**Error:** ${errorMessage}\n\n**Tips:**\n- Check column names match field names in sources\n- Check table names match source names\n- Use \`preview_insight\` to test queries before creating\n- Make sure field IDs are correct (use \`get_workflow_schema\`)`,
227
+ }],
228
+ };
229
+ }
230
+ // Handle permission errors
231
+ if (errorMessage.includes('permission') || errorMessage.includes('PermissionDenied')) {
232
+ return {
233
+ content: [{
234
+ type: "text",
235
+ text: `โŒ **Permission Denied**\n\nYou may not have permission to create insights or access the specified workflows.\n\n**Error:** ${errorMessage}`,
236
+ }],
237
+ };
238
+ }
239
+ return {
240
+ content: [{
241
+ type: "text",
242
+ text: `โŒ **Error creating insight**\n\n**Error:** ${errorMessage}${errorDetails}\n\n**Common Issues:**\n- SQL query syntax errors\n- Invalid field IDs or workflow IDs\n- Workflow fields don't exist\n- Permission issues\n- Check field IDs with \`get_workflow_schema\`\n- Test query with \`preview_insight\` first`,
243
+ }],
244
+ };
245
+ }
246
+ }
247
+ };
248
+ // ============================================================================
249
+ // PREVIEW INSIGHT TOOL
250
+ // ============================================================================
251
+ const previewInsightDescription = `๐Ÿงช [PLAYGROUND] Preview insight - Test SQL on ~20 activities before saving
252
+
253
+ โš ๏ธ **MANDATORY: YOU MUST LOAD SKILL FIRST**
254
+ **BEFORE calling this tool, you are REQUIRED to:**
255
+ 1. Load the skill: \`get_skill({ skillName: "preview-insight-skill" })\`
256
+ 2. Read the debugging tips and security notes
257
+ 3. Understand the SQL testing patterns
258
+ **FAILURE TO LOAD THE SKILL FIRST IS AN ERROR**
259
+
260
+ **Purpose**: Debug SQL syntax, test JOINs, verify field mappings without creating insight
261
+
262
+ **Required Parameters**:
263
+ - sources: Same format as create_insight (name, workflowId, fields)
264
+ - query: SQL query to test
265
+ - insightId (optional): Test changes to existing insight`;
266
+ exports.previewInsightTool = {
267
+ name: 'preview_insight',
268
+ group: tool_registry_1.ToolGroup.PLAYGROUND,
269
+ description: previewInsightDescription,
270
+ schema: zod_1.z.object({
271
+ workspaceId: zod_1.z
272
+ .string()
273
+ .optional()
274
+ .describe("Optional workspace ID or name - defaults to current workspace"),
275
+ sources: zod_1.z
276
+ .array(sourceSchema)
277
+ .min(1)
278
+ .describe("Workflow sources (like SQL table references)"),
279
+ query: zod_1.z
280
+ .string()
281
+ .min(1)
282
+ .describe("SQL query to test"),
283
+ insightId: zod_1.z
284
+ .string()
285
+ .optional()
286
+ .describe("Optional insight ID if previewing changes to existing insight"),
287
+ }),
288
+ async execute(args, context) {
289
+ logger.debug('Previewing insight', {
290
+ workspaceId: args.workspaceId,
291
+ sourcesCount: args.sources.length,
292
+ insightId: args.insightId,
293
+ apiKey: context.apiKey.substring(0, 8) + '...'
294
+ });
295
+ try {
296
+ if (!context.workspaceCache) {
297
+ return {
298
+ content: [{
299
+ type: "text",
300
+ text: "โŒ Workspace cache not available",
301
+ }],
302
+ };
303
+ }
304
+ // Resolve workspace ID
305
+ const workspaceId = args.workspaceId
306
+ ? (0, workspace_cache_1.resolveWorkspaceId)(context.workspaceCache, args.workspaceId)
307
+ : context.workspaceCache.currentWorkspace._id;
308
+ if (!workspaceId) {
309
+ return {
310
+ content: [{
311
+ type: "text",
312
+ text: `โŒ Could not resolve workspace: ${args.workspaceId}`,
313
+ }],
314
+ };
315
+ }
316
+ logger.debug('Calling v3.insight.preview', {
317
+ workspaceId,
318
+ sourcesCount: args.sources.length,
319
+ insightId: args.insightId
320
+ });
321
+ // Build preview payload
322
+ const previewData = {
323
+ sources: args.sources,
324
+ query: args.query,
325
+ ...(args.insightId && { insightId: args.insightId }),
326
+ };
327
+ // Call v3.insight.preview endpoint
328
+ const result = await context.hailer.request('v3.insight.preview', [workspaceId, previewData]);
329
+ logger.debug('Preview successful', {
330
+ columns: result.columns?.length,
331
+ rows: result.rows?.length
332
+ });
333
+ // Format results
334
+ let responseText = `โœ… **Preview Results** (~${result.rows?.length || 0} rows)\n\n`;
335
+ if (!result.columns || !result.rows) {
336
+ responseText += `โš ๏ธ No data returned from preview\n`;
337
+ }
338
+ else if (result.rows.length === 0) {
339
+ responseText += `**Columns:** ${result.columns.join(', ')}\n\n`;
340
+ responseText += `โš ๏ธ **No rows matched** - Check your query filters\n`;
341
+ }
342
+ else {
343
+ responseText += `**Columns:** ${result.columns.join(', ')}\n\n`;
344
+ responseText += `**Sample Data:**\n\`\`\`\n`;
345
+ // Show column headers
346
+ responseText += result.columns.join(' | ') + '\n';
347
+ responseText += result.columns.map(() => '---').join(' | ') + '\n';
348
+ // Show first 10 rows
349
+ const rowsToShow = Math.min(result.rows.length, 10);
350
+ for (let i = 0; i < rowsToShow; i++) {
351
+ responseText += result.rows[i].map(v => String(v || '')).join(' | ') + '\n';
352
+ }
353
+ if (result.rows.length > 10) {
354
+ responseText += `\n... and ${result.rows.length - 10} more rows\n`;
355
+ }
356
+ responseText += `\`\`\`\n\n`;
357
+ }
358
+ responseText += `\nโœ… **Query is valid!** Ready to use in \`create_insight\` or \`update_insight\`.`;
359
+ return {
360
+ content: [{
361
+ type: "text",
362
+ text: responseText,
363
+ }],
364
+ };
365
+ }
366
+ catch (error) {
367
+ logger.error("Error previewing insight", error);
368
+ let errorMessage = 'Unknown error occurred';
369
+ if (error instanceof Error) {
370
+ errorMessage = error.message;
371
+ }
372
+ else if (typeof error === 'object' && error !== null) {
373
+ try {
374
+ errorMessage = JSON.stringify(error, null, 2);
375
+ }
376
+ catch {
377
+ errorMessage = String(error);
378
+ }
379
+ }
380
+ else {
381
+ errorMessage = String(error);
382
+ }
383
+ return {
384
+ content: [{
385
+ type: "text",
386
+ text: `โŒ **Preview Failed**\n\n**Error:** ${errorMessage}\n\n**Tips:**\n- Check SQL syntax\n- Verify field names match source definitions\n- Ensure workflow IDs are correct\n- Check table aliases match source names`,
387
+ }],
388
+ };
389
+ }
390
+ }
391
+ };
392
+ // ============================================================================
393
+ // GET INSIGHT DATA TOOL
394
+ // ============================================================================
395
+ const getInsightDataDescription = `๐Ÿงช [PLAYGROUND] Get Insight Data - Execute insight and retrieve results
396
+
397
+ **What is Get Insight Data?**
398
+ Executes a saved insight's SQL query and returns the complete results. Unlike preview (limited to ~20 rows), this returns all matching activities.
399
+
400
+ **When to Use**:
401
+ - Get full results from a saved insight
402
+ - Export insight data
403
+ - Verify insight after creation
404
+ - Check updated data after changes
405
+
406
+ **Example - Basic Usage**:
407
+ \`\`\`javascript
408
+ get_insight_data({
409
+ insightId: '<insight-id>'
410
+ })
411
+ \`\`\`
412
+
413
+ **Update Option**:
414
+ - \`update: false\` (default) - Returns cached results (faster)
415
+ - \`update: true\` - Recalculates from current activity data (slower but fresh)
416
+
417
+ **Tips**:
418
+ - Use \`update: true\` if activity data has changed
419
+ - Results can be large - may take time for big datasets
420
+ - Use \`preview_insight\` first to test queries
421
+ - Get insight ID from \`create_insight\` or \`list_insights\``;
422
+ exports.getInsightDataTool = {
423
+ name: 'get_insight_data',
424
+ group: tool_registry_1.ToolGroup.PLAYGROUND,
425
+ description: getInsightDataDescription,
426
+ schema: zod_1.z.object({
427
+ insightId: zod_1.z
428
+ .string()
429
+ .describe("Insight ID to execute"),
430
+ update: zod_1.z
431
+ .boolean()
432
+ .optional()
433
+ .default(false)
434
+ .describe("Whether to recalculate data (true) or use cached results (false, default)"),
435
+ }),
436
+ async execute(args, context) {
437
+ logger.debug('Getting insight data', {
438
+ insightId: args.insightId,
439
+ update: args.update,
440
+ apiKey: context.apiKey.substring(0, 8) + '...'
441
+ });
442
+ try {
443
+ logger.debug('Calling v3.insight.data', {
444
+ insightId: args.insightId,
445
+ update: args.update
446
+ });
447
+ // Call v3.insight.data endpoint
448
+ const result = await context.hailer.request('v3.insight.data', [args.insightId, { update: args.update || false }]);
449
+ logger.debug('Insight data retrieved', {
450
+ headers: result.headers?.length,
451
+ rows: result.rows?.length,
452
+ fullResult: JSON.stringify(result).substring(0, 500)
453
+ });
454
+ // Format results
455
+ let responseText = `โœ… **Insight Data Retrieved** (${result.rows?.length || 0} rows)\n\n`;
456
+ if (!result.headers || !result.rows) {
457
+ responseText += `โš ๏ธ No data returned\n`;
458
+ responseText += `**Debug:** Response keys: ${Object.keys(result).join(', ')}\n`;
459
+ responseText += `**Full response (truncated):** \`${JSON.stringify(result).substring(0, 300)}\`\n`;
460
+ }
461
+ else if (result.rows.length === 0) {
462
+ responseText += `**Columns:** ${result.headers.join(', ')}\n\n`;
463
+ responseText += `โš ๏ธ **No rows matched**\n`;
464
+ }
465
+ else {
466
+ responseText += `**Columns:** ${result.headers.join(', ')}\n\n`;
467
+ responseText += `**Sample Data (first 10 rows):**\n\`\`\`\n`;
468
+ // Show column headers
469
+ responseText += result.headers.join(' | ') + '\n';
470
+ responseText += result.headers.map(() => '---').join(' | ') + '\n';
471
+ // Show first 10 rows
472
+ const rowsToShow = Math.min(result.rows.length, 10);
473
+ for (let i = 0; i < rowsToShow; i++) {
474
+ responseText += result.rows[i].map(v => String(v || '')).join(' | ') + '\n';
475
+ }
476
+ if (result.rows.length > 10) {
477
+ responseText += `\n... and ${result.rows.length - 10} more rows\n`;
478
+ }
479
+ responseText += `\`\`\`\n`;
480
+ }
481
+ return {
482
+ content: [{
483
+ type: "text",
484
+ text: responseText,
485
+ }],
486
+ };
487
+ }
488
+ catch (error) {
489
+ logger.error("Error getting insight data", error);
490
+ let errorMessage = 'Unknown error occurred';
491
+ if (error instanceof Error) {
492
+ errorMessage = error.message;
493
+ }
494
+ else if (typeof error === 'object' && error !== null) {
495
+ try {
496
+ errorMessage = JSON.stringify(error, null, 2);
497
+ }
498
+ catch {
499
+ errorMessage = String(error);
500
+ }
501
+ }
502
+ else {
503
+ errorMessage = String(error);
504
+ }
505
+ return {
506
+ content: [{
507
+ type: "text",
508
+ text: `โŒ **Error getting insight data**\n\n**Error:** ${errorMessage}\n\n**Common Issues:**\n- Insight ID not found\n- Permission denied\n- Insight query has errors\n- Use \`list_insights\` to verify insight ID`,
509
+ }],
510
+ };
511
+ }
512
+ }
513
+ };
514
+ // ============================================================================
515
+ // REMOVE INSIGHT TOOL
516
+ // ============================================================================
517
+ const removeInsightDescription = `๐Ÿงช [PLAYGROUND] Remove Insight - โš ๏ธ DANGER: Permanently deletes insight and all its data
518
+
519
+ โš ๏ธ **MANDATORY: GATHER COMPLETE CONTEXT BEFORE CALLING THIS TOOL**
520
+ **BEFORE calling this tool, you are REQUIRED to:**
521
+ 1. Load the skill: \`get_skill({ skillName: "remove-insight-skill" })\`
522
+ 2. Fetch insight details with \`list_insights\` to get:
523
+ - Insight name and ID
524
+ - Workspace ID and name
525
+ - SQL query
526
+ - Source workflows
527
+ - Number of sources
528
+ 3. Show comprehensive confirmation message including:
529
+ - Workspace ID and name
530
+ - Insight ID and name
531
+ - What will be deleted (definition, results, permissions, discussion)
532
+ - Sources being queried (workflows)
533
+ - Clear irreversibility warning
534
+ 4. Wait for explicit user confirmation
535
+ **FAILURE TO GATHER AND SHOW THIS CONTEXT IS AN ERROR**
536
+
537
+ **Required**: insightId
538
+ **Permission**: Workspace administrator
539
+
540
+ **What Gets Deleted**:
541
+ - Insight definition (sources, query, name)
542
+ - Saved query results
543
+ - Insight permissions
544
+ - Associated discussion
545
+
546
+ **Example**:
547
+ \`\`\`javascript
548
+ remove_insight({
549
+ insightId: '<insight-id>'
550
+ })
551
+ \`\`\`
552
+
553
+ **Tips**:
554
+ - Use \`list_insights\` to find insight IDs
555
+ - Use \`get_insight_data\` to verify before deleting
556
+ - Operation cannot be undone - data is permanently lost`;
557
+ exports.removeInsightTool = {
558
+ name: 'remove_insight',
559
+ group: tool_registry_1.ToolGroup.NUCLEAR,
560
+ description: removeInsightDescription,
561
+ schema: zod_1.z.object({
562
+ insightId: zod_1.z
563
+ .string()
564
+ .describe("Insight ID to remove (get from list_insights or create_insight)"),
565
+ confirmed: zod_1.z
566
+ .boolean()
567
+ .optional()
568
+ .describe("First confirmation - must be true to proceed"),
569
+ secondConfirmed: zod_1.z
570
+ .boolean()
571
+ .optional()
572
+ .describe("Second confirmation - must be true to proceed (required for double-check safety)"),
573
+ }),
574
+ async execute(args, context) {
575
+ logger.debug('Removing insight', {
576
+ insightId: args.insightId,
577
+ confirmed: args.confirmed,
578
+ secondConfirmed: args.secondConfirmed,
579
+ apiKey: context.apiKey.substring(0, 8) + '...'
580
+ });
581
+ try {
582
+ if (!context.workspaceCache) {
583
+ return {
584
+ content: [{
585
+ type: "text",
586
+ text: "โŒ Workspace cache not available",
587
+ }],
588
+ };
589
+ }
590
+ const workspaceId = context.workspaceCache.currentWorkspace._id;
591
+ // Fetch insight info and workspace info
592
+ const [insightListResult, initData] = await Promise.all([
593
+ context.hailer.request('v3.insight.list', [workspaceId]),
594
+ context.hailer.request('v2.core.init', [["network"]])
595
+ ]);
596
+ const insights = Array.isArray(insightListResult) ? insightListResult : (insightListResult.details || insightListResult.insights || []);
597
+ const insight = insights.find((i) => i._id === args.insightId);
598
+ const insightName = insight?.name || 'Unknown';
599
+ const workspaceName = initData.network?.name || 'Unknown';
600
+ // SAFETY CHECK: Require double confirmation
601
+ if (!args.confirmed || !args.secondConfirmed) {
602
+ let warningText = `โš ๏ธ **DESTRUCTIVE OPERATION - CONFIRMATION REQUIRED**\n\n`;
603
+ warningText += `You are about to **permanently delete** the following:\n\n`;
604
+ warningText += `**Insight:** ${insightName}\n`;
605
+ warningText += `**Insight ID:** \`${args.insightId}\`\n`;
606
+ warningText += `**Workspace:** ${workspaceName} (\`${workspaceId}\`)\n\n`;
607
+ warningText += `**โš ๏ธ This will permanently delete:**\n`;
608
+ warningText += `- Insight definition (sources, query, name)\n`;
609
+ warningText += `- Saved query results\n`;
610
+ warningText += `- Insight permissions\n`;
611
+ warningText += `- Associated discussion\n\n`;
612
+ warningText += `**๐Ÿšจ THIS CANNOT BE UNDONE! ๐Ÿšจ**\n\n`;
613
+ warningText += `**To proceed, you must:**\n`;
614
+ warningText += `1. Review the \`remove-insight-skill\` (REQUIRED)\n`;
615
+ warningText += `2. Call this tool again with BOTH confirmations:\n\n`;
616
+ warningText += `\`\`\`javascript\n`;
617
+ warningText += `remove_insight({\n`;
618
+ warningText += ` insightId: "${args.insightId}",\n`;
619
+ warningText += ` confirmed: true,\n`;
620
+ warningText += ` secondConfirmed: true\n`;
621
+ warningText += `})\n`;
622
+ warningText += `\`\`\`\n\n`;
623
+ warningText += `๐Ÿ’ก **Before proceeding:**\n`;
624
+ warningText += `- Load \`remove-insight-skill\` to review safety checklist\n`;
625
+ warningText += `- Use \`get_insight_data\` to verify before deleting\n`;
626
+ warningText += `- Verify with user that this is intentional`;
627
+ return {
628
+ content: [{
629
+ type: "text",
630
+ text: warningText,
631
+ }],
632
+ };
633
+ }
634
+ logger.debug('Calling v3.insight.remove', {
635
+ insightId: args.insightId,
636
+ insightName,
637
+ workspaceId,
638
+ workspaceName
639
+ });
640
+ // Call v3.insight.remove endpoint
641
+ await context.hailer.request('v3.insight.remove', [args.insightId]);
642
+ logger.debug('Insight removed successfully', {
643
+ insightId: args.insightId,
644
+ insightName
645
+ });
646
+ let responseText = `โœ… **Insight Removed Successfully**\n\n`;
647
+ responseText += `**Insight:** ${insightName}\n`;
648
+ responseText += `**Insight ID:** \`${args.insightId}\`\n`;
649
+ responseText += `**Workspace:** ${workspaceName} (\`${workspaceId}\`)\n\n`;
650
+ responseText += `โš ๏ธ **The insight, its SQL definition, and all associated data have been permanently deleted.**\n\n`;
651
+ responseText += `๐Ÿ’ก Use \`list_insights\` to see remaining insights.`;
652
+ return {
653
+ content: [{
654
+ type: "text",
655
+ text: responseText,
656
+ }],
657
+ };
658
+ }
659
+ catch (error) {
660
+ logger.error("Error removing insight", error);
661
+ let errorMessage = 'Unknown error occurred';
662
+ if (error instanceof Error) {
663
+ errorMessage = error.message;
664
+ }
665
+ else if (typeof error === 'object' && error !== null) {
666
+ try {
667
+ errorMessage = JSON.stringify(error, null, 2);
668
+ }
669
+ catch {
670
+ errorMessage = String(error);
671
+ }
672
+ }
673
+ else {
674
+ errorMessage = String(error);
675
+ }
676
+ return {
677
+ content: [{
678
+ type: "text",
679
+ text: `โŒ **Error removing insight**\n\n**Error:** ${errorMessage}\n\n**Common Issues:**\n- Insight ID not found\n- Permission denied\n- Insight already deleted\n- Use \`list_insights\` to verify insight ID`,
680
+ }],
681
+ };
682
+ }
683
+ }
684
+ };
685
+ // ============================================================================
686
+ // LIST INSIGHTS TOOL
687
+ // ============================================================================
688
+ const listInsightsDescription = `๐Ÿงช [PLAYGROUND] List Insights - View all insights in workspace
689
+
690
+ **What are Insights?**
691
+ Insights are SQL-like reports over Hailer workflow data. They allow querying activities like database tables.
692
+
693
+ **Purpose**: List all insights in the workspace to find insight IDs.
694
+
695
+ **Example**:
696
+ \`\`\`javascript
697
+ list_insights({
698
+ workspaceId: "optional-workspace-id"
699
+ })
700
+ \`\`\`
701
+
702
+ **Response includes**:
703
+ - Insight ID and name
704
+ - SQL query
705
+ - Sources (workflows being queried)
706
+ - Public/private status
707
+ - Created/updated timestamps`;
708
+ exports.listInsightsTool = {
709
+ name: 'list_insights',
710
+ group: tool_registry_1.ToolGroup.PLAYGROUND,
711
+ description: listInsightsDescription,
712
+ schema: zod_1.z.object({
713
+ workspaceId: zod_1.z
714
+ .string()
715
+ .optional()
716
+ .describe("Optional workspace ID or name - defaults to current workspace"),
717
+ }),
718
+ async execute(args, context) {
719
+ logger.debug('Listing insights', {
720
+ workspaceId: args.workspaceId,
721
+ apiKey: context.apiKey.substring(0, 8) + '...'
722
+ });
723
+ try {
724
+ if (!context.workspaceCache) {
725
+ return {
726
+ content: [{
727
+ type: "text",
728
+ text: "โŒ Workspace cache not available",
729
+ }],
730
+ };
731
+ }
732
+ // Resolve workspace ID
733
+ const workspaceId = args.workspaceId
734
+ ? (0, workspace_cache_1.resolveWorkspaceId)(context.workspaceCache, args.workspaceId)
735
+ : context.workspaceCache.currentWorkspace._id;
736
+ if (!workspaceId) {
737
+ return {
738
+ content: [{
739
+ type: "text",
740
+ text: `โŒ Could not resolve workspace: ${args.workspaceId}`,
741
+ }],
742
+ };
743
+ }
744
+ logger.debug('Calling v3.insight.list', { workspaceId });
745
+ // Call v3.insight.list endpoint
746
+ const result = await context.hailer.request('v3.insight.list', [workspaceId]);
747
+ // API returns array directly for list_insights
748
+ const insights = Array.isArray(result) ? result : (result.details || result.insights || []);
749
+ logger.debug('Insights retrieved', {
750
+ count: insights.length || 0,
751
+ isArray: Array.isArray(result),
752
+ responseKeys: Array.isArray(result) ? `array[${result.length}]` : Object.keys(result).join(',')
753
+ });
754
+ // Format output
755
+ let responseText = `๐Ÿ“Š **Insights Found** (${insights.length || 0} total)\n\n`;
756
+ if (!insights || insights.length === 0) {
757
+ responseText += `No insights found in this workspace.\n\n`;
758
+ responseText += `๐Ÿ’ก Use \`create_insight\` to create a new SQL-like report.`;
759
+ }
760
+ else {
761
+ insights.forEach((insight, index) => {
762
+ responseText += `${index + 1}. **${insight.name}**\n`;
763
+ responseText += ` - Insight ID: \`${insight._id}\`\n`;
764
+ responseText += ` - Public: ${insight.public ? 'Yes' : 'No'}\n`;
765
+ responseText += ` - Sources: ${insight.sources.length} workflow(s)\n`;
766
+ responseText += ` - Query: \`${insight.query.substring(0, 80)}${insight.query.length > 80 ? '...' : ''}\`\n\n`;
767
+ });
768
+ responseText += `๐Ÿ’ก **Next Steps:**\n`;
769
+ responseText += `- Use \`get_insight_data\` to execute an insight\n`;
770
+ responseText += `- Use \`preview_insight\` to test query changes\n`;
771
+ responseText += `- Use \`remove_insight\` to delete an insight\n`;
772
+ }
773
+ return {
774
+ content: [{
775
+ type: "text",
776
+ text: responseText,
777
+ }],
778
+ };
779
+ }
780
+ catch (error) {
781
+ logger.error("Error listing insights", error);
782
+ let errorMessage = 'Unknown error occurred';
783
+ if (error instanceof Error) {
784
+ errorMessage = error.message;
785
+ }
786
+ else if (typeof error === 'object' && error !== null) {
787
+ try {
788
+ errorMessage = JSON.stringify(error, null, 2);
789
+ }
790
+ catch {
791
+ errorMessage = String(error);
792
+ }
793
+ }
794
+ else {
795
+ errorMessage = String(error);
796
+ }
797
+ return {
798
+ content: [{
799
+ type: "text",
800
+ text: `โŒ **Error listing insights**\n\n**Error:** ${errorMessage}\n\n**Tips:**\n- Check workspace ID is valid\n- Verify you have permission to list insights`,
801
+ }],
802
+ };
803
+ }
804
+ }
805
+ };
806
+ //# sourceMappingURL=insight.js.map