@cuylabs/channel-slack 0.9.0 → 0.11.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 (40) hide show
  1. package/README.md +15 -2
  2. package/dist/adapter/index.d.ts +53 -0
  3. package/dist/adapter/index.js +13 -0
  4. package/dist/app-surface.d.ts +86 -0
  5. package/dist/app-surface.js +15 -0
  6. package/dist/app.d.ts +58 -0
  7. package/dist/app.js +86 -0
  8. package/dist/artifacts/index.d.ts +57 -3
  9. package/dist/artifacts/index.js +88 -0
  10. package/dist/assistant/index.d.ts +18 -53
  11. package/dist/assistant/index.js +15 -184
  12. package/dist/bolt-app-BM0tiL7c.d.ts +49 -0
  13. package/dist/{chunk-TWJGVDA2.js → chunk-37RN2YUI.js} +88 -1
  14. package/dist/chunk-IAQXQESO.js +1008 -0
  15. package/dist/chunk-LFQCINHI.js +187 -0
  16. package/dist/chunk-Q6YX7HHK.js +1062 -0
  17. package/dist/chunk-RHOIVQLD.js +127 -0
  18. package/dist/chunk-RTDLIYEE.js +446 -0
  19. package/dist/core.d.ts +5 -201
  20. package/dist/core.js +10 -12
  21. package/dist/feedback/index.d.ts +2 -2
  22. package/dist/feedback/index.js +5 -120
  23. package/dist/formatting-C-kwQseI.d.ts +25 -0
  24. package/dist/index.d.ts +8 -1
  25. package/dist/index.js +18 -12
  26. package/dist/interactive/index.d.ts +4 -91
  27. package/dist/options-B0xQCaez.d.ts +221 -0
  28. package/dist/options-DQacQDmD.d.ts +368 -0
  29. package/dist/runtime/index.d.ts +46 -0
  30. package/dist/runtime/index.js +10 -0
  31. package/dist/socket.d.ts +142 -0
  32. package/dist/socket.js +77 -0
  33. package/dist/transports/index.d.ts +2 -1
  34. package/dist/transports/socket/index.d.ts +4 -49
  35. package/dist/turn-BGAXddH_.d.ts +178 -0
  36. package/dist/types-Cywfj8Mj.d.ts +91 -0
  37. package/dist/types-wLZzyI9r.d.ts +375 -0
  38. package/docs/reference/exports.md +5 -1
  39. package/package.json +28 -3
  40. package/dist/chunk-ISOMBQXE.js +0 -89
