@inkeep/agents-work-apps 0.0.0-dev-20260204182014 → 0.0.0-dev-20260204210021

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (68) hide show
  1. package/dist/db/index.d.ts +1 -2
  2. package/dist/db/index.js +1 -2
  3. package/dist/db/runDbClient.d.ts +2 -2
  4. package/dist/env.d.ts +2 -24
  5. package/dist/env.js +1 -12
  6. package/dist/github/routes/setup.d.ts +2 -2
  7. package/dist/github/routes/tokenExchange.d.ts +2 -2
  8. package/package.json +2 -10
  9. package/dist/db/manageDbClient.d.ts +0 -7
  10. package/dist/db/manageDbClient.js +0 -16
  11. package/dist/slack/index.d.ts +0 -19
  12. package/dist/slack/index.js +0 -29
  13. package/dist/slack/middleware/permissions.d.ts +0 -16
  14. package/dist/slack/middleware/permissions.js +0 -49
  15. package/dist/slack/routes/events.d.ts +0 -10
  16. package/dist/slack/routes/events.js +0 -319
  17. package/dist/slack/routes/index.d.ts +0 -11
  18. package/dist/slack/routes/index.js +0 -64
  19. package/dist/slack/routes/internal.d.ts +0 -10
  20. package/dist/slack/routes/internal.js +0 -107
  21. package/dist/slack/routes/oauth.d.ts +0 -12
  22. package/dist/slack/routes/oauth.js +0 -218
  23. package/dist/slack/routes/resources.d.ts +0 -10
  24. package/dist/slack/routes/resources.js +0 -163
  25. package/dist/slack/routes/users.d.ts +0 -15
  26. package/dist/slack/routes/users.js +0 -430
  27. package/dist/slack/routes/workspaces.d.ts +0 -10
  28. package/dist/slack/routes/workspaces.js +0 -828
  29. package/dist/slack/routes.d.ts +0 -7
  30. package/dist/slack/routes.js +0 -12
  31. package/dist/slack/services/agent-resolution.d.ts +0 -49
  32. package/dist/slack/services/agent-resolution.js +0 -135
  33. package/dist/slack/services/api-client.d.ts +0 -161
  34. package/dist/slack/services/api-client.js +0 -248
  35. package/dist/slack/services/auth/index.d.ts +0 -61
  36. package/dist/slack/services/auth/index.js +0 -164
  37. package/dist/slack/services/blocks/index.d.ts +0 -60
  38. package/dist/slack/services/blocks/index.js +0 -143
  39. package/dist/slack/services/client.d.ts +0 -78
  40. package/dist/slack/services/client.js +0 -152
  41. package/dist/slack/services/commands/index.d.ts +0 -15
  42. package/dist/slack/services/commands/index.js +0 -556
  43. package/dist/slack/services/events/app-mention.d.ts +0 -41
  44. package/dist/slack/services/events/app-mention.js +0 -212
  45. package/dist/slack/services/events/block-actions.d.ts +0 -47
  46. package/dist/slack/services/events/block-actions.js +0 -287
  47. package/dist/slack/services/events/index.d.ts +0 -6
  48. package/dist/slack/services/events/index.js +0 -7
  49. package/dist/slack/services/events/modal-submission.d.ts +0 -12
  50. package/dist/slack/services/events/modal-submission.js +0 -279
  51. package/dist/slack/services/events/streaming.d.ts +0 -27
  52. package/dist/slack/services/events/streaming.js +0 -285
  53. package/dist/slack/services/events/utils.d.ts +0 -129
  54. package/dist/slack/services/events/utils.js +0 -315
  55. package/dist/slack/services/index.d.ts +0 -18
  56. package/dist/slack/services/index.js +0 -18
  57. package/dist/slack/services/modals.d.ts +0 -67
  58. package/dist/slack/services/modals.js +0 -203
  59. package/dist/slack/services/nango.d.ts +0 -82
  60. package/dist/slack/services/nango.js +0 -326
  61. package/dist/slack/services/security.d.ts +0 -35
  62. package/dist/slack/services/security.js +0 -65
  63. package/dist/slack/services/types.d.ts +0 -26
  64. package/dist/slack/services/types.js +0 -1
  65. package/dist/slack/services/workspace-tokens.d.ts +0 -37
  66. package/dist/slack/services/workspace-tokens.js +0 -39
  67. package/dist/slack/types.d.ts +0 -10
  68. package/dist/slack/types.js +0 -1
