@inkeep/agents-work-apps 0.65.1 → 0.65.2

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.
@@ -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 hono2 from "hono";
2
2
 
3
3
  //#region src/github/mcp/auth.d.ts
4
- declare const githubMcpAuth: () => hono0.MiddlewareHandler<{
4
+ declare const githubMcpAuth: () => hono2.MiddlewareHandler<{
5
5
  Variables: {
6
6
  toolId: string;
7
7
  tenantId: string;
@@ -1,5 +1,5 @@
1
1
  import { Hono } from "hono";
2
- import * as hono_types7 from "hono/types";
2
+ import * as hono_types10 from "hono/types";
3
3
 
4
4
  //#region src/github/mcp/index.d.ts
5
5
  declare const app: Hono<{
@@ -8,6 +8,6 @@ declare const app: Hono<{
8
8
  tenantId: string;
9
9
  projectId: string;
10
10
  };
11
- }, hono_types7.BlankSchema, "/">;
11
+ }, hono_types10.BlankSchema, "/">;
12
12
  //#endregion
13
13
  export { app as default };
@@ -76,8 +76,8 @@ declare const ChangedFileSchema: z.ZodObject<{
76
76
  path: z.ZodString;
77
77
  status: z.ZodEnum<{
78
78
  added: "added";
79
- removed: "removed";
80
79
  modified: "modified";
80
+ removed: "removed";
81
81
  renamed: "renamed";
82
82
  copied: "copied";
83
83
  changed: "changed";
@@ -1,7 +1,7 @@
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/routes/setup.d.ts
5
- declare const app: Hono<hono_types3.BlankEnv, hono_types3.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_types5 from "hono/types";
2
+ import * as hono_types3 from "hono/types";
3
3
 
4
4
  //#region src/github/routes/tokenExchange.d.ts
5
- declare const app: Hono<hono_types5.BlankEnv, hono_types5.BlankSchema, "/">;
5
+ declare const app: Hono<hono_types3.BlankEnv, hono_types3.BlankSchema, "/">;
6
6
  //#endregion
7
7
  export { app as default };
@@ -1,5 +1,5 @@
1
1
  import { Hono } from "hono";
2
- import * as hono_types9 from "hono/types";
2
+ import * as hono_types1 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_types9.BlankEnv, hono_types9.BlankSchema, "/">;
10
+ declare const app: Hono<hono_types1.BlankEnv, hono_types1.BlankSchema, "/">;
11
11
  //#endregion
12
12
  export { WebhookVerificationResult, app as default, verifyWebhookSignature };
@@ -8,6 +8,7 @@ import { handleMessageShortcut, handleOpenAgentSelectorModal, handleToolApproval
8
8
  import { handleDirectMessage } from "./services/events/direct-message.js";
9
9
  import { handleModalSubmission } from "./services/events/modal-submission.js";
10
10
  import "./services/events/index.js";
11
+ import { cleanupWorkspaceInstallation } from "./services/workspace-cleanup.js";
11
12
  import "./services/index.js";
12
13
  import { flushTraces } from "@inkeep/agents-core";
13
14
 
@@ -131,6 +132,55 @@ async function dispatchSlackEvent(eventType, payload, options, span) {
131
132
  errorStack
132
133
  }, "Failed to handle direct message (outer catch)");
133
134
  }).finally(() => flushTraces()));
135
+ } else if (innerEventType === "app_uninstalled" && teamId) {
136
+ outcome = "handled";
137
+ span.setAttribute(SLACK_SPAN_KEYS.OUTCOME, outcome);
138
+ span.updateName("slack.webhook app_uninstalled");
139
+ logger.info({ teamId }, "Handling event: app_uninstalled");
140
+ registerBackgroundWork(cleanupWorkspaceInstallation({
141
+ teamId,
142
+ skipTokenRevocation: true
143
+ }).then((result) => {
144
+ logger.info({
145
+ teamId,
146
+ success: result.success,
147
+ dbCleaned: result.dbCleaned
148
+ }, "app_uninstalled cleanup completed");
149
+ }).catch((err) => {
150
+ const errorMessage = err instanceof Error ? err.message : String(err);
151
+ logger.error({
152
+ errorMessage,
153
+ teamId
154
+ }, "Failed to handle app_uninstalled");
155
+ }).finally(() => flushTraces()));
156
+ } else if (innerEventType === "tokens_revoked" && teamId) {
157
+ outcome = "handled";
158
+ span.setAttribute(SLACK_SPAN_KEYS.OUTCOME, outcome);
159
+ span.updateName("slack.webhook tokens_revoked");
160
+ const tokensEvent = payload.event;
161
+ const revokedBotTokens = tokensEvent?.tokens?.bot ?? [];
162
+ const revokedOauthTokens = tokensEvent?.tokens?.oauth ?? [];
163
+ logger.info({
164
+ teamId,
165
+ revokedBotCount: revokedBotTokens.length,
166
+ revokedOauthCount: revokedOauthTokens.length
167
+ }, "Handling event: tokens_revoked");
168
+ if (revokedBotTokens.length > 0) registerBackgroundWork(cleanupWorkspaceInstallation({
169
+ teamId,
170
+ skipTokenRevocation: true
171
+ }).then((result) => {
172
+ logger.info({
173
+ teamId,
174
+ success: result.success,
175
+ dbCleaned: result.dbCleaned
176
+ }, "tokens_revoked (bot) cleanup completed");
177
+ }).catch((err) => {
178
+ const errorMessage = err instanceof Error ? err.message : String(err);
179
+ logger.error({
180
+ errorMessage,
181
+ teamId
182
+ }, "Failed to handle tokens_revoked (bot)");
183
+ }).finally(() => flushTraces()));
134
184
  } else {
135
185
  outcome = "ignored_unknown_event";
136
186
  span.setAttribute(SLACK_SPAN_KEYS.OUTCOME, outcome);
@@ -1,7 +1,7 @@
1
- import * as hono0 from "hono";
1
+ import * as hono1 from "hono";
2
2
 
3
3
  //#region src/slack/mcp/auth.d.ts
4
- declare const slackMcpAuth: () => hono0.MiddlewareHandler<{
4
+ declare const slackMcpAuth: () => hono1.MiddlewareHandler<{
5
5
  Variables: {
6
6
  toolId: string;
7
7
  tenantId: string;
@@ -1,5 +1,5 @@
1
1
  import { Hono } from "hono";
2
- import * as hono_types8 from "hono/types";
2
+ import * as hono_types5 from "hono/types";
3
3
 
4
4
  //#region src/slack/mcp/index.d.ts
5
5
  interface ChannelInfo {
@@ -18,6 +18,6 @@ declare const app: Hono<{
18
18
  tenantId: string;
19
19
  projectId: string;
20
20
  };
21
- }, hono_types8.BlankSchema, "/">;
21
+ }, hono_types5.BlankSchema, "/">;
22
22
  //#endregion
23
23
  export { ChannelInfo, app as default, pruneStaleChannelIds };
@@ -1,5 +1,5 @@
1
1
  import { ManageAppVariables } from "../types.js";
2
- import * as hono1 from "hono";
2
+ import * as hono0 from "hono";
3
3
 
4
4
  //#region src/slack/middleware/permissions.d.ts
5
5
  /**
@@ -14,7 +14,7 @@ declare const requireWorkspaceAdmin: <Env extends {
14
14
  Variables: ManageAppVariables;
15
15
  } = {
16
16
  Variables: ManageAppVariables;
17
- }>() => hono1.MiddlewareHandler<Env, string, {}, Response>;
17
+ }>() => hono0.MiddlewareHandler<Env, string, {}, Response>;
18
18
  /**
19
19
  * Middleware that requires either:
20
20
  * 1. Org admin/owner role (can modify any channel), OR
@@ -26,6 +26,6 @@ declare const requireChannelMemberOrAdmin: <Env extends {
26
26
  Variables: ManageAppVariables;
27
27
  } = {
28
28
  Variables: ManageAppVariables;
29
- }>() => hono1.MiddlewareHandler<Env, string, {}, Response>;
29
+ }>() => hono0.MiddlewareHandler<Env, string, {}, Response>;
30
30
  //#endregion
31
31
  export { isOrgAdmin, requireChannelMemberOrAdmin, requireWorkspaceAdmin };
@@ -1,12 +1,13 @@
1
1
  import { getLogger } from "../../logger.js";
2
2
  import runDbClient_default from "../../db/runDbClient.js";
3
- import { clearWorkspaceConnectionCache, computeWorkspaceConnectionId, deleteWorkspaceInstallation, findWorkspaceConnectionByTeamId, listWorkspaceInstallations, setWorkspaceDefaultAgent } from "../services/nango.js";
3
+ import { findWorkspaceConnectionByTeamId, listWorkspaceInstallations, setWorkspaceDefaultAgent } from "../services/nango.js";
4
4
  import { lookupAgentName } from "../services/agent-resolution.js";
5
- import { getBotMemberChannels, getSlackChannels, getSlackClient, revokeSlackToken } from "../services/client.js";
5
+ import { getBotMemberChannels, getSlackChannels, getSlackClient } from "../services/client.js";
6
+ import { cleanupWorkspaceInstallation } from "../services/workspace-cleanup.js";
6
7
  import "../services/index.js";
7
8
  import { requireChannelMemberOrAdmin, requireWorkspaceAdmin } from "../middleware/permissions.js";
8
9
  import { OpenAPIHono, z } from "@hono/zod-openapi";
9
- import { WorkAppSlackAgentConfigRequestSchema, deleteAllSlackMcpToolAccessConfigsByTenant, deleteAllWorkAppSlackChannelAgentConfigsByTeam, deleteAllWorkAppSlackUserMappingsByTeam, deleteWorkAppSlackChannelAgentConfig, deleteWorkAppSlackWorkspaceByNangoConnectionId, findWorkAppSlackChannelAgentConfig, findWorkAppSlackWorkspaceByTeamId, listWorkAppSlackChannelAgentConfigsByTeam, listWorkAppSlackUserMappingsByTeam, updateWorkAppSlackWorkspace, upsertWorkAppSlackChannelAgentConfig } from "@inkeep/agents-core";
10
+ import { WorkAppSlackAgentConfigRequestSchema, deleteWorkAppSlackChannelAgentConfig, findWorkAppSlackChannelAgentConfig, findWorkAppSlackWorkspaceByTeamId, listWorkAppSlackChannelAgentConfigsByTeam, listWorkAppSlackUserMappingsByTeam, updateWorkAppSlackWorkspace, upsertWorkAppSlackChannelAgentConfig } from "@inkeep/agents-core";
10
11
  import { createProtectedRoute, inheritedWorkAppsAuth } from "@inkeep/agents-core/middleware";
11
12
 
12
13
  //#region src/slack/routes/workspaces.ts
@@ -347,47 +348,21 @@ app.openapi(createProtectedRoute({
347
348
  }), async (c) => {
348
349
  const { teamId: workspaceIdentifier } = c.req.valid("param");
349
350
  let teamId;
350
- let connectionId;
351
351
  try {
352
352
  if (workspaceIdentifier.includes(":")) {
353
- connectionId = workspaceIdentifier;
354
353
  const teamMatch = workspaceIdentifier.match(/T:([A-Z0-9]+)/);
355
354
  if (!teamMatch) return c.json({ error: "Invalid connectionId format" }, 400);
356
355
  teamId = teamMatch[1];
357
- } else {
358
- teamId = workspaceIdentifier;
359
- connectionId = computeWorkspaceConnectionId({
360
- teamId,
361
- enterpriseId: void 0
362
- });
363
- }
356
+ } else teamId = workspaceIdentifier;
364
357
  const workspace = await findWorkspaceConnectionByTeamId(teamId);
365
358
  if (!workspace) return c.json({ error: "Workspace not found" }, 404);
366
- if (workspace.botToken) if (await revokeSlackToken(workspace.botToken)) logger.info({ teamId }, "Revoked Slack bot token");
367
- else logger.warn({ teamId }, "Failed to revoke Slack bot token, continuing with uninstall");
368
- const tenantId = workspace.tenantId;
369
- const deletedChannelConfigs = await deleteAllWorkAppSlackChannelAgentConfigsByTeam(runDbClient_default)(tenantId, teamId);
370
- if (deletedChannelConfigs > 0) logger.info({
371
- teamId,
372
- deletedChannelConfigs
373
- }, "Deleted channel configs for uninstalled workspace");
374
- const deletedMappings = await deleteAllWorkAppSlackUserMappingsByTeam(runDbClient_default)(tenantId, teamId);
375
- if (deletedMappings > 0) logger.info({
359
+ if (!verifyTenantOwnership(c, workspace.tenantId)) return c.json({ error: "Access denied" }, 403);
360
+ const result = await cleanupWorkspaceInstallation({ teamId });
361
+ if (!result.success) logger.error({
376
362
  teamId,
377
- deletedMappings
378
- }, "Deleted user mappings for uninstalled workspace");
379
- const deletedMcpConfigs = await deleteAllSlackMcpToolAccessConfigsByTenant(runDbClient_default)(tenantId);
380
- if (deletedMcpConfigs > 0) logger.info({
381
- teamId,
382
- deletedMcpConfigs
383
- }, "Deleted MCP tool access configs for uninstalled workspace");
384
- if (await deleteWorkAppSlackWorkspaceByNangoConnectionId(runDbClient_default)(connectionId)) logger.info({ connectionId }, "Deleted workspace from database");
385
- if (!await deleteWorkspaceInstallation(connectionId)) logger.error({ connectionId }, "deleteWorkspaceInstallation returned false (DB already cleaned up)");
386
- clearWorkspaceConnectionCache(teamId);
387
- logger.info({
388
- connectionId,
389
- teamId
390
- }, "Deleted workspace installation and cleared cache");
363
+ result
364
+ }, "Workspace uninstall partially failed");
365
+ logger.info({ teamId }, "Workspace uninstalled via API");
391
366
  return c.json({ success: true });
392
367
  } catch (error) {
393
368
  logger.error({
@@ -9,10 +9,10 @@ import { AgentOption } from "../modals.js";
9
9
  * Called on every @mention and /inkeep command — caching avoids redundant DB queries.
10
10
  */
11
11
  declare function findCachedUserMapping(tenantId: string, slackUserId: string, teamId: string, clientId?: string): Promise<{
12
+ slackUserId: string;
12
13
  id: string;
13
14
  createdAt: string;
14
15
  updatedAt: string;
15
- slackUserId: string;
16
16
  tenantId: string;
17
17
  clientId: string;
18
18
  slackTeamId: string;
@@ -14,5 +14,6 @@ import { PublicExecutionParams, executeAgentPublicly } from "./events/execution.
14
14
  import { handleModalSubmission } from "./events/modal-submission.js";
15
15
  import "./events/index.js";
16
16
  import { parseSlackCommandBody, parseSlackEventBody, verifySlackRequest } from "./security.js";
17
+ import { WorkspaceCleanupResult, cleanupWorkspaceInstallation } from "./workspace-cleanup.js";
17
18
  import { getBotTokenForTeam, setBotTokenForTeam } from "./workspace-tokens.js";
18
- export { AgentConfigSources, AgentOption, AgentResolutionParams, BuildAgentSelectorModalParams, BuildMessageShortcutModalParams, ContextBlockParams, DefaultAgentConfig, InlineSelectorMetadata, ModalMetadata, PublicExecutionParams, ResolvedAgentConfig, SlackCommandPayload, SlackCommandResponse, SlackErrorType, SlackWorkspaceConnection, StreamResult, ToolApprovalButtonValue, ToolApprovalButtonValueSchema, WorkspaceInstallData, buildAgentSelectorModal, buildCitationsBlock, buildDataArtifactBlocks, buildDataComponentBlocks, buildMessageShortcutModal, buildSummaryBreadcrumbBlock, buildToolApprovalBlocks, buildToolApprovalDoneBlocks, buildToolApprovalExpiredBlocks, buildToolOutputErrorBlock, checkIfBotThread, checkUserIsChannelMember, classifyError, clearWorkspaceConnectionCache, computeWorkspaceConnectionId, createAlreadyLinkedMessage, createConnectSession, createContextBlock, createContextBlockFromText, createCreateInkeepAccountMessage, createErrorMessage, createNotLinkedMessage, createSmartLinkMessage, createStatusMessage, createUnlinkSuccessMessage, createUpdatedHelpMessage, deleteWorkspaceInstallation, executeAgentPublicly, extractApiErrorMessage, fetchAgentsForProject, fetchProjectsForTenant, findCachedUserMapping, findWorkspaceConnectionByTeamId, generateSlackConversationId, getAgentConfigSources, getBotMemberChannels, getBotTokenForTeam, getChannelAgentConfig, getConnectionAccessToken, getSlackChannelInfo, getSlackChannels, getSlackClient, getSlackIntegrationId, getSlackNango, getSlackTeamInfo, getSlackUserByEmail, getSlackUserInfo, getSlackUsers, getThreadContext, getUserFriendlyErrorMessage, getWorkspaceDefaultAgent, getWorkspaceDefaultAgentFromNango, handleAgentPickerCommand, handleAppMention, handleCommand, handleDirectMessage, handleHelpCommand, handleLinkCommand, handleMessageShortcut, handleModalSubmission, handleOpenAgentSelectorModal, handleQuestionCommand, handleStatusCommand, handleToolApproval, handleUnlinkCommand, listWorkspaceInstallations, lookupAgentName, lookupProjectName, markdownToMrkdwn, openDmConversation, parseSlackCommandBody, parseSlackEventBody, postMessage, postMessageInThread, resolveEffectiveAgent, revokeSlackToken, sendResponseUrlMessage, setBotTokenForTeam, setWorkspaceDefaultAgent, storeWorkspaceInstallation, streamAgentResponse, updateConnectionMetadata, validateBotChannelMembership, verifySlackRequest };
19
+ export { AgentConfigSources, AgentOption, AgentResolutionParams, BuildAgentSelectorModalParams, BuildMessageShortcutModalParams, ContextBlockParams, DefaultAgentConfig, InlineSelectorMetadata, ModalMetadata, PublicExecutionParams, ResolvedAgentConfig, SlackCommandPayload, SlackCommandResponse, SlackErrorType, SlackWorkspaceConnection, StreamResult, ToolApprovalButtonValue, ToolApprovalButtonValueSchema, WorkspaceCleanupResult, WorkspaceInstallData, buildAgentSelectorModal, buildCitationsBlock, buildDataArtifactBlocks, buildDataComponentBlocks, buildMessageShortcutModal, buildSummaryBreadcrumbBlock, buildToolApprovalBlocks, buildToolApprovalDoneBlocks, buildToolApprovalExpiredBlocks, buildToolOutputErrorBlock, checkIfBotThread, checkUserIsChannelMember, classifyError, cleanupWorkspaceInstallation, clearWorkspaceConnectionCache, computeWorkspaceConnectionId, createAlreadyLinkedMessage, createConnectSession, createContextBlock, createContextBlockFromText, createCreateInkeepAccountMessage, createErrorMessage, createNotLinkedMessage, createSmartLinkMessage, createStatusMessage, createUnlinkSuccessMessage, createUpdatedHelpMessage, deleteWorkspaceInstallation, executeAgentPublicly, extractApiErrorMessage, fetchAgentsForProject, fetchProjectsForTenant, findCachedUserMapping, findWorkspaceConnectionByTeamId, generateSlackConversationId, getAgentConfigSources, getBotMemberChannels, getBotTokenForTeam, getChannelAgentConfig, getConnectionAccessToken, getSlackChannelInfo, getSlackChannels, getSlackClient, getSlackIntegrationId, getSlackNango, getSlackTeamInfo, getSlackUserByEmail, getSlackUserInfo, getSlackUsers, getThreadContext, getUserFriendlyErrorMessage, getWorkspaceDefaultAgent, getWorkspaceDefaultAgentFromNango, handleAgentPickerCommand, handleAppMention, handleCommand, handleDirectMessage, handleHelpCommand, handleLinkCommand, handleMessageShortcut, handleModalSubmission, handleOpenAgentSelectorModal, handleQuestionCommand, handleStatusCommand, handleToolApproval, handleUnlinkCommand, listWorkspaceInstallations, lookupAgentName, lookupProjectName, markdownToMrkdwn, openDmConversation, parseSlackCommandBody, parseSlackEventBody, postMessage, postMessageInThread, resolveEffectiveAgent, revokeSlackToken, sendResponseUrlMessage, setBotTokenForTeam, setWorkspaceDefaultAgent, storeWorkspaceInstallation, streamAgentResponse, updateConnectionMetadata, validateBotChannelMembership, verifySlackRequest };
@@ -13,6 +13,7 @@ import { handleDirectMessage } from "./events/direct-message.js";
13
13
  import { handleModalSubmission } from "./events/modal-submission.js";
14
14
  import "./events/index.js";
15
15
  import { parseSlackCommandBody, parseSlackEventBody, verifySlackRequest } from "./security.js";
16
+ import { cleanupWorkspaceInstallation } from "./workspace-cleanup.js";
16
17
  import { getBotTokenForTeam, setBotTokenForTeam } from "./workspace-tokens.js";
17
18
 
18
- export { SlackErrorType, ToolApprovalButtonValueSchema, buildAgentSelectorModal, buildCitationsBlock, buildDataArtifactBlocks, buildDataComponentBlocks, buildMessageShortcutModal, buildSummaryBreadcrumbBlock, buildToolApprovalBlocks, buildToolApprovalDoneBlocks, buildToolApprovalExpiredBlocks, buildToolOutputErrorBlock, checkIfBotThread, checkUserIsChannelMember, classifyError, clearWorkspaceConnectionCache, computeWorkspaceConnectionId, createAlreadyLinkedMessage, createConnectSession, createContextBlock, createContextBlockFromText, createCreateInkeepAccountMessage, createErrorMessage, createNotLinkedMessage, createSmartLinkMessage, createStatusMessage, createUnlinkSuccessMessage, createUpdatedHelpMessage, deleteWorkspaceInstallation, executeAgentPublicly, extractApiErrorMessage, fetchAgentsForProject, fetchProjectsForTenant, findCachedUserMapping, findWorkspaceConnectionByTeamId, generateSlackConversationId, getAgentConfigSources, getBotMemberChannels, getBotTokenForTeam, getChannelAgentConfig, getConnectionAccessToken, getSlackChannelInfo, getSlackChannels, getSlackClient, getSlackIntegrationId, getSlackNango, getSlackTeamInfo, getSlackUserByEmail, getSlackUserInfo, getSlackUsers, getThreadContext, getUserFriendlyErrorMessage, getWorkspaceDefaultAgent, getWorkspaceDefaultAgentFromNango, handleAgentPickerCommand, handleAppMention, handleCommand, handleDirectMessage, handleHelpCommand, handleLinkCommand, handleMessageShortcut, handleModalSubmission, handleOpenAgentSelectorModal, handleQuestionCommand, handleStatusCommand, handleToolApproval, handleUnlinkCommand, listWorkspaceInstallations, lookupAgentName, lookupProjectName, markdownToMrkdwn, openDmConversation, parseSlackCommandBody, parseSlackEventBody, postMessage, postMessageInThread, resolveEffectiveAgent, revokeSlackToken, sendResponseUrlMessage, setBotTokenForTeam, setWorkspaceDefaultAgent, storeWorkspaceInstallation, streamAgentResponse, updateConnectionMetadata, validateBotChannelMembership, verifySlackRequest };
19
+ export { SlackErrorType, ToolApprovalButtonValueSchema, buildAgentSelectorModal, buildCitationsBlock, buildDataArtifactBlocks, buildDataComponentBlocks, buildMessageShortcutModal, buildSummaryBreadcrumbBlock, buildToolApprovalBlocks, buildToolApprovalDoneBlocks, buildToolApprovalExpiredBlocks, buildToolOutputErrorBlock, checkIfBotThread, checkUserIsChannelMember, classifyError, cleanupWorkspaceInstallation, clearWorkspaceConnectionCache, computeWorkspaceConnectionId, createAlreadyLinkedMessage, createConnectSession, createContextBlock, createContextBlockFromText, createCreateInkeepAccountMessage, createErrorMessage, createNotLinkedMessage, createSmartLinkMessage, createStatusMessage, createUnlinkSuccessMessage, createUpdatedHelpMessage, deleteWorkspaceInstallation, executeAgentPublicly, extractApiErrorMessage, fetchAgentsForProject, fetchProjectsForTenant, findCachedUserMapping, findWorkspaceConnectionByTeamId, generateSlackConversationId, getAgentConfigSources, getBotMemberChannels, getBotTokenForTeam, getChannelAgentConfig, getConnectionAccessToken, getSlackChannelInfo, getSlackChannels, getSlackClient, getSlackIntegrationId, getSlackNango, getSlackTeamInfo, getSlackUserByEmail, getSlackUserInfo, getSlackUsers, getThreadContext, getUserFriendlyErrorMessage, getWorkspaceDefaultAgent, getWorkspaceDefaultAgentFromNango, handleAgentPickerCommand, handleAppMention, handleCommand, handleDirectMessage, handleHelpCommand, handleLinkCommand, handleMessageShortcut, handleModalSubmission, handleOpenAgentSelectorModal, handleQuestionCommand, handleStatusCommand, handleToolApproval, handleUnlinkCommand, listWorkspaceInstallations, lookupAgentName, lookupProjectName, markdownToMrkdwn, openDmConversation, parseSlackCommandBody, parseSlackEventBody, postMessage, postMessageInThread, resolveEffectiveAgent, revokeSlackToken, sendResponseUrlMessage, setBotTokenForTeam, setWorkspaceDefaultAgent, storeWorkspaceInstallation, streamAgentResponse, updateConnectionMetadata, validateBotChannelMembership, verifySlackRequest };
@@ -0,0 +1,17 @@
1
+ //#region src/slack/services/workspace-cleanup.d.ts
2
+ interface WorkspaceCleanupResult {
3
+ success: boolean;
4
+ teamId: string;
5
+ tokenRevoked: boolean;
6
+ dbCleaned: boolean;
7
+ nangoCleaned: boolean;
8
+ }
9
+ declare function cleanupWorkspaceInstallation({
10
+ teamId,
11
+ skipTokenRevocation
12
+ }: {
13
+ teamId: string;
14
+ skipTokenRevocation?: boolean;
15
+ }): Promise<WorkspaceCleanupResult>;
16
+ //#endregion
17
+ export { WorkspaceCleanupResult, cleanupWorkspaceInstallation };
@@ -0,0 +1,82 @@
1
+ import { getLogger } from "../../logger.js";
2
+ import runDbClient_default from "../../db/runDbClient.js";
3
+ import { clearWorkspaceConnectionCache, deleteWorkspaceInstallation, findWorkspaceConnectionByTeamId } from "./nango.js";
4
+ import { revokeSlackToken } from "./client.js";
5
+ import "./index.js";
6
+ import { deleteAllSlackMcpToolAccessConfigsByTenant, deleteAllWorkAppSlackChannelAgentConfigsByTeam, deleteAllWorkAppSlackUserMappingsByTeam, deleteWorkAppSlackWorkspaceByNangoConnectionId } from "@inkeep/agents-core";
7
+
8
+ //#region src/slack/services/workspace-cleanup.ts
9
+ const logger = getLogger("slack-workspace-cleanup");
10
+ async function cleanupWorkspaceInstallation({ teamId, skipTokenRevocation = false }) {
11
+ const result = {
12
+ success: false,
13
+ teamId,
14
+ tokenRevoked: false,
15
+ dbCleaned: false,
16
+ nangoCleaned: false
17
+ };
18
+ const workspace = await findWorkspaceConnectionByTeamId(teamId);
19
+ if (!workspace) {
20
+ logger.warn({ teamId }, "No workspace found for cleanup");
21
+ clearWorkspaceConnectionCache(teamId);
22
+ result.success = true;
23
+ return result;
24
+ }
25
+ const { tenantId, botToken, connectionId } = workspace;
26
+ if (!skipTokenRevocation && botToken) {
27
+ result.tokenRevoked = await revokeSlackToken(botToken);
28
+ if (result.tokenRevoked) logger.info({ teamId }, "Revoked Slack bot token during cleanup");
29
+ else logger.warn({ teamId }, "Failed to revoke Slack bot token, continuing with cleanup");
30
+ }
31
+ const steps = [
32
+ {
33
+ name: "channel_configs",
34
+ run: () => deleteAllWorkAppSlackChannelAgentConfigsByTeam(runDbClient_default)(tenantId, teamId)
35
+ },
36
+ {
37
+ name: "user_mappings",
38
+ run: () => deleteAllWorkAppSlackUserMappingsByTeam(runDbClient_default)(tenantId, teamId)
39
+ },
40
+ {
41
+ name: "mcp_configs",
42
+ run: () => deleteAllSlackMcpToolAccessConfigsByTenant(runDbClient_default)(tenantId)
43
+ },
44
+ {
45
+ name: "workspace_row",
46
+ run: () => deleteWorkAppSlackWorkspaceByNangoConnectionId(runDbClient_default)(connectionId)
47
+ },
48
+ {
49
+ name: "nango_connection",
50
+ run: () => deleteWorkspaceInstallation(connectionId)
51
+ }
52
+ ];
53
+ const failures = [];
54
+ for (const step of steps) try {
55
+ await step.run();
56
+ } catch (error) {
57
+ failures.push(step.name);
58
+ logger.error({
59
+ error,
60
+ teamId,
61
+ connectionId,
62
+ step: step.name
63
+ }, "Cleanup step failed");
64
+ }
65
+ result.dbCleaned = !failures.some((f) => f !== "nango_connection");
66
+ result.nangoCleaned = !failures.includes("nango_connection");
67
+ clearWorkspaceConnectionCache(teamId);
68
+ result.success = failures.length === 0;
69
+ if (failures.length > 0) logger.error({
70
+ teamId,
71
+ connectionId,
72
+ failures
73
+ }, "Workspace cleanup completed with failures");
74
+ else logger.info({
75
+ teamId,
76
+ connectionId
77
+ }, "Workspace cleanup completed");
78
+ return result;
79
+ }
80
+
81
+ //#endregion
82
+ export { cleanupWorkspaceInstallation };
@@ -7,7 +7,6 @@ var oauth_config = {
7
7
  "app_mentions:read",
8
8
  "channels:history",
9
9
  "channels:read",
10
- "channels:join",
11
10
  "chat:write",
12
11
  "chat:write.public",
13
12
  "commands",
@@ -23,10 +22,7 @@ var oauth_config = {
23
22
  "mpim:write",
24
23
  "team:read",
25
24
  "users:read",
26
- "users:read.email",
27
- "search:read.public",
28
- "search:read.files",
29
- "search:read.users"
25
+ "users:read.email"
30
26
  ]
31
27
  }
32
28
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@inkeep/agents-work-apps",
3
- "version": "0.65.1",
3
+ "version": "0.65.2",
4
4
  "description": "First party integrations for Inkeep Agents",
5
5
  "type": "module",
6
6
  "license": "SEE LICENSE IN LICENSE.md",
@@ -35,7 +35,7 @@
35
35
  "minimatch": "^10.2.1",
36
36
  "oxfmt": "^0.42.0",
37
37
  "slack-block-builder": "^2.8.0",
38
- "@inkeep/agents-core": "0.65.1"
38
+ "@inkeep/agents-core": "0.65.2"
39
39
  },
40
40
  "peerDependencies": {
41
41
  "@hono/zod-openapi": "^1.1.5",