@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 +2 -2
- package/dist/github/index.d.ts +3 -3
- package/dist/github/mcp/auth.d.ts +2 -2
- package/dist/github/mcp/index.d.ts +2 -2
- package/dist/github/routes/setup.d.ts +2 -2
- package/dist/github/routes/tokenExchange.d.ts +2 -2
- package/dist/github/routes/webhooks.d.ts +2 -2
- package/dist/slack/routes/users.js +12 -10
- package/dist/slack/routes/workspaces.js +85 -1
- package/dist/slack/services/blocks/index.d.ts +2 -1
- package/dist/slack/services/blocks/index.js +4 -1
- package/dist/slack/services/commands/index.d.ts +1 -1
- package/dist/slack/services/commands/index.js +98 -4
- package/dist/slack/services/events/utils.d.ts +1 -1
- package/dist/slack/services/index.d.ts +2 -2
- package/dist/slack/services/index.js +2 -2
- package/package.json +2 -2
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: "
|
|
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;
|
package/dist/github/index.d.ts
CHANGED
|
@@ -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
|
|
7
|
+
import * as hono_types6 from "hono/types";
|
|
8
8
|
|
|
9
9
|
//#region src/github/index.d.ts
|
|
10
|
-
declare function createGithubRoutes(): Hono<
|
|
11
|
-
declare const githubRoutes: Hono<
|
|
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
|
|
1
|
+
import * as hono1 from "hono";
|
|
2
2
|
|
|
3
3
|
//#region src/github/mcp/auth.d.ts
|
|
4
|
-
declare const githubMcpAuth: () =>
|
|
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
|
|
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
|
-
},
|
|
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
|
|
2
|
+
import * as hono_types0 from "hono/types";
|
|
3
3
|
|
|
4
4
|
//#region src/github/routes/setup.d.ts
|
|
5
|
-
declare const app: Hono<
|
|
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
|
|
2
|
+
import * as hono_types2 from "hono/types";
|
|
3
3
|
|
|
4
4
|
//#region src/github/routes/tokenExchange.d.ts
|
|
5
|
-
declare const app: Hono<
|
|
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
|
|
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<
|
|
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)
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
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
|
-
|
|
166
|
-
|
|
167
|
-
|
|
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
|
-
|
|
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-
|
|
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-
|
|
36
|
+
"@inkeep/agents-core": "0.0.0-dev-20260221002805"
|
|
37
37
|
},
|
|
38
38
|
"peerDependencies": {
|
|
39
39
|
"@hono/zod-openapi": "^1.1.5",
|