@inkeep/agents-work-apps 0.47.5 → 0.48.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (65) hide show
  1. package/dist/env.d.ts +24 -2
  2. package/dist/env.js +13 -2
  3. package/dist/github/index.d.ts +3 -3
  4. package/dist/github/mcp/auth.d.ts +2 -2
  5. package/dist/github/mcp/index.d.ts +2 -2
  6. package/dist/github/mcp/index.js +23 -34
  7. package/dist/github/mcp/schemas.d.ts +1 -1
  8. package/dist/github/routes/setup.d.ts +2 -2
  9. package/dist/github/routes/tokenExchange.d.ts +2 -2
  10. package/dist/github/routes/webhooks.d.ts +2 -2
  11. package/dist/slack/i18n/index.d.ts +2 -0
  12. package/dist/slack/i18n/index.js +3 -0
  13. package/dist/slack/i18n/strings.d.ts +73 -0
  14. package/dist/slack/i18n/strings.js +67 -0
  15. package/dist/slack/index.d.ts +18 -0
  16. package/dist/slack/index.js +28 -0
  17. package/dist/slack/middleware/permissions.d.ts +31 -0
  18. package/dist/slack/middleware/permissions.js +167 -0
  19. package/dist/slack/routes/events.d.ts +10 -0
  20. package/dist/slack/routes/events.js +551 -0
  21. package/dist/slack/routes/index.d.ts +10 -0
  22. package/dist/slack/routes/index.js +47 -0
  23. package/dist/slack/routes/oauth.d.ts +20 -0
  24. package/dist/slack/routes/oauth.js +344 -0
  25. package/dist/slack/routes/users.d.ts +10 -0
  26. package/dist/slack/routes/users.js +365 -0
  27. package/dist/slack/routes/workspaces.d.ts +10 -0
  28. package/dist/slack/routes/workspaces.js +909 -0
  29. package/dist/slack/services/agent-resolution.d.ts +41 -0
  30. package/dist/slack/services/agent-resolution.js +99 -0
  31. package/dist/slack/services/blocks/index.d.ts +73 -0
  32. package/dist/slack/services/blocks/index.js +103 -0
  33. package/dist/slack/services/client.d.ts +108 -0
  34. package/dist/slack/services/client.js +232 -0
  35. package/dist/slack/services/commands/index.d.ts +19 -0
  36. package/dist/slack/services/commands/index.js +553 -0
  37. package/dist/slack/services/events/app-mention.d.ts +40 -0
  38. package/dist/slack/services/events/app-mention.js +297 -0
  39. package/dist/slack/services/events/block-actions.d.ts +40 -0
  40. package/dist/slack/services/events/block-actions.js +265 -0
  41. package/dist/slack/services/events/index.d.ts +6 -0
  42. package/dist/slack/services/events/index.js +7 -0
  43. package/dist/slack/services/events/modal-submission.d.ts +30 -0
  44. package/dist/slack/services/events/modal-submission.js +400 -0
  45. package/dist/slack/services/events/streaming.d.ts +26 -0
  46. package/dist/slack/services/events/streaming.js +255 -0
  47. package/dist/slack/services/events/utils.d.ts +146 -0
  48. package/dist/slack/services/events/utils.js +370 -0
  49. package/dist/slack/services/index.d.ts +16 -0
  50. package/dist/slack/services/index.js +16 -0
  51. package/dist/slack/services/modals.d.ts +86 -0
  52. package/dist/slack/services/modals.js +355 -0
  53. package/dist/slack/services/nango.d.ts +85 -0
  54. package/dist/slack/services/nango.js +476 -0
  55. package/dist/slack/services/security.d.ts +35 -0
  56. package/dist/slack/services/security.js +65 -0
  57. package/dist/slack/services/types.d.ts +26 -0
  58. package/dist/slack/services/types.js +1 -0
  59. package/dist/slack/services/workspace-tokens.d.ts +25 -0
  60. package/dist/slack/services/workspace-tokens.js +27 -0
  61. package/dist/slack/tracer.d.ts +40 -0
  62. package/dist/slack/tracer.js +39 -0
  63. package/dist/slack/types.d.ts +10 -0
  64. package/dist/slack/types.js +1 -0
  65. package/package.json +11 -2
