@inkeep/agents-work-apps 0.0.0-dev-20260220231539 → 0.0.0-dev-20260221002805

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.
package/dist/env.d.ts CHANGED
@@ -14,11 +14,11 @@ declare const envSchema: z.ZodObject<{
14
14
  pentest: "pentest";
15
15
  }>>;
16
16
  LOG_LEVEL: z.ZodDefault<z.ZodEnum<{
17
+ error: "error";
17
18
  trace: "trace";
18
19
  debug: "debug";
19
20
  info: "info";
20
21
  warn: "warn";
21
- error: "error";
22
22
  }>>;
23
23
  INKEEP_AGENTS_RUN_DATABASE_URL: z.ZodOptional<z.ZodString>;
24
24
  INKEEP_AGENTS_MANAGE_UI_URL: z.ZodOptional<z.ZodString>;
@@ -44,7 +44,7 @@ declare const envSchema: z.ZodObject<{
44
44
  declare const env: {
45
45
  NODE_ENV: "development" | "production" | "test";
46
46
  ENVIRONMENT: "development" | "production" | "test" | "pentest";
47
- LOG_LEVEL: "trace" | "debug" | "info" | "warn" | "error";
47
+ LOG_LEVEL: "error" | "trace" | "debug" | "info" | "warn";
48
48
  INKEEP_AGENTS_RUN_DATABASE_URL?: string | undefined;
49
49
  INKEEP_AGENTS_MANAGE_UI_URL?: string | undefined;
50
50
  GITHUB_APP_ID?: string | undefined;
@@ -4,10 +4,10 @@ import "./routes/setup.js";
4
4
  import "./routes/tokenExchange.js";
5
5
  import { WebhookVerificationResult, verifyWebhookSignature } from "./routes/webhooks.js";
6
6
  import { Hono } from "hono";
7
- import * as hono_types0 from "hono/types";
7
+ import * as hono_types6 from "hono/types";
8
8
 
9
9
  //#region src/github/index.d.ts
10
- declare function createGithubRoutes(): Hono<hono_types0.BlankEnv, hono_types0.BlankSchema, "/">;
11
- declare const githubRoutes: Hono<hono_types0.BlankEnv, hono_types0.BlankSchema, "/">;
10
+ declare function createGithubRoutes(): Hono<hono_types6.BlankEnv, hono_types6.BlankSchema, "/">;
11
+ declare const githubRoutes: Hono<hono_types6.BlankEnv, hono_types6.BlankSchema, "/">;
12
12
  //#endregion
13
13
  export { GenerateInstallationAccessTokenResult, GenerateTokenError, GenerateTokenResult, GitHubAppConfig, InstallationAccessToken, InstallationInfo, LookupInstallationError, LookupInstallationForRepoResult, LookupInstallationResult, WebhookVerificationResult, clearConfigCache, createAppJwt, createGithubRoutes, determineStatus, fetchInstallationDetails, fetchInstallationRepositories, generateInstallationAccessToken, getGitHubAppConfig, getGitHubAppName, getStateSigningSecret, getWebhookSecret, githubRoutes, isGitHubAppConfigured, isGitHubAppNameConfigured, isStateSigningConfigured, isWebhookConfigured, lookupInstallationForRepo, validateGitHubAppConfigOnStartup, validateGitHubInstallFlowConfigOnStartup, validateGitHubWebhookConfigOnStartup, verifyWebhookSignature };
@@ -1,7 +1,7 @@
1
- import * as hono0 from "hono";
1
+ import * as hono1 from "hono";
2
2
 
3
3
  //#region src/github/mcp/auth.d.ts
4
- declare const githubMcpAuth: () => hono0.MiddlewareHandler<{
4
+ declare const githubMcpAuth: () => hono1.MiddlewareHandler<{
5
5
  Variables: {
6
6
  toolId: string;
7
7
  };
@@ -1,11 +1,11 @@
1
1
  import { Hono } from "hono";
2
- import * as hono_types3 from "hono/types";
2
+ import * as hono_types0 from "hono/types";
3
3
 
4
4
  //#region src/github/mcp/index.d.ts
5
5
  declare const app: Hono<{
6
6
  Variables: {
7
7
  toolId: string;
8
8
  };
9
- }, hono_types3.BlankSchema, "/">;
9
+ }, hono_types0.BlankSchema, "/">;
10
10
  //#endregion
11
11
  export { app as default };
@@ -1,7 +1,7 @@
1
1
  import { Hono } from "hono";
2
- import * as hono_types4 from "hono/types";
2
+ import * as hono_types0 from "hono/types";
3
3
 
4
4
  //#region src/github/routes/setup.d.ts
5
- declare const app: Hono<hono_types4.BlankEnv, hono_types4.BlankSchema, "/">;
5
+ declare const app: Hono<hono_types0.BlankEnv, hono_types0.BlankSchema, "/">;
6
6
  //#endregion
7
7
  export { app as default };
@@ -1,7 +1,7 @@
1
1
  import { Hono } from "hono";
2
- import * as hono_types6 from "hono/types";
2
+ import * as hono_types2 from "hono/types";
3
3
 
4
4
  //#region src/github/routes/tokenExchange.d.ts
5
- declare const app: Hono<hono_types6.BlankEnv, hono_types6.BlankSchema, "/">;
5
+ declare const app: Hono<hono_types2.BlankEnv, hono_types2.BlankSchema, "/">;
6
6
  //#endregion
7
7
  export { app as default };
@@ -1,5 +1,5 @@
1
1
  import { Hono } from "hono";
2
- import * as hono_types8 from "hono/types";
2
+ import * as hono_types4 from "hono/types";
3
3
 
4
4
  //#region src/github/routes/webhooks.d.ts
5
5
  interface WebhookVerificationResult {
@@ -7,6 +7,6 @@ interface WebhookVerificationResult {
7
7
  error?: string;
8
8
  }
9
9
  declare function verifyWebhookSignature(payload: string, signature: string | undefined, secret: string): WebhookVerificationResult;
10
- declare const app: Hono<hono_types8.BlankEnv, hono_types8.BlankSchema, "/">;
10
+ declare const app: Hono<hono_types4.BlankEnv, hono_types4.BlankSchema, "/">;
11
11
  //#endregion
12
12
  export { WebhookVerificationResult, app as default, verifyWebhookSignature };
@@ -131,12 +131,15 @@ app.openapi(createProtectedRoute({
131
131
  tenantId
132
132
  });
133
133
  }
134
- if (existingLink) logger.info({
135
- slackUserId,
136
- existingUserId: existingLink.inkeepUserId,
137
- newUserId: inkeepUserId,
138
- tenantId
139
- }, "Slack user already linked, updating to new user");
134
+ if (existingLink) {
135
+ logger.info({
136
+ slackUserId,
137
+ existingUserId: existingLink.inkeepUserId,
138
+ newUserId: inkeepUserId,
139
+ tenantId
140
+ }, "Slack user already linked, updating to new user");
141
+ await deleteWorkAppSlackUserMapping(runDbClient_default)(tenantId, slackUserId, teamId, "work-apps-slack");
142
+ }
140
143
  const slackUserMapping = await createWorkAppSlackUserMapping(runDbClient_default)({
141
144
  tenantId,
142
145
  clientId: "work-apps-slack",
@@ -162,10 +165,9 @@ app.openapi(createProtectedRoute({
162
165
  tenantId
163
166
  });
164
167
  } catch (error) {
165
- const errorMessage = error instanceof Error ? error.message : String(error);
166
- if (errorMessage.includes("duplicate key") || errorMessage.includes("unique constraint")) {
167
- logger.warn({ userId: body.userId }, "Slack user already linked");
168
- return c.json({ error: "This Slack account is already linked to an Inkeep account." }, 409);
168
+ if (error instanceof Error && (error.message.includes("duplicate key") || error.message.includes("unique constraint")) || typeof error === "object" && error !== null && "cause" in error && typeof error.cause === "object" && error.cause?.code === "23505") {
169
+ logger.info({ userId: body.userId }, "Concurrent link resolved — mapping already exists");
170
+ return c.json({ success: true });
169
171
  }
170
172
  logger.error({
171
173
  error,
@@ -5,7 +5,7 @@ import { getSlackChannels, getSlackClient, revokeSlackToken } from "../services/
5
5
  import "../services/index.js";
6
6
  import { requireChannelMemberOrAdmin, requireWorkspaceAdmin } from "../middleware/permissions.js";
7
7
  import { OpenAPIHono, z } from "@hono/zod-openapi";
8
- import { deleteAllWorkAppSlackChannelAgentConfigsByTeam, deleteAllWorkAppSlackUserMappingsByTeam, deleteWorkAppSlackChannelAgentConfig, deleteWorkAppSlackWorkspaceByNangoConnectionId, findWorkAppSlackChannelAgentConfig, listWorkAppSlackChannelAgentConfigsByTeam, listWorkAppSlackUserMappingsByTeam, upsertWorkAppSlackChannelAgentConfig } from "@inkeep/agents-core";
8
+ import { deleteAllWorkAppSlackChannelAgentConfigsByTeam, deleteAllWorkAppSlackUserMappingsByTeam, deleteWorkAppSlackChannelAgentConfig, deleteWorkAppSlackWorkspaceByNangoConnectionId, findWorkAppSlackChannelAgentConfig, findWorkAppSlackWorkspaceByTeamId, listWorkAppSlackChannelAgentConfigsByTeam, listWorkAppSlackUserMappingsByTeam, updateWorkAppSlackWorkspace, upsertWorkAppSlackChannelAgentConfig } from "@inkeep/agents-core";
9
9
  import { createProtectedRoute, inheritedWorkAppsAuth } from "@inkeep/agents-core/middleware";
10
10
 
11
11
  //#region src/slack/routes/workspaces.ts
@@ -48,6 +48,7 @@ const ChannelAgentConfigSchema = z.object({
48
48
  grantAccessToMembers: z.boolean().optional()
49
49
  });
50
50
  const WorkspaceSettingsSchema = z.object({ defaultAgent: ChannelAgentConfigSchema.optional() });
51
+ const JoinFromWorkspaceSettingsSchema = z.object({ shouldAllowJoinFromWorkspace: z.boolean() });
51
52
  app.openapi(createProtectedRoute({
52
53
  method: "get",
53
54
  path: "/",
@@ -222,6 +223,89 @@ app.openapi(createProtectedRoute({
222
223
  }
223
224
  return c.json({ success: true });
224
225
  });
226
+ app.openapi(createProtectedRoute({
227
+ method: "get",
228
+ path: "/{teamId}/join-from-workspace",
229
+ summary: "Get Join From Workspace Setting",
230
+ description: "Get the join from workspace setting for the workspace",
231
+ operationId: "slack-get-join-from-workspace",
232
+ tags: [
233
+ "Work Apps",
234
+ "Slack",
235
+ "Workspaces"
236
+ ],
237
+ permission: inheritedWorkAppsAuth(),
238
+ request: { params: z.object({ teamId: z.string() }) },
239
+ responses: {
240
+ 200: {
241
+ description: "Join from workspace setting",
242
+ content: { "application/json": { schema: JoinFromWorkspaceSettingsSchema } }
243
+ },
244
+ 404: { description: "Workspace not found" }
245
+ }
246
+ }), async (c) => {
247
+ const { teamId } = c.req.valid("param");
248
+ const sessionTenantId = c.get("tenantId");
249
+ if (!sessionTenantId) return c.json({ error: "Unauthorized" }, 401);
250
+ const workspace = await findWorkAppSlackWorkspaceByTeamId(runDbClient_default)(sessionTenantId, teamId);
251
+ if (!workspace) return c.json({ shouldAllowJoinFromWorkspace: false });
252
+ return c.json({ shouldAllowJoinFromWorkspace: workspace.shouldAllowJoinFromWorkspace ?? false });
253
+ });
254
+ app.openapi(createProtectedRoute({
255
+ method: "put",
256
+ path: "/{teamId}/join-from-workspace",
257
+ summary: "Update Join From Workspace Setting",
258
+ description: "Enable or disable join from workspace for the workspace",
259
+ operationId: "slack-update-join-from-workspace",
260
+ tags: [
261
+ "Work Apps",
262
+ "Slack",
263
+ "Workspaces"
264
+ ],
265
+ permission: requireWorkspaceAdmin(),
266
+ request: {
267
+ params: z.object({ teamId: z.string() }),
268
+ body: { content: { "application/json": { schema: JoinFromWorkspaceSettingsSchema } } }
269
+ },
270
+ responses: {
271
+ 200: {
272
+ description: "Join from workspace setting updated",
273
+ content: { "application/json": { schema: z.object({ success: z.boolean() }) } }
274
+ },
275
+ 401: { description: "Unauthorized" },
276
+ 404: { description: "Workspace not found" },
277
+ 500: { description: "Failed to update setting" }
278
+ }
279
+ }), async (c) => {
280
+ const { teamId } = c.req.valid("param");
281
+ const { shouldAllowJoinFromWorkspace } = c.req.valid("json");
282
+ const sessionTenantId = c.get("tenantId");
283
+ if (!sessionTenantId) return c.json({ error: "Unauthorized" }, 401);
284
+ const workspace = await findWorkAppSlackWorkspaceByTeamId(runDbClient_default)(sessionTenantId, teamId);
285
+ if (!workspace) return c.json({ error: "Workspace not found" }, 404);
286
+ try {
287
+ if (!await updateWorkAppSlackWorkspace(runDbClient_default)(workspace.id, { shouldAllowJoinFromWorkspace })) {
288
+ logger.error({
289
+ teamId,
290
+ shouldAllowJoinFromWorkspace
291
+ }, "Failed to update join from workspace setting");
292
+ return c.json({ error: "Failed to update setting" }, 500);
293
+ }
294
+ logger.info({
295
+ teamId,
296
+ shouldAllowJoinFromWorkspace,
297
+ workspaceId: workspace.id
298
+ }, "Updated workspace join from workspace settings");
299
+ return c.json({ success: true });
300
+ } catch (error) {
301
+ logger.error({
302
+ teamId,
303
+ shouldAllowJoinFromWorkspace,
304
+ error
305
+ }, "Failed to update join from workspace setting");
306
+ return c.json({ error: "Failed to update setting" }, 500);
307
+ }
308
+ });
225
309
  app.openapi(createProtectedRoute({
226
310
  method: "delete",
227
311
  path: "/{teamId}",
@@ -110,5 +110,6 @@ declare function buildToolApprovalExpiredBlocks(params: {
110
110
  }[];
111
111
  }[];
112
112
  declare function createJwtLinkMessage(linkUrl: string, expiresInMinutes: number): Readonly<slack_block_builder0.SlackMessageDto>;
113
+ declare function createCreateInkeepAccountMessage(acceptUrl: string, expiresInMinutes: number): Readonly<slack_block_builder0.SlackMessageDto>;
113
114
  //#endregion
114
- export { AgentConfigSources, ContextBlockParams, FollowUpButtonParams, ToolApprovalButtonValue, ToolApprovalButtonValueSchema, buildConversationResponseBlocks, buildFollowUpButton, buildToolApprovalBlocks, buildToolApprovalDoneBlocks, buildToolApprovalExpiredBlocks, createAlreadyLinkedMessage, createContextBlock, createErrorMessage, createJwtLinkMessage, createNotLinkedMessage, createStatusMessage, createUnlinkSuccessMessage, createUpdatedHelpMessage };
115
+ export { AgentConfigSources, ContextBlockParams, FollowUpButtonParams, ToolApprovalButtonValue, ToolApprovalButtonValueSchema, buildConversationResponseBlocks, buildFollowUpButton, buildToolApprovalBlocks, buildToolApprovalDoneBlocks, buildToolApprovalExpiredBlocks, createAlreadyLinkedMessage, createContextBlock, createCreateInkeepAccountMessage, createErrorMessage, createJwtLinkMessage, createNotLinkedMessage, createStatusMessage, createUnlinkSuccessMessage, createUpdatedHelpMessage };
@@ -161,6 +161,9 @@ function buildToolApprovalExpiredBlocks(params) {
161
161
  function createJwtLinkMessage(linkUrl, expiresInMinutes) {
162
162
  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();
163
163
  }
164
+ function createCreateInkeepAccountMessage(acceptUrl, expiresInMinutes) {
165
+ return Message().blocks(Blocks.Section().text(`${Md.bold("Create your Inkeep account")}\n\nYou've been invited to join Inkeep. Create an account to start using Inkeep agents in Slack.`), Blocks.Actions().elements(Elements.Button().text("Create Account").url(acceptUrl).actionId("create_account").primary()), Blocks.Context().elements(`This link expires in ${expiresInMinutes} minutes.`)).buildToObject();
166
+ }
164
167
 
165
168
  //#endregion
166
- export { ToolApprovalButtonValueSchema, buildConversationResponseBlocks, buildFollowUpButton, buildToolApprovalBlocks, buildToolApprovalDoneBlocks, buildToolApprovalExpiredBlocks, createAlreadyLinkedMessage, createContextBlock, createErrorMessage, createJwtLinkMessage, createNotLinkedMessage, createStatusMessage, createUnlinkSuccessMessage, createUpdatedHelpMessage };
169
+ export { ToolApprovalButtonValueSchema, buildConversationResponseBlocks, buildFollowUpButton, buildToolApprovalBlocks, buildToolApprovalDoneBlocks, buildToolApprovalExpiredBlocks, createAlreadyLinkedMessage, createContextBlock, createCreateInkeepAccountMessage, createErrorMessage, createJwtLinkMessage, createNotLinkedMessage, createStatusMessage, createUnlinkSuccessMessage, createUpdatedHelpMessage };
@@ -2,7 +2,7 @@ import { SlackWorkspaceConnection } from "../nango.js";
2
2
  import { SlackCommandPayload, SlackCommandResponse } from "../types.js";
3
3
 
4
4
  //#region src/slack/services/commands/index.d.ts
5
- declare function handleLinkCommand(payload: SlackCommandPayload, dashboardUrl: string, tenantId: string): Promise<SlackCommandResponse>;
5
+ declare function handleLinkCommand(payload: SlackCommandPayload, dashboardUrl: string, tenantId: string, botToken?: string): Promise<SlackCommandResponse>;
6
6
  declare function handleUnlinkCommand(payload: SlackCommandPayload, tenantId: string): Promise<SlackCommandResponse>;
7
7
  declare function handleStatusCommand(payload: SlackCommandPayload, dashboardUrl: string, tenantId: string): Promise<SlackCommandResponse>;
8
8
  declare function handleHelpCommand(): Promise<SlackCommandResponse>;
@@ -4,22 +4,116 @@ import runDbClient_default from "../../../db/runDbClient.js";
4
4
  import { findWorkspaceConnectionByTeamId } from "../nango.js";
5
5
  import { resolveEffectiveAgent } from "../agent-resolution.js";
6
6
  import { SlackStrings } from "../../i18n/strings.js";
7
- import { createAlreadyLinkedMessage, createContextBlock, createErrorMessage, createJwtLinkMessage, createNotLinkedMessage, createStatusMessage, createUnlinkSuccessMessage, createUpdatedHelpMessage } from "../blocks/index.js";
7
+ import { createAlreadyLinkedMessage, createContextBlock, createCreateInkeepAccountMessage, createErrorMessage, createJwtLinkMessage, createNotLinkedMessage, createStatusMessage, createUnlinkSuccessMessage, createUpdatedHelpMessage } from "../blocks/index.js";
8
8
  import { getSlackClient } from "../client.js";
9
9
  import { extractApiErrorMessage, fetchAgentsForProject, fetchProjectsForTenant, getChannelAgentConfig, sendResponseUrlMessage } from "../events/utils.js";
10
10
  import { buildAgentSelectorModal } from "../modals.js";
11
- import { deleteWorkAppSlackUserMapping, findWorkAppSlackUserMapping, findWorkAppSlackUserMappingBySlackUser, flushTraces, getInProcessFetch, getWaitUntil, signSlackLinkToken, signSlackUserToken } from "@inkeep/agents-core";
11
+ import { createInvitationInDb, deleteWorkAppSlackUserMapping, findWorkAppSlackUserMapping, findWorkAppSlackUserMappingBySlackUser, findWorkAppSlackWorkspaceByTeamId, flushTraces, getInProcessFetch, getOrganizationMemberByEmail, getPendingInvitationsByEmail, 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";
15
15
  const LINK_CODE_TTL_MINUTES = 10;
16
16
  const logger = getLogger("slack-commands");
17
- async function handleLinkCommand(payload, dashboardUrl, tenantId) {
17
+ /**
18
+ * Create an invitation for a Slack user who doesn't have an Inkeep account yet.
19
+ * Returns the invitation ID and email so the caller can direct the user
20
+ * to the accept-invitation page.
21
+ *
22
+ * Returns null if:
23
+ * - Workspace doesn't have shouldAllowJoinFromWorkspace enabled
24
+ * - User already has an Inkeep account (JWT link flow is sufficient)
25
+ * - Service account is not configured
26
+ */
27
+ async function tryAutoInvite(payload, tenantId, botToken) {
28
+ try {
29
+ if (!(await findWorkAppSlackWorkspaceByTeamId(runDbClient_default)(tenantId, payload.teamId))?.shouldAllowJoinFromWorkspace) return null;
30
+ const slackClient = getSlackClient(botToken);
31
+ let userEmail;
32
+ try {
33
+ userEmail = (await slackClient.users.info({ user: payload.userId })).user?.profile?.email;
34
+ } catch (error) {
35
+ logger.warn({
36
+ error,
37
+ userId: payload.userId
38
+ }, "Failed to get user info from Slack");
39
+ return null;
40
+ }
41
+ if (!userEmail) {
42
+ logger.warn({ userId: payload.userId }, "No email found in Slack user profile");
43
+ return null;
44
+ }
45
+ if (await getOrganizationMemberByEmail(runDbClient_default)(tenantId, userEmail)) {
46
+ logger.debug({
47
+ userId: payload.userId,
48
+ email: userEmail
49
+ }, "User already has Inkeep account, skipping auto-invite");
50
+ return null;
51
+ }
52
+ const existingInvitation = (await getPendingInvitationsByEmail(runDbClient_default)(userEmail)).find((inv) => inv.organizationId === tenantId);
53
+ if (existingInvitation) {
54
+ logger.info({
55
+ userId: payload.userId,
56
+ tenantId,
57
+ invitationId: existingInvitation.id,
58
+ email: userEmail
59
+ }, "Reusing existing pending invitation for Slack user");
60
+ return {
61
+ invitationId: existingInvitation.id,
62
+ email: userEmail
63
+ };
64
+ }
65
+ const invitation = await createInvitationInDb(runDbClient_default)({
66
+ organizationId: tenantId,
67
+ email: userEmail
68
+ });
69
+ logger.info({
70
+ userId: payload.userId,
71
+ tenantId,
72
+ invitationId: invitation.id,
73
+ email: userEmail
74
+ }, "Invitation created for Slack user without Inkeep account");
75
+ return {
76
+ invitationId: invitation.id,
77
+ email: userEmail
78
+ };
79
+ } catch (error) {
80
+ logger.warn({
81
+ error,
82
+ userId: payload.userId,
83
+ tenantId
84
+ }, "Auto-invite attempt failed");
85
+ return null;
86
+ }
87
+ }
88
+ async function handleLinkCommand(payload, dashboardUrl, tenantId, botToken) {
18
89
  const existingLink = await findWorkAppSlackUserMapping(runDbClient_default)(tenantId, payload.userId, payload.teamId, DEFAULT_CLIENT_ID);
19
90
  if (existingLink) return {
20
91
  response_type: "ephemeral",
21
92
  ...createAlreadyLinkedMessage(existingLink.slackEmail || existingLink.slackUsername || "Unknown", existingLink.linkedAt, dashboardUrl)
22
93
  };
94
+ if (botToken) {
95
+ const autoInvite = await tryAutoInvite(payload, tenantId, botToken);
96
+ if (autoInvite) {
97
+ const manageUiUrl = env.INKEEP_AGENTS_MANAGE_UI_URL || "http://localhost:3000";
98
+ const linkToken = await signSlackLinkToken({
99
+ tenantId,
100
+ slackTeamId: payload.teamId,
101
+ slackUserId: payload.userId,
102
+ slackEnterpriseId: payload.enterpriseId,
103
+ slackUsername: payload.userName
104
+ });
105
+ const linkReturnUrl = `/link?token=${encodeURIComponent(linkToken)}`;
106
+ const acceptUrl = `${manageUiUrl}/accept-invitation/${autoInvite.invitationId}?email=${encodeURIComponent(autoInvite.email)}&returnUrl=${encodeURIComponent(linkReturnUrl)}`;
107
+ logger.info({
108
+ invitationId: autoInvite.invitationId,
109
+ email: autoInvite.email
110
+ }, "Directing new user to accept-invitation page with link returnUrl");
111
+ return {
112
+ response_type: "ephemeral",
113
+ ...createCreateInkeepAccountMessage(acceptUrl, LINK_CODE_TTL_MINUTES)
114
+ };
115
+ }
116
+ }
23
117
  try {
24
118
  const linkToken = await signSlackLinkToken({
25
119
  tenantId,
@@ -363,7 +457,7 @@ async function handleCommand(payload) {
363
457
  }, "Slack command received");
364
458
  switch (subcommand) {
365
459
  case "link":
366
- case "connect": return handleLinkCommand(payload, dashboardUrl, tenantId);
460
+ case "connect": return handleLinkCommand(payload, dashboardUrl, tenantId, workspaceConnection.botToken);
367
461
  case "status": return handleStatusCommand(payload, dashboardUrl, tenantId);
368
462
  case "unlink":
369
463
  case "logout":
@@ -8,9 +8,9 @@ import { AgentOption } from "../modals.js";
8
8
  * Called on every @mention and /inkeep command — caching avoids redundant DB queries.
9
9
  */
10
10
  declare function findCachedUserMapping(tenantId: string, slackUserId: string, teamId: string, clientId?: string): Promise<{
11
- id: string;
12
11
  createdAt: string;
13
12
  updatedAt: string;
13
+ id: string;
14
14
  tenantId: string;
15
15
  clientId: string;
16
16
  slackUserId: string;
@@ -1,5 +1,5 @@
1
1
  import { AgentResolutionParams, ResolvedAgentConfig, getAgentConfigSources, resolveEffectiveAgent } from "./agent-resolution.js";
2
- import { AgentConfigSources, ContextBlockParams, FollowUpButtonParams, ToolApprovalButtonValue, ToolApprovalButtonValueSchema, buildConversationResponseBlocks, buildFollowUpButton, buildToolApprovalBlocks, buildToolApprovalDoneBlocks, buildToolApprovalExpiredBlocks, createAlreadyLinkedMessage, createContextBlock, createErrorMessage, createJwtLinkMessage, createNotLinkedMessage, createStatusMessage, createUnlinkSuccessMessage, createUpdatedHelpMessage } from "./blocks/index.js";
2
+ import { AgentConfigSources, ContextBlockParams, FollowUpButtonParams, ToolApprovalButtonValue, ToolApprovalButtonValueSchema, buildConversationResponseBlocks, buildFollowUpButton, buildToolApprovalBlocks, buildToolApprovalDoneBlocks, buildToolApprovalExpiredBlocks, createAlreadyLinkedMessage, createContextBlock, createCreateInkeepAccountMessage, createErrorMessage, createJwtLinkMessage, createNotLinkedMessage, createStatusMessage, createUnlinkSuccessMessage, createUpdatedHelpMessage } from "./blocks/index.js";
3
3
  import { checkUserIsChannelMember, getSlackChannelInfo, getSlackChannels, getSlackClient, getSlackTeamInfo, getSlackUserInfo, postMessage, postMessageInThread, revokeSlackToken } from "./client.js";
4
4
  import { DefaultAgentConfig, SlackWorkspaceConnection, WorkspaceInstallData, clearWorkspaceConnectionCache, computeWorkspaceConnectionId, createConnectSession, deleteWorkspaceInstallation, findWorkspaceConnectionByTeamId, getConnectionAccessToken, getSlackIntegrationId, getSlackNango, getWorkspaceDefaultAgentFromNango, listWorkspaceInstallations, setWorkspaceDefaultAgent, storeWorkspaceInstallation, updateConnectionMetadata } from "./nango.js";
5
5
  import { SlackCommandPayload, SlackCommandResponse } from "./types.js";
@@ -13,4 +13,4 @@ import { StreamResult, streamAgentResponse } from "./events/streaming.js";
13
13
  import "./events/index.js";
14
14
  import { parseSlackCommandBody, parseSlackEventBody, verifySlackRequest } from "./security.js";
15
15
  import { getBotTokenForTeam, setBotTokenForTeam } from "./workspace-tokens.js";
16
- export { AgentConfigSources, AgentOption, AgentResolutionParams, BuildAgentSelectorModalParams, BuildMessageShortcutModalParams, ContextBlockParams, DefaultAgentConfig, FollowUpButtonParams, FollowUpModalMetadata, InlineSelectorMetadata, ModalMetadata, ResolvedAgentConfig, SlackCommandPayload, SlackCommandResponse, SlackErrorType, SlackWorkspaceConnection, StreamResult, ToolApprovalButtonValue, ToolApprovalButtonValueSchema, WorkspaceInstallData, buildAgentSelectorModal, buildConversationResponseBlocks, buildFollowUpButton, buildFollowUpModal, buildMessageShortcutModal, buildToolApprovalBlocks, buildToolApprovalDoneBlocks, buildToolApprovalExpiredBlocks, checkIfBotThread, checkUserIsChannelMember, classifyError, clearWorkspaceConnectionCache, computeWorkspaceConnectionId, createAlreadyLinkedMessage, createConnectSession, createContextBlock, createErrorMessage, createJwtLinkMessage, createNotLinkedMessage, createStatusMessage, createUnlinkSuccessMessage, createUpdatedHelpMessage, deleteWorkspaceInstallation, extractApiErrorMessage, fetchAgentsForProject, fetchProjectsForTenant, findCachedUserMapping, findWorkspaceConnectionByTeamId, generateSlackConversationId, getAgentConfigSources, getBotTokenForTeam, getChannelAgentConfig, getConnectionAccessToken, getSlackChannelInfo, getSlackChannels, getSlackClient, getSlackIntegrationId, getSlackNango, getSlackTeamInfo, getSlackUserInfo, getThreadContext, getUserFriendlyErrorMessage, getWorkspaceDefaultAgent, getWorkspaceDefaultAgentFromNango, handleAgentPickerCommand, handleAppMention, handleCommand, handleFollowUpSubmission, handleHelpCommand, handleLinkCommand, handleMessageShortcut, handleModalSubmission, handleOpenAgentSelectorModal, handleOpenFollowUpModal, handleQuestionCommand, handleStatusCommand, handleToolApproval, handleUnlinkCommand, listWorkspaceInstallations, markdownToMrkdwn, parseSlackCommandBody, parseSlackEventBody, postMessage, postMessageInThread, resolveEffectiveAgent, revokeSlackToken, sendResponseUrlMessage, setBotTokenForTeam, setWorkspaceDefaultAgent, storeWorkspaceInstallation, streamAgentResponse, updateConnectionMetadata, verifySlackRequest };
16
+ export { AgentConfigSources, AgentOption, AgentResolutionParams, BuildAgentSelectorModalParams, BuildMessageShortcutModalParams, ContextBlockParams, DefaultAgentConfig, FollowUpButtonParams, FollowUpModalMetadata, InlineSelectorMetadata, ModalMetadata, ResolvedAgentConfig, SlackCommandPayload, SlackCommandResponse, SlackErrorType, SlackWorkspaceConnection, StreamResult, ToolApprovalButtonValue, ToolApprovalButtonValueSchema, WorkspaceInstallData, buildAgentSelectorModal, buildConversationResponseBlocks, buildFollowUpButton, buildFollowUpModal, buildMessageShortcutModal, buildToolApprovalBlocks, buildToolApprovalDoneBlocks, buildToolApprovalExpiredBlocks, checkIfBotThread, checkUserIsChannelMember, classifyError, clearWorkspaceConnectionCache, computeWorkspaceConnectionId, createAlreadyLinkedMessage, createConnectSession, createContextBlock, createCreateInkeepAccountMessage, createErrorMessage, createJwtLinkMessage, createNotLinkedMessage, createStatusMessage, createUnlinkSuccessMessage, createUpdatedHelpMessage, deleteWorkspaceInstallation, extractApiErrorMessage, fetchAgentsForProject, fetchProjectsForTenant, findCachedUserMapping, findWorkspaceConnectionByTeamId, generateSlackConversationId, getAgentConfigSources, getBotTokenForTeam, getChannelAgentConfig, getConnectionAccessToken, getSlackChannelInfo, getSlackChannels, getSlackClient, getSlackIntegrationId, getSlackNango, getSlackTeamInfo, getSlackUserInfo, getThreadContext, getUserFriendlyErrorMessage, getWorkspaceDefaultAgent, getWorkspaceDefaultAgentFromNango, handleAgentPickerCommand, handleAppMention, handleCommand, handleFollowUpSubmission, handleHelpCommand, handleLinkCommand, handleMessageShortcut, handleModalSubmission, handleOpenAgentSelectorModal, handleOpenFollowUpModal, handleQuestionCommand, handleStatusCommand, handleToolApproval, handleUnlinkCommand, listWorkspaceInstallations, markdownToMrkdwn, parseSlackCommandBody, parseSlackEventBody, postMessage, postMessageInThread, resolveEffectiveAgent, revokeSlackToken, sendResponseUrlMessage, setBotTokenForTeam, setWorkspaceDefaultAgent, storeWorkspaceInstallation, streamAgentResponse, updateConnectionMetadata, verifySlackRequest };
@@ -1,6 +1,6 @@
1
1
  import { clearWorkspaceConnectionCache, computeWorkspaceConnectionId, createConnectSession, deleteWorkspaceInstallation, findWorkspaceConnectionByTeamId, getConnectionAccessToken, getSlackIntegrationId, getSlackNango, getWorkspaceDefaultAgentFromNango, listWorkspaceInstallations, setWorkspaceDefaultAgent, storeWorkspaceInstallation, updateConnectionMetadata } from "./nango.js";
2
2
  import { getAgentConfigSources, resolveEffectiveAgent } from "./agent-resolution.js";
3
- import { ToolApprovalButtonValueSchema, buildConversationResponseBlocks, buildFollowUpButton, buildToolApprovalBlocks, buildToolApprovalDoneBlocks, buildToolApprovalExpiredBlocks, createAlreadyLinkedMessage, createContextBlock, createErrorMessage, createJwtLinkMessage, createNotLinkedMessage, createStatusMessage, createUnlinkSuccessMessage, createUpdatedHelpMessage } from "./blocks/index.js";
3
+ import { ToolApprovalButtonValueSchema, buildConversationResponseBlocks, buildFollowUpButton, buildToolApprovalBlocks, buildToolApprovalDoneBlocks, buildToolApprovalExpiredBlocks, createAlreadyLinkedMessage, createContextBlock, createCreateInkeepAccountMessage, createErrorMessage, createJwtLinkMessage, createNotLinkedMessage, createStatusMessage, createUnlinkSuccessMessage, createUpdatedHelpMessage } from "./blocks/index.js";
4
4
  import { checkUserIsChannelMember, getSlackChannelInfo, getSlackChannels, getSlackClient, getSlackTeamInfo, getSlackUserInfo, postMessage, postMessageInThread, revokeSlackToken } from "./client.js";
5
5
  import { SlackErrorType, checkIfBotThread, classifyError, extractApiErrorMessage, fetchAgentsForProject, fetchProjectsForTenant, findCachedUserMapping, generateSlackConversationId, getChannelAgentConfig, getThreadContext, getUserFriendlyErrorMessage, getWorkspaceDefaultAgent, markdownToMrkdwn, sendResponseUrlMessage } from "./events/utils.js";
6
6
  import { buildAgentSelectorModal, buildFollowUpModal, buildMessageShortcutModal } from "./modals.js";
@@ -13,4 +13,4 @@ import "./events/index.js";
13
13
  import { parseSlackCommandBody, parseSlackEventBody, verifySlackRequest } from "./security.js";
14
14
  import { getBotTokenForTeam, setBotTokenForTeam } from "./workspace-tokens.js";
15
15
 
16
- export { SlackErrorType, ToolApprovalButtonValueSchema, buildAgentSelectorModal, buildConversationResponseBlocks, buildFollowUpButton, buildFollowUpModal, buildMessageShortcutModal, buildToolApprovalBlocks, buildToolApprovalDoneBlocks, buildToolApprovalExpiredBlocks, checkIfBotThread, checkUserIsChannelMember, classifyError, clearWorkspaceConnectionCache, computeWorkspaceConnectionId, createAlreadyLinkedMessage, createConnectSession, createContextBlock, createErrorMessage, createJwtLinkMessage, createNotLinkedMessage, createStatusMessage, createUnlinkSuccessMessage, createUpdatedHelpMessage, deleteWorkspaceInstallation, extractApiErrorMessage, fetchAgentsForProject, fetchProjectsForTenant, findCachedUserMapping, findWorkspaceConnectionByTeamId, generateSlackConversationId, getAgentConfigSources, getBotTokenForTeam, getChannelAgentConfig, getConnectionAccessToken, getSlackChannelInfo, getSlackChannels, getSlackClient, getSlackIntegrationId, getSlackNango, getSlackTeamInfo, getSlackUserInfo, getThreadContext, getUserFriendlyErrorMessage, getWorkspaceDefaultAgent, getWorkspaceDefaultAgentFromNango, handleAgentPickerCommand, handleAppMention, handleCommand, handleFollowUpSubmission, handleHelpCommand, handleLinkCommand, handleMessageShortcut, handleModalSubmission, handleOpenAgentSelectorModal, handleOpenFollowUpModal, handleQuestionCommand, handleStatusCommand, handleToolApproval, handleUnlinkCommand, listWorkspaceInstallations, markdownToMrkdwn, parseSlackCommandBody, parseSlackEventBody, postMessage, postMessageInThread, resolveEffectiveAgent, revokeSlackToken, sendResponseUrlMessage, setBotTokenForTeam, setWorkspaceDefaultAgent, storeWorkspaceInstallation, streamAgentResponse, updateConnectionMetadata, verifySlackRequest };
16
+ export { SlackErrorType, ToolApprovalButtonValueSchema, buildAgentSelectorModal, buildConversationResponseBlocks, buildFollowUpButton, buildFollowUpModal, buildMessageShortcutModal, buildToolApprovalBlocks, buildToolApprovalDoneBlocks, buildToolApprovalExpiredBlocks, checkIfBotThread, checkUserIsChannelMember, classifyError, clearWorkspaceConnectionCache, computeWorkspaceConnectionId, createAlreadyLinkedMessage, createConnectSession, createContextBlock, createCreateInkeepAccountMessage, createErrorMessage, createJwtLinkMessage, createNotLinkedMessage, createStatusMessage, createUnlinkSuccessMessage, createUpdatedHelpMessage, deleteWorkspaceInstallation, extractApiErrorMessage, fetchAgentsForProject, fetchProjectsForTenant, findCachedUserMapping, findWorkspaceConnectionByTeamId, generateSlackConversationId, getAgentConfigSources, getBotTokenForTeam, getChannelAgentConfig, getConnectionAccessToken, getSlackChannelInfo, getSlackChannels, getSlackClient, getSlackIntegrationId, getSlackNango, getSlackTeamInfo, getSlackUserInfo, getThreadContext, getUserFriendlyErrorMessage, getWorkspaceDefaultAgent, getWorkspaceDefaultAgentFromNango, handleAgentPickerCommand, handleAppMention, handleCommand, handleFollowUpSubmission, handleHelpCommand, handleLinkCommand, handleMessageShortcut, handleModalSubmission, handleOpenAgentSelectorModal, handleOpenFollowUpModal, handleQuestionCommand, handleStatusCommand, handleToolApproval, handleUnlinkCommand, listWorkspaceInstallations, markdownToMrkdwn, parseSlackCommandBody, parseSlackEventBody, postMessage, postMessageInThread, resolveEffectiveAgent, revokeSlackToken, sendResponseUrlMessage, setBotTokenForTeam, setWorkspaceDefaultAgent, storeWorkspaceInstallation, streamAgentResponse, updateConnectionMetadata, verifySlackRequest };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@inkeep/agents-work-apps",
3
- "version": "0.0.0-dev-20260220231539",
3
+ "version": "0.0.0-dev-20260221002805",
4
4
  "description": "First party integrations for Inkeep Agents",
5
5
  "type": "module",
6
6
  "license": "SEE LICENSE IN LICENSE.md",
@@ -33,7 +33,7 @@
33
33
  "jose": "^6.1.0",
34
34
  "minimatch": "^10.1.1",
35
35
  "slack-block-builder": "^2.8.0",
36
- "@inkeep/agents-core": "0.0.0-dev-20260220231539"
36
+ "@inkeep/agents-core": "0.0.0-dev-20260221002805"
37
37
  },
38
38
  "peerDependencies": {
39
39
  "@hono/zod-openapi": "^1.1.5",