@cuylabs/channel-slack 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 (47) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +168 -0
  3. package/dist/activity-ByrD9Ftr.d.ts +66 -0
  4. package/dist/assistant.d.ts +58 -0
  5. package/dist/assistant.js +188 -0
  6. package/dist/bolt.d.ts +344 -0
  7. package/dist/bolt.js +705 -0
  8. package/dist/chunk-BODPT4I6.js +322 -0
  9. package/dist/chunk-FPCE5V5Y.js +292 -0
  10. package/dist/chunk-FX2JOVX5.js +405 -0
  11. package/dist/chunk-JZG4IETE.js +141 -0
  12. package/dist/chunk-NE57BLLU.js +0 -0
  13. package/dist/chunk-TWJGVDA2.js +108 -0
  14. package/dist/core.d.ts +425 -0
  15. package/dist/core.js +42 -0
  16. package/dist/diagnostics.d.ts +105 -0
  17. package/dist/diagnostics.js +8 -0
  18. package/dist/feedback.d.ts +137 -0
  19. package/dist/feedback.js +128 -0
  20. package/dist/history.d.ts +266 -0
  21. package/dist/history.js +747 -0
  22. package/dist/index.d.ts +4 -0
  23. package/dist/index.js +57 -0
  24. package/dist/logging-Bl3HfcC8.d.ts +8 -0
  25. package/dist/policy.d.ts +130 -0
  26. package/dist/policy.js +16 -0
  27. package/dist/setup.d.ts +165 -0
  28. package/dist/setup.js +453 -0
  29. package/dist/shared.d.ts +2 -0
  30. package/dist/shared.js +43 -0
  31. package/dist/targets.d.ts +113 -0
  32. package/dist/targets.js +484 -0
  33. package/dist/users.d.ts +109 -0
  34. package/dist/users.js +240 -0
  35. package/docs/concepts/activity.md +33 -0
  36. package/docs/concepts/bolt-runtime.md +30 -0
  37. package/docs/concepts/message-policy.md +49 -0
  38. package/docs/concepts/setup-requirements.md +44 -0
  39. package/docs/concepts/supplemental-history.md +55 -0
  40. package/docs/recipes/app-mention-handler.md +34 -0
  41. package/docs/recipes/assistant-thread-handler.md +28 -0
  42. package/docs/recipes/generate-slack-manifest.md +28 -0
  43. package/docs/recipes/history-visibility.md +36 -0
  44. package/docs/recipes/socket-mode-app.md +29 -0
  45. package/docs/reference/channel-slack-boundary.md +50 -0
  46. package/docs/reference/exports.md +32 -0
  47. package/package.json +130 -0
