@inkeep/agents-work-apps 0.50.1 → 0.50.4

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 (64) hide show
  1. package/dist/_virtual/rolldown_runtime.js +32 -0
  2. package/dist/env.d.ts +4 -2
  3. package/dist/env.js +2 -1
  4. package/dist/github/mcp/index.d.ts +2 -2
  5. package/dist/github/routes/setup.d.ts +2 -2
  6. package/dist/github/routes/tokenExchange.d.ts +2 -2
  7. package/dist/github/routes/webhooks.d.ts +2 -2
  8. package/dist/node_modules/.pnpm/@slack_logger@4.0.0/node_modules/@slack/logger/dist/index.js +89 -0
  9. package/dist/node_modules/.pnpm/@slack_socket-mode@2.0.5/node_modules/@slack/socket-mode/dist/package.js +85 -0
  10. package/dist/node_modules/.pnpm/@slack_socket-mode@2.0.5/node_modules/@slack/socket-mode/dist/src/SlackWebSocket.js +223 -0
  11. package/dist/node_modules/.pnpm/@slack_socket-mode@2.0.5/node_modules/@slack/socket-mode/dist/src/SocketModeClient.js +367 -0
  12. package/dist/node_modules/.pnpm/@slack_socket-mode@2.0.5/node_modules/@slack/socket-mode/dist/src/UnrecoverableSocketModeStartError.js +20 -0
  13. package/dist/node_modules/.pnpm/@slack_socket-mode@2.0.5/node_modules/@slack/socket-mode/dist/src/errors.js +71 -0
  14. package/dist/node_modules/.pnpm/@slack_socket-mode@2.0.5/node_modules/@slack/socket-mode/dist/src/index.js +44 -0
  15. package/dist/node_modules/.pnpm/@slack_socket-mode@2.0.5/node_modules/@slack/socket-mode/dist/src/logger.js +32 -0
  16. package/dist/node_modules/.pnpm/eventemitter3@5.0.1/node_modules/eventemitter3/index.js +241 -0
  17. package/dist/node_modules/.pnpm/ws@8.19.0/node_modules/ws/index.js +23 -0
  18. package/dist/node_modules/.pnpm/ws@8.19.0/node_modules/ws/lib/buffer-util.js +107 -0
  19. package/dist/node_modules/.pnpm/ws@8.19.0/node_modules/ws/lib/constants.js +29 -0
  20. package/dist/node_modules/.pnpm/ws@8.19.0/node_modules/ws/lib/event-target.js +226 -0
  21. package/dist/node_modules/.pnpm/ws@8.19.0/node_modules/ws/lib/extension.js +150 -0
  22. package/dist/node_modules/.pnpm/ws@8.19.0/node_modules/ws/lib/limiter.js +57 -0
  23. package/dist/node_modules/.pnpm/ws@8.19.0/node_modules/ws/lib/permessage-deflate.js +342 -0
  24. package/dist/node_modules/.pnpm/ws@8.19.0/node_modules/ws/lib/receiver.js +457 -0
  25. package/dist/node_modules/.pnpm/ws@8.19.0/node_modules/ws/lib/sender.js +505 -0
  26. package/dist/node_modules/.pnpm/ws@8.19.0/node_modules/ws/lib/stream.js +123 -0
  27. package/dist/node_modules/.pnpm/ws@8.19.0/node_modules/ws/lib/subprotocol.js +46 -0
  28. package/dist/node_modules/.pnpm/ws@8.19.0/node_modules/ws/lib/validation.js +203 -0
  29. package/dist/node_modules/.pnpm/ws@8.19.0/node_modules/ws/lib/websocket-server.js +385 -0
  30. package/dist/node_modules/.pnpm/ws@8.19.0/node_modules/ws/lib/websocket.js +985 -0
  31. package/dist/slack/dispatcher.d.ts +16 -0
  32. package/dist/slack/dispatcher.js +335 -0
  33. package/dist/slack/i18n/strings.d.ts +5 -5
  34. package/dist/slack/i18n/strings.js +9 -9
  35. package/dist/slack/index.d.ts +3 -1
  36. package/dist/slack/index.js +4 -2
  37. package/dist/slack/middleware/permissions.js +120 -107
  38. package/dist/slack/routes/events.js +10 -328
  39. package/dist/slack/routes/oauth.js +6 -3
  40. package/dist/slack/routes/users.js +12 -6
  41. package/dist/slack/routes/workspaces.js +39 -39
  42. package/dist/slack/services/agent-resolution.d.ts +1 -0
  43. package/dist/slack/services/agent-resolution.js +8 -4
  44. package/dist/slack/services/blocks/index.js +7 -11
  45. package/dist/slack/services/commands/index.js +15 -7
  46. package/dist/slack/services/dev-config.d.ts +23 -0
  47. package/dist/slack/services/dev-config.js +91 -0
  48. package/dist/slack/services/events/app-mention.js +25 -21
  49. package/dist/slack/services/events/index.d.ts +2 -2
  50. package/dist/slack/services/events/index.js +2 -2
  51. package/dist/slack/services/events/modal-submission.js +18 -10
  52. package/dist/slack/services/events/streaming.js +7 -5
  53. package/dist/slack/services/events/utils.d.ts +2 -1
  54. package/dist/slack/services/events/utils.js +16 -9
  55. package/dist/slack/services/index.d.ts +2 -2
  56. package/dist/slack/services/index.js +3 -3
  57. package/dist/slack/services/modals.js +4 -4
  58. package/dist/slack/services/nango.d.ts +3 -0
  59. package/dist/slack/services/nango.js +84 -2
  60. package/dist/slack/socket-mode.d.ts +4 -0
  61. package/dist/slack/socket-mode.js +130 -0
  62. package/dist/slack/tracer.d.ts +2 -0
  63. package/dist/slack/tracer.js +3 -1
  64. package/package.json +3 -2
