@credal/actions 0.2.150 → 0.2.152
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.
|
@@ -1,4 +1,6 @@
|
|
|
1
|
+
import { type KnownBlock } from "@slack/web-api";
|
|
1
2
|
import { type slackUserSearchSlackFunction } from "../../autogen/types.js";
|
|
3
|
+
import type { Attachment } from "@slack/web-api/dist/types/response/ChannelsHistoryResponse.js";
|
|
2
4
|
export type TimeRange = "latest" | "today" | "yesterday" | "last_7d" | "last_30d" | "all";
|
|
3
5
|
export interface SlackSearchMessage {
|
|
4
6
|
channelId: string;
|
|
@@ -19,5 +21,18 @@ export interface SlackSearchMessage {
|
|
|
19
21
|
userName?: string;
|
|
20
22
|
}>;
|
|
21
23
|
}
|
|
24
|
+
interface SlackMessage {
|
|
25
|
+
ts?: string;
|
|
26
|
+
text?: string;
|
|
27
|
+
user?: string;
|
|
28
|
+
username?: string;
|
|
29
|
+
thread_ts?: string;
|
|
30
|
+
blocks?: KnownBlock[];
|
|
31
|
+
attachments?: Attachment[];
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Extracts all visible text from a Slack message
|
|
35
|
+
*/
|
|
36
|
+
export declare function extractMessageText(m: SlackMessage | undefined): string | undefined;
|
|
22
37
|
declare const searchSlack: slackUserSearchSlackFunction;
|
|
23
38
|
export default searchSlack;
|
|
@@ -63,6 +63,164 @@ class SlackUserCache {
|
|
|
63
63
|
}
|
|
64
64
|
}
|
|
65
65
|
/* ===================== Helpers ===================== */
|
|
66
|
+
/* ===================== Helpers ===================== */
|
|
67
|
+
/**
|
|
68
|
+
* Extracts all visible text from a Slack message
|
|
69
|
+
*/
|
|
70
|
+
export function extractMessageText(m) {
|
|
71
|
+
var _a, _b, _c, _d;
|
|
72
|
+
if (!m)
|
|
73
|
+
return undefined;
|
|
74
|
+
const pieces = [];
|
|
75
|
+
// ---- Rich text helpers ----
|
|
76
|
+
const walkRichTextInline = (el) => {
|
|
77
|
+
var _a;
|
|
78
|
+
const blockPieces = [];
|
|
79
|
+
switch (el.type) {
|
|
80
|
+
case "text":
|
|
81
|
+
blockPieces.push(el.text);
|
|
82
|
+
break;
|
|
83
|
+
case "link":
|
|
84
|
+
blockPieces.push(el.text || el.url);
|
|
85
|
+
break;
|
|
86
|
+
case "user":
|
|
87
|
+
blockPieces.push(`<@${el.user_id}>`);
|
|
88
|
+
break;
|
|
89
|
+
case "channel":
|
|
90
|
+
blockPieces.push(`<#${el.channel_id}>`);
|
|
91
|
+
break;
|
|
92
|
+
case "emoji":
|
|
93
|
+
blockPieces.push(`:${el.name}:`);
|
|
94
|
+
break;
|
|
95
|
+
case "broadcast":
|
|
96
|
+
blockPieces.push(`@${el.range}`);
|
|
97
|
+
break;
|
|
98
|
+
case "date":
|
|
99
|
+
blockPieces.push((_a = el.fallback) !== null && _a !== void 0 ? _a : `<date:${el.timestamp}>`);
|
|
100
|
+
break;
|
|
101
|
+
case "team":
|
|
102
|
+
blockPieces.push(`<team:${el.team_id}>`);
|
|
103
|
+
break;
|
|
104
|
+
case "usergroup":
|
|
105
|
+
blockPieces.push(`<usergroup:${el.usergroup_id}>`);
|
|
106
|
+
break;
|
|
107
|
+
case "color":
|
|
108
|
+
// Usually formatting only, skip
|
|
109
|
+
break;
|
|
110
|
+
}
|
|
111
|
+
return blockPieces;
|
|
112
|
+
};
|
|
113
|
+
const walkRichTextElement = (el) => {
|
|
114
|
+
const result = [];
|
|
115
|
+
switch (el.type) {
|
|
116
|
+
case "rich_text_section":
|
|
117
|
+
case "rich_text_quote":
|
|
118
|
+
result.push(el.elements.map(walkRichTextInline).join("\n"));
|
|
119
|
+
break;
|
|
120
|
+
case "rich_text_list":
|
|
121
|
+
result.push(el.elements.map(section => section.elements.map(walkRichTextInline).join("\n")).join("\n"));
|
|
122
|
+
break;
|
|
123
|
+
case "rich_text_preformatted":
|
|
124
|
+
result.push(el.elements.map(walkRichTextInline).join("\n"));
|
|
125
|
+
break;
|
|
126
|
+
}
|
|
127
|
+
return result;
|
|
128
|
+
};
|
|
129
|
+
// ---- Block helpers ----
|
|
130
|
+
const walkBlock = (block) => {
|
|
131
|
+
var _a, _b, _c, _d, _e, _f, _g;
|
|
132
|
+
const blockPieces = [];
|
|
133
|
+
switch (block.type) {
|
|
134
|
+
case "section":
|
|
135
|
+
if ((_a = block.text) === null || _a === void 0 ? void 0 : _a.text)
|
|
136
|
+
blockPieces.push(block.text.text);
|
|
137
|
+
if (block.fields) {
|
|
138
|
+
for (const f of block.fields)
|
|
139
|
+
if (f.text)
|
|
140
|
+
blockPieces.push(f.text);
|
|
141
|
+
}
|
|
142
|
+
if (block.accessory && "text" in block.accessory && block.accessory.text) {
|
|
143
|
+
blockPieces.push(block.accessory.text.text);
|
|
144
|
+
}
|
|
145
|
+
break;
|
|
146
|
+
case "context":
|
|
147
|
+
if (Array.isArray(block.elements)) {
|
|
148
|
+
block.elements.forEach(el => {
|
|
149
|
+
if ("text" in el && el.text)
|
|
150
|
+
blockPieces.push(el.text);
|
|
151
|
+
});
|
|
152
|
+
}
|
|
153
|
+
break;
|
|
154
|
+
case "header":
|
|
155
|
+
if ((_b = block.text) === null || _b === void 0 ? void 0 : _b.text)
|
|
156
|
+
blockPieces.push(block.text.text);
|
|
157
|
+
break;
|
|
158
|
+
case "rich_text":
|
|
159
|
+
blockPieces.push(block.elements.map(walkRichTextElement).join("\n"));
|
|
160
|
+
break;
|
|
161
|
+
case "markdown":
|
|
162
|
+
if (block.text)
|
|
163
|
+
blockPieces.push(block.text);
|
|
164
|
+
break;
|
|
165
|
+
case "video":
|
|
166
|
+
if ((_c = block.title) === null || _c === void 0 ? void 0 : _c.text)
|
|
167
|
+
blockPieces.push(block.title.text);
|
|
168
|
+
if ((_d = block.description) === null || _d === void 0 ? void 0 : _d.text)
|
|
169
|
+
blockPieces.push(block.description.text);
|
|
170
|
+
break;
|
|
171
|
+
case "image":
|
|
172
|
+
if ((_e = block.title) === null || _e === void 0 ? void 0 : _e.text)
|
|
173
|
+
blockPieces.push(block.title.text);
|
|
174
|
+
break;
|
|
175
|
+
case "input":
|
|
176
|
+
if ((_f = block.label) === null || _f === void 0 ? void 0 : _f.text)
|
|
177
|
+
blockPieces.push(block.label.text);
|
|
178
|
+
if ((_g = block.hint) === null || _g === void 0 ? void 0 : _g.text)
|
|
179
|
+
blockPieces.push(block.hint.text);
|
|
180
|
+
break;
|
|
181
|
+
// divider, file, actions, input don’t contribute visible text
|
|
182
|
+
case "divider":
|
|
183
|
+
case "file":
|
|
184
|
+
case "actions":
|
|
185
|
+
break;
|
|
186
|
+
}
|
|
187
|
+
return blockPieces;
|
|
188
|
+
};
|
|
189
|
+
let blockText = "";
|
|
190
|
+
if (Array.isArray(m.blocks)) {
|
|
191
|
+
const blockPieces = m.blocks.map(b => walkBlock(b));
|
|
192
|
+
blockText = blockPieces.join("\n");
|
|
193
|
+
}
|
|
194
|
+
if (blockText) {
|
|
195
|
+
pieces.push(blockText);
|
|
196
|
+
}
|
|
197
|
+
else if (m.text) {
|
|
198
|
+
pieces.push(m.text);
|
|
199
|
+
}
|
|
200
|
+
// 3. Attachments
|
|
201
|
+
if (m.attachments) {
|
|
202
|
+
for (const att of m.attachments) {
|
|
203
|
+
if (att.pretext)
|
|
204
|
+
pieces.push(att.pretext);
|
|
205
|
+
if (att.title)
|
|
206
|
+
pieces.push(att.title);
|
|
207
|
+
if (att.text)
|
|
208
|
+
pieces.push(att.text);
|
|
209
|
+
if (att.fields) {
|
|
210
|
+
for (const f of att.fields) {
|
|
211
|
+
const title = (_b = (_a = f.title) === null || _a === void 0 ? void 0 : _a.trim()) !== null && _b !== void 0 ? _b : "";
|
|
212
|
+
const value = (_d = (_c = f.value) === null || _c === void 0 ? void 0 : _c.trim()) !== null && _d !== void 0 ? _d : "";
|
|
213
|
+
if (title || value) {
|
|
214
|
+
pieces.push(title && value ? `${title}: ${value}` : title || value);
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
// Deduplicate and join
|
|
221
|
+
const out = Array.from(new Set(pieces.map(s => s.trim()).filter(Boolean))).join("\n");
|
|
222
|
+
return out || undefined;
|
|
223
|
+
}
|
|
66
224
|
function normalizeChannelOperand(ch) {
|
|
67
225
|
const s = ch.trim();
|
|
68
226
|
if (/^[CGD][A-Z0-9]/i.test(s))
|
|
@@ -139,18 +297,32 @@ function getPermalink(client, channel, ts) {
|
|
|
139
297
|
}
|
|
140
298
|
});
|
|
141
299
|
}
|
|
300
|
+
function transformToSlackMessage(message) {
|
|
301
|
+
return {
|
|
302
|
+
ts: message.ts,
|
|
303
|
+
text: message.text,
|
|
304
|
+
user: message.user,
|
|
305
|
+
username: message.username,
|
|
306
|
+
thread_ts: message.thread_ts,
|
|
307
|
+
blocks: message.blocks,
|
|
308
|
+
attachments: message.attachments,
|
|
309
|
+
};
|
|
310
|
+
}
|
|
142
311
|
function fetchOneMessage(client, channel, ts) {
|
|
143
312
|
return __awaiter(this, void 0, void 0, function* () {
|
|
144
313
|
var _a;
|
|
145
314
|
const r = yield client.conversations.history({ channel, latest: ts, inclusive: true, limit: 1 });
|
|
146
|
-
|
|
315
|
+
const message = (_a = r.messages) === null || _a === void 0 ? void 0 : _a[0];
|
|
316
|
+
if (!message)
|
|
317
|
+
return undefined;
|
|
318
|
+
return transformToSlackMessage(message);
|
|
147
319
|
});
|
|
148
320
|
}
|
|
149
321
|
function fetchThread(client, channel, threadTs) {
|
|
150
322
|
return __awaiter(this, void 0, void 0, function* () {
|
|
151
|
-
var _a;
|
|
323
|
+
var _a, _b;
|
|
152
324
|
const r = yield client.conversations.replies({ channel, ts: threadTs, limit: 20 });
|
|
153
|
-
return (_a = r.messages) !== null &&
|
|
325
|
+
return (_b = (_a = r.messages) === null || _a === void 0 ? void 0 : _a.map(transformToSlackMessage)) !== null && _b !== void 0 ? _b : [];
|
|
154
326
|
});
|
|
155
327
|
}
|
|
156
328
|
function fetchContextWindow(client, channel, ts) {
|
|
@@ -161,10 +333,12 @@ function fetchContextWindow(client, channel, ts) {
|
|
|
161
333
|
if (!anchor)
|
|
162
334
|
return out;
|
|
163
335
|
const before = yield client.conversations.history({ channel, latest: ts, inclusive: false, limit: 3 });
|
|
164
|
-
|
|
336
|
+
const beforeMessages = (_a = before.messages) === null || _a === void 0 ? void 0 : _a.map(transformToSlackMessage);
|
|
337
|
+
out.push(...(beforeMessages !== null && beforeMessages !== void 0 ? beforeMessages : []).reverse());
|
|
165
338
|
out.push(anchor);
|
|
166
339
|
const after = yield client.conversations.history({ channel, oldest: ts, inclusive: false, limit: 3 });
|
|
167
|
-
|
|
340
|
+
const afterMessages = (_b = after.messages) === null || _b === void 0 ? void 0 : _b.map(transformToSlackMessage);
|
|
341
|
+
out.push(...(afterMessages !== null && afterMessages !== void 0 ? afterMessages : []));
|
|
168
342
|
return out;
|
|
169
343
|
});
|
|
170
344
|
}
|
|
@@ -258,16 +432,35 @@ const searchSlack = (_a) => __awaiter(void 0, [_a], void 0, function* ({ params,
|
|
|
258
432
|
else if (filteredTargetIds.length >= 2) {
|
|
259
433
|
const searchMPIM = () => __awaiter(void 0, void 0, void 0, function* () {
|
|
260
434
|
const mpimName = yield tryGetMPIMName(client, filteredTargetIds);
|
|
261
|
-
return mpimName
|
|
435
|
+
return mpimName
|
|
436
|
+
? searchScoped({ client, scope: mpimName, topic, timeRange, limit: Math.max(Math.floor(limit / 2), 1) })
|
|
437
|
+
: [];
|
|
262
438
|
});
|
|
263
439
|
searchPromises.push(searchMPIM());
|
|
264
|
-
searchPromises.push(...filteredTargetIds.map(id => searchScoped({
|
|
440
|
+
searchPromises.push(...filteredTargetIds.map(id => searchScoped({
|
|
441
|
+
client,
|
|
442
|
+
scope: `<@${id}>`,
|
|
443
|
+
topic,
|
|
444
|
+
timeRange,
|
|
445
|
+
limit: Math.max(Math.floor(limit / filteredTargetIds.length), 1),
|
|
446
|
+
})));
|
|
265
447
|
}
|
|
266
448
|
else if (channel) {
|
|
267
|
-
searchPromises.push(searchScoped({
|
|
449
|
+
searchPromises.push(searchScoped({
|
|
450
|
+
client,
|
|
451
|
+
scope: normalizeChannelOperand(channel),
|
|
452
|
+
topic,
|
|
453
|
+
timeRange,
|
|
454
|
+
limit: Math.max(Math.floor(limit / 2), 1),
|
|
455
|
+
}));
|
|
268
456
|
}
|
|
269
457
|
if (topic) {
|
|
270
|
-
searchPromises.push(searchByTopic({
|
|
458
|
+
searchPromises.push(searchByTopic({
|
|
459
|
+
client,
|
|
460
|
+
topic,
|
|
461
|
+
timeRange,
|
|
462
|
+
limit: Math.max(Math.floor(limit / Math.max(searchPromises.length, 1)), 1),
|
|
463
|
+
}));
|
|
271
464
|
}
|
|
272
465
|
const searchResults = yield Promise.all(searchPromises);
|
|
273
466
|
searchResults.forEach(matches => allMatches.push(...matches));
|
|
@@ -316,18 +509,20 @@ const searchSlack = (_a) => __awaiter(void 0, [_a], void 0, function* ({ params,
|
|
|
316
509
|
const context = yield Promise.all(contextMsgs.map((t) => __awaiter(void 0, void 0, void 0, function* () {
|
|
317
510
|
var _a;
|
|
318
511
|
const u = t.user ? yield cache.get(t.user) : undefined;
|
|
512
|
+
const rawText = extractMessageText(t);
|
|
319
513
|
return {
|
|
320
514
|
ts: t.ts,
|
|
321
|
-
text:
|
|
515
|
+
text: rawText ? yield expandSlackEntities(cache, rawText) : undefined,
|
|
322
516
|
userEmail: u === null || u === void 0 ? void 0 : u.email,
|
|
323
517
|
userName: (_a = u === null || u === void 0 ? void 0 : u.name) !== null && _a !== void 0 ? _a : t.username,
|
|
324
518
|
};
|
|
325
519
|
})));
|
|
326
520
|
const anchorUser = (anchor === null || anchor === void 0 ? void 0 : anchor.user) ? yield cache.get(anchor.user) : undefined;
|
|
521
|
+
const anchorText = extractMessageText(anchor);
|
|
327
522
|
return {
|
|
328
523
|
channelId: m.channel.id,
|
|
329
524
|
ts: rootTs,
|
|
330
|
-
text:
|
|
525
|
+
text: anchorText ? yield expandSlackEntities(cache, anchorText) : undefined,
|
|
331
526
|
userEmail: anchorUser === null || anchorUser === void 0 ? void 0 : anchorUser.email,
|
|
332
527
|
userName: (_j = anchorUser === null || anchorUser === void 0 ? void 0 : anchorUser.name) !== null && _j !== void 0 ? _j : anchor === null || anchor === void 0 ? void 0 : anchor.username,
|
|
333
528
|
context,
|