@@ -1,164 +0,0 @@
1
- import { env } from "../../../env.js";
2
- import { getLogger } from "../../../logger.js";
3
- import runDbClient_default from "../../../db/runDbClient.js";
4
- import { findWorkAppSlackUserMapping, parseSSEResponse, signSlackUserToken, verifySlackUserToken } from "@inkeep/agents-core";
5
-
6
- //#region src/slack/services/auth/index.ts
7
- /**
8
- * Slack JWT Authentication Service
9
- *
10
- * Provides JWT-based authentication for Slack integrations to call Inkeep APIs.
11
- * This is Slack's dedicated auth service - isolated from other auth mechanisms.
12
- *
13
- * Flow:
14
- * 1. Slack user links account via /inkeep link → user mapping saved in DB
15
- * 2. When Slack needs to call APIs, we look up the inkeepUserId from the mapping
16
- * 3. Sign a short-lived JWT with the user's identity and Slack context
17
- * 4. Use the JWT to call manage/run APIs
18
- *
19
- * This approach:
20
- * - Doesn't require storing API keys in Nango metadata
21
- * - Uses the linked user's permissions
22
- * - Provides audit trail of who triggered the action
23
- * - Tokens expire in 5 minutes for security
24
- */
25
- const logger = getLogger("slack-jwt-auth");
26
- const DEFAULT_CLIENT_ID = "work-apps-slack";
27
- var SlackJwtAuthError = class extends Error {
28
- constructor(message, code) {
29
- super(message);
30
- this.code = code;
31
- this.name = "SlackJwtAuthError";
32
- }
33
- };
34
- /**
35
- * Get a JWT token for a Slack user to call Inkeep APIs.
36
- *
37
- * Looks up the user's linked Inkeep account and generates a short-lived JWT.
38
- */
39
- async function getSlackUserJwt(context, tenantId) {
40
- const userMapping = await findWorkAppSlackUserMapping(runDbClient_default)(tenantId, context.slackUserId, context.slackTeamId, DEFAULT_CLIENT_ID);
41
- if (!userMapping) throw new SlackJwtAuthError("Slack account not linked. Use /inkeep link to connect your account.", "NOT_LINKED");
42
- const token = await signSlackUserToken({
43
- inkeepUserId: userMapping.inkeepUserId,
44
- tenantId,
45
- slackTeamId: context.slackTeamId,
46
- slackUserId: context.slackUserId,
47
- slackEnterpriseId: context.slackEnterpriseId,
48
- slackEmail: userMapping.slackEmail || void 0
49
- });
50
- logger.debug({
51
- slackUserId: context.slackUserId,
52
- slackTeamId: context.slackTeamId,
53
- inkeepUserId: userMapping.inkeepUserId
54
- }, "Generated Slack JWT for API calls");
55
- return {
56
- token,
57
- inkeepUserId: userMapping.inkeepUserId,
58
- tenantId
59
- };
60
- }
61
- /**
62
- * Verify a Slack JWT token and extract the payload.
63
- */
64
- async function verifySlackJwt(token) {
65
- const result = await verifySlackUserToken(token);
66
- if (!result.valid || !result.payload) throw new SlackJwtAuthError(result.error || "Invalid token", "TOKEN_INVALID");
67
- return result.payload;
68
- }
69
- /**
70
- * Execute an agent using Slack JWT authentication.
71
- *
72
- * This is the unified way to call agents from Slack - uses JWT, not API keys.
73
- */
74
- async function executeAgentWithSlackJwt(params) {
75
- const { jwt, projectId, agentId, message, options = {} } = params;
76
- const apiBaseUrl = env.INKEEP_AGENTS_API_URL || "http://localhost:3002";
77
- logger.debug({
78
- projectId,
79
- agentId,
80
- stream: options.stream
81
- }, "Executing agent with Slack JWT");
82
- const response = await fetch(`${apiBaseUrl}/run/api/chat`, {
83
- method: "POST",
84
- headers: {
85
- "Content-Type": "application/json",
86
- Authorization: `Bearer ${jwt}`,
87
- "x-inkeep-project-id": projectId,
88
- "x-inkeep-agent-id": agentId
89
- },
90
- body: JSON.stringify({
91
- messages: [{
92
- role: "user",
93
- content: message
94
- }],
95
- stream: options.stream ?? false,
96
- ...options.conversationId && { conversationId: options.conversationId }
97
- })
98
- });
99
- if (!response.ok) {
100
- const errorBody = await response.text().catch(() => "Unknown error");
101
- logger.error({
102
- status: response.status,
103
- errorBody,
104
- projectId,
105
- agentId
106
- }, "Agent execution failed");
107
- if (response.status === 401) throw new SlackJwtAuthError("Authentication failed. Please re-link your Slack account.", "TOKEN_EXPIRED");
108
- throw new SlackJwtAuthError(`Agent execution failed: ${response.status}`, "EXECUTION_FAILED");
109
- }
110
- if ((response.headers.get("content-type") || "").includes("text/event-stream")) {
111
- const result$1 = parseSSEResponse(await response.text());
112
- if (result$1.error) throw new SlackJwtAuthError(result$1.error, "EXECUTION_FAILED");
113
- return { content: result$1.text || "No response from agent" };
114
- }
115
- const result = await response.json();
116
- return {
117
- content: result.choices?.[0]?.message?.content || result.message?.content || "No response from agent",
118
- conversationId: result.conversationId
119
- };
120
- }
121
- /**
122
- * Stream agent response with Slack JWT authentication.
123
- *
124
- * Returns a readable stream of SSE events for real-time streaming to Slack.
125
- */
126
- async function streamAgentWithSlackJwt(params) {
127
- const { jwt, projectId, agentId, message } = params;
128
- const apiBaseUrl = env.INKEEP_AGENTS_API_URL || "http://localhost:3002";
129
- logger.debug({
130
- projectId,
131
- agentId
132
- }, "Streaming agent with Slack JWT");
133
- const response = await fetch(`${apiBaseUrl}/run/api/chat`, {
134
- method: "POST",
135
- headers: {
136
- "Content-Type": "application/json",
137
- Authorization: `Bearer ${jwt}`,
138
- "x-inkeep-project-id": projectId,
139
- "x-inkeep-agent-id": agentId
140
- },
141
- body: JSON.stringify({
142
- messages: [{
143
- role: "user",
144
- content: message
145
- }],
146
- stream: true
147
- })
148
- });
149
- if (!response.ok) {
150
- const errorBody = await response.text().catch(() => "Unknown error");
151
- logger.error({
152
- status: response.status,
153
- errorBody,
154
- projectId,
155
- agentId
156
- }, "Agent stream failed");
157
- if (response.status === 401) throw new SlackJwtAuthError("Authentication failed. Please re-link your Slack account.", "TOKEN_EXPIRED");
158
- throw new SlackJwtAuthError(`Agent stream failed: ${response.status}`, "EXECUTION_FAILED");
159
- }
160
- return response;
161
- }
162
-
163
- //#endregion
164
- export { SlackJwtAuthError, executeAgentWithSlackJwt, getSlackUserJwt, streamAgentWithSlackJwt, verifySlackJwt };
@@ -1,60 +0,0 @@
1
- import * as slack_block_builder0 from "slack-block-builder";
2
-
3
- //#region src/slack/services/blocks/index.d.ts
4
- declare function createLinkMessage(dashboardUrl: string): Readonly<slack_block_builder0.SlackMessageDto>;
5
- declare function createAlreadyConnectedMessage(email: string, linkedAt: string, dashboardUrl: string): Readonly<slack_block_builder0.SlackMessageDto>;
6
- declare function createStatusConnectedMessage(userName: string, email: string, linkedAt: string, dashboardUrl: string): Readonly<slack_block_builder0.SlackMessageDto>;
7
- declare function createStatusNotConnectedMessage(userName: string, teamDomain: string, _dashboardUrl: string): Readonly<slack_block_builder0.SlackMessageDto>;
8
- declare function createLogoutSuccessMessage(): Readonly<slack_block_builder0.SlackMessageDto>;
9
- declare function createProjectListMessage(email: string, projects: Array<{
10
- id: string;
11
- name: string | null;
12
- description: string | null;
13
- }>, dashboardUrl: string, totalCount: number): Readonly<slack_block_builder0.SlackMessageDto>;
14
- declare function createNoProjectsMessage(email: string, dashboardUrl: string): Readonly<slack_block_builder0.SlackMessageDto>;
15
- declare function createHelpMessage(): Readonly<slack_block_builder0.SlackMessageDto>;
16
- declare function createErrorMessage(message: string): Readonly<slack_block_builder0.SlackMessageDto>;
17
- declare function createAgentResponseMessage(agentName: string, response: string, channelId?: string): Readonly<slack_block_builder0.SlackMessageDto>;
18
- declare function createSettingsMessage(currentConfig: {
19
- agentId: string;
20
- agentName?: string;
21
- source: string;
22
- } | null, dashboardUrl: string): Readonly<slack_block_builder0.SlackMessageDto>;
23
- declare function createSettingsUpdatedMessage(agentName: string): Readonly<slack_block_builder0.SlackMessageDto>;
24
- declare function createAgentListMessage(agents: Array<{
25
- id: string;
26
- name: string | null;
27
- projectName: string | null;
28
- }>, dashboardUrl: string): Readonly<slack_block_builder0.SlackMessageDto>;
29
- declare function createNoDefaultAgentMessage(dashboardUrl: string): Readonly<slack_block_builder0.SlackMessageDto>;
30
- declare function createThinkingMessage(agentName: string): Readonly<slack_block_builder0.SlackMessageDto>;
31
- declare function createUpdatedHelpMessage(): Readonly<slack_block_builder0.SlackMessageDto>;
32
- declare function createDeviceCodeMessage(code: string, linkUrl: string, expiresInMinutes: number): Readonly<slack_block_builder0.SlackMessageDto>;
33
- declare function createLinkSuccessMessage(email: string, dashboardUrl: string): Readonly<slack_block_builder0.SlackMessageDto>;
34
- declare function createLinkExpiredMessage(_dashboardUrl: string): Readonly<slack_block_builder0.SlackMessageDto>;
35
- declare function createAlreadyLinkedMessage(email: string, linkedAt: string, dashboardUrl: string): Readonly<slack_block_builder0.SlackMessageDto>;
36
- declare function createUnlinkSuccessMessage(): Readonly<slack_block_builder0.SlackMessageDto>;
37
- declare function createNotLinkedMessage(): Readonly<slack_block_builder0.SlackMessageDto>;
38
- interface AgentConfigSources {
39
- channelConfig: {
40
- agentName?: string;
41
- agentId: string;
42
- } | null;
43
- workspaceConfig: {
44
- agentName?: string;
45
- agentId: string;
46
- } | null;
47
- userConfig: {
48
- agentName?: string;
49
- agentId: string;
50
- } | null;
51
- effective: {
52
- agentName?: string;
53
- agentId: string;
54
- source: string;
55
- } | null;
56
- }
57
- declare function createStatusMessage(email: string, linkedAt: string, dashboardUrl: string, agentConfigs: AgentConfigSources): Readonly<slack_block_builder0.SlackMessageDto>;
58
- declare function createJwtLinkMessage(linkUrl: string, expiresInMinutes: number): Readonly<slack_block_builder0.SlackMessageDto>;
59
- //#endregion
60
- export { AgentConfigSources, createAgentListMessage, createAgentResponseMessage, createAlreadyConnectedMessage, createAlreadyLinkedMessage, createDeviceCodeMessage, createErrorMessage, createHelpMessage, createJwtLinkMessage, createLinkExpiredMessage, createLinkMessage, createLinkSuccessMessage, createLogoutSuccessMessage, createNoDefaultAgentMessage, createNoProjectsMessage, createNotLinkedMessage, createProjectListMessage, createSettingsMessage, createSettingsUpdatedMessage, createStatusConnectedMessage, createStatusMessage, createStatusNotConnectedMessage, createThinkingMessage, createUnlinkSuccessMessage, createUpdatedHelpMessage };
@@ -1,143 +0,0 @@
1
- import { Blocks, Elements, Md, Message } from "slack-block-builder";
2
-
3
- //#region src/slack/services/blocks/index.ts
4
- function createLinkMessage(dashboardUrl) {
5
- return Message().blocks(Blocks.Section().text(Md.bold("Connect your Inkeep account") + "\n\nTo link your Slack account to Inkeep:\n1. Click the button below to open the dashboard\n2. Sign in to your Inkeep account\n3. Click \"Connect Slack Account\"\n4. Authorize the connection"), Blocks.Actions().elements(Elements.Button().text("🔗 Go to Inkeep Dashboard").url(dashboardUrl).actionId("open_dashboard").primary())).buildToObject();
6
- }
7
- function createAlreadyConnectedMessage(email, linkedAt, dashboardUrl) {
8
- return Message().blocks(Blocks.Section().text(Md.bold("✅ Already Connected!") + "\n\nYour Slack account is linked to Inkeep.\n\n" + Md.bold("Inkeep Account:") + ` ${email}\n` + Md.bold("Linked:") + ` ${new Date(linkedAt).toLocaleDateString()}`), Blocks.Actions().elements(Elements.Button().text("📊 View Dashboard").url(dashboardUrl).actionId("view_dashboard"))).buildToObject();
9
- }
10
- function createStatusConnectedMessage(userName, email, linkedAt, dashboardUrl) {
11
- return Message().blocks(Blocks.Section().text(Md.bold("✅ Connected to Inkeep") + `\n\n${Md.bold("Slack User:")} @${userName}\n${Md.bold("Inkeep Account:")} ${email}\n${Md.bold("Linked:")} ${new Date(linkedAt).toLocaleDateString()}\n\nYou can now use Inkeep from Slack!`), Blocks.Actions().elements(Elements.Button().text("📊 View Dashboard").url(dashboardUrl).actionId("view_dashboard"))).buildToObject();
12
- }
13
- function createStatusNotConnectedMessage(userName, teamDomain, _dashboardUrl) {
14
- return Message().blocks(Blocks.Section().text(Md.bold("❌ Not Linked") + `\n\n${Md.bold("Slack User:")} @${userName}\n${Md.bold("Team:")} ${teamDomain}\n\nRun \`/inkeep link\` to connect your Inkeep account.`)).buildToObject();
15
- }
16
- function createLogoutSuccessMessage() {
17
- return Message().blocks(Blocks.Section().text(Md.bold("✅ Logged out successfully") + "\n\nYour Slack account has been unlinked from Inkeep.\n\nUse `/inkeep link` to reconnect anytime.")).buildToObject();
18
- }
19
- function createProjectListMessage(email, projects, dashboardUrl, totalCount) {
20
- const projectList = projects.slice(0, 10).map((p) => `• ${Md.bold(p.name || p.id)} (\`${p.id}\`)${p.description ? `\n ${Md.italic(p.description)}` : ""}`).join("\n");
21
- const moreText = totalCount > 10 ? `\n\n...and ${totalCount - 10} more` : "";
22
- return Message().blocks(Blocks.Section().text(Md.bold("📋 Your Inkeep Projects") + `\n\n${Md.bold("Account:")} ${email}\n\n` + projectList + moreText), Blocks.Actions().elements(Elements.Button().text("📊 View All in Dashboard").url(`${dashboardUrl}/projects`).actionId("view_projects"))).buildToObject();
23
- }
24
- function createNoProjectsMessage(email, dashboardUrl) {
25
- return Message().blocks(Blocks.Section().text(Md.bold("📋 Your Inkeep Projects") + `\n\n${Md.bold("Account:")} ${email}\n\n` + Md.italic("No projects found. Create one in the dashboard!")), Blocks.Actions().elements(Elements.Button().text("➕ Create Project").url(`${dashboardUrl}/projects`).actionId("create_project").primary())).buildToObject();
26
- }
27
- function createHelpMessage() {
28
- return Message().blocks(Blocks.Section().text(`${Md.bold("Inkeep Slack Commands")}\n\nAvailable commands:`), Blocks.Section().text("• `/inkeep link` - Connect your Slack account to Inkeep\n• `/inkeep status` - Check your connection status\n• `/inkeep list` - List your Inkeep projects\n• `/inkeep logout` - Unlink your account\n• `/inkeep help` - Show this help message")).buildToObject();
29
- }
30
- function createErrorMessage(message) {
31
- return Message().blocks(Blocks.Section().text(`❌ ${message}`)).buildToObject();
32
- }
33
- function createAgentResponseMessage(agentName, response, channelId) {
34
- if (channelId) {
35
- const truncatedResponse = response.length > 1800 ? `${response.slice(0, 1800)}...` : response;
36
- return Message().blocks(Blocks.Section().text(response), Blocks.Context().elements(`Powered by ${Md.bold(agentName)} via Inkeep`), Blocks.Actions().elements(Elements.Button().text("📢 Share to Channel").actionId("share_to_channel").value(JSON.stringify({
37
- channelId,
38
- text: truncatedResponse,
39
- agentName
40
- })))).buildToObject();
41
- }
42
- return Message().blocks(Blocks.Section().text(response), Blocks.Context().elements(`Powered by ${Md.bold(agentName)} via Inkeep`)).buildToObject();
43
- }
44
- function createSettingsMessage(currentConfig, dashboardUrl) {
45
- let configText;
46
- if (currentConfig) {
47
- const sourceLabel = currentConfig.source === "user" ? "Your personal default" : currentConfig.source === "channel" ? "Channel default (admin-set)" : "Workspace default (admin-set)";
48
- configText = `${Md.bold("/inkeep commands use:")} ${currentConfig.agentName || currentConfig.agentId}\n${Md.bold("Source:")} ${sourceLabel}`;
49
- if (currentConfig.source !== "user") configText += `\n\n${Md.italic("You can set your own personal default below.")}`;
50
- } else configText = `${Md.bold("No default agent configured")}\n\nSet your personal default to use /inkeep commands.`;
51
- return Message().blocks(Blocks.Section().text(`${Md.bold("⚙️ Your /inkeep Settings")}\n\n${configText}`), Blocks.Divider(), Blocks.Section().text(`${Md.bold("Set Your Personal Default:")}\n• \`/inkeep settings set "agent name"\` - Set your default for /inkeep
52
- • \`/inkeep list\` - See available agents
53
-
54
- ${Md.italic("Note: @Inkeep mentions always use the workspace agent set by admin.")}`), Blocks.Actions().elements(Elements.Button().text("📊 View Dashboard").url(dashboardUrl).actionId("view_dashboard"))).buildToObject();
55
- }
56
- function createSettingsUpdatedMessage(agentName) {
57
- return Message().blocks(Blocks.Section().text(`${Md.bold("✅ Settings Updated")}\n\nYour personal default agent is now ${Md.bold(agentName)}.\n\nYou can now use \`/inkeep [question]\` to ask questions directly!`)).buildToObject();
58
- }
59
- function createAgentListMessage(agents, dashboardUrl) {
60
- const agentList = agents.slice(0, 15).map((a) => `• ${Md.bold(a.name || a.id)} ${a.projectName ? `(${Md.italic(a.projectName)})` : ""}`).join("\n");
61
- const moreText = agents.length > 15 ? `\n\n...and ${agents.length - 15} more` : "";
62
- return Message().blocks(Blocks.Section().text(`${Md.bold("🤖 Available Agents")}\n\n` + agentList + moreText + `
63
-
64
- ${Md.bold("Usage:")}\n• \`/inkeep run "agent name" question\` - Run a specific agent
65
- • \`/inkeep settings set "agent name"\` - Set your default agent`), Blocks.Actions().elements(Elements.Button().text("📊 View All in Dashboard").url(dashboardUrl).actionId("view_agents"))).buildToObject();
66
- }
67
- function createNoDefaultAgentMessage(dashboardUrl) {
68
- return Message().blocks(Blocks.Section().text(`${Md.bold("⚠️ No Default Agent Configured")}\n\nTo use \`/inkeep [question]\`, you need to set a default agent first.
69
-
70
- 1. Use \`/inkeep list\` to see available agents
71
- 2. Use \`/inkeep settings set [agent-name]\` to set your default`), Blocks.Actions().elements(Elements.Button().text("🔗 Configure in Dashboard").url(dashboardUrl).actionId("configure_default").primary())).buildToObject();
72
- }
73
- function createThinkingMessage(agentName) {
74
- return Message().blocks(Blocks.Section().text(`🤔 ${Md.italic(`${agentName} is thinking...`)}`)).buildToObject();
75
- }
76
- function createUpdatedHelpMessage() {
77
- return Message().blocks(Blocks.Section().text(`${Md.bold("Inkeep Slack Commands")}`), Blocks.Section().text(`${Md.bold("Two Ways to Ask Questions:")}\n\n${Md.bold("@Inkeep [question]")} - Public in channels\n• Creates a thread visible to everyone
78
- • Uses the workspace agent (set by admin)
79
-
80
- ${Md.bold("/inkeep [question]")} - Private to you\n• Only you see the response
81
- • Uses YOUR personal default agent
82
- • Set your own with \`/inkeep settings set "agent name"\``), Blocks.Divider(), Blocks.Section().text(`${Md.bold("Commands:")}\n• \`/inkeep run "agent name" [question]\` - Ask a specific agent
83
- • \`/inkeep settings\` - View/set your personal default agent
84
- • \`/inkeep list\` - List available agents
85
- • \`/inkeep status\` - Check connection and agent settings
86
- • \`/inkeep link\` / \`/inkeep unlink\` - Manage account connection
87
- • \`/inkeep help\` - Show this help message`)).buildToObject();
88
- }
89
- function createDeviceCodeMessage(code, linkUrl, expiresInMinutes) {
90
- return Message().blocks(Blocks.Section().text(`${Md.bold("🔗 Link your Inkeep account")}\n\nTo connect your Slack and Inkeep accounts:`), Blocks.Section().text(`${Md.bold("Your code:")} \`${code}\`\n\n1. Click the button below (or copy the code)
91
- 2. Sign in to Inkeep (or create an account)
92
- 3. The link will complete automatically!`), Blocks.Actions().elements(Elements.Button().text("🔗 Link Account").url(linkUrl).actionId("link_account").primary()), Blocks.Context().elements(`${Md.emoji("clock")} This code expires in ${expiresInMinutes} minutes`)).buildToObject();
93
- }
94
- function createLinkSuccessMessage(email, dashboardUrl) {
95
- return Message().blocks(Blocks.Section().text(Md.bold("✅ Account Linked!") + "\n\nYour Slack account is now connected to Inkeep.\n\n" + Md.bold("Inkeep Account:") + ` ${email}`), Blocks.Divider(), Blocks.Section().text(`${Md.bold("🚀 Two Ways to Ask Questions:")}\n\n${Md.bold("@Inkeep")} - Ask publicly in channels (uses workspace agent)\n${Md.bold("/inkeep")} - Ask privately (uses YOUR personal agent)\n\n• \`/inkeep list\` - See available agents
96
- • \`/inkeep settings set "agent name"\` - Set your personal default
97
- • \`/inkeep help\` - See all commands`), Blocks.Actions().elements(Elements.Button().text("📊 Open Dashboard").url(dashboardUrl).actionId("open_dashboard"))).buildToObject();
98
- }
99
- function createLinkExpiredMessage(_dashboardUrl) {
100
- return Message().blocks(Blocks.Section().text(Md.bold("⏰ Code Expired") + "\n\nYour link code has expired. Please run `/inkeep link` again to get a new code."), Blocks.Actions().elements(Elements.Button().text("🔗 Get New Code").actionId("get_new_code"))).buildToObject();
101
- }
102
- function createAlreadyLinkedMessage(email, linkedAt, dashboardUrl) {
103
- return Message().blocks(Blocks.Section().text(Md.bold("✅ Already Linked!") + "\n\nYour Slack account is already connected to Inkeep.\n\n" + Md.bold("Inkeep Account:") + ` ${email}\n` + Md.bold("Linked:") + ` ${new Date(linkedAt).toLocaleDateString()}\n\nTo switch accounts, first run \`/inkeep unlink\``), Blocks.Actions().elements(Elements.Button().text("📊 Open Dashboard").url(dashboardUrl).actionId("open_dashboard"))).buildToObject();
104
- }
105
- function createUnlinkSuccessMessage() {
106
- return Message().blocks(Blocks.Section().text(Md.bold("✅ Account Unlinked") + "\n\nYour Slack account has been disconnected from Inkeep.\n\nTo use Inkeep agents again, run `/inkeep link` to connect a new account.")).buildToObject();
107
- }
108
- function createNotLinkedMessage() {
109
- return Message().blocks(Blocks.Section().text(Md.bold("❌ Not Linked") + "\n\nYour Slack account is not connected to Inkeep.\n\nRun `/inkeep link` to connect your account.")).buildToObject();
110
- }
111
- function createStatusMessage(email, linkedAt, dashboardUrl, agentConfigs) {
112
- const { workspaceConfig, userConfig, effective } = agentConfigs;
113
- let agentSection = `\n\n${Md.bold("Agent Configuration")}\n\n`;
114
- if (workspaceConfig) {
115
- agentSection += `${Md.bold("@Inkeep bot uses:")} ${workspaceConfig.agentName || workspaceConfig.agentId}\n`;
116
- agentSection += `${Md.italic("(Set by admin in dashboard)")}\n\n`;
117
- } else {
118
- agentSection += `${Md.bold("@Inkeep bot:")} Not configured\n`;
119
- agentSection += `${Md.italic("(Admin can set this in the dashboard)")}\n\n`;
120
- }
121
- if (userConfig) {
122
- agentSection += `${Md.bold("/inkeep commands use:")} ${userConfig.agentName || userConfig.agentId}\n`;
123
- agentSection += `${Md.italic("(Your personal default)")}\n`;
124
- } else if (effective) {
125
- agentSection += `${Md.bold("/inkeep commands use:")} ${effective.agentName || effective.agentId}\n`;
126
- agentSection += `${Md.italic("(Workspace default - set your own with /inkeep settings)")}\n`;
127
- } else {
128
- agentSection += `${Md.bold("/inkeep commands:")} No default configured\n`;
129
- agentSection += `${Md.italic("Use /inkeep settings set \"agent name\" to set your default")}\n`;
130
- }
131
- return Message().blocks(Blocks.Section().text(Md.bold("✅ Connected to Inkeep") + `\n\n${Md.bold("Inkeep Account:")} ${email}\n${Md.bold("Linked:")} ${new Date(linkedAt).toLocaleDateString()}` + agentSection), Blocks.Divider(), Blocks.Section().text(`${Md.bold("Tip:")}\n• \`@Inkeep\` uses the admin-configured agent for public responses in channels
132
- • \`/inkeep\` commands can use your personal default (private, only visible to you)`), Blocks.Actions().elements(Elements.Button().text("📊 Open Dashboard").url(dashboardUrl).actionId("open_dashboard"))).buildToObject();
133
- }
134
- function createJwtLinkMessage(linkUrl, expiresInMinutes) {
135
- return Message().blocks(Blocks.Section().text(`${Md.bold("🔗 Link your Inkeep account")}\n\nConnect your Slack and Inkeep accounts to unlock AI-powered assistance:`), Blocks.Section().text(`${Md.bold("What you can do after linking:")}\n• Ask questions with \`/inkeep [question]\` or \`@Inkeep\`
136
- • Get personalized responses from AI agents
137
- • Set your own default agent preferences`), Blocks.Section().text(`${Md.bold("How to link:")}\n1. Click the button below
138
- 2. Sign in to Inkeep (or create an account)
139
- 3. Done! Come back here and start asking questions`), Blocks.Actions().elements(Elements.Button().text("🔗 Link Account").url(linkUrl).actionId("link_account").primary()), Blocks.Context().elements(`${Md.emoji("clock")} This link expires in ${expiresInMinutes} minutes`)).buildToObject();
140
- }
141
-
142
- //#endregion
143
- export { createAgentListMessage, createAgentResponseMessage, createAlreadyConnectedMessage, createAlreadyLinkedMessage, createDeviceCodeMessage, createErrorMessage, createHelpMessage, createJwtLinkMessage, createLinkExpiredMessage, createLinkMessage, createLinkSuccessMessage, createLogoutSuccessMessage, createNoDefaultAgentMessage, createNoProjectsMessage, createNotLinkedMessage, createProjectListMessage, createSettingsMessage, createSettingsUpdatedMessage, createStatusConnectedMessage, createStatusMessage, createStatusNotConnectedMessage, createThinkingMessage, createUnlinkSuccessMessage, createUpdatedHelpMessage };
@@ -1,78 +0,0 @@
1
- import * as _slack_web_api0 from "@slack/web-api";
2
- import { WebClient } from "@slack/web-api";
3
-
4
- //#region src/slack/services/client.d.ts
5
-
6
- /**
7
- * Create a Slack WebClient with the provided bot token.
8
- *
9
- * @param token - Bot OAuth token from Nango connection
10
- * @returns Configured Slack WebClient instance
11
- */
12
- declare function getSlackClient(token: string): WebClient;
13
- /**
14
- * Fetch user profile information from Slack.
15
- *
16
- * @param client - Authenticated Slack WebClient
17
- * @param userId - Slack user ID (e.g., U0ABC123)
18
- * @returns User profile object, or null if not found
19
- */
20
- declare function getSlackUserInfo(client: WebClient, userId: string): Promise<{
21
- id: string | undefined;
22
- name: string | undefined;
23
- realName: string | undefined;
24
- displayName: string | undefined;
25
- email: string | undefined;
26
- isAdmin: boolean | undefined;
27
- isOwner: boolean | undefined;
28
- avatar: string | undefined;
29
- } | null>;
30
- /**
31
- * Fetch workspace (team) information from Slack.
32
- *
33
- * @param client - Authenticated Slack WebClient
34
- * @returns Team info object, or null if not available
35
- */
36
- declare function getSlackTeamInfo(client: WebClient): Promise<{
37
- id: string | undefined;
38
- name: string | undefined;
39
- domain: string | undefined;
40
- icon: string | undefined;
41
- url: string | undefined;
42
- } | null>;
43
- /**
44
- * List public channels in the workspace.
45
- *
46
- * @param client - Authenticated Slack WebClient
47
- * @param limit - Maximum number of channels to return (default 20)
48
- * @returns Array of channel objects with id, name, and member count
49
- */
50
- declare function getSlackChannels(client: WebClient, limit?: number): Promise<{
51
- id: string | undefined;
52
- name: string | undefined;
53
- memberCount: number | undefined;
54
- isBotMember: boolean | undefined;
55
- }[]>;
56
- /**
57
- * Post a message to a Slack channel.
58
- *
59
- * @param client - Authenticated Slack WebClient
60
- * @param channel - Channel ID to post to
61
- * @param text - Fallback text for notifications
62
- * @param blocks - Optional Block Kit blocks for rich formatting
63
- * @returns Slack API response with message timestamp
64
- */
65
- declare function postMessage(client: WebClient, channel: string, text: string, blocks?: unknown[]): Promise<_slack_web_api0.ChatPostMessageResponse>;
66
- /**
67
- * Post a message as a reply in a thread.
68
- *
69
- * @param client - Authenticated Slack WebClient
70
- * @param channel - Channel ID containing the thread
71
- * @param threadTs - Thread parent message timestamp
72
- * @param text - Fallback text for notifications
73
- * @param blocks - Optional Block Kit blocks for rich formatting
74
- * @returns Slack API response with message timestamp
75
- */
76
- declare function postMessageInThread(client: WebClient, channel: string, threadTs: string, text: string, blocks?: unknown[]): Promise<_slack_web_api0.ChatPostMessageResponse>;
77
- //#endregion
78
- export { getSlackChannels, getSlackClient, getSlackTeamInfo, getSlackUserInfo, postMessage, postMessageInThread };
@@ -1,152 +0,0 @@
1
- import { getLogger } from "../../logger.js";
2
- import { WebClient } from "@slack/web-api";
3
-
4
- //#region src/slack/services/client.ts
5
- /**
6
- * Slack Web API Client Utilities
7
- *
8
- * Wrapper functions for common Slack Web API operations.
9
- * Tokens are fetched from Nango at runtime and passed to these functions.
10
- */
11
- const logger = getLogger("slack-client");
12
- /**
13
- * Create a Slack WebClient with the provided bot token.
14
- *
15
- * @param token - Bot OAuth token from Nango connection
16
- * @returns Configured Slack WebClient instance
17
- */
18
- function getSlackClient(token) {
19
- return new WebClient(token);
20
- }
21
- /**
22
- * Fetch user profile information from Slack.
23
- *
24
- * @param client - Authenticated Slack WebClient
25
- * @param userId - Slack user ID (e.g., U0ABC123)
26
- * @returns User profile object, or null if not found
27
- */
28
- async function getSlackUserInfo(client, userId) {
29
- try {
30
- const result = await client.users.info({ user: userId });
31
- if (result.ok && result.user) return {
32
- id: result.user.id,
33
- name: result.user.name,
34
- realName: result.user.real_name,
35
- displayName: result.user.profile?.display_name,
36
- email: result.user.profile?.email,
37
- isAdmin: result.user.is_admin,
38
- isOwner: result.user.is_owner,
39
- avatar: result.user.profile?.image_72
40
- };
41
- return null;
42
- } catch (error) {
43
- logger.error({
44
- error,
45
- userId
46
- }, "Failed to fetch Slack user info");
47
- return null;
48
- }
49
- }
50
- /**
51
- * Fetch workspace (team) information from Slack.
52
- *
53
- * @param client - Authenticated Slack WebClient
54
- * @returns Team info object, or null if not available
55
- */
56
- async function getSlackTeamInfo(client) {
57
- try {
58
- const result = await client.team.info();
59
- if (result.ok && result.team) return {
60
- id: result.team.id,
61
- name: result.team.name,
62
- domain: result.team.domain,
63
- icon: result.team.icon?.image_68,
64
- url: result.team.url
65
- };
66
- return null;
67
- } catch (error) {
68
- logger.error({ error }, "Failed to fetch Slack team info");
69
- return null;
70
- }
71
- }
72
- /**
73
- * List public channels in the workspace.
74
- *
75
- * @param client - Authenticated Slack WebClient
76
- * @param limit - Maximum number of channels to return (default 20)
77
- * @returns Array of channel objects with id, name, and member count
78
- */
79
- async function getSlackChannels(client, limit = 20) {
80
- try {
81
- const result = await client.conversations.list({
82
- types: "public_channel",
83
- limit
84
- });
85
- if (result.ok && result.channels) return result.channels.map((ch) => ({
86
- id: ch.id,
87
- name: ch.name,
88
- memberCount: ch.num_members,
89
- isBotMember: ch.is_member
90
- }));
91
- return [];
92
- } catch (error) {
93
- logger.error({ error }, "Failed to fetch Slack channels");
94
- return [];
95
- }
96
- }
97
- /**
98
- * Post a message to a Slack channel.
99
- *
100
- * @param client - Authenticated Slack WebClient
101
- * @param channel - Channel ID to post to
102
- * @param text - Fallback text for notifications
103
- * @param blocks - Optional Block Kit blocks for rich formatting
104
- * @returns Slack API response with message timestamp
105
- */
106
- async function postMessage(client, channel, text, blocks) {
107
- try {
108
- const args = {
109
- channel,
110
- text
111
- };
112
- if (blocks) args.blocks = blocks;
113
- return await client.chat.postMessage(args);
114
- } catch (error) {
115
- logger.error({
116
- error,
117
- channel
118
- }, "Failed to post Slack message");
119
- throw error;
120
- }
121
- }
122
- /**
123
- * Post a message as a reply in a thread.
124
- *
125
- * @param client - Authenticated Slack WebClient
126
- * @param channel - Channel ID containing the thread
127
- * @param threadTs - Thread parent message timestamp
128
- * @param text - Fallback text for notifications
129
- * @param blocks - Optional Block Kit blocks for rich formatting
130
- * @returns Slack API response with message timestamp
131
- */
132
- async function postMessageInThread(client, channel, threadTs, text, blocks) {
133
- try {
134
- const args = {
135
- channel,
136
- text,
137
- thread_ts: threadTs
138
- };
139
- if (blocks) args.blocks = blocks;
140
- return await client.chat.postMessage(args);
141
- } catch (error) {
142
- logger.error({
143
- error,
144
- channel,
145
- threadTs
146
- }, "Failed to post Slack message in thread");
147
- throw error;
148
- }
149
- }
150
-
151
- //#endregion
152
- export { getSlackChannels, getSlackClient, getSlackTeamInfo, getSlackUserInfo, postMessage, postMessageInThread };
@@ -1,15 +0,0 @@
1
- import { SlackCommandPayload, SlackCommandResponse } from "../types.js";
2
-
3
- //#region src/slack/services/commands/index.d.ts
4
- declare function handleLinkCommand(payload: SlackCommandPayload, dashboardUrl: string, tenantId: string): Promise<SlackCommandResponse>;
5
- declare function handleUnlinkCommand(payload: SlackCommandPayload, tenantId: string): Promise<SlackCommandResponse>;
6
- declare function handleStatusCommand(payload: SlackCommandPayload, dashboardUrl: string, tenantId: string): Promise<SlackCommandResponse>;
7
- declare function handleLogoutCommand(payload: SlackCommandPayload, tenantId: string): Promise<SlackCommandResponse>;
8
- declare function handleHelpCommand(): Promise<SlackCommandResponse>;
9
- declare function handleQuestionCommand(payload: SlackCommandPayload, question: string, _dashboardUrl: string, tenantId: string): Promise<SlackCommandResponse>;
10
- declare function handleRunCommand(payload: SlackCommandPayload, agentIdentifier: string, question: string, _dashboardUrl: string, tenantId: string): Promise<SlackCommandResponse>;
11
- declare function handleSettingsCommand(payload: SlackCommandPayload, subCommand: string | undefined, agentIdentifier: string | undefined, dashboardUrl: string, _tenantId: string): Promise<SlackCommandResponse>;
12
- declare function handleAgentListCommand(payload: SlackCommandPayload, dashboardUrl: string, _tenantId: string): Promise<SlackCommandResponse>;
13
- declare function handleCommand(payload: SlackCommandPayload): Promise<SlackCommandResponse>;
14
- //#endregion
15
- export { handleAgentListCommand, handleCommand, handleHelpCommand, handleLinkCommand, handleLogoutCommand, handleQuestionCommand, handleRunCommand, handleSettingsCommand, handleStatusCommand, handleUnlinkCommand };