@chaaskit/server 0.1.0

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 (189) hide show
  1. package/dist/api/admin.js +438 -0
  2. package/dist/api/admin.js.map +1 -0
  3. package/dist/api/agents.js +21 -0
  4. package/dist/api/agents.js.map +1 -0
  5. package/dist/api/api-keys.js +122 -0
  6. package/dist/api/api-keys.js.map +1 -0
  7. package/dist/api/auth.js +399 -0
  8. package/dist/api/auth.js.map +1 -0
  9. package/dist/api/chat.js +900 -0
  10. package/dist/api/chat.js.map +1 -0
  11. package/dist/api/config.js +91 -0
  12. package/dist/api/config.js.map +1 -0
  13. package/dist/api/documents.js +237 -0
  14. package/dist/api/documents.js.map +1 -0
  15. package/dist/api/export.js +107 -0
  16. package/dist/api/export.js.map +1 -0
  17. package/dist/api/health.js +25 -0
  18. package/dist/api/health.js.map +1 -0
  19. package/dist/api/mcp-server.js +84 -0
  20. package/dist/api/mcp-server.js.map +1 -0
  21. package/dist/api/mcp.js +400 -0
  22. package/dist/api/mcp.js.map +1 -0
  23. package/dist/api/mentions.js +94 -0
  24. package/dist/api/mentions.js.map +1 -0
  25. package/dist/api/oauth.js +366 -0
  26. package/dist/api/oauth.js.map +1 -0
  27. package/dist/api/payments.js +473 -0
  28. package/dist/api/payments.js.map +1 -0
  29. package/dist/api/projects.js +301 -0
  30. package/dist/api/projects.js.map +1 -0
  31. package/dist/api/scheduled-prompts.js +617 -0
  32. package/dist/api/scheduled-prompts.js.map +1 -0
  33. package/dist/api/search.js +85 -0
  34. package/dist/api/search.js.map +1 -0
  35. package/dist/api/share.js +188 -0
  36. package/dist/api/share.js.map +1 -0
  37. package/dist/api/slack.js +468 -0
  38. package/dist/api/slack.js.map +1 -0
  39. package/dist/api/teams.js +693 -0
  40. package/dist/api/teams.js.map +1 -0
  41. package/dist/api/templates.js +134 -0
  42. package/dist/api/templates.js.map +1 -0
  43. package/dist/api/threads.js +323 -0
  44. package/dist/api/threads.js.map +1 -0
  45. package/dist/api/upload.js +57 -0
  46. package/dist/api/upload.js.map +1 -0
  47. package/dist/api/user.js +111 -0
  48. package/dist/api/user.js.map +1 -0
  49. package/dist/api/v1/openai.js +245 -0
  50. package/dist/api/v1/openai.js.map +1 -0
  51. package/dist/app.js +168 -0
  52. package/dist/app.js.map +1 -0
  53. package/dist/bin/cli.js +57 -0
  54. package/dist/bin/cli.js.map +1 -0
  55. package/dist/commands/db-sync.js +108 -0
  56. package/dist/commands/db-sync.js.map +1 -0
  57. package/dist/config/loader.js +374 -0
  58. package/dist/config/loader.js.map +1 -0
  59. package/dist/documents/extractors.js +136 -0
  60. package/dist/documents/extractors.js.map +1 -0
  61. package/dist/extensions/glob.js +53 -0
  62. package/dist/extensions/glob.js.map +1 -0
  63. package/dist/extensions/loader.js +72 -0
  64. package/dist/extensions/loader.js.map +1 -0
  65. package/dist/index.js +25 -0
  66. package/dist/index.js.map +1 -0
  67. package/dist/loaders/index.js +75 -0
  68. package/dist/loaders/index.js.map +1 -0
  69. package/dist/mcp/client.js +551 -0
  70. package/dist/mcp/client.js.map +1 -0
  71. package/dist/mcp/server.js +335 -0
  72. package/dist/mcp/server.js.map +1 -0
  73. package/dist/middleware/apiKeyAuth.js +136 -0
  74. package/dist/middleware/apiKeyAuth.js.map +1 -0
  75. package/dist/middleware/auth.js +192 -0
  76. package/dist/middleware/auth.js.map +1 -0
  77. package/dist/middleware/errorHandler.js +41 -0
  78. package/dist/middleware/errorHandler.js.map +1 -0
  79. package/dist/middleware/mcpServerAuth.js +164 -0
  80. package/dist/middleware/mcpServerAuth.js.map +1 -0
  81. package/dist/middleware/requestLogger.js +9 -0
  82. package/dist/middleware/requestLogger.js.map +1 -0
  83. package/dist/middleware/team.js +132 -0
  84. package/dist/middleware/team.js.map +1 -0
  85. package/dist/oauth/server.js +410 -0
  86. package/dist/oauth/server.js.map +1 -0
  87. package/dist/queue/cli.js +93 -0
  88. package/dist/queue/cli.js.map +1 -0
  89. package/dist/queue/handlers/index.js +91 -0
  90. package/dist/queue/handlers/index.js.map +1 -0
  91. package/dist/queue/handlers/scheduled-prompt.js +270 -0
  92. package/dist/queue/handlers/scheduled-prompt.js.map +1 -0
  93. package/dist/queue/index.js +91 -0
  94. package/dist/queue/index.js.map +1 -0
  95. package/dist/queue/providers/memory.js +296 -0
  96. package/dist/queue/providers/memory.js.map +1 -0
  97. package/dist/queue/providers/sqs.js +275 -0
  98. package/dist/queue/providers/sqs.js.map +1 -0
  99. package/dist/queue/scheduler.js +355 -0
  100. package/dist/queue/scheduler.js.map +1 -0
  101. package/dist/queue/types.js +5 -0
  102. package/dist/queue/types.js.map +1 -0
  103. package/dist/queue/worker.js +230 -0
  104. package/dist/queue/worker.js.map +1 -0
  105. package/dist/registry/index.js +40 -0
  106. package/dist/registry/index.js.map +1 -0
  107. package/dist/server.js +207 -0
  108. package/dist/server.js.map +1 -0
  109. package/dist/services/agent.js +530 -0
  110. package/dist/services/agent.js.map +1 -0
  111. package/dist/services/agents.js +194 -0
  112. package/dist/services/agents.js.map +1 -0
  113. package/dist/services/documents.js +507 -0
  114. package/dist/services/documents.js.map +1 -0
  115. package/dist/services/email/index.js +91 -0
  116. package/dist/services/email/index.js.map +1 -0
  117. package/dist/services/email/providers/ses.js +97 -0
  118. package/dist/services/email/providers/ses.js.map +1 -0
  119. package/dist/services/email/templates.js +194 -0
  120. package/dist/services/email/templates.js.map +1 -0
  121. package/dist/services/email/types.js +5 -0
  122. package/dist/services/email/types.js.map +1 -0
  123. package/dist/services/encryption.js +69 -0
  124. package/dist/services/encryption.js.map +1 -0
  125. package/dist/services/oauth-discovery.js +226 -0
  126. package/dist/services/oauth-discovery.js.map +1 -0
  127. package/dist/services/pendingConfirmation.js +105 -0
  128. package/dist/services/pendingConfirmation.js.map +1 -0
  129. package/dist/services/scheduledPrompts.js +70 -0
  130. package/dist/services/scheduledPrompts.js.map +1 -0
  131. package/dist/services/slack/client.js +174 -0
  132. package/dist/services/slack/client.js.map +1 -0
  133. package/dist/services/slack/events.js +189 -0
  134. package/dist/services/slack/events.js.map +1 -0
  135. package/dist/services/slack/index.js +6 -0
  136. package/dist/services/slack/index.js.map +1 -0
  137. package/dist/services/slack/notifications.js +124 -0
  138. package/dist/services/slack/notifications.js.map +1 -0
  139. package/dist/services/slack/signature.js +74 -0
  140. package/dist/services/slack/signature.js.map +1 -0
  141. package/dist/services/slack/thread-context.js +191 -0
  142. package/dist/services/slack/thread-context.js.map +1 -0
  143. package/dist/services/toolConfirmation.js +55 -0
  144. package/dist/services/toolConfirmation.js.map +1 -0
  145. package/dist/services/usage.js +241 -0
  146. package/dist/services/usage.js.map +1 -0
  147. package/dist/ssr/build.js +90 -0
  148. package/dist/ssr/build.js.map +1 -0
  149. package/dist/ssr/components/SSRMessageList.js +120 -0
  150. package/dist/ssr/components/SSRMessageList.js.map +1 -0
  151. package/dist/ssr/entry.client.js +8 -0
  152. package/dist/ssr/entry.client.js.map +1 -0
  153. package/dist/ssr/entry.server.js +71 -0
  154. package/dist/ssr/entry.server.js.map +1 -0
  155. package/dist/ssr/handler.js +51 -0
  156. package/dist/ssr/handler.js.map +1 -0
  157. package/dist/ssr/root.js +184 -0
  158. package/dist/ssr/root.js.map +1 -0
  159. package/dist/ssr/routes/login.js +140 -0
  160. package/dist/ssr/routes/login.js.map +1 -0
  161. package/dist/ssr/routes/pricing.js +195 -0
  162. package/dist/ssr/routes/pricing.js.map +1 -0
  163. package/dist/ssr/routes/privacy.js +39 -0
  164. package/dist/ssr/routes/privacy.js.map +1 -0
  165. package/dist/ssr/routes/register.js +148 -0
  166. package/dist/ssr/routes/register.js.map +1 -0
  167. package/dist/ssr/routes/shared.$shareId.js +153 -0
  168. package/dist/ssr/routes/shared.$shareId.js.map +1 -0
  169. package/dist/ssr/routes/terms.js +39 -0
  170. package/dist/ssr/routes/terms.js.map +1 -0
  171. package/dist/storage/index.js +43 -0
  172. package/dist/storage/index.js.map +1 -0
  173. package/dist/storage/providers/database.js +38 -0
  174. package/dist/storage/providers/database.js.map +1 -0
  175. package/dist/storage/providers/filesystem.js +51 -0
  176. package/dist/storage/providers/filesystem.js.map +1 -0
  177. package/dist/storage/types.js +2 -0
  178. package/dist/storage/types.js.map +1 -0
  179. package/dist/tools/documents.js +336 -0
  180. package/dist/tools/documents.js.map +1 -0
  181. package/dist/tools/get-plan-usage.js +82 -0
  182. package/dist/tools/get-plan-usage.js.map +1 -0
  183. package/dist/tools/index.js +106 -0
  184. package/dist/tools/index.js.map +1 -0
  185. package/dist/tools/types.js +2 -0
  186. package/dist/tools/types.js.map +1 -0
  187. package/dist/tools/web-scrape.js +145 -0
  188. package/dist/tools/web-scrape.js.map +1 -0
  189. package/package.json +93 -0