@@ -1,188 +1,19 @@
1
1
  import {
2
- extractSlackActionToken
3
- } from "../chunk-TWJGVDA2.js";
4
- import {
5
- resolveSlackChannelType,
6
- stripLeadingMentions
7
- } from "../chunk-FPCE5V5Y.js";
8
-
9
- // src/assistant/thread-context-store.ts
10
- var ASSISTANT_THREAD_CONTEXT_EVENT_TYPE = "assistant_thread_context";
11
- function createSlackAssistantThreadContextStore() {
12
- const cache = /* @__PURE__ */ new Map();
13
- return {
14
- async get(args) {
15
- args.logger?.debug?.("[channel-slack] thread context store get called");
16
- const { channelId, threadTs } = extractThreadInfo(args.payload);
17
- const cacheKey = contextCacheKey(channelId, threadTs);
18
- const cached = cache.get(cacheKey);
19
- if (cached) return cached;
20
- const messages = await readThreadMessages(args, channelId, threadTs);
21
- const botUserId = args.context?.botUserId;
22
- const metadataMessage = findContextMessage(messages, botUserId);
23
- const context = toThreadContext(metadataMessage?.metadata?.event_payload);
24
- cache.set(cacheKey, context);
25
- return context;
26
- },
27
- async save(args) {
28
- args.logger?.debug?.("[channel-slack] thread context store save called");
29
- const { channelId, threadTs, context } = extractThreadInfo(args.payload);
30
- const cacheKey = contextCacheKey(channelId, threadTs);
31
- cache.set(cacheKey, context);
32
- const messages = await readThreadMessages(args, channelId, threadTs);
33
- const initialMessage = findInitialBotMessage(
34
- messages,
35
- args.context?.botUserId
36
- );
37
- if (!initialMessage?.ts) return;
38
- await args.client?.chat?.update?.({
39
- channel: channelId,
40
- ts: initialMessage.ts,
41
- text: initialMessage.text ?? "",
42
- blocks: Array.isArray(initialMessage.blocks) ? initialMessage.blocks : [],
43
- metadata: {
44
- event_type: ASSISTANT_THREAD_CONTEXT_EVENT_TYPE,
45
- event_payload: context
46
- }
47
- });
48
- }
49
- };
50
- }
51
- async function readThreadMessages(args, channelId, threadTs) {
52
- const replies = args.client?.conversations?.replies;
53
- if (typeof replies !== "function") return [];
54
- const result = await replies({
55
- channel: channelId,
56
- ts: threadTs,
57
- oldest: threadTs,
58
- include_all_metadata: true,
59
- limit: 4
60
- });
61
- return Array.isArray(result.messages) ? result.messages.filter(isSlackMessageWithMetadata) : [];
62
- }
63
- function findContextMessage(messages, botUserId) {
64
- return messages.find(
65
- (message) => isBotAuthoredMessage(message, botUserId) && message.metadata?.event_type === ASSISTANT_THREAD_CONTEXT_EVENT_TYPE
66
- ) ?? messages.find(
67
- (message) => isBotAuthoredMessage(message, botUserId) && message.metadata?.event_payload
68
- );
69
- }
70
- function findInitialBotMessage(messages, botUserId) {
71
- return messages.find((message) => isBotAuthoredMessage(message, botUserId));
72
- }
73
- function isBotAuthoredMessage(message, botUserId) {
74
- if (message.subtype) return false;
75
- return botUserId ? message.user === botUserId : Boolean(message.user);
76
- }
77
- function extractThreadInfo(payload) {
78
- const channelId = extractChannelId(payload);
79
- const threadTs = extractThreadTs(payload);
80
- if (!channelId || !threadTs) {
81
- const missing = [];
82
- if (!channelId) missing.push("channel_id");
83
- if (!threadTs) missing.push("thread_ts");
84
- throw new Error(
85
- `Assistant payload is missing required properties: ${missing.join(", ")}`
86
- );
87
- }
88
- return {
89
- channelId,
90
- threadTs,
91
- context: extractThreadContext(payload)
92
- };
93
- }
94
- function extractThreadContext(payload) {
95
- if (!isRecord(payload)) return {};
96
- const assistantThread = payload.assistant_thread;
97
- if (!isRecord(assistantThread) || !isRecord(assistantThread.context)) {
98
- return {};
99
- }
100
- return toThreadContext(assistantThread.context);
101
- }
102
- function extractThreadTs(payload) {
103
- if (!isRecord(payload)) return void 0;
104
- if (isNonEmptyString(payload.thread_ts)) return payload.thread_ts;
105
- if (isRecord(payload.assistant_thread) && isNonEmptyString(payload.assistant_thread.thread_ts)) {
106
- return payload.assistant_thread.thread_ts;
107
- }
108
- if (isRecord(payload.message) && isNonEmptyString(payload.message.thread_ts)) {
109
- return payload.message.thread_ts;
110
- }
111
- if (isRecord(payload.previous_message) && isNonEmptyString(payload.previous_message.thread_ts)) {
112
- return payload.previous_message.thread_ts;
113
- }
114
- return void 0;
115
- }
116
- function extractChannelId(payload) {
117
- if (!isRecord(payload)) return void 0;
118
- if (isNonEmptyString(payload.channel)) return payload.channel;
119
- if (isRecord(payload.channel) && isNonEmptyString(payload.channel.id)) {
120
- return payload.channel.id;
121
- }
122
- if (isNonEmptyString(payload.channel_id)) return payload.channel_id;
123
- if (isRecord(payload.item) && isNonEmptyString(payload.item.channel)) {
124
- return payload.item.channel;
125
- }
126
- if (isRecord(payload.assistant_thread) && isNonEmptyString(payload.assistant_thread.channel_id)) {
127
- return payload.assistant_thread.channel_id;
128
- }
129
- return void 0;
130
- }
131
- function toThreadContext(value) {
132
- if (!isRecord(value)) return {};
133
- return {
134
- ...isNonEmptyString(value.channel_id) ? { channel_id: value.channel_id } : {},
135
- ...isNonEmptyString(value.team_id) ? { team_id: value.team_id } : {},
136
- ..."enterprise_id" in value ? {
137
- enterprise_id: typeof value.enterprise_id === "string" ? value.enterprise_id : null
138
- } : {}
139
- };
140
- }
141
- function isSlackMessageWithMetadata(value) {
142
- return isRecord(value);
143
- }
144
- function contextCacheKey(channelId, threadTs) {
145
- return `${channelId}:${threadTs}`;
146
- }
147
- function isNonEmptyString(value) {
148
- return typeof value === "string" && value.length > 0;
149
- }
150
- function isRecord(value) {
151
- return typeof value === "object" && value !== null;
152
- }
153
-
154
- // src/assistant/message-parser.ts
155
- function parseSlackMessageActivityFromMessageEvent(message) {
156
- if (!message || typeof message !== "object") return void 0;
157
- const m = message;
158
- if (m.subtype && m.subtype.length > 0) return void 0;
159
- if (typeof m.text !== "string" || m.text.length === 0) return void 0;
160
- if (typeof m.thread_ts !== "string" || m.thread_ts.length === 0) {
161
- return void 0;
162
- }
163
- const channel = typeof m.channel === "string" ? m.channel : void 0;
164
- if (!channel) return void 0;
165
- const threadTs = m.thread_ts;
166
- const messageTs = m.ts;
167
- const isThread = threadTs !== messageTs;
168
- const channelType = resolveSlackChannelType(channel, threadTs, isThread);
169
- const rawText = m.text;
170
- const text = channelType === "dm" ? rawText.trim() : stripLeadingMentions(rawText);
171
- return {
172
- channel,
173
- threadTs,
174
- channelId: channel,
175
- channelType,
176
- userId: m.user ?? "unknown",
177
- teamId: m.team ?? void 0,
178
- parentUserId: m.parent_user_id,
179
- actionToken: extractSlackActionToken(m),
180
- text,
181
- isMention: false,
182
- ...messageTs ? { messageTs } : {}
183
- };
184
- }
2
+ createSlackAssistantBridge,
3
+ createSlackAssistantThreadContextStore,
4
+ parseSlackMessageActivityFromMessageEvent,
5
+ resolveAssistantSessionId
6
+ } from "../chunk-Q6YX7HHK.js";
7
+ import "../chunk-RHOIVQLD.js";
8
+ import "../chunk-IRFKUPJN.js";
9
+ import "../chunk-IAQXQESO.js";
10
+ import "../chunk-37RN2YUI.js";
11
+ import "../chunk-3KP3CBCC.js";
12
+ import "../chunk-FPCE5V5Y.js";
13
+ import "../chunk-6WHFQUYQ.js";
185
14
  export {
15
+ createSlackAssistantBridge,
186
16
  createSlackAssistantThreadContextStore,
187
- parseSlackMessageActivityFromMessageEvent
17
+ parseSlackMessageActivityFromMessageEvent,
18
+ resolveAssistantSessionId
188
19
  };