@@ -2,8 +2,9 @@ import { getLogger } from "../../logger.js";
2
2
  import runDbClient_default from "../../db/runDbClient.js";
3
3
  import { createConnectSession } from "../services/nango.js";
4
4
  import "../services/index.js";
5
- import { OpenAPIHono, createRoute, z } from "@hono/zod-openapi";
5
+ import { OpenAPIHono, z } from "@hono/zod-openapi";
6
6
  import { createWorkAppSlackUserMapping, deleteWorkAppSlackUserMapping, findWorkAppSlackUserMapping, findWorkAppSlackUserMappingByInkeepUserId, verifySlackLinkToken } from "@inkeep/agents-core";
7
+ import { createProtectedRoute, inheritedWorkAppsAuth } from "@inkeep/agents-core/middleware";
7
8
 
8
9
  //#region src/slack/routes/users.ts
9
10
  /**
@@ -29,7 +30,7 @@ function isAuthorizedForUser(c, requestedUserId) {
29
30
  return false;
30
31
  }
31
32
  const app = new OpenAPIHono();
32
- app.openapi(createRoute({
33
+ app.openapi(createProtectedRoute({
33
34
  method: "get",
34
35
  path: "/link-status",
35
36
  summary: "Check Link Status",
@@ -40,6 +41,7 @@ app.openapi(createRoute({
40
41
  "Slack",
41
42
  "Users"
42
43
  ],
44
+ permission: inheritedWorkAppsAuth(),
43
45
  request: { query: z.object({
44
46
  slackUserId: z.string(),
45
47
  slackTeamId: z.string(),
@@ -67,7 +69,7 @@ app.openapi(createRoute({
67
69
  });
68
70
  return c.json({ linked: false });
69
71
  });
70
- app.openapi(createRoute({
72
+ app.openapi(createProtectedRoute({
71
73
  method: "post",
72
74
  path: "/link/verify-token",
73
75
  summary: "Verify Link Token",
@@ -78,6 +80,7 @@ app.openapi(createRoute({
78
80
  "Slack",
79
81
  "Users"
80
82
  ],
83
+ permission: inheritedWorkAppsAuth(),
81
84
  request: { body: { content: { "application/json": { schema: z.object({
82
85
  token: z.string().min(1),
83
86
  userId: z.string().min(1),
@@ -171,7 +174,7 @@ app.openapi(createRoute({
171
174
  return c.json({ error: "Failed to verify link. Please try again." }, 500);
172
175
  }
173
176
  });
174
- app.openapi(createRoute({
177
+ app.openapi(createProtectedRoute({
175
178
  method: "post",
176
179
  path: "/connect",
177
180
  summary: "Create Nango Connect Session",
@@ -182,6 +185,7 @@ app.openapi(createRoute({
182
185
  "Slack",
183
186
  "Users"
184
187
  ],
188
+ permission: inheritedWorkAppsAuth(),
185
189
  request: { body: { content: { "application/json": { schema: z.object({
186
190
  userId: z.string().describe("Inkeep user ID"),
187
191
  userEmail: z.string().optional().describe("User email"),
@@ -217,7 +221,7 @@ app.openapi(createRoute({
217
221
  if (!session) return c.json({ error: "Failed to create session" }, 500);
218
222
  return c.json(session);
219
223
  });
220
- app.openapi(createRoute({
224
+ app.openapi(createProtectedRoute({
221
225
  method: "post",
222
226
  path: "/disconnect",
223
227
  summary: "Disconnect User",
@@ -228,6 +232,7 @@ app.openapi(createRoute({
228
232
  "Slack",
229
233
  "Users"
230
234
  ],
235
+ permission: inheritedWorkAppsAuth(),
231
236
  request: { body: { content: { "application/json": { schema: z.object({
232
237
  userId: z.string().optional().describe("Inkeep user ID"),
233
238
  slackUserId: z.string().optional().describe("Slack user ID"),
@@ -285,7 +290,7 @@ app.openapi(createRoute({
285
290
  return c.json({ error: "Failed to disconnect" }, 500);
286
291
  }
287
292
  });
288
- app.openapi(createRoute({
293
+ app.openapi(createProtectedRoute({
289
294
  method: "get",
290
295
  path: "/status",
291
296
  summary: "Get Connection Status",
@@ -296,6 +301,7 @@ app.openapi(createRoute({
296
301
  "Slack",
297
302
  "Users"
298
303
  ],
304
+ permission: inheritedWorkAppsAuth(),
299
305
  request: { query: z.object({ userId: z.string().describe("Inkeep user ID") }) },
300
306
  responses: {
301
307
  200: {
@@ -4,8 +4,9 @@ import { clearWorkspaceConnectionCache, computeWorkspaceConnectionId, deleteWork
4
4
  import { getSlackChannels, getSlackClient, revokeSlackToken } from "../services/client.js";
5
5
  import "../services/index.js";
6
6
  import { requireChannelMemberOrAdmin, requireWorkspaceAdmin } from "../middleware/permissions.js";
7
- import { OpenAPIHono, createRoute, z } from "@hono/zod-openapi";
7
+ import { OpenAPIHono, z } from "@hono/zod-openapi";
8
8
  import { deleteAllWorkAppSlackChannelAgentConfigsByTeam, deleteAllWorkAppSlackUserMappingsByTeam, deleteWorkAppSlackChannelAgentConfig, deleteWorkAppSlackWorkspaceByNangoConnectionId, findWorkAppSlackChannelAgentConfig, listWorkAppSlackChannelAgentConfigsByTeam, listWorkAppSlackUserMappingsByTeam, upsertWorkAppSlackChannelAgentConfig } from "@inkeep/agents-core";
9
+ import { createProtectedRoute, inheritedWorkAppsAuth } from "@inkeep/agents-core/middleware";
9
10
 
10
11
  //#region src/slack/routes/workspaces.ts
11
12
  /**
@@ -39,30 +40,15 @@ function verifyTenantOwnership(c, workspaceTenantId) {
39
40
  return sessionTenantId === workspaceTenantId;
40
41
  }
41
42
  const app = new OpenAPIHono();
42
- app.use("/:teamId/settings", async (c, next) => {
43
- if (c.req.method === "PUT") return requireWorkspaceAdmin()(c, next);
44
- return next();
45
- });
46
- app.use("/:teamId", async (c, next) => {
47
- if (c.req.method === "DELETE") return requireWorkspaceAdmin()(c, next);
48
- return next();
49
- });
50
- app.use("/:teamId/channels/:channelId/settings", async (c, next) => {
51
- if (c.req.method === "PUT" || c.req.method === "DELETE") return requireChannelMemberOrAdmin()(c, next);
52
- return next();
53
- });
54
- app.use("/:teamId/test-message", async (c, next) => {
55
- if (c.req.method === "POST") return requireWorkspaceAdmin()(c, next);
56
- return next();
57
- });
58
43
  const ChannelAgentConfigSchema = z.object({
59
44
  projectId: z.string(),
60
45
  agentId: z.string(),
61
46
  agentName: z.string().optional(),
62
- projectName: z.string().optional()
47
+ projectName: z.string().optional(),
48
+ grantAccessToMembers: z.boolean().optional()
63
49
  });
64
50
  const WorkspaceSettingsSchema = z.object({ defaultAgent: ChannelAgentConfigSchema.optional() });
65
- app.openapi(createRoute({
51
+ app.openapi(createProtectedRoute({
66
52
  method: "get",
67
53
  path: "/",
68
54
  summary: "List Workspaces",
@@ -73,6 +59,7 @@ app.openapi(createRoute({
73
59
  "Slack",
74
60
  "Workspaces"
75
61
  ],
62
+ permission: inheritedWorkAppsAuth(),
76
63
  responses: { 200: {
77
64
  description: "List of workspaces",
78
65
  content: { "application/json": { schema: z.object({ workspaces: z.array(z.object({
@@ -111,7 +98,7 @@ app.openapi(createRoute({
111
98
  return c.json({ workspaces: [] });
112
99
  }
113
100
  });
114
- app.openapi(createRoute({
101
+ app.openapi(createProtectedRoute({
115
102
  method: "get",
116
103
  path: "/{teamId}",
117
104
  summary: "Get Workspace",
@@ -122,6 +109,7 @@ app.openapi(createRoute({
122
109
  "Slack",
123
110
  "Workspaces"
124
111
  ],
112
+ permission: inheritedWorkAppsAuth(),
125
113
  request: { params: z.object({ teamId: z.string() }) },
126
114
  responses: {
127
115
  200: {
@@ -155,7 +143,7 @@ app.openapi(createRoute({
155
143
  defaultAgent
156
144
  });
157
145
  });
158
- app.openapi(createRoute({
146
+ app.openapi(createProtectedRoute({
159
147
  method: "get",
160
148
  path: "/{teamId}/settings",
161
149
  summary: "Get Workspace Settings",
@@ -166,6 +154,7 @@ app.openapi(createRoute({
166
154
  "Slack",
167
155
  "Workspaces"
168
156
  ],
157
+ permission: inheritedWorkAppsAuth(),
169
158
  request: { params: z.object({ teamId: z.string() }) },
170
159
  responses: { 200: {
171
160
  description: "Workspace settings",
@@ -188,7 +177,7 @@ app.openapi(createRoute({
188
177
  };
189
178
  return c.json({ defaultAgent });
190
179
  });
191
- app.openapi(createRoute({
180
+ app.openapi(createProtectedRoute({
192
181
  method: "put",
193
182
  path: "/{teamId}/settings",
194
183
  summary: "Update Workspace Settings",
@@ -199,6 +188,7 @@ app.openapi(createRoute({
199
188
  "Slack",
200
189
  "Workspaces"
201
190
  ],
191
+ permission: requireWorkspaceAdmin(),
202
192
  request: {
203
193
  params: z.object({ teamId: z.string() }),
204
194
  body: { content: { "application/json": { schema: WorkspaceSettingsSchema } } }
@@ -232,7 +222,7 @@ app.openapi(createRoute({
232
222
  }
233
223
  return c.json({ success: true });
234
224
  });
235
- app.openapi(createRoute({
225
+ app.openapi(createProtectedRoute({
236
226
  method: "delete",
237
227
  path: "/{teamId}",
238
228
  summary: "Uninstall Workspace",
@@ -243,6 +233,7 @@ app.openapi(createRoute({
243
233
  "Slack",
244
234
  "Workspaces"
245
235
  ],
236
+ permission: requireWorkspaceAdmin(),
246
237
  request: { params: z.object({ teamId: z.string() }) },
247
238
  responses: {
248
239
  200: {
@@ -301,7 +292,7 @@ app.openapi(createRoute({
301
292
  return c.json({ error: "Failed to uninstall workspace" }, 500);
302
293
  }
303
294
  });
304
- app.openapi(createRoute({
295
+ app.openapi(createProtectedRoute({
305
296
  method: "get",
306
297
  path: "/{teamId}/channels",
307
298
  summary: "List Channels",
@@ -312,6 +303,7 @@ app.openapi(createRoute({
312
303
  "Slack",
313
304
  "Channels"
314
305
  ],
306
+ permission: inheritedWorkAppsAuth(),
315
307
  request: {
316
308
  params: z.object({ teamId: z.string() }),
317
309
  query: z.object({
@@ -369,7 +361,8 @@ app.openapi(createRoute({
369
361
  agentConfig: config ? {
370
362
  projectId: config.projectId,
371
363
  agentId: config.agentId,
372
- agentName: config.agentName || void 0
364
+ agentName: config.agentName || void 0,
365
+ grantAccessToMembers: config.grantAccessToMembers
373
366
  } : void 0
374
367
  };
375
368
  });
@@ -385,7 +378,7 @@ app.openapi(createRoute({
385
378
  return c.json({ error: "Failed to list channels" }, 500);
386
379
  }
387
380
  });
388
- app.openapi(createRoute({
381
+ app.openapi(createProtectedRoute({
389
382
  method: "get",
390
383
  path: "/{teamId}/channels/{channelId}/settings",
391
384
  summary: "Get Channel Settings",
@@ -396,6 +389,7 @@ app.openapi(createRoute({
396
389
  "Slack",
397
390
  "Channels"
398
391
  ],
392
+ permission: inheritedWorkAppsAuth(),
399
393
  request: { params: z.object({
400
394
  teamId: z.string(),
401
395
  channelId: z.string()
@@ -424,11 +418,12 @@ app.openapi(createRoute({
424
418
  agentConfig: config ? {
425
419
  projectId: config.projectId,
426
420
  agentId: config.agentId,
427
- agentName: config.agentName || void 0
421
+ agentName: config.agentName || void 0,
422
+ grantAccessToMembers: config.grantAccessToMembers
428
423
  } : void 0
429
424
  });
430
425
  });
431
- app.openapi(createRoute({
426
+ app.openapi(createProtectedRoute({
432
427
  method: "put",
433
428
  path: "/{teamId}/channels/{channelId}/settings",
434
429
  summary: "Set Channel Default Agent",
@@ -439,6 +434,7 @@ app.openapi(createRoute({
439
434
  "Slack",
440
435
  "Channels"
441
436
  ],
437
+ permission: requireChannelMemberOrAdmin(),
442
438
  request: {
443
439
  params: z.object({
444
440
  teamId: z.string(),
@@ -478,6 +474,7 @@ app.openapi(createRoute({
478
474
  projectId: body.agentConfig.projectId,
479
475
  agentId: body.agentConfig.agentId,
480
476
  agentName: body.agentConfig.agentName,
477
+ grantAccessToMembers: body.agentConfig.grantAccessToMembers ?? true,
481
478
  enabled: true
482
479
  });
483
480
  logger.info({
@@ -490,11 +487,7 @@ app.openapi(createRoute({
490
487
  configId: config.id
491
488
  });
492
489
  });
493
- app.use("/:teamId/channels/bulk", async (c, next) => {
494
- if (c.req.method === "PUT" || c.req.method === "DELETE") return requireWorkspaceAdmin()(c, next);
495
- return next();
496
- });
497
- app.openapi(createRoute({
490
+ app.openapi(createProtectedRoute({
498
491
  method: "put",
499
492
  path: "/{teamId}/channels/bulk",
500
493
  summary: "Bulk Set Channel Agents",
@@ -505,6 +498,7 @@ app.openapi(createRoute({
505
498
  "Slack",
506
499
  "Channels"
507
500
  ],
501
+ permission: requireWorkspaceAdmin(),
508
502
  request: {
509
503
  params: z.object({ teamId: z.string() }),
510
504
  body: { content: { "application/json": { schema: z.object({
@@ -567,6 +561,7 @@ app.openapi(createRoute({
567
561
  projectId: body.agentConfig.projectId,
568
562
  agentId: body.agentConfig.agentId,
569
563
  agentName: body.agentConfig.agentName,
564
+ grantAccessToMembers: body.agentConfig.grantAccessToMembers ?? true,
570
565
  enabled: true
571
566
  });
572
567
  updated++;
@@ -591,7 +586,7 @@ app.openapi(createRoute({
591
586
  errors: errors.length > 0 ? errors : void 0
592
587
  });
593
588
  });
594
- app.openapi(createRoute({
589
+ app.openapi(createProtectedRoute({
595
590
  method: "delete",
596
591
  path: "/{teamId}/channels/bulk",
597
592
  summary: "Bulk Remove Channel Configs",
@@ -602,6 +597,7 @@ app.openapi(createRoute({
602
597
  "Slack",
603
598
  "Channels"
604
599
  ],
600
+ permission: requireWorkspaceAdmin(),
605
601
  request: {
606
602
  params: z.object({ teamId: z.string() }),
607
603
  body: { content: { "application/json": { schema: z.object({ channelIds: z.array(z.string()).min(1) }) } } }
@@ -638,7 +634,7 @@ app.openapi(createRoute({
638
634
  removed
639
635
  });
640
636
  });
641
- app.openapi(createRoute({
637
+ app.openapi(createProtectedRoute({
642
638
  method: "delete",
643
639
  path: "/{teamId}/channels/{channelId}/settings",
644
640
  summary: "Remove Channel Config",
@@ -649,6 +645,7 @@ app.openapi(createRoute({
649
645
  "Slack",
650
646
  "Channels"
651
647
  ],
648
+ permission: requireChannelMemberOrAdmin(),
652
649
  request: { params: z.object({
653
650
  teamId: z.string(),
654
651
  channelId: z.string()
@@ -673,7 +670,7 @@ app.openapi(createRoute({
673
670
  }, "Removed channel agent config");
674
671
  return c.json({ success: deleted });
675
672
  });
676
- app.openapi(createRoute({
673
+ app.openapi(createProtectedRoute({
677
674
  method: "get",
678
675
  path: "/{teamId}/users",
679
676
  summary: "List Linked Users",
@@ -684,6 +681,7 @@ app.openapi(createRoute({
684
681
  "Slack",
685
682
  "Users"
686
683
  ],
684
+ permission: inheritedWorkAppsAuth(),
687
685
  request: { params: z.object({ teamId: z.string() }) },
688
686
  responses: { 200: {
689
687
  description: "List of linked users",
@@ -723,7 +721,7 @@ app.openapi(createRoute({
723
721
  lastUsedAt: link.lastUsedAt || void 0
724
722
  })) });
725
723
  });
726
- app.openapi(createRoute({
724
+ app.openapi(createProtectedRoute({
727
725
  method: "get",
728
726
  path: "/{teamId}/health",
729
727
  summary: "Check Workspace Health",
@@ -734,6 +732,7 @@ app.openapi(createRoute({
734
732
  "Slack",
735
733
  "Workspaces"
736
734
  ],
735
+ permission: inheritedWorkAppsAuth(),
737
736
  request: { params: z.object({ teamId: z.string() }) },
738
737
  responses: {
739
738
  200: {
@@ -819,7 +818,7 @@ app.openapi(createRoute({
819
818
  });
820
819
  }
821
820
  });
822
- app.openapi(createRoute({
821
+ app.openapi(createProtectedRoute({
823
822
  method: "post",
824
823
  path: "/{teamId}/test-message",
825
824
  summary: "Send Test Message",
@@ -830,6 +829,7 @@ app.openapi(createRoute({
830
829
  "Slack",
831
830
  "Workspaces"
832
831
  ],
832
+ permission: requireWorkspaceAdmin(),
833
833
  request: {
834
834
  params: z.object({ teamId: z.string() }),
835
835
  body: { content: { "application/json": { schema: z.object({
@@ -859,7 +859,7 @@ app.openapi(createRoute({
859
859
  }, 404);
860
860
  try {
861
861
  const slackClient = getSlackClient(workspace.botToken);
862
- const testMessage = message || "*Test message from Inkeep*\n\nYour Slack integration is working correctly!";
862
+ const testMessage = message || "*Test message from Inkeep*\n\nYour Slack integration is working correctly.";
863
863
  const result = await slackClient.chat.postMessage({
864
864
  channel: channelId,
865
865
  text: testMessage,
@@ -11,6 +11,7 @@ interface ResolvedAgentConfig {
11
11
  agentId: string;
12
12
  agentName?: string;
13
13
  source: 'channel' | 'workspace' | 'none';
14
+ grantAccessToMembers: boolean;
14
15
  }
15
16
  interface AgentResolutionParams {
16
17
  tenantId: string;
@@ -37,7 +37,8 @@ async function resolveEffectiveAgent(params) {
37
37
  projectId: channelConfig.projectId,
38
38
  agentId: channelConfig.agentId,
39
39
  agentName: channelConfig.agentName || void 0,
40
- source: "channel"
40
+ source: "channel",
41
+ grantAccessToMembers: channelConfig.grantAccessToMembers
41
42
  };
42
43
  }
43
44
  }
@@ -52,7 +53,8 @@ async function resolveEffectiveAgent(params) {
52
53
  projectId: workspaceConfig.projectId,
53
54
  agentId: workspaceConfig.agentId,
54
55
  agentName: workspaceConfig.agentName,
55
- source: "workspace"
56
+ source: "workspace",
57
+ grantAccessToMembers: workspaceConfig.grantAccessToMembers ?? true
56
58
  };
57
59
  }
58
60
  logger.debug({
@@ -78,7 +80,8 @@ async function getAgentConfigSources(params) {
78
80
  projectId: config.projectId,
79
81
  agentId: config.agentId,
80
82
  agentName: config.agentName || void 0,
81
- source: "channel"
83
+ source: "channel",
84
+ grantAccessToMembers: config.grantAccessToMembers
82
85
  };
83
86
  }
84
87
  const wsConfig = await getWorkspaceDefaultAgentFromNango(teamId);
@@ -86,7 +89,8 @@ async function getAgentConfigSources(params) {
86
89
  projectId: wsConfig.projectId,
87
90
  agentId: wsConfig.agentId,
88
91
  agentName: wsConfig.agentName,
89
- source: "workspace"
92
+ source: "workspace",
93
+ grantAccessToMembers: wsConfig.grantAccessToMembers ?? true
90
94
  };
91
95
  return {
92
96
  channelConfig,
@@ -3,7 +3,7 @@ import { Blocks, Elements, Md, Message } from "slack-block-builder";
3
3
 
4
4
  //#region src/slack/services/blocks/index.ts
5
5
  function createErrorMessage(message) {
6
- return Message().blocks(Blocks.Section().text(`❌ ${message}`)).buildToObject();
6
+ return Message().blocks(Blocks.Section().text(message)).buildToObject();
7
7
  }
8
8
  function createContextBlock(params) {
9
9
  const { agentName, isPrivate = false } = params;
@@ -40,7 +40,7 @@ function buildConversationResponseBlocks(params) {
40
40
  type: "context",
41
41
  elements: [{
42
42
  type: "mrkdwn",
43
- text: `💬 *You:* ${userMessage.length > 200 ? `${userMessage.slice(0, 200)}...` : userMessage}`
43
+ text: `*You:* ${userMessage.length > 200 ? `${userMessage.slice(0, 200)}...` : userMessage}`
44
44
  }]
45
45
  },
46
46
  { type: "divider" },
@@ -69,27 +69,23 @@ function createUpdatedHelpMessage() {
69
69
  return Message().blocks(Blocks.Section().text(`${Md.bold(SlackStrings.help.title)}`), Blocks.Section().text(SlackStrings.help.publicSection), Blocks.Divider(), Blocks.Section().text(SlackStrings.help.privateSection), Blocks.Divider(), Blocks.Section().text(SlackStrings.help.otherCommands), Blocks.Divider(), Blocks.Section().text(SlackStrings.help.docsLink)).buildToObject();
70
70
  }
71
71
  function createAlreadyLinkedMessage(email, linkedAt, dashboardUrl) {
72
- return Message().blocks(Blocks.Section().text(Md.bold("Already Linked!") + "\n\nYour Slack account is already connected to Inkeep.\n\n" + Md.bold("Inkeep Account:") + ` ${email}\n` + Md.bold("Linked:") + ` ${new Date(linkedAt).toLocaleDateString()}\n\nTo switch accounts, first run \`/inkeep unlink\``), Blocks.Actions().elements(Elements.Button().text(SlackStrings.buttons.openDashboard).url(dashboardUrl).actionId("open_dashboard"))).buildToObject();
72
+ return Message().blocks(Blocks.Section().text(Md.bold("Already linked") + "\n\nYour Slack account is connected to Inkeep.\n\n" + Md.bold("Account:") + ` ${email}\n` + Md.bold("Linked:") + ` ${new Date(linkedAt).toLocaleDateString()}\n\nTo switch accounts, first run \`/inkeep unlink\``), Blocks.Actions().elements(Elements.Button().text(SlackStrings.buttons.openDashboard).url(dashboardUrl).actionId("open_dashboard"))).buildToObject();
73
73
  }
74
74
  function createUnlinkSuccessMessage() {
75
- return Message().blocks(Blocks.Section().text(Md.bold("Account Unlinked") + "\n\nYour Slack account has been disconnected from Inkeep.\n\nTo use Inkeep agents again, run `/inkeep link` to connect a new account.")).buildToObject();
75
+ return Message().blocks(Blocks.Section().text(Md.bold("Account unlinked") + "\n\nYour Slack account has been disconnected from Inkeep.\n\nRun `/inkeep link` to connect a new account.")).buildToObject();
76
76
  }
77
77
  function createNotLinkedMessage() {
78
- return Message().blocks(Blocks.Section().text(Md.bold("Not Linked") + "\n\nYour Slack account is not connected to Inkeep.\n\nRun `/inkeep link` to connect your account.")).buildToObject();
78
+ return Message().blocks(Blocks.Section().text(Md.bold("Not linked") + "\n\nYour Slack account is not connected to Inkeep. Run `/inkeep link` to connect.")).buildToObject();
79
79
  }
80
80
  function createStatusMessage(email, linkedAt, dashboardUrl, agentConfigs) {
81
81
  const { effective } = agentConfigs;
82
82
  let agentLine;
83
83
  if (effective) agentLine = `${Md.bold("Agent:")} ${effective.agentName || effective.agentId}`;
84
84
  else agentLine = `${Md.bold("Agent:")} None configured\n${Md.italic("Ask your admin to set up an agent in the dashboard.")}`;
85
- return Message().blocks(Blocks.Section().text(Md.bold("Connected to Inkeep") + `\n\n${Md.bold("Account:")} ${email}\n${Md.bold("Linked:")} ${new Date(linkedAt).toLocaleDateString()}\n` + agentLine), Blocks.Actions().elements(Elements.Button().text(SlackStrings.buttons.openDashboard).url(dashboardUrl).actionId("open_dashboard"))).buildToObject();
85
+ return Message().blocks(Blocks.Section().text(Md.bold("Connected to Inkeep") + `\n\n${Md.bold("Account:")} ${email}\n${Md.bold("Linked:")} ${new Date(linkedAt).toLocaleDateString()}\n` + agentLine), Blocks.Actions().elements(Elements.Button().text(SlackStrings.buttons.openDashboard).url(dashboardUrl).actionId("open_dashboard"))).buildToObject();
86
86
  }
87
87
  function createJwtLinkMessage(linkUrl, expiresInMinutes) {
88
- return Message().blocks(Blocks.Section().text(`${Md.bold("🔗 Link your Inkeep account")}\n\nConnect your Slack and Inkeep accounts to unlock AI-powered assistance:`), Blocks.Section().text(`${Md.bold("What you can do after linking:")}\n• Ask questions with \`/inkeep [question]\` or \`@Inkeep\`
89
- • Get personalized responses from AI agents
90
- • Set your own default agent preferences`), Blocks.Section().text(`${Md.bold("How to link:")}\n1. Click the button below
91
- 2. Sign in to Inkeep (or create an account)
92
- 3. Done! Come back here and start asking questions`), Blocks.Actions().elements(Elements.Button().text("🔗 Link Account").url(linkUrl).actionId("link_account").primary()), Blocks.Context().elements(`This link expires in ${expiresInMinutes} minutes`)).buildToObject();
88
+ return Message().blocks(Blocks.Section().text(`${Md.bold("Link your Inkeep account")}\n\nConnect your Slack and Inkeep accounts to use Inkeep agents.`), Blocks.Actions().elements(Elements.Button().text("Link Account").url(linkUrl).actionId("link_account").primary()), Blocks.Context().elements(`This link expires in ${expiresInMinutes} minutes.`)).buildToObject();
93
89
  }
94
90
 
95
91
  //#endregion
@@ -6,9 +6,9 @@ import { resolveEffectiveAgent } from "../agent-resolution.js";
6
6
  import { SlackStrings } from "../../i18n/strings.js";
7
7
  import { createAlreadyLinkedMessage, createContextBlock, createErrorMessage, createJwtLinkMessage, createNotLinkedMessage, createStatusMessage, createUnlinkSuccessMessage, createUpdatedHelpMessage } from "../blocks/index.js";
8
8
  import { getSlackClient } from "../client.js";
9
- import { fetchAgentsForProject, fetchProjectsForTenant, getChannelAgentConfig, sendResponseUrlMessage } from "../events/utils.js";
9
+ import { extractApiErrorMessage, fetchAgentsForProject, fetchProjectsForTenant, getChannelAgentConfig, sendResponseUrlMessage } from "../events/utils.js";
10
10
  import { buildAgentSelectorModal } from "../modals.js";
11
- import { deleteWorkAppSlackUserMapping, findWorkAppSlackUserMapping, findWorkAppSlackUserMappingBySlackUser, flushTraces, getWaitUntil, signSlackLinkToken, signSlackUserToken } from "@inkeep/agents-core";
11
+ import { deleteWorkAppSlackUserMapping, findWorkAppSlackUserMapping, findWorkAppSlackUserMappingBySlackUser, flushTraces, getInProcessFetch, getWaitUntil, signSlackLinkToken, signSlackUserToken } from "@inkeep/agents-core";
12
12
 
13
13
  //#region src/slack/services/commands/index.ts
14
14
  const DEFAULT_CLIENT_ID = "work-apps-slack";
@@ -232,28 +232,34 @@ async function handleQuestionCommand(payload, question, _dashboardUrl, tenantId)
232
232
  id: resolvedAgent.agentId,
233
233
  name: resolvedAgent.agentName || null,
234
234
  projectId: resolvedAgent.projectId
235
- }, question, userTenantId).catch((error) => {
235
+ }, question, userTenantId, {
236
+ slackAuthorized: resolvedAgent.grantAccessToMembers,
237
+ slackAuthSource: resolvedAgent.source === "none" ? void 0 : resolvedAgent.source,
238
+ slackChannelId: payload.channelId,
239
+ slackAuthorizedProjectId: resolvedAgent.projectId
240
+ }).catch((error) => {
236
241
  logger.error({ error }, "Background execution promise rejected");
237
242
  }).finally(() => flushTraces());
238
243
  const waitUntil = await getWaitUntil();
239
244
  if (waitUntil) waitUntil(questionWork);
240
245
  return {};
241
246
  }
242
- async function executeAgentInBackground(payload, existingLink, targetAgent, question, tenantId) {
247
+ async function executeAgentInBackground(payload, existingLink, targetAgent, question, tenantId, channelAuth) {
243
248
  try {
244
249
  const slackUserToken = await signSlackUserToken({
245
250
  inkeepUserId: existingLink.inkeepUserId,
246
251
  tenantId,
247
252
  slackTeamId: payload.teamId,
248
253
  slackUserId: payload.userId,
249
- slackEnterpriseId: payload.enterpriseId
254
+ slackEnterpriseId: payload.enterpriseId,
255
+ ...channelAuth
250
256
  });
251
257
  const apiBaseUrl = env.INKEEP_AGENTS_API_URL || "http://localhost:3002";
252
258
  const controller = new AbortController();
253
259
  const timeout = setTimeout(() => controller.abort(), 3e4);
254
260
  let response;
255
261
  try {
256
- response = await fetch(`${apiBaseUrl}/run/api/chat`, {
262
+ response = await getInProcessFetch()(`${apiBaseUrl}/run/api/chat`, {
257
263
  method: "POST",
258
264
  headers: {
259
265
  "Content-Type": "application/json",
@@ -295,9 +301,11 @@ async function executeAgentInBackground(payload, existingLink, targetAgent, ques
295
301
  agentId: targetAgent.id,
296
302
  projectId: targetAgent.projectId
297
303
  }, "Run API call failed");
304
+ const apiMessage = extractApiErrorMessage(errorText);
305
+ const errorMessage = apiMessage ? `*Error.* ${apiMessage}` : `Failed to run agent: ${response.status} ${response.statusText}`;
298
306
  await sendResponseUrlMessage(payload.responseUrl, {
299
307
  response_type: "ephemeral",
300
- text: `Failed to run agent: ${response.status} ${response.statusText}`
308
+ text: errorMessage
301
309
  });
302
310
  } else {
303
311
  const result = await response.json();
@@ -0,0 +1,23 @@
1
+ import { DefaultAgentConfig } from "./nango.js";
2
+
3
+ //#region src/slack/services/dev-config.d.ts
4
+ interface SlackDevConfig {
5
+ devId: string;
6
+ appId: string;
7
+ clientId: string;
8
+ clientSecret: string;
9
+ signingSecret: string;
10
+ appToken: string;
11
+ botToken: string;
12
+ teamId: string;
13
+ teamName: string;
14
+ configRefreshToken?: string;
15
+ metadata?: Record<string, string>;
16
+ }
17
+ declare function isSlackDevMode(): boolean;
18
+ declare function loadSlackDevConfig(): SlackDevConfig | null;
19
+ declare function getDevDefaultAgent(config: SlackDevConfig | null): DefaultAgentConfig | null;
20
+ declare function resetDevConfigCache(): void;
21
+ declare function saveSlackDevConfig(config: SlackDevConfig): boolean;
22
+ //#endregion
23
+ export { SlackDevConfig, getDevDefaultAgent, isSlackDevMode, loadSlackDevConfig, resetDevConfigCache, saveSlackDevConfig };
@@ -0,0 +1,91 @@
1
+ import { env } from "../../env.js";
2
+ import { getLogger } from "../../logger.js";
3
+ import { existsSync, readFileSync, writeFileSync } from "node:fs";
4
+ import { dirname, join, parse } from "node:path";
5
+
6
+ //#region src/slack/services/dev-config.ts
7
+ const logger = getLogger("slack-dev-config");
8
+ const DEV_CONFIG_FILENAME = ".slack-dev.json";
9
+ const CACHE_TTL_MS = 5e3;
10
+ let cachedConfig = null;
11
+ let cacheExpiresAt = 0;
12
+ let resolvedConfigPath;
13
+ function findDevConfigPath() {
14
+ let dir = process.cwd();
15
+ while (true) {
16
+ const candidate = join(dir, DEV_CONFIG_FILENAME);
17
+ if (existsSync(candidate)) return candidate;
18
+ const parent = dirname(dir);
19
+ if (parent === dir || parse(dir).root === dir) break;
20
+ dir = parent;
21
+ }
22
+ return null;
23
+ }
24
+ function getDevConfigPath() {
25
+ if (resolvedConfigPath !== void 0) return resolvedConfigPath;
26
+ resolvedConfigPath = findDevConfigPath();
27
+ return resolvedConfigPath;
28
+ }
29
+ let devModeChecked = false;
30
+ let devModeResult = false;
31
+ function isSlackDevMode() {
32
+ if (devModeChecked) return devModeResult;
33
+ devModeResult = env.ENVIRONMENT === "development" && getDevConfigPath() !== null;
34
+ devModeChecked = true;
35
+ return devModeResult;
36
+ }
37
+ function loadSlackDevConfig() {
38
+ if (cachedConfig && Date.now() < cacheExpiresAt) return cachedConfig;
39
+ const configPath = getDevConfigPath();
40
+ if (!configPath) return null;
41
+ try {
42
+ const raw = readFileSync(configPath, "utf-8");
43
+ cachedConfig = JSON.parse(raw);
44
+ cacheExpiresAt = Date.now() + CACHE_TTL_MS;
45
+ return cachedConfig;
46
+ } catch (error) {
47
+ logger.error({
48
+ error,
49
+ configPath
50
+ }, "Failed to read .slack-dev.json");
51
+ return null;
52
+ }
53
+ }
54
+ function getDevDefaultAgent(config) {
55
+ if (!config?.metadata?.default_agent) return null;
56
+ try {
57
+ return JSON.parse(config.metadata.default_agent);
58
+ } catch (error) {
59
+ logger.warn({
60
+ error,
61
+ rawValue: config.metadata.default_agent
62
+ }, "Failed to parse default_agent metadata as JSON - check .slack-dev.json format");
63
+ return null;
64
+ }
65
+ }
66
+ function resetDevConfigCache() {
67
+ cachedConfig = null;
68
+ cacheExpiresAt = 0;
69
+ resolvedConfigPath = void 0;
70
+ devModeChecked = false;
71
+ devModeResult = false;
72
+ }
73
+ function saveSlackDevConfig(config) {
74
+ const configPath = getDevConfigPath();
75
+ if (!configPath) return false;
76
+ try {
77
+ writeFileSync(configPath, JSON.stringify(config, null, 2) + "\n", "utf-8");
78
+ cachedConfig = config;
79
+ cacheExpiresAt = Date.now() + CACHE_TTL_MS;
80
+ return true;
81
+ } catch (error) {
82
+ logger.error({
83
+ error,
84
+ configPath
85
+ }, "Failed to write .slack-dev.json");
86
+ return false;
87
+ }
88
+ }
89
+
90
+ //#endregion
91
+ export { getDevDefaultAgent, isSlackDevMode, loadSlackDevConfig, resetDevConfigCache, saveSlackDevConfig };