@@ -0,0 +1,124 @@
1
+ import { db } from '@chaaskit/db';
2
+ import { getConfig } from '../../config/loader.js';
3
+ import { SlackClient } from './client.js';
4
+ /**
5
+ * Check if a notification event is enabled in config.
6
+ */
7
+ function isEventEnabled(event) {
8
+ const config = getConfig();
9
+ if (!config.slack?.notifications?.events) {
10
+ return false;
11
+ }
12
+ const eventConfig = config.slack.notifications.events.find(e => e.event === event);
13
+ return eventConfig?.enabled ?? false;
14
+ }
15
+ /**
16
+ * Format notification message based on event type.
17
+ */
18
+ function formatNotificationMessage(payload) {
19
+ const { event, data } = payload;
20
+ switch (event) {
21
+ case 'thread_shared':
22
+ return [
23
+ ':outbox_tray: *Thread Shared*',
24
+ `${data.userName || data.userEmail || 'Someone'} shared "${data.threadTitle || 'a thread'}"`,
25
+ data.shareUrl ? `View: ${data.shareUrl}` : '',
26
+ ].filter(Boolean).join('\n');
27
+ case 'message_liked':
28
+ return [
29
+ ':thumbsup: *Message Liked*',
30
+ `${data.userName || data.userEmail || 'Someone'} liked a response in "${data.threadTitle || 'a thread'}"`,
31
+ ].join('\n');
32
+ case 'team_member_joined':
33
+ return [
34
+ ':wave: *New Team Member*',
35
+ `${data.userName || data.userEmail || 'Someone'} joined ${data.teamName || 'the team'}`,
36
+ ].join('\n');
37
+ default:
38
+ return `Notification: ${event}`;
39
+ }
40
+ }
41
+ /**
42
+ * Send a notification to a team's Slack workspace.
43
+ */
44
+ export async function sendSlackNotification(payload) {
45
+ const config = getConfig();
46
+ // Check if Slack is enabled
47
+ if (!config.slack?.enabled) {
48
+ return false;
49
+ }
50
+ // Check if this event type is enabled
51
+ if (!isEventEnabled(payload.event)) {
52
+ return false;
53
+ }
54
+ // Get the team's Slack integration
55
+ const integration = await db.slackIntegration.findUnique({
56
+ where: { teamId: payload.teamId },
57
+ });
58
+ if (!integration || integration.status !== 'active') {
59
+ return false;
60
+ }
61
+ // Must have a notification channel configured
62
+ if (!integration.notificationChannel) {
63
+ console.log('[Slack] No notification channel configured for team:', payload.teamId);
64
+ return false;
65
+ }
66
+ try {
67
+ const client = SlackClient.fromEncrypted(integration.encryptedTokens);
68
+ const message = formatNotificationMessage(payload);
69
+ const result = await client.postMessage(integration.notificationChannel, message);
70
+ if (!result.ok) {
71
+ console.error('[Slack] Failed to send notification:', result.error);
72
+ return false;
73
+ }
74
+ return true;
75
+ }
76
+ catch (error) {
77
+ console.error('[Slack] Error sending notification:', error);
78
+ return false;
79
+ }
80
+ }
81
+ /**
82
+ * Send notification when a thread is shared.
83
+ */
84
+ export async function notifyThreadShared(teamId, userName, userEmail, threadTitle, shareUrl) {
85
+ await sendSlackNotification({
86
+ event: 'thread_shared',
87
+ teamId,
88
+ data: {
89
+ userName: userName || undefined,
90
+ userEmail,
91
+ threadTitle,
92
+ shareUrl,
93
+ },
94
+ });
95
+ }
96
+ /**
97
+ * Send notification when a message is liked.
98
+ */
99
+ export async function notifyMessageLiked(teamId, userName, userEmail, threadTitle) {
100
+ await sendSlackNotification({
101
+ event: 'message_liked',
102
+ teamId,
103
+ data: {
104
+ userName: userName || undefined,
105
+ userEmail,
106
+ threadTitle,
107
+ },
108
+ });
109
+ }
110
+ /**
111
+ * Send notification when a team member joins.
112
+ */
113
+ export async function notifyTeamMemberJoined(teamId, userName, userEmail, teamName) {
114
+ await sendSlackNotification({
115
+ event: 'team_member_joined',
116
+ teamId,
117
+ data: {
118
+ userName: userName || undefined,
119
+ userEmail,
120
+ teamName,
121
+ },
122
+ });
123
+ }
124
+ //# sourceMappingURL=notifications.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"notifications.js","sourceRoot":"","sources":["../../../src/services/slack/notifications.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,74 @@
1
+ import crypto from 'crypto';
2
+ import { getConfig } from '../../config/loader.js';
3
+ /**
4
+ * Verify Slack request signature using HMAC-SHA256.
5
+ * See: https://api.slack.com/authentication/verifying-requests-from-slack
6
+ */
7
+ export function verifySlackSignature(signature, timestamp, rawBody) {
8
+ if (!signature || !timestamp) {
9
+ return false;
10
+ }
11
+ const config = getConfig();
12
+ const signingSecretEnvVar = config.slack?.signingSecretEnvVar || 'SLACK_SIGNING_SECRET';
13
+ const signingSecret = process.env[signingSecretEnvVar];
14
+ if (!signingSecret) {
15
+ console.error('[Slack] Missing signing secret:', signingSecretEnvVar);
16
+ return false;
17
+ }
18
+ // Verify timestamp to prevent replay attacks (allow 5 minutes)
19
+ const requestTimestamp = parseInt(timestamp, 10);
20
+ const now = Math.floor(Date.now() / 1000);
21
+ if (Math.abs(now - requestTimestamp) > 300) {
22
+ console.warn('[Slack] Request timestamp too old:', requestTimestamp);
23
+ return false;
24
+ }
25
+ // Construct the base string
26
+ const baseString = `v0:${timestamp}:${rawBody}`;
27
+ // Compute HMAC-SHA256
28
+ const hmac = crypto.createHmac('sha256', signingSecret);
29
+ hmac.update(baseString);
30
+ const expectedSignature = `v0=${hmac.digest('hex')}`;
31
+ // Timing-safe comparison
32
+ try {
33
+ return crypto.timingSafeEqual(Buffer.from(signature), Buffer.from(expectedSignature));
34
+ }
35
+ catch {
36
+ // Buffers have different lengths
37
+ return false;
38
+ }
39
+ }
40
+ /**
41
+ * Verify internal secret for self-calling endpoints.
42
+ */
43
+ export function verifyInternalSecret(headerValue) {
44
+ const config = getConfig();
45
+ const internalSecretEnvVar = config.slack?.internalSecretEnvVar || 'SLACK_INTERNAL_SECRET';
46
+ const internalSecret = process.env[internalSecretEnvVar];
47
+ if (!internalSecret) {
48
+ console.error('[Slack] Missing internal secret:', internalSecretEnvVar);
49
+ return false;
50
+ }
51
+ if (!headerValue) {
52
+ return false;
53
+ }
54
+ // Timing-safe comparison
55
+ try {
56
+ return crypto.timingSafeEqual(Buffer.from(headerValue), Buffer.from(internalSecret));
57
+ }
58
+ catch {
59
+ return false;
60
+ }
61
+ }
62
+ /**
63
+ * Get the internal secret for self-calling endpoints.
64
+ */
65
+ export function getInternalSecret() {
66
+ const config = getConfig();
67
+ const internalSecretEnvVar = config.slack?.internalSecretEnvVar || 'SLACK_INTERNAL_SECRET';
68
+ const internalSecret = process.env[internalSecretEnvVar];
69
+ if (!internalSecret) {
70
+ throw new Error(`Missing required environment variable: ${internalSecretEnvVar}`);
71
+ }
72
+ return internalSecret;
73
+ }
74
+ //# sourceMappingURL=signature.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"signature.js","sourceRoot":"","sources":["../../../src/services/slack/signature.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,191 @@
1
+ import { db } from '@chaaskit/db';
2
+ /**
3
+ * Build thread context from Slack conversation history.
4
+ */
5
+ export async function buildSlackThreadContext(client, channelId, threadTs, botUserId) {
6
+ // If not in a thread, no context to build
7
+ if (!threadTs) {
8
+ return null;
9
+ }
10
+ try {
11
+ const history = await client.getConversationHistory(channelId, {
12
+ threadTs,
13
+ limit: 20, // Get last 20 messages in thread
14
+ });
15
+ if (!history.ok || !history.messages) {
16
+ console.error('[Slack] Failed to get thread history:', history.error);
17
+ return null;
18
+ }
19
+ // Convert Slack messages to context format
20
+ // Messages come newest-first, so reverse them
21
+ const messages = history.messages
22
+ .slice()
23
+ .reverse()
24
+ .filter(msg => msg.text && msg.ts !== threadTs) // Exclude parent message
25
+ .map(msg => ({
26
+ role: (msg.bot_id || msg.user === botUserId ? 'assistant' : 'user'),
27
+ content: cleanSlackMessage(msg.text || '', botUserId),
28
+ slackUserId: msg.user,
29
+ }));
30
+ return {
31
+ messages,
32
+ slackThreadTs: threadTs,
33
+ };
34
+ }
35
+ catch (error) {
36
+ console.error('[Slack] Error building thread context:', error);
37
+ return null;
38
+ }
39
+ }
40
+ /**
41
+ * Find or create an internal thread for Slack context continuity.
42
+ */
43
+ export async function findOrCreateInternalThread(teamId, slackChannelId, slackThreadTs) {
44
+ // If no thread timestamp, always create a new thread
45
+ if (!slackThreadTs) {
46
+ const thread = await db.thread.create({
47
+ data: {
48
+ title: 'Slack Chat',
49
+ teamId,
50
+ },
51
+ });
52
+ return thread.id;
53
+ }
54
+ // Look for existing event with same channel/thread that has an internal thread
55
+ const existingEvent = await db.slackMessageEvent.findFirst({
56
+ where: {
57
+ slackChannelId,
58
+ slackThreadTs,
59
+ internalThreadId: { not: null },
60
+ },
61
+ orderBy: { createdAt: 'desc' },
62
+ select: { internalThreadId: true },
63
+ });
64
+ if (existingEvent?.internalThreadId) {
65
+ // Verify thread still exists
66
+ const thread = await db.thread.findUnique({
67
+ where: { id: existingEvent.internalThreadId },
68
+ });
69
+ if (thread) {
70
+ return existingEvent.internalThreadId;
71
+ }
72
+ }
73
+ // Create new internal thread
74
+ const thread = await db.thread.create({
75
+ data: {
76
+ title: 'Slack Thread',
77
+ teamId,
78
+ },
79
+ });
80
+ return thread.id;
81
+ }
82
+ /**
83
+ * Get message history from internal thread.
84
+ */
85
+ export async function getInternalThreadHistory(threadId) {
86
+ const messages = await db.message.findMany({
87
+ where: { threadId },
88
+ orderBy: { createdAt: 'asc' },
89
+ take: 20, // Last 20 messages
90
+ select: {
91
+ role: true,
92
+ content: true,
93
+ },
94
+ });
95
+ return messages
96
+ .filter(m => m.role === 'user' || m.role === 'assistant')
97
+ .map(m => ({
98
+ role: m.role,
99
+ content: m.content,
100
+ }));
101
+ }
102
+ /**
103
+ * Save a message to internal thread.
104
+ */
105
+ export async function saveToInternalThread(threadId, role, content) {
106
+ await db.message.create({
107
+ data: {
108
+ threadId,
109
+ role,
110
+ content,
111
+ },
112
+ });
113
+ // Update thread's updatedAt
114
+ await db.thread.update({
115
+ where: { id: threadId },
116
+ data: { updatedAt: new Date() },
117
+ });
118
+ }
119
+ /**
120
+ * Clean Slack message text:
121
+ * - Remove @mentions of the bot
122
+ * - Convert user mentions to readable format
123
+ * - Handle formatting
124
+ */
125
+ export function cleanSlackMessage(text, botUserId) {
126
+ // Remove bot mentions
127
+ const botMentionRegex = new RegExp(`<@${botUserId}>`, 'g');
128
+ let cleaned = text.replace(botMentionRegex, '').trim();
129
+ // Convert user mentions <@U123> to @user
130
+ cleaned = cleaned.replace(/<@([A-Z0-9]+)>/g, '@user');
131
+ // Convert links <url|text> to just text or url
132
+ cleaned = cleaned.replace(/<(https?:\/\/[^|>]+)\|([^>]+)>/g, '$2');
133
+ cleaned = cleaned.replace(/<(https?:\/\/[^>]+)>/g, '$1');
134
+ // Convert channel references <#C123|channel-name> to #channel-name
135
+ cleaned = cleaned.replace(/<#[A-Z0-9]+\|([^>]+)>/g, '#$1');
136
+ return cleaned.trim();
137
+ }
138
+ /**
139
+ * Format response for Slack mrkdwn:
140
+ * - Convert standard markdown to Slack mrkdwn syntax
141
+ * - Handle bold, italic, strikethrough, links
142
+ */
143
+ export function formatForSlack(text) {
144
+ let result = text;
145
+ // Preserve code blocks first (we don't want to process inside them)
146
+ const codeBlocks = [];
147
+ result = result.replace(/```[\s\S]*?```/g, match => {
148
+ codeBlocks.push(match);
149
+ return `__CODE_BLOCK_${codeBlocks.length - 1}__`;
150
+ });
151
+ // Preserve inline code
152
+ const inlineCode = [];
153
+ result = result.replace(/`[^`]+`/g, match => {
154
+ inlineCode.push(match);
155
+ return `__INLINE_CODE_${inlineCode.length - 1}__`;
156
+ });
157
+ // Convert markdown links [text](url) to Slack format <url|text>
158
+ result = result.replace(/\[([^\]]+)\]\(([^)]+)\)/g, '<$2|$1>');
159
+ // Convert markdown bold **text** to Slack bold *text*
160
+ // Be careful not to convert already single asterisks
161
+ result = result.replace(/\*\*([^*]+)\*\*/g, '*$1*');
162
+ // Convert markdown strikethrough ~~text~~ to Slack ~text~
163
+ result = result.replace(/~~([^~]+)~~/g, '~$1~');
164
+ // Markdown italic with underscores _text_ already works in Slack
165
+ // Markdown italic with single asterisks *text* would conflict with Slack bold,
166
+ // but after converting **bold** to *bold*, remaining single asterisks should be fine
167
+ // Restore inline code
168
+ inlineCode.forEach((code, i) => {
169
+ result = result.replace(`__INLINE_CODE_${i}__`, code);
170
+ });
171
+ // Restore code blocks
172
+ codeBlocks.forEach((block, i) => {
173
+ result = result.replace(`__CODE_BLOCK_${i}__`, block);
174
+ });
175
+ return result;
176
+ }
177
+ /**
178
+ * System prompt suffix for Slack responses.
179
+ * Instructs the AI to format responses using Slack's mrkdwn syntax.
180
+ */
181
+ export const SLACK_FORMAT_INSTRUCTIONS = `
182
+ Format your responses using Slack's mrkdwn syntax:
183
+ - Bold: *bold text*
184
+ - Italic: _italic text_
185
+ - Strikethrough: ~strikethrough~
186
+ - Code: \`inline code\` or \`\`\`code block\`\`\`
187
+ - Links: <https://example.com|link text>
188
+ - Lists: Use - or • for bullets
189
+ - Quotes: >quoted text
190
+ Keep responses concise and well-formatted for chat.`.trim();
191
+ //# sourceMappingURL=thread-context.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"thread-context.js","sourceRoot":"","sources":["../../../src/services/slack/thread-context.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,55 @@
1
+ /**
2
+ * Tool Confirmation Service
3
+ *
4
+ * Determines whether a tool call requires user confirmation based on:
5
+ * 1. Admin configuration (mode: none, all, whitelist, blacklist)
6
+ * 2. User's "always allow" settings
7
+ * 3. Thread-level allowances (tools allowed for this thread)
8
+ */
9
+ import { getConfig } from '../config/loader.js';
10
+ /**
11
+ * Check if a tool call requires user confirmation
12
+ */
13
+ export function checkToolConfirmationRequired(params) {
14
+ const { serverId, toolName, userSettings, threadAllowedTools } = params;
15
+ const config = getConfig().mcp?.toolConfirmation;
16
+ const toolId = `${serverId}:${toolName}`;
17
+ // 1. Check admin config mode
18
+ if (!config || config.mode === 'none') {
19
+ return { required: false, autoApproveReason: 'config_none' };
20
+ }
21
+ // 2. Check whitelist mode (listed tools DON'T require confirmation)
22
+ if (config.mode === 'whitelist') {
23
+ const tools = config.tools || [];
24
+ if (tools.includes(toolId) || tools.includes(toolName)) {
25
+ return { required: false, autoApproveReason: 'whitelist' };
26
+ }
27
+ // In whitelist mode, if tool is not in whitelist, check other allowances
28
+ }
29
+ // 3. Check blacklist mode (listed tools DO require confirmation)
30
+ if (config.mode === 'blacklist') {
31
+ const tools = config.tools || [];
32
+ // If tool is NOT in the blacklist, it's auto-approved
33
+ if (!tools.includes(toolId) && !tools.includes(toolName)) {
34
+ return { required: false, autoApproveReason: 'config_none' };
35
+ }
36
+ // Tool is in blacklist, check other allowances below
37
+ }
38
+ // 4. Check user's "always allow" settings
39
+ if (userSettings?.allowedTools?.includes(toolId)) {
40
+ return { required: false, autoApproveReason: 'user_always' };
41
+ }
42
+ // 5. Check thread-level allowance
43
+ if (threadAllowedTools?.includes(toolId)) {
44
+ return { required: false, autoApproveReason: 'thread_allowed' };
45
+ }
46
+ // 6. If we got here, confirmation is required
47
+ return { required: true };
48
+ }
49
+ /**
50
+ * Format a tool result for denial
51
+ */
52
+ export function createDenialToolResult(toolName) {
53
+ return `The user denied permission to execute the tool "${toolName}". Please respect their decision and continue the conversation without using this tool, or ask if they'd like to try a different approach.`;
54
+ }
55
+ //# sourceMappingURL=toolConfirmation.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"toolConfirmation.js","sourceRoot":"","sources":["../../src/services/toolConfirmation.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAGH,OAAO,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAC;AAoBhD;;GAEG;AACH,MAAM,UAAU,6BAA6B,CAAC,MAA+B;IAC3E,MAAM,EAAE,QAAQ,EAAE,QAAQ,EAAE,YAAY,EAAE,kBAAkB,EAAE,GAAG,MAAM,CAAC;IACxE,MAAM,MAAM,GAAG,SAAS,EAAE,CAAC,GAAG,EAAE,gBAAgB,CAAC;IACjD,MAAM,MAAM,GAAG,GAAG,QAAQ,IAAI,QAAQ,EAAE,CAAC;IAEzC,6BAA6B;IAC7B,IAAI,CAAC,MAAM,IAAI,MAAM,CAAC,IAAI,KAAK,MAAM,EAAE,CAAC;QACtC,OAAO,EAAE,QAAQ,EAAE,KAAK,EAAE,iBAAiB,EAAE,aAAa,EAAE,CAAC;IAC/D,CAAC;IAED,oEAAoE;IACpE,IAAI,MAAM,CAAC,IAAI,KAAK,WAAW,EAAE,CAAC;QAChC,MAAM,KAAK,GAAG,MAAM,CAAC,KAAK,IAAI,EAAE,CAAC;QACjC,IAAI,KAAK,CAAC,QAAQ,CAAC,MAAM,CAAC,IAAI,KAAK,CAAC,QAAQ,CAAC,QAAQ,CAAC,EAAE,CAAC;YACvD,OAAO,EAAE,QAAQ,EAAE,KAAK,EAAE,iBAAiB,EAAE,WAAW,EAAE,CAAC;QAC7D,CAAC;QACD,yEAAyE;IAC3E,CAAC;IAED,iEAAiE;IACjE,IAAI,MAAM,CAAC,IAAI,KAAK,WAAW,EAAE,CAAC;QAChC,MAAM,KAAK,GAAG,MAAM,CAAC,KAAK,IAAI,EAAE,CAAC;QACjC,sDAAsD;QACtD,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,QAAQ,CAAC,EAAE,CAAC;YACzD,OAAO,EAAE,QAAQ,EAAE,KAAK,EAAE,iBAAiB,EAAE,aAAa,EAAE,CAAC;QAC/D,CAAC;QACD,qDAAqD;IACvD,CAAC;IAED,0CAA0C;IAC1C,IAAI,YAAY,EAAE,YAAY,EAAE,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC;QACjD,OAAO,EAAE,QAAQ,EAAE,KAAK,EAAE,iBAAiB,EAAE,aAAa,EAAE,CAAC;IAC/D,CAAC;IAED,kCAAkC;IAClC,IAAI,kBAAkB,EAAE,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC;QACzC,OAAO,EAAE,QAAQ,EAAE,KAAK,EAAE,iBAAiB,EAAE,gBAAgB,EAAE,CAAC;IAClE,CAAC;IAED,8CAA8C;IAC9C,OAAO,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;AAC5B,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,sBAAsB,CAAC,QAAgB;IACrD,OAAO,mDAAmD,QAAQ,4IAA4I,CAAC;AACjN,CAAC"}