@@ -0,0 +1,49 @@
1
+ import { AppOptions, SocketModeReceiverOptions, App } from '@slack/bolt';
2
+ import { e as SlackDirectAuthOptions, d as SlackDirectAuthMode } from './types-B9NfCVrk.js';
3
+
4
+ /**
5
+ * `createSlackSocketBoltApp` — builds a Socket Mode Bolt `App` from the
6
+ * package's structured auth options. Mirrors `createSlackBoltApp` without
7
+ * owning any assistant/app surface mounting.
8
+ */
9
+
10
+ type ControlledSocketBoltAppOption = "receiver" | "socketMode" | "appToken" | "token" | "authorize" | "botId" | "botUserId" | "clientId" | "clientSecret" | "stateSecret" | "redirectUri" | "installationStore" | "scopes" | "installerOptions";
11
+ type ControlledSocketModeReceiverOption = "appToken" | "clientId" | "clientSecret" | "stateSecret" | "redirectUri" | "installationStore" | "scopes" | "installerOptions" | "logger" | "logLevel";
12
+ interface CreateSlackSocketBoltAppOptions {
13
+ /**
14
+ * Slack app-level token (`xapp-...`) with `connections:write` scope.
15
+ * @default process.env.SLACK_APP_TOKEN
16
+ */
17
+ appToken?: string;
18
+ /**
19
+ * Convenience override for single-workspace mode.
20
+ * @default process.env.SLACK_BOT_TOKEN
21
+ */
22
+ botToken?: string;
23
+ /**
24
+ * Direct-mode auth configuration.
25
+ *
26
+ * - omit for single-workspace token mode
27
+ * - use `{ mode: "oauth", ... }` for Bolt-managed installs
28
+ * - use `{ mode: "authorize", authorize }` for external token resolution
29
+ */
30
+ auth?: SlackDirectAuthOptions;
31
+ /**
32
+ * Additional Bolt `App` options passed after this package sets Socket Mode
33
+ * and auth. Use for logger/clientOptions and non-auth native Bolt config.
34
+ */
35
+ boltAppOptions?: Partial<Omit<AppOptions, ControlledSocketBoltAppOption>>;
36
+ /**
37
+ * Additional native Socket Mode receiver options. Use this for websocket
38
+ * health tuning such as ping timeouts, reconnect behavior, and receiver
39
+ * error handling. Auth/OAuth fields stay controlled by this helper.
40
+ */
41
+ socketModeReceiverOptions?: Partial<Omit<SocketModeReceiverOptions, ControlledSocketModeReceiverOption>>;
42
+ }
43
+ interface CreateSlackSocketBoltAppResult {
44
+ boltApp: App;
45
+ authMode: SlackDirectAuthMode;
46
+ }
47
+ declare function createSlackSocketBoltApp(options?: CreateSlackSocketBoltAppOptions): Promise<CreateSlackSocketBoltAppResult>;
48
+
49
+ export { type CreateSlackSocketBoltAppOptions as C, type CreateSlackSocketBoltAppResult as a, createSlackSocketBoltApp as c };
@@ -99,10 +99,97 @@ function extractSlackAuthContext(context, eventUserId) {
99
99
  return auth;
100
100
  }