@@ -0,0 +1,355 @@
1
+ import { env } from "../../env.js";
2
+ import { SlackStrings } from "../i18n/strings.js";
3
+
4
+ //#region src/slack/services/modals.ts
5
+ const manageUiBaseUrl = env.INKEEP_AGENTS_MANAGE_UI_URL || "http://localhost:3000";
6
+ /**
7
+ * Build the agent selector modal.
8
+ *
9
+ * Shows:
10
+ * - Project dropdown
11
+ * - Agent dropdown (updates based on project selection)
12
+ * - Include thread context checkbox (if in thread)
13
+ * - Question/instructions input
14
+ * - Dashboard link
15
+ *
16
+ * All responses from this modal are private (ephemeral).
17
+ */
18
+ function buildAgentSelectorModal(params) {
19
+ const { projects, agents, metadata, selectedProjectId } = params;
20
+ const isInThread = metadata.isInThread;
21
+ const projectOptions = projects.map((project) => ({
22
+ text: {
23
+ type: "plain_text",
24
+ text: project.name,
25
+ emoji: true
26
+ },
27
+ value: project.id
28
+ }));
29
+ const agentOptions = agents.length > 0 ? agents.map((agent) => ({
30
+ text: {
31
+ type: "plain_text",
32
+ text: agent.name || agent.id,
33
+ emoji: true
34
+ },
35
+ value: JSON.stringify({
36
+ agentId: agent.id,
37
+ projectId: agent.projectId
38
+ })
39
+ })) : [{
40
+ text: {
41
+ type: "plain_text",
42
+ text: SlackStrings.status.noAgentsAvailable,
43
+ emoji: true
44
+ },
45
+ value: "none"
46
+ }];
47
+ const selectedProjectOption = selectedProjectId ? projectOptions.find((p) => p.value === selectedProjectId) : projectOptions[0];
48
+ const blocks = [{
49
+ type: "input",
50
+ block_id: "project_select_block",
51
+ dispatch_action: true,
52
+ element: {
53
+ type: "static_select",
54
+ action_id: "modal_project_select",
55
+ placeholder: {
56
+ type: "plain_text",
57
+ text: SlackStrings.placeholders.selectProject
58
+ },
59
+ options: projectOptions,
60
+ ...selectedProjectOption ? { initial_option: selectedProjectOption } : {}
61
+ },
62
+ label: {
63
+ type: "plain_text",
64
+ text: SlackStrings.labels.project,
65
+ emoji: true
66
+ }
67
+ }, {
68
+ type: "input",
69
+ block_id: "agent_select_block",
70
+ element: {
71
+ type: "static_select",
72
+ action_id: "agent_select",
73
+ placeholder: {
74
+ type: "plain_text",
75
+ text: SlackStrings.placeholders.selectAgent
76
+ },
77
+ options: agentOptions,
78
+ ...agents.length > 0 ? { initial_option: agentOptions[0] } : {}
79
+ },
80
+ label: {
81
+ type: "plain_text",
82
+ text: SlackStrings.labels.agent,
83
+ emoji: true
84
+ }
85
+ }];
86
+ if (isInThread) blocks.push({
87
+ type: "input",
88
+ block_id: "context_block",
89
+ element: {
90
+ type: "checkboxes",
91
+ action_id: "include_context_checkbox",
92
+ options: [{
93
+ text: {
94
+ type: "plain_text",
95
+ text: SlackStrings.visibility.includeThreadContext,
96
+ emoji: true
97
+ },
98
+ value: "include_context"
99
+ }],
100
+ initial_options: [{
101
+ text: {
102
+ type: "plain_text",
103
+ text: SlackStrings.visibility.includeThreadContext,
104
+ emoji: true
105
+ },
106
+ value: "include_context"
107
+ }]
108
+ },
109
+ label: {
110
+ type: "plain_text",
111
+ text: SlackStrings.labels.context,
112
+ emoji: true
113
+ },
114
+ optional: true
115
+ });
116
+ blocks.push({
117
+ type: "input",
118
+ block_id: "question_block",
119
+ element: {
120
+ type: "plain_text_input",
121
+ action_id: "question_input",
122
+ multiline: true,
123
+ placeholder: {
124
+ type: "plain_text",
125
+ text: isInThread ? SlackStrings.placeholders.additionalInstructionsOptional : SlackStrings.placeholders.enterPrompt
126
+ }
127
+ },
128
+ label: {
129
+ type: "plain_text",
130
+ text: isInThread ? SlackStrings.labels.additionalInstructions : SlackStrings.labels.prompt,
131
+ emoji: true
132
+ },
133
+ optional: isInThread
134
+ });
135
+ const dashboardUrl = `${metadata.tenantId ? `/${metadata.tenantId}` : ""}/work-apps/slack`;
136
+ blocks.push({
137
+ type: "context",
138
+ elements: [{
139
+ type: "mrkdwn",
140
+ text: `⚙️ <${manageUiBaseUrl}${dashboardUrl}|Open Dashboard>`
141
+ }]
142
+ });
143
+ return {
144
+ type: "modal",
145
+ callback_id: "agent_selector_modal",
146
+ private_metadata: JSON.stringify(metadata),
147
+ title: {
148
+ type: "plain_text",
149
+ text: isInThread ? SlackStrings.modals.triggerAgentThread : SlackStrings.modals.triggerAgent,
150
+ emoji: true
151
+ },
152
+ submit: {
153
+ type: "plain_text",
154
+ text: SlackStrings.buttons.triggerAgent,
155
+ emoji: true
156
+ },
157
+ close: {
158
+ type: "plain_text",
159
+ text: SlackStrings.buttons.cancel,
160
+ emoji: true
161
+ },
162
+ blocks
163
+ };
164
+ }
165
+ /**
166
+ * Build a follow-up modal for continuing a conversation.
167
+ *
168
+ * Shows only a prompt input. Agent and project are carried from the previous turn
169
+ * via metadata. The conversationId ensures the agent has full history.
170
+ */
171
+ function buildFollowUpModal(metadata) {
172
+ const blocks = [{
173
+ type: "input",
174
+ block_id: "question_block",
175
+ element: {
176
+ type: "plain_text_input",
177
+ action_id: "question_input",
178
+ multiline: true,
179
+ placeholder: {
180
+ type: "plain_text",
181
+ text: SlackStrings.placeholders.enterPrompt
182
+ }
183
+ },
184
+ label: {
185
+ type: "plain_text",
186
+ text: SlackStrings.labels.prompt,
187
+ emoji: true
188
+ }
189
+ }];
190
+ return {
191
+ type: "modal",
192
+ callback_id: "follow_up_modal",
193
+ private_metadata: JSON.stringify(metadata),
194
+ title: {
195
+ type: "plain_text",
196
+ text: SlackStrings.modals.followUp,
197
+ emoji: true
198
+ },
199
+ submit: {
200
+ type: "plain_text",
201
+ text: SlackStrings.buttons.send,
202
+ emoji: true
203
+ },
204
+ close: {
205
+ type: "plain_text",
206
+ text: SlackStrings.buttons.cancel,
207
+ emoji: true
208
+ },
209
+ blocks
210
+ };
211
+ }
212
+ /**
213
+ * Build the modal for message shortcut (context menu on a message).
214
+ *
215
+ * Shows:
216
+ * - Message context (read-only display)
217
+ * - Project dropdown
218
+ * - Agent dropdown
219
+ * - Additional instructions input
220
+ * - Dashboard link
221
+ *
222
+ * All responses from this modal are private (ephemeral).
223
+ */
224
+ function buildMessageShortcutModal(params) {
225
+ const { projects, agents, metadata, selectedProjectId, messageContext } = params;
226
+ const projectOptions = projects.map((project) => ({
227
+ text: {
228
+ type: "plain_text",
229
+ text: project.name,
230
+ emoji: true
231
+ },
232
+ value: project.id
233
+ }));
234
+ const agentOptions = agents.length > 0 ? agents.map((agent) => ({
235
+ text: {
236
+ type: "plain_text",
237
+ text: agent.name || agent.id,
238
+ emoji: true
239
+ },
240
+ value: JSON.stringify({
241
+ agentId: agent.id,
242
+ projectId: agent.projectId
243
+ })
244
+ })) : [{
245
+ text: {
246
+ type: "plain_text",
247
+ text: SlackStrings.status.noAgentsAvailable,
248
+ emoji: true
249
+ },
250
+ value: "none"
251
+ }];
252
+ const selectedProjectOption = selectedProjectId ? projectOptions.find((p) => p.value === selectedProjectId) : projectOptions[0];
253
+ const truncatedContext = messageContext.length > 500 ? `${messageContext.slice(0, 500)}...` : messageContext;
254
+ const blocks = [
255
+ {
256
+ type: "section",
257
+ block_id: "message_context_display",
258
+ text: {
259
+ type: "mrkdwn",
260
+ text: `*${SlackStrings.messageContext.label}*\n>${truncatedContext.split("\n").join("\n>")}`
261
+ }
262
+ },
263
+ { type: "divider" },
264
+ {
265
+ type: "input",
266
+ block_id: "project_select_block",
267
+ dispatch_action: true,
268
+ element: {
269
+ type: "static_select",
270
+ action_id: "modal_project_select",
271
+ placeholder: {
272
+ type: "plain_text",
273
+ text: SlackStrings.placeholders.selectProject
274
+ },
275
+ options: projectOptions,
276
+ ...selectedProjectOption ? { initial_option: selectedProjectOption } : {}
277
+ },
278
+ label: {
279
+ type: "plain_text",
280
+ text: SlackStrings.labels.project,
281
+ emoji: true
282
+ }
283
+ },
284
+ {
285
+ type: "input",
286
+ block_id: "agent_select_block",
287
+ element: {
288
+ type: "static_select",
289
+ action_id: "agent_select",
290
+ placeholder: {
291
+ type: "plain_text",
292
+ text: SlackStrings.placeholders.selectAgent
293
+ },
294
+ options: agentOptions,
295
+ ...agents.length > 0 ? { initial_option: agentOptions[0] } : {}
296
+ },
297
+ label: {
298
+ type: "plain_text",
299
+ text: SlackStrings.labels.agent,
300
+ emoji: true
301
+ }
302
+ },
303
+ {
304
+ type: "input",
305
+ block_id: "question_block",
306
+ element: {
307
+ type: "plain_text_input",
308
+ action_id: "question_input",
309
+ multiline: true,
310
+ placeholder: {
311
+ type: "plain_text",
312
+ text: SlackStrings.placeholders.additionalInstructionsMessage
313
+ }
314
+ },
315
+ label: {
316
+ type: "plain_text",
317
+ text: SlackStrings.labels.additionalInstructions,
318
+ emoji: true
319
+ },
320
+ optional: true
321
+ }
322
+ ];
323
+ const dashboardUrl = `${metadata.tenantId ? `/${metadata.tenantId}` : ""}/work-apps/slack`;
324
+ blocks.push({
325
+ type: "context",
326
+ elements: [{
327
+ type: "mrkdwn",
328
+ text: `⚙️ <${manageUiBaseUrl}${dashboardUrl}|Open Dashboard>`
329
+ }]
330
+ });
331
+ return {
332
+ type: "modal",
333
+ callback_id: "agent_selector_modal",
334
+ private_metadata: JSON.stringify(metadata),
335
+ title: {
336
+ type: "plain_text",
337
+ text: SlackStrings.modals.askAboutMessage,
338
+ emoji: true
339
+ },
340
+ submit: {
341
+ type: "plain_text",
342
+ text: SlackStrings.buttons.triggerAgent,
343
+ emoji: true
344
+ },
345
+ close: {
346
+ type: "plain_text",
347
+ text: SlackStrings.buttons.cancel,
348
+ emoji: true
349
+ },
350
+ blocks
351
+ };
352
+ }
353
+
354
+ //#endregion
355
+ export { buildAgentSelectorModal, buildFollowUpModal, buildMessageShortcutModal };
@@ -0,0 +1,85 @@
1
+ import { Nango } from "@nangohq/node";
2
+
3
+ //#region src/slack/services/nango.d.ts
4
+
5
+ declare function getSlackNango(): Nango;
6
+ declare function getSlackIntegrationId(): string;
7
+ declare function createConnectSession(params: {
8
+ userId: string;
9
+ userEmail?: string;
10
+ userName?: string;
11
+ tenantId: string;
12
+ }): Promise<{
13
+ sessionToken: string;
14
+ } | null>;
15
+ declare function getConnectionAccessToken(connectionId: string): Promise<string | null>;
16
+ interface DefaultAgentConfig {
17
+ agentId: string;
18
+ agentName?: string;
19
+ projectId: string;
20
+ projectName?: string;
21
+ }
22
+ interface SlackWorkspaceConnection {
23
+ connectionId: string;
24
+ teamId: string;
25
+ teamName?: string;
26
+ botToken: string;
27
+ tenantId: string;
28
+ defaultAgent?: DefaultAgentConfig;
29
+ }
30
+ /**
31
+ * Find a workspace connection by Slack team ID.
32
+ * Uses PostgreSQL first (O(1)) with in-memory caching, then falls back to Nango.
33
+ *
34
+ * Performance: This function is called on every @mention and command.
35
+ * The PostgreSQL-first approach with caching provides O(1) lookups.
36
+ */
37
+ declare function findWorkspaceConnectionByTeamId(teamId: string): Promise<SlackWorkspaceConnection | null>;
38
+ declare function clearWorkspaceConnectionCache(teamId?: string): void;
39
+ declare function updateConnectionMetadata(connectionId: string, metadata: Record<string, string>): Promise<boolean>;
40
+ declare function setWorkspaceDefaultAgent(teamId: string, defaultAgent: DefaultAgentConfig | null): Promise<boolean>;
41
+ declare function getWorkspaceDefaultAgentFromNango(teamId: string): Promise<DefaultAgentConfig | null>;
42
+ /**
43
+ * Compute a stable, deterministic connection ID for a Slack workspace.
44
+ * Format: "T:<team_id>" or "E:<enterprise_id>:T:<team_id>" for Enterprise Grid
45
+ */
46
+ declare function computeWorkspaceConnectionId(params: {
47
+ teamId: string;
48
+ enterpriseId?: string;
49
+ }): string;
50
+ interface WorkspaceInstallData {
51
+ teamId: string;
52
+ teamName?: string;
53
+ teamDomain?: string;
54
+ enterpriseId?: string;
55
+ enterpriseName?: string;
56
+ botUserId?: string;
57
+ botToken: string;
58
+ botScopes?: string;
59
+ installerUserId?: string;
60
+ installerUserName?: string;
61
+ isEnterpriseInstall?: boolean;
62
+ appId?: string;
63
+ tenantId?: string;
64
+ workspaceUrl?: string;
65
+ workspaceIconUrl?: string;
66
+ installationSource?: string;
67
+ }
68
+ /**
69
+ * Store a workspace installation in Nango.
70
+ * Uses upsert semantics - will update if the connection already exists.
71
+ */
72
+ declare function storeWorkspaceInstallation(data: WorkspaceInstallData): Promise<{
73
+ connectionId: string;
74
+ success: boolean;
75
+ }>;
76
+ /**
77
+ * List all workspace installations from Nango.
78
+ */
79
+ declare function listWorkspaceInstallations(): Promise<SlackWorkspaceConnection[]>;
80
+ /**
81
+ * Delete a workspace installation from Nango.
82
+ */
83
+ declare function deleteWorkspaceInstallation(connectionId: string): Promise<boolean>;
84
+ //#endregion
85
+ export { DefaultAgentConfig, SlackWorkspaceConnection, WorkspaceInstallData, clearWorkspaceConnectionCache, computeWorkspaceConnectionId, createConnectSession, deleteWorkspaceInstallation, findWorkspaceConnectionByTeamId, getConnectionAccessToken, getSlackIntegrationId, getSlackNango, getWorkspaceDefaultAgentFromNango, listWorkspaceInstallations, setWorkspaceDefaultAgent, storeWorkspaceInstallation, updateConnectionMetadata };