package/dist/setup.js ADDED
@@ -0,0 +1,453 @@
1
+ import {
2
+ inspectSlackConnection
3
+ } from "./chunk-FX2JOVX5.js";
4
+
5
+ // src/setup/requirements.ts
6
+ var DEFAULT_EVENTS_PATH = "/slack/events";
7
+ var slackSetupFeaturePresets = {
8
+ assistant: ["assistant", "feedback"],
9
+ "channel-adapter": ["app-mentions", "direct-messages"],
10
+ "agent-app": ["assistant", "app-mentions", "direct-messages", "feedback"]
11
+ };
12
+ var FEATURE_REQUIREMENTS = {
13
+ assistant: {
14
+ botScopes: ["assistant:write", "chat:write"],
15
+ botEvents: ["assistant_thread_started", "assistant_thread_context_changed"],
16
+ assistantView: true
17
+ },
18
+ "app-mentions": {
19
+ botScopes: ["app_mentions:read", "chat:write"],
20
+ botEvents: ["app_mention"]
21
+ },
22
+ "direct-messages": {
23
+ botScopes: ["chat:write", "im:history", "im:read"],
24
+ botEvents: ["message.im"]
25
+ },
26
+ "channel-messages": {
27
+ botScopes: ["channels:history", "chat:write", "groups:history"],
28
+ botEvents: ["message.channels", "message.groups"]
29
+ },
30
+ history: {
31
+ botScopes: [
32
+ "channels:history",
33
+ "groups:history",
34
+ "im:history",
35
+ "mpim:history"
36
+ ]
37
+ },
38
+ interactivity: {
39
+ botScopes: ["chat:write"],
40
+ interactivity: true
41
+ },
42
+ feedback: {
43
+ botScopes: ["chat:write"],
44
+ interactivity: true
45
+ },
46
+ "user-profiles": {
47
+ botScopes: ["users:read"],
48
+ optionalBotScopes: ["users:read.email"]
49
+ },
50
+ "user-emails": {
51
+ botScopes: ["users:read", "users:read.email"]
52
+ }
53
+ };
54
+ function getSlackSetupRequirements(options = {}) {
55
+ const features = resolveSetupFeatures(options);
56
+ const transport = options.transport ?? "http";
57
+ const eventsPath = normalizeSlackEventsPath(
58
+ options.eventsPath ?? DEFAULT_EVENTS_PATH
59
+ );
60
+ const requestUrl = resolveRequestUrl(options.baseUrl, eventsPath);
61
+ const botScopes = [];
62
+ const optionalBotScopes = [];
63
+ const botEvents = [];
64
+ let assistantView = false;
65
+ let interactivity = false;
66
+ for (const feature of features) {
67
+ const requirement = FEATURE_REQUIREMENTS[feature];
68
+ if (!requirement) {
69
+ throw new Error(`Unknown Slack setup feature: ${feature}`);
70
+ }
71
+ collect(requirement.botScopes, botScopes);
72
+ collect(requirement.optionalBotScopes, optionalBotScopes);
73
+ collect(requirement.botEvents, botEvents);
74
+ assistantView ||= requirement.assistantView === true;
75
+ interactivity ||= requirement.interactivity === true;
76
+ }
77
+ collect(options.extraBotScopes, botScopes);
78
+ collect(options.extraOptionalBotScopes, optionalBotScopes);
79
+ collect(options.extraBotEvents, botEvents);
80
+ const normalizedBotScopes = uniqueSorted(botScopes);
81
+ const normalizedBotEvents = uniqueSorted(botEvents);
82
+ const requiredScopeKeys = new Set(
83
+ normalizedBotScopes.map((scope) => scope.toLowerCase())
84
+ );
85
+ const normalizedOptionalBotScopes = uniqueSorted(
86
+ optionalBotScopes.filter(
87
+ (scope) => !requiredScopeKeys.has(scope.trim().toLowerCase())
88
+ )
89
+ );
90
+ const settings = {
91
+ assistantView,
92
+ eventSubscriptions: normalizedBotEvents.length > 0,
93
+ interactivity,
94
+ socketMode: transport === "socket"
95
+ };
96
+ const environment = resolveEnvironment({
97
+ botScopes: normalizedBotScopes,
98
+ settings,
99
+ transport
100
+ });
101
+ return {
102
+ features,
103
+ transport,
104
+ eventsPath,
105
+ ...requestUrl ? { requestUrl } : {},
106
+ botScopes: normalizedBotScopes,
107
+ optionalBotScopes: normalizedOptionalBotScopes,
108
+ appTokenScopes: transport === "socket" ? ["connections:write"] : [],
109
+ botEvents: normalizedBotEvents,
110
+ settings,
111
+ environment
112
+ };
113
+ }
114
+ function resolveSetupFeatures(options) {
115
+ const preset = options.preset ?? "agent-app";
116
+ if (preset === false) {
117
+ return uniqueFeatures(options.features ?? []);
118
+ }
119
+ const presetFeatures = slackSetupFeaturePresets[preset];
120
+ if (!presetFeatures) {
121
+ throw new Error(`Unknown Slack setup preset: ${preset}`);
122
+ }
123
+ return uniqueFeatures([
124
+ ...presetFeatures ?? [],
125
+ ...options.features ?? []
126
+ ]);
127
+ }
128
+ function resolveEnvironment(context) {
129
+ const environment = [];
130
+ if (context.botScopes.length > 0) {
131
+ environment.push({
132
+ name: "SLACK_BOT_TOKEN",
133
+ purpose: "Bot OAuth token used by single-workspace direct mode and setup inspection."
134
+ });
135
+ }
136
+ if (context.transport === "http" && (context.settings.eventSubscriptions || context.settings.interactivity)) {
137
+ environment.push({
138
+ name: "SLACK_SIGNING_SECRET",
139
+ purpose: "Signing secret used by Bolt to verify inbound Slack requests."
140
+ });
141
+ }
142
+ if (context.transport === "socket") {
143
+ environment.push({
144
+ name: "SLACK_APP_TOKEN",
145
+ purpose: "App-level token with connections:write used by Socket Mode transport."
146
+ });
147
+ }
148
+ return environment;
149
+ }
150
+ function normalizeSlackEventsPath(path) {
151
+ const trimmed = path.trim();
152
+ if (!trimmed) {
153
+ throw new Error("Slack events path must not be empty.");
154
+ }
155
+ return trimmed.startsWith("/") ? trimmed : `/${trimmed}`;
156
+ }
157
+ function resolveRequestUrl(baseUrl, eventsPath) {
158
+ const trimmed = trimString(baseUrl);
159
+ if (!trimmed) return void 0;
160
+ return `${trimmed.replace(/\/+$/, "")}${eventsPath}`;
161
+ }
162
+ function collect(source, target) {
163
+ if (!source) return;
164
+ for (const value of source) {
165
+ const trimmed = value.trim();
166
+ if (trimmed) target.push(trimmed);
167
+ }
168
+ }
169
+ function uniqueSorted(values) {
170
+ const unique = /* @__PURE__ */ new Map();
171
+ for (const value of values) {
172
+ const trimmed = value.trim();
173
+ if (trimmed) {
174
+ unique.set(trimmed.toLowerCase(), trimmed);
175
+ }
176
+ }
177
+ return [...unique.values()].sort((a, b) => a.localeCompare(b));
178
+ }
179
+ function uniqueFeatures(values) {
180
+ const unique = /* @__PURE__ */ new Set();
181
+ for (const value of values) {
182
+ if (!FEATURE_REQUIREMENTS[value]) {
183
+ throw new Error(`Unknown Slack setup feature: ${value}`);
184
+ }
185
+ unique.add(value);
186
+ }
187
+ return [...unique];
188
+ }
189
+ function trimString(value) {
190
+ const trimmed = value?.trim();
191
+ return trimmed || void 0;
192
+ }
193
+
194
+ // src/setup/manifest.ts
195
+ function createSlackAppManifest(options) {
196
+ const requirements = getSlackSetupRequirements(options);
197
+ const name = options.name.trim();
198
+ if (!name) {
199
+ throw new Error("Slack app manifest name is required.");
200
+ }
201
+ const description = trimString2(options.description);
202
+ const backgroundColor = trimString2(options.backgroundColor);
203
+ const assistantDescription = trimString2(options.assistantDescription);
204
+ const botDisplayName = trimString2(options.botDisplayName) ?? name;
205
+ const displayInformation = {
206
+ name
207
+ };
208
+ if (description) displayInformation.description = description;
209
+ if (backgroundColor) displayInformation.background_color = backgroundColor;
210
+ const features = {
211
+ bot_user: {
212
+ display_name: botDisplayName,
213
+ always_online: options.alwaysOnline ?? true
214
+ }
215
+ };
216
+ if (requirements.settings.assistantView) {
217
+ if (options.appHome !== false) {
218
+ features.app_home = {
219
+ home_tab_enabled: options.appHome?.home_tab_enabled ?? true,
220
+ messages_tab_enabled: options.appHome?.messages_tab_enabled ?? true,
221
+ messages_tab_read_only_enabled: options.appHome?.messages_tab_read_only_enabled ?? false
222
+ };
223
+ }
224
+ features.assistant_view = {
225
+ ...assistantDescription ? { assistant_description: assistantDescription } : {},
226
+ ...options.suggestedPrompts ? { suggested_prompts: [...options.suggestedPrompts] } : {}
227
+ };
228
+ }
229
+ const settings = {
230
+ socket_mode_enabled: requirements.settings.socketMode,
231
+ token_rotation_enabled: options.tokenRotationEnabled ?? false
232
+ };
233
+ if (requirements.settings.eventSubscriptions) {
234
+ settings.event_subscriptions = {
235
+ ...requirements.requestUrl && requirements.transport === "http" ? { request_url: requirements.requestUrl } : {},
236
+ bot_events: requirements.botEvents
237
+ };
238
+ }
239
+ if (requirements.settings.interactivity) {
240
+ settings.interactivity = {
241
+ is_enabled: true,
242
+ ...requirements.requestUrl && requirements.transport === "http" ? { request_url: requirements.requestUrl } : {}
243
+ };
244
+ }
245
+ if (options.orgDeployEnabled !== void 0) {
246
+ settings.org_deploy_enabled = options.orgDeployEnabled;
247
+ }
248
+ if (options.isMcpEnabled !== void 0) {
249
+ settings.is_mcp_enabled = options.isMcpEnabled;
250
+ }
251
+ const userScopes = uniqueSorted2(options.extraUserScopes ?? []);
252
+ return {
253
+ display_information: displayInformation,
254
+ features,
255
+ oauth_config: {
256
+ scopes: {
257
+ bot: requirements.botScopes,
258
+ ...userScopes.length > 0 ? { user: userScopes } : {}
259
+ }
260
+ },
261
+ settings
262
+ };
263
+ }
264
+ function compareSlackAppManifest(manifest, requirements) {
265
+ const findings = [];
266
+ const manifestRecord = readRecord(manifest);
267
+ const oauthConfig = readRecord(manifestRecord?.oauth_config);
268
+ const scopes = readRecord(oauthConfig?.scopes);
269
+ const settings = readRecord(manifestRecord?.settings);
270
+ const eventSubscriptions = readRecord(settings?.event_subscriptions);
271
+ const botScopes = readStringArray(scopes?.bot);
272
+ const botEvents = readStringArray(eventSubscriptions?.bot_events);
273
+ const missingBotScopes = missingValues(requirements.botScopes, botScopes);
274
+ const missingOptionalBotScopes = missingValues(
275
+ requirements.optionalBotScopes,
276
+ botScopes
277
+ );
278
+ const missingBotEvents = missingValues(requirements.botEvents, botEvents);
279
+ if (missingBotScopes.length > 0) {
280
+ findings.push({
281
+ severity: "error",
282
+ code: "missing-bot-scopes",
283
+ message: `Slack manifest is missing required bot scope(s): ${missingBotScopes.join(
284
+ ", "
285
+ )}.`,
286
+ path: "oauth_config.scopes.bot",
287
+ expected: requirements.botScopes,
288
+ actual: botScopes
289
+ });
290
+ }
291
+ if (missingOptionalBotScopes.length > 0) {
292
+ findings.push({
293
+ severity: "warning",
294
+ code: "missing-optional-bot-scopes",
295
+ message: `Slack manifest is missing optional bot scope(s): ${missingOptionalBotScopes.join(
296
+ ", "
297
+ )}.`,
298
+ path: "oauth_config.scopes.bot",
299
+ expected: requirements.optionalBotScopes,
300
+ actual: botScopes
301
+ });
302
+ }
303
+ if (missingBotEvents.length > 0) {
304
+ findings.push({
305
+ severity: "error",
306
+ code: "missing-bot-events",
307
+ message: `Slack manifest is missing required bot event(s): ${missingBotEvents.join(
308
+ ", "
309
+ )}.`,
310
+ path: "settings.event_subscriptions.bot_events",
311
+ expected: requirements.botEvents,
312
+ actual: botEvents
313
+ });
314
+ }
315
+ compareSettings(manifest, requirements, findings);
316
+ return {
317
+ ok: findings.every((finding) => finding.severity !== "error"),
318
+ missingBotScopes,
319
+ missingOptionalBotScopes,
320
+ missingBotEvents,
321
+ findings
322
+ };
323
+ }
324
+ function compareSettings(manifest, requirements, findings) {
325
+ const manifestRecord = readRecord(manifest);
326
+ const features = readRecord(manifestRecord?.features);
327
+ const settings = readRecord(manifestRecord?.settings);
328
+ const eventSubscriptions = readRecord(settings?.event_subscriptions);
329
+ const interactivity = readRecord(settings?.interactivity);
330
+ if (requirements.settings.assistantView && !readRecord(features?.assistant_view)) {
331
+ findings.push({
332
+ severity: "error",
333
+ code: "assistant-view-disabled",
334
+ message: "Slack manifest must enable Assistant view for Assistant features.",
335
+ path: "features.assistant_view",
336
+ expected: true,
337
+ actual: false
338
+ });
339
+ }
340
+ if (requirements.settings.eventSubscriptions && !Array.isArray(eventSubscriptions?.bot_events)) {
341
+ findings.push({
342
+ severity: "error",
343
+ code: "event-subscriptions-disabled",
344
+ message: "Slack manifest must configure event subscriptions for selected features.",
345
+ path: "settings.event_subscriptions.bot_events",
346
+ expected: requirements.botEvents,
347
+ actual: void 0
348
+ });
349
+ }
350
+ if (requirements.settings.interactivity && readBoolean(interactivity?.is_enabled) !== true) {
351
+ findings.push({
352
+ severity: "error",
353
+ code: "interactivity-disabled",
354
+ message: "Slack manifest must enable interactivity for selected features.",
355
+ path: "settings.interactivity.is_enabled",
356
+ expected: true,
357
+ actual: readBoolean(interactivity?.is_enabled) ?? false
358
+ });
359
+ }
360
+ if (requirements.settings.socketMode && readBoolean(settings?.socket_mode_enabled) !== true) {
361
+ findings.push({
362
+ severity: "error",
363
+ code: "socket-mode-disabled",
364
+ message: "Slack manifest must enable Socket Mode for socket transport.",
365
+ path: "settings.socket_mode_enabled",
366
+ expected: true,
367
+ actual: readBoolean(settings?.socket_mode_enabled) ?? false
368
+ });
369
+ }
370
+ if (requirements.requestUrl && requirements.transport === "http" && requirements.settings.eventSubscriptions && readString(eventSubscriptions?.request_url) !== requirements.requestUrl) {
371
+ findings.push({
372
+ severity: "error",
373
+ code: "event-request-url-mismatch",
374
+ message: `Slack manifest event request URL must be ${requirements.requestUrl}.`,
375
+ path: "settings.event_subscriptions.request_url",
376
+ expected: requirements.requestUrl,
377
+ actual: readString(eventSubscriptions?.request_url)
378
+ });
379
+ }
380
+ if (requirements.requestUrl && requirements.transport === "http" && requirements.settings.interactivity && readString(interactivity?.request_url) !== requirements.requestUrl) {
381
+ findings.push({
382
+ severity: "error",
383
+ code: "interactivity-request-url-mismatch",
384
+ message: `Slack manifest interactivity request URL must be ${requirements.requestUrl}.`,
385
+ path: "settings.interactivity.request_url",
386
+ expected: requirements.requestUrl,
387
+ actual: readString(interactivity?.request_url)
388
+ });
389
+ }
390
+ }
391
+ function trimString2(value) {
392
+ const trimmed = value?.trim();
393
+ return trimmed || void 0;
394
+ }
395
+ function missingValues(expected, actual) {
396
+ const actualSet = new Set(
397
+ actual.map((value) => value.trim().toLowerCase()).filter(Boolean)
398
+ );
399
+ return expected.filter((value) => !actualSet.has(value.trim().toLowerCase()));
400
+ }
401
+ function uniqueSorted2(values) {
402
+ const unique = /* @__PURE__ */ new Map();
403
+ for (const value of values) {
404
+ const trimmed = value.trim();
405
+ if (trimmed) {
406
+ unique.set(trimmed.toLowerCase(), trimmed);
407
+ }
408
+ }
409
+ return [...unique.values()].sort((a, b) => a.localeCompare(b));
410
+ }
411
+ function readRecord(value) {
412
+ return value && typeof value === "object" && !Array.isArray(value) ? value : void 0;
413
+ }
414
+ function readStringArray(value) {
415
+ if (!Array.isArray(value)) {
416
+ return [];
417
+ }
418
+ return uniqueSorted2(
419
+ value.filter((entry) => typeof entry === "string")
420
+ );
421
+ }
422
+ function readString(value) {
423
+ return typeof value === "string" && value.trim() ? value.trim() : void 0;
424
+ }
425
+ function readBoolean(value) {
426
+ return typeof value === "boolean" ? value : void 0;
427
+ }
428
+
429
+ // src/setup/inspection.ts
430
+ async function inspectSlackAppSetup(options = {}) {
431
+ const requirements = getSlackSetupRequirements(options);
432
+ const connection = await inspectSlackConnection({
433
+ token: options.token,
434
+ client: options.client,
435
+ requestTimeoutMs: options.requestTimeoutMs,
436
+ inspectScopes: options.inspectScopes,
437
+ scopeMethods: options.scopeMethods,
438
+ requiredScopes: requirements.botScopes,
439
+ optionalScopes: requirements.optionalBotScopes
440
+ });
441
+ return {
442
+ ok: connection.ok,
443
+ requirements,
444
+ connection
445
+ };
446
+ }
447
+ export {
448
+ compareSlackAppManifest,
449
+ createSlackAppManifest,
450
+ getSlackSetupRequirements,
451
+ inspectSlackAppSetup,
452
+ slackSetupFeaturePresets
453
+ };
@@ -0,0 +1,2 @@
1
+ export { S as SlackActivityInfo, a as SlackChannelType, b as SlackUserIdentity } from './activity-ByrD9Ftr.js';
2
+ export { ExtractSlackMessageTextOptions, RawSlackActionTokenPayload, RawSlackAppMentionPayload, RawSlackAssistantThreadPayload, RawSlackMessagePayload, SlackAmbientTurnContext, SlackApprovalRequest, SlackAssistantStatusUpdate, SlackAssistantSuggestedPrompt, SlackAssistantSuggestedPrompts, SlackAssistantTaskDisplayMode, SlackAssistantThreadContext, SlackAssistantUtilities, SlackAuthContext, SlackChatStreamStartArgs, SlackEventInteractiveRequestHandler, SlackHumanInputRequest, SlackInteractiveMessage, SlackInteractiveMessageRef, SlackInteractiveRequest, SlackInteractiveRequestBaseContext, SlackInteractiveRequestContext, SlackInteractiveRequestHandler, SlackInteractiveRequestKind, SlackInteractiveResponder, SlackMessageAuthorshipOptions, SlackMessageFormatter, SlackMessageFormattingOptions, SlackMessageTextPayload, SlackThreadStatusSetter, SlackTurnPreparation, SlackTurnRequestContext, currentSlackTurnContext, extractSlackActionToken, extractSlackAttachmentsText, extractSlackAuthContext, extractSlackBlocksText, extractSlackMessageText, extractSlackUserIdentity, formatSlackAttributedFollowUp, isProcessableMessage, markdownToSlackMrkdwn, parseSlackMentionActivity, parseSlackMessageActivity, resolveSlackChannelType, resolveSlackMessageFormatter, resolveThreadAwareSlackSessionId, runWithSlackTurnContext, stripLeadingMentions } from './core.js';
package/dist/shared.js ADDED
@@ -0,0 +1,43 @@
1
+ import "./chunk-NE57BLLU.js";
2
+ import {
3
+ currentSlackTurnContext,
4
+ formatSlackAttributedFollowUp,
5
+ markdownToSlackMrkdwn,
6
+ resolveSlackMessageFormatter,
7
+ resolveThreadAwareSlackSessionId,
8
+ runWithSlackTurnContext
9
+ } from "./chunk-JZG4IETE.js";
10
+ import {
11
+ extractSlackActionToken,
12
+ extractSlackAuthContext,
13
+ extractSlackUserIdentity,
14
+ parseSlackMentionActivity,
15
+ parseSlackMessageActivity
16
+ } from "./chunk-TWJGVDA2.js";
17
+ import {
18
+ extractSlackAttachmentsText,
19
+ extractSlackBlocksText,
20
+ extractSlackMessageText,
21
+ isProcessableMessage,
22
+ resolveSlackChannelType,
23
+ stripLeadingMentions
24
+ } from "./chunk-FPCE5V5Y.js";
25
+ export {
26
+ currentSlackTurnContext,
27
+ extractSlackActionToken,
28
+ extractSlackAttachmentsText,
29
+ extractSlackAuthContext,
30
+ extractSlackBlocksText,
31
+ extractSlackMessageText,
32
+ extractSlackUserIdentity,
33
+ formatSlackAttributedFollowUp,
34
+ isProcessableMessage,
35
+ markdownToSlackMrkdwn,
36
+ parseSlackMentionActivity,
37
+ parseSlackMessageActivity,
38
+ resolveSlackChannelType,
39
+ resolveSlackMessageFormatter,
40
+ resolveThreadAwareSlackSessionId,
41
+ runWithSlackTurnContext,
42
+ stripLeadingMentions
43
+ };
@@ -0,0 +1,113 @@
1
+ type SlackTargetKind = "channel" | "user";
2
+ type SlackTargetValueKind = "id" | "name";
3
+ type SlackTargetSource = "prefixed" | "mention" | "link" | "id" | "name";
4
+ interface SlackTarget {
5
+ input: string;
6
+ kind: SlackTargetKind;
7
+ valueKind: SlackTargetValueKind;
8
+ value: string;
9
+ source: SlackTargetSource;
10
+ id?: string;
11
+ name?: string;
12
+ label?: string;
13
+ }
14
+ interface ParseSlackTargetOptions {
15
+ /**
16
+ * Interpret bare non-ID values as this target kind.
17
+ *
18
+ * @example `parseSlackTarget("general", { defaultKind: "channel" })`
19
+ */
20
+ defaultKind?: SlackTargetKind;
21
+ /**
22
+ * Whether bare non-ID values may be parsed through `defaultKind`.
23
+ *
24
+ * @default Boolean(defaultKind)
25
+ */
26
+ allowBareNames?: boolean;
27
+ }
28
+ interface ParseSlackTargetsResult {
29
+ targets: SlackTarget[];
30
+ invalid: string[];
31
+ }
32
+ declare function parseSlackTarget(input: string, options?: ParseSlackTargetOptions): SlackTarget | undefined;
33
+ declare function parseSlackTargets(inputs: string | readonly string[], options?: ParseSlackTargetOptions): ParseSlackTargetsResult;
34
+
35
+ interface SlackTargetResolutionClient {
36
+ conversations?: {
37
+ list(args?: Record<string, unknown>): Promise<unknown>;
38
+ };
39
+ users?: {
40
+ list(args?: Record<string, unknown>): Promise<unknown>;
41
+ };
42
+ }
43
+ interface SlackResolvedTarget {
44
+ input: string;
45
+ kind: SlackTargetKind;
46
+ id: string;
47
+ valueKind: "id" | "name";
48
+ name?: string;
49
+ label?: string;
50
+ raw?: unknown;
51
+ }
52
+ type SlackTargetResolutionErrorCode = "invalid-target" | "target-kind-mismatch" | "missing-client-method" | "not-found" | "api-error";
53
+ interface SlackTargetResolutionError {
54
+ input: string;
55
+ code: SlackTargetResolutionErrorCode;
56
+ message: string;
57
+ kind?: SlackTargetKind;
58
+ name?: string;
59
+ error?: unknown;
60
+ }
61
+ interface SlackTargetResolutionResult {
62
+ resolved: SlackResolvedTarget[];
63
+ unresolved: SlackTargetResolutionError[];
64
+ }
65
+ interface ResolveSlackChannelTargetsOptions {
66
+ client: SlackTargetResolutionClient;
67
+ targets: readonly (string | SlackTarget)[];
68
+ token?: string;
69
+ /**
70
+ * Conversation types passed to `conversations.list`.
71
+ *
72
+ * @default "public_channel,private_channel"
73
+ */
74
+ types?: string;
75
+ /** Include archived channels while resolving names. @default false */
76
+ includeArchived?: boolean;
77
+ /** Slack API page size. @default 200 */
78
+ limit?: number;
79
+ }
80
+ interface ResolveSlackUserTargetsOptions {
81
+ client: SlackTargetResolutionClient;
82
+ targets: readonly (string | SlackTarget)[];
83
+ token?: string;
84
+ /** Include deleted users while resolving names. @default false */
85
+ includeDeleted?: boolean;
86
+ /** Include bot users while resolving names. @default false */
87
+ includeBots?: boolean;
88
+ /** Slack API page size. @default 200 */
89
+ limit?: number;
90
+ }
91
+ interface ResolveSlackAllowedChannelIdsOptions extends Omit<ResolveSlackChannelTargetsOptions, "client" | "targets"> {
92
+ /**
93
+ * Human-friendly channel targets from policy config, such as `C123`,
94
+ * `#engineering`, `<#C123|engineering>`, or `channel:engineering`.
95
+ */
96
+ targets: readonly (string | SlackTarget)[];
97
+ /**
98
+ * Slack Web API client used when a target needs name resolution. Direct
99
+ * channel IDs do not require a client.
100
+ */
101
+ client?: SlackTargetResolutionClient;
102
+ }
103
+ interface SlackAllowedChannelIdsResolution {
104
+ ok: boolean;
105
+ allowedChannelIds: string[];
106
+ resolved: SlackResolvedTarget[];
107
+ unresolved: SlackTargetResolutionError[];
108
+ }
109
+ declare function resolveSlackChannelTargets(options: ResolveSlackChannelTargetsOptions): Promise<SlackTargetResolutionResult>;
110
+ declare function resolveSlackUserTargets(options: ResolveSlackUserTargetsOptions): Promise<SlackTargetResolutionResult>;
111
+ declare function resolveSlackAllowedChannelIds(options: ResolveSlackAllowedChannelIdsOptions): Promise<SlackAllowedChannelIdsResolution>;
112
+
113
+ export { type ParseSlackTargetOptions, type ParseSlackTargetsResult, type ResolveSlackAllowedChannelIdsOptions, type ResolveSlackChannelTargetsOptions, type ResolveSlackUserTargetsOptions, type SlackAllowedChannelIdsResolution, type SlackResolvedTarget, type SlackTarget, type SlackTargetKind, type SlackTargetResolutionClient, type SlackTargetResolutionError, type SlackTargetResolutionErrorCode, type SlackTargetResolutionResult, type SlackTargetSource, type SlackTargetValueKind, parseSlackTarget, parseSlackTargets, resolveSlackAllowedChannelIds, resolveSlackChannelTargets, resolveSlackUserTargets };