101
101
 
102
+ // src/shared/turn-context.ts
103
+ import { AsyncLocalStorage } from "async_hooks";
104
+ var store = new AsyncLocalStorage();
105
+ function currentSlackTurnContext() {
106
+ return store.getStore();
107
+ }
108
+ function runWithSlackTurnContext(value, fn) {
109
+ return Promise.resolve(store.run({ ...value }, fn));
110
+ }
111
+
112
+ // src/shared/follow-up.ts
113
+ function formatSlackAttributedFollowUp(message) {
114
+ const slack = currentSlackTurnContext();
115
+ if (!slack) {
116
+ return message;
117
+ }
118
+ const sender = formatSlackSender(slack);
119
+ const conversation = formatSlackConversation(slack);
120
+ if (!sender && !conversation) {
121
+ return message;
122
+ }
123
+ const lines = ["Additional Slack follow-up for the running request."];
124
+ if (sender) {
125
+ lines.push(`Sender: ${sender}`);
126
+ }
127
+ if (conversation) {
128
+ lines.push(`Conversation: ${conversation}`);
129
+ }
130
+ lines.push("Message:", message);
131
+ return lines.join("\n");
132
+ }
133
+ function formatSlackSender(slack) {
134
+ const userId = slack.slackActivity.userId || slack.user.userId;
135
+ const displayName = readPreparedSlackDisplayName(slack.context) ?? slack.user.userName;
136
+ if (displayName && userId) {
137
+ return `${displayName} (${userId})`;
138
+ }
139
+ return displayName ?? userId ?? "unknown Slack user";
140
+ }
141
+ function formatSlackConversation(slack) {
142
+ const activity = slack.slackActivity;
143
+ const surface = formatSlackSurface(activity.channelType);
144
+ const parts = [
145
+ activity.teamId ? `team ${activity.teamId}` : void 0,
146
+ activity.channelId ? `channel ${activity.channelId}` : void 0,
147
+ activity.threadTs ? `thread ${activity.threadTs}` : activity.messageTs ? `message ${activity.messageTs}` : void 0
148
+ ].filter((part) => Boolean(part));
149
+ return parts.length > 0 ? `${surface} (${parts.join(", ")})` : surface;
150
+ }
151
+ function formatSlackSurface(channelType) {
152
+ switch (channelType) {
153
+ case "dm":
154
+ return "private Slack DM";
155
+ case "thread":
156
+ return "shared Slack thread";
157
+ case "channel":
158
+ return "shared Slack channel";
159
+ case "group":
160
+ return "shared Slack group conversation";
161
+ default:
162
+ return "Slack conversation";
163
+ }
164
+ }
165
+ function readPreparedSlackDisplayName(context) {
166
+ const slack = context?.slack;
167
+ if (!slack || typeof slack !== "object") {
168
+ return void 0;
169
+ }
170
+ const value = slack.userDisplayName;
171
+ return typeof value === "string" && value.length > 0 ? value : void 0;
172
+ }
173
+
174
+ // src/shared/session.ts
175
+ function resolveThreadAwareSlackSessionId(info) {
176
+ if (info.channelType === "dm") {
177
+ return info.channelId;
178
+ }
179
+ if (info.threadTs) {
180
+ return `${info.channelId}:${info.threadTs}`;
181
+ }
182
+ return `${info.channelId}:${info.messageTs ?? info.channelId}`;
183
+ }
184
+
102
185
  export {
103
186
  extractSlackActionToken,
104
187
  parseSlackMessageActivity,
105
188
  parseSlackMentionActivity,
106
189
  extractSlackUserIdentity,
107
- extractSlackAuthContext
190
+ extractSlackAuthContext,
191
+ currentSlackTurnContext,
192
+ runWithSlackTurnContext,
193
+ formatSlackAttributedFollowUp,
194
+ resolveThreadAwareSlackSessionId
108
195
  };