agent-slack 0.7.1 → 0.8.5
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.
- package/dist/index.js +599 -253
- package/dist/index.js.map +14 -13
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -3927,6 +3927,413 @@ function toThreadListMessage(m) {
|
|
|
3927
3927
|
return rest;
|
|
3928
3928
|
}
|
|
3929
3929
|
|
|
3930
|
+
// src/slack/user-cache.ts
|
|
3931
|
+
import { createHash } from "node:crypto";
|
|
3932
|
+
import { join as join13 } from "node:path";
|
|
3933
|
+
|
|
3934
|
+
// src/slack/users.ts
|
|
3935
|
+
async function listUsers(client, options) {
|
|
3936
|
+
const limit = Math.min(Math.max(options?.limit ?? 200, 1), 1000);
|
|
3937
|
+
const includeBots = options?.includeBots ?? false;
|
|
3938
|
+
let next_cursor;
|
|
3939
|
+
const [out, dmMap] = await Promise.all([
|
|
3940
|
+
(async () => {
|
|
3941
|
+
const users = [];
|
|
3942
|
+
let cursor = options?.cursor;
|
|
3943
|
+
while (users.length < limit) {
|
|
3944
|
+
const pageSize = Math.min(200, limit - users.length);
|
|
3945
|
+
const resp = await client.api("users.list", { limit: pageSize, cursor });
|
|
3946
|
+
const members = asArray(resp.members).filter(isRecord);
|
|
3947
|
+
for (const m of members) {
|
|
3948
|
+
const id = getString(m.id);
|
|
3949
|
+
if (!id) {
|
|
3950
|
+
continue;
|
|
3951
|
+
}
|
|
3952
|
+
if (!includeBots && m.is_bot) {
|
|
3953
|
+
continue;
|
|
3954
|
+
}
|
|
3955
|
+
users.push(toCompactUser(m));
|
|
3956
|
+
if (users.length >= limit) {
|
|
3957
|
+
break;
|
|
3958
|
+
}
|
|
3959
|
+
}
|
|
3960
|
+
const meta = isRecord(resp.response_metadata) ? resp.response_metadata : null;
|
|
3961
|
+
const next = meta ? getString(meta.next_cursor) : undefined;
|
|
3962
|
+
if (!next) {
|
|
3963
|
+
break;
|
|
3964
|
+
}
|
|
3965
|
+
cursor = next;
|
|
3966
|
+
next_cursor = next;
|
|
3967
|
+
}
|
|
3968
|
+
return users;
|
|
3969
|
+
})(),
|
|
3970
|
+
fetchDmMap(client)
|
|
3971
|
+
]);
|
|
3972
|
+
for (const u of out) {
|
|
3973
|
+
const dmId = dmMap.get(u.id);
|
|
3974
|
+
if (dmId) {
|
|
3975
|
+
u.dm_id = dmId;
|
|
3976
|
+
}
|
|
3977
|
+
}
|
|
3978
|
+
return { users: out, next_cursor };
|
|
3979
|
+
}
|
|
3980
|
+
async function getUser(client, input) {
|
|
3981
|
+
const trimmed = input.trim();
|
|
3982
|
+
if (!trimmed) {
|
|
3983
|
+
throw new Error("User is empty");
|
|
3984
|
+
}
|
|
3985
|
+
const userId = await resolveUserId(client, trimmed);
|
|
3986
|
+
if (!userId) {
|
|
3987
|
+
throw new Error(`Could not resolve user: ${input}`);
|
|
3988
|
+
}
|
|
3989
|
+
const resp = await client.api("users.info", { user: userId });
|
|
3990
|
+
const u = isRecord(resp.user) ? resp.user : null;
|
|
3991
|
+
if (!u || !getString(u.id)) {
|
|
3992
|
+
throw new Error("users.info returned no user");
|
|
3993
|
+
}
|
|
3994
|
+
return toCompactUser(u);
|
|
3995
|
+
}
|
|
3996
|
+
async function resolveUserId(client, input) {
|
|
3997
|
+
const trimmed = input.trim();
|
|
3998
|
+
if (/^U[A-Z0-9]{8,}$/.test(trimmed)) {
|
|
3999
|
+
return trimmed;
|
|
4000
|
+
}
|
|
4001
|
+
const looksLikeEmail = /^[^@\s]+@[^@\s]+\.[^@\s]+$/.test(trimmed) && !trimmed.startsWith("@");
|
|
4002
|
+
if (looksLikeEmail) {
|
|
4003
|
+
try {
|
|
4004
|
+
const byEmail = await client.api("users.lookupByEmail", { email: trimmed });
|
|
4005
|
+
const user = isRecord(byEmail.user) ? byEmail.user : null;
|
|
4006
|
+
const userId = user ? getString(user.id) : undefined;
|
|
4007
|
+
if (userId) {
|
|
4008
|
+
return userId;
|
|
4009
|
+
}
|
|
4010
|
+
} catch {}
|
|
4011
|
+
}
|
|
4012
|
+
const handle = trimmed.startsWith("@") ? trimmed.slice(1) : trimmed;
|
|
4013
|
+
if (!handle) {
|
|
4014
|
+
return null;
|
|
4015
|
+
}
|
|
4016
|
+
const handleLower = handle.toLowerCase();
|
|
4017
|
+
let cursor;
|
|
4018
|
+
for (;; ) {
|
|
4019
|
+
const resp = await client.api("users.list", { limit: 200, cursor });
|
|
4020
|
+
const members = asArray(resp.members).filter(isRecord);
|
|
4021
|
+
const found = members.find((m) => {
|
|
4022
|
+
if (getString(m.name)?.toLowerCase() === handleLower) {
|
|
4023
|
+
return true;
|
|
4024
|
+
}
|
|
4025
|
+
if (looksLikeEmail) {
|
|
4026
|
+
const profile = isRecord(m.profile) ? m.profile : null;
|
|
4027
|
+
const email = profile ? getString(profile.email) : undefined;
|
|
4028
|
+
return Boolean(email) && email?.toLowerCase() === trimmed.toLowerCase();
|
|
4029
|
+
}
|
|
4030
|
+
return false;
|
|
4031
|
+
});
|
|
4032
|
+
if (found) {
|
|
4033
|
+
const id = getString(found.id);
|
|
4034
|
+
if (id) {
|
|
4035
|
+
return id;
|
|
4036
|
+
}
|
|
4037
|
+
}
|
|
4038
|
+
const meta = isRecord(resp.response_metadata) ? resp.response_metadata : null;
|
|
4039
|
+
const next = meta ? getString(meta.next_cursor) : undefined;
|
|
4040
|
+
if (!next) {
|
|
4041
|
+
break;
|
|
4042
|
+
}
|
|
4043
|
+
cursor = next;
|
|
4044
|
+
}
|
|
4045
|
+
return null;
|
|
4046
|
+
}
|
|
4047
|
+
async function fetchDmMap(client) {
|
|
4048
|
+
const map = new Map;
|
|
4049
|
+
let cursor;
|
|
4050
|
+
for (;; ) {
|
|
4051
|
+
const resp = await client.api("conversations.list", {
|
|
4052
|
+
types: "im",
|
|
4053
|
+
limit: 200,
|
|
4054
|
+
cursor
|
|
4055
|
+
});
|
|
4056
|
+
const channels = asArray(resp.channels).filter(isRecord);
|
|
4057
|
+
for (const ch of channels) {
|
|
4058
|
+
const id = getString(ch.id);
|
|
4059
|
+
const user = getString(ch.user);
|
|
4060
|
+
if (id && user) {
|
|
4061
|
+
map.set(user, id);
|
|
4062
|
+
}
|
|
4063
|
+
}
|
|
4064
|
+
const meta = isRecord(resp.response_metadata) ? resp.response_metadata : null;
|
|
4065
|
+
const next = meta ? getString(meta.next_cursor) : undefined;
|
|
4066
|
+
if (!next) {
|
|
4067
|
+
break;
|
|
4068
|
+
}
|
|
4069
|
+
cursor = next;
|
|
4070
|
+
}
|
|
4071
|
+
return map;
|
|
4072
|
+
}
|
|
4073
|
+
async function getDmChannelForUsers(client, inputs) {
|
|
4074
|
+
if (!inputs || inputs.length === 0) {
|
|
4075
|
+
throw new Error("At least one user is required");
|
|
4076
|
+
}
|
|
4077
|
+
if (inputs.length > 8) {
|
|
4078
|
+
throw new Error("Slack supports a maximum of 8 users in a group DM");
|
|
4079
|
+
}
|
|
4080
|
+
const userIds = [];
|
|
4081
|
+
for (const input of inputs) {
|
|
4082
|
+
const trimmed = input.trim();
|
|
4083
|
+
if (!trimmed) {
|
|
4084
|
+
continue;
|
|
4085
|
+
}
|
|
4086
|
+
const userId = await resolveUserId(client, trimmed);
|
|
4087
|
+
if (!userId) {
|
|
4088
|
+
throw new Error(`Could not resolve user: ${input}`);
|
|
4089
|
+
}
|
|
4090
|
+
userIds.push(userId);
|
|
4091
|
+
}
|
|
4092
|
+
if (userIds.length === 0) {
|
|
4093
|
+
throw new Error("No valid users provided");
|
|
4094
|
+
}
|
|
4095
|
+
const resp = await client.api("conversations.open", { users: userIds.join(",") });
|
|
4096
|
+
const channel = isRecord(resp.channel) ? resp.channel : null;
|
|
4097
|
+
const channelId = channel ? getString(channel.id) : null;
|
|
4098
|
+
if (!channelId) {
|
|
4099
|
+
throw new Error("conversations.open returned no channel");
|
|
4100
|
+
}
|
|
4101
|
+
const channelType = channelId.startsWith("D") ? "dm" : "group_dm";
|
|
4102
|
+
return {
|
|
4103
|
+
user_ids: userIds,
|
|
4104
|
+
dm_channel_id: channelId,
|
|
4105
|
+
channel_type: channelType
|
|
4106
|
+
};
|
|
4107
|
+
}
|
|
4108
|
+
function toCompactUser(u) {
|
|
4109
|
+
const profile = isRecord(u.profile) ? u.profile : {};
|
|
4110
|
+
return {
|
|
4111
|
+
id: getString(u.id) ?? "",
|
|
4112
|
+
name: getString(u.name) ?? undefined,
|
|
4113
|
+
real_name: getString(u.real_name) ?? getString(profile.real_name) ?? undefined,
|
|
4114
|
+
display_name: getString(profile.display_name) ?? undefined,
|
|
4115
|
+
email: getString(profile.email) ?? undefined,
|
|
4116
|
+
title: getString(profile.title) ?? undefined,
|
|
4117
|
+
tz: getString(u.tz) ?? undefined,
|
|
4118
|
+
is_bot: typeof u.is_bot === "boolean" ? u.is_bot : undefined,
|
|
4119
|
+
deleted: typeof u.deleted === "boolean" ? u.deleted : undefined
|
|
4120
|
+
};
|
|
4121
|
+
}
|
|
4122
|
+
|
|
4123
|
+
// src/slack/user-cache.ts
|
|
4124
|
+
var CACHE_VERSION = 1;
|
|
4125
|
+
var USER_TTL_MS = 24 * 60 * 60 * 1000;
|
|
4126
|
+
var USER_ID_PATTERN = /^(U|W)[A-Z0-9]{8,}$/;
|
|
4127
|
+
var USER_MENTION_PATTERN = /<@((U|W)[A-Z0-9]{8,})(?:\|[^>]+)?>/g;
|
|
4128
|
+
async function resolveUsersById(input) {
|
|
4129
|
+
const uniqueIds = dedupeUserIds(input.userIds);
|
|
4130
|
+
if (uniqueIds.length === 0) {
|
|
4131
|
+
return new Map;
|
|
4132
|
+
}
|
|
4133
|
+
const forceRefresh = input.forceRefresh ?? false;
|
|
4134
|
+
const now = Date.now();
|
|
4135
|
+
const workspaceKey = hashWorkspaceUrl(input.workspaceUrl);
|
|
4136
|
+
const isUnknownWorkspace = workspaceKey === "unknown";
|
|
4137
|
+
const cachePath = isUnknownWorkspace ? "" : join13(getAppDir(), `users-cache-${workspaceKey}.json`);
|
|
4138
|
+
const diskCache = cachePath ? await loadCache(cachePath) : { version: CACHE_VERSION, entries: {} };
|
|
4139
|
+
const out = new Map;
|
|
4140
|
+
const missing = [];
|
|
4141
|
+
for (const userId of uniqueIds) {
|
|
4142
|
+
const cached = diskCache.entries[userId];
|
|
4143
|
+
if (!forceRefresh && cached && now - cached.fetched_at < USER_TTL_MS) {
|
|
4144
|
+
out.set(userId, cached.user);
|
|
4145
|
+
continue;
|
|
4146
|
+
}
|
|
4147
|
+
missing.push(userId);
|
|
4148
|
+
}
|
|
4149
|
+
let cacheChanged = false;
|
|
4150
|
+
if (missing.length > 0) {
|
|
4151
|
+
const fetched = [];
|
|
4152
|
+
const concurrency = 5;
|
|
4153
|
+
for (let i = 0;i < missing.length; i += concurrency) {
|
|
4154
|
+
const chunk = missing.slice(i, i + concurrency);
|
|
4155
|
+
const results = await Promise.all(chunk.map(async (userId) => ({ userId, user: await fetchUserById(input.client, userId) })));
|
|
4156
|
+
fetched.push(...results);
|
|
4157
|
+
}
|
|
4158
|
+
for (const item of fetched) {
|
|
4159
|
+
if (!item.user) {
|
|
4160
|
+
continue;
|
|
4161
|
+
}
|
|
4162
|
+
const entry = {
|
|
4163
|
+
fetched_at: now,
|
|
4164
|
+
user: item.user
|
|
4165
|
+
};
|
|
4166
|
+
diskCache.entries[item.userId] = entry;
|
|
4167
|
+
out.set(item.userId, item.user);
|
|
4168
|
+
cacheChanged = true;
|
|
4169
|
+
}
|
|
4170
|
+
}
|
|
4171
|
+
if (cachePath) {
|
|
4172
|
+
const prunedCache = pruneExpiredEntries(diskCache, now);
|
|
4173
|
+
if (Object.keys(diskCache.entries).length !== Object.keys(prunedCache.entries).length) {
|
|
4174
|
+
cacheChanged = true;
|
|
4175
|
+
}
|
|
4176
|
+
if (cacheChanged) {
|
|
4177
|
+
await writeCache(cachePath, prunedCache);
|
|
4178
|
+
}
|
|
4179
|
+
}
|
|
4180
|
+
return out;
|
|
4181
|
+
}
|
|
4182
|
+
function collectReferencedUserIds(messages, options) {
|
|
4183
|
+
const ids = new Set;
|
|
4184
|
+
const includeReactions = options?.includeReactions ?? false;
|
|
4185
|
+
for (const message of messages) {
|
|
4186
|
+
collectUserIdsFromMessage(message, ids, { includeReactions });
|
|
4187
|
+
}
|
|
4188
|
+
return Array.from(ids);
|
|
4189
|
+
}
|
|
4190
|
+
function toReferencedUsers(userIds, usersById) {
|
|
4191
|
+
const out = {};
|
|
4192
|
+
for (const userId of dedupeUserIds(userIds)) {
|
|
4193
|
+
const user = usersById.get(userId);
|
|
4194
|
+
if (!user) {
|
|
4195
|
+
continue;
|
|
4196
|
+
}
|
|
4197
|
+
out[userId] = user;
|
|
4198
|
+
}
|
|
4199
|
+
return Object.keys(out).length > 0 ? out : undefined;
|
|
4200
|
+
}
|
|
4201
|
+
function dedupeUserIds(ids) {
|
|
4202
|
+
const seen = new Set;
|
|
4203
|
+
for (const raw of ids) {
|
|
4204
|
+
const userId = String(raw).trim();
|
|
4205
|
+
if (!USER_ID_PATTERN.test(userId)) {
|
|
4206
|
+
continue;
|
|
4207
|
+
}
|
|
4208
|
+
seen.add(userId);
|
|
4209
|
+
}
|
|
4210
|
+
return Array.from(seen);
|
|
4211
|
+
}
|
|
4212
|
+
function hashWorkspaceUrl(workspaceUrl) {
|
|
4213
|
+
const trimmed = workspaceUrl.trim();
|
|
4214
|
+
if (!trimmed) {
|
|
4215
|
+
return "unknown";
|
|
4216
|
+
}
|
|
4217
|
+
let source = trimmed;
|
|
4218
|
+
try {
|
|
4219
|
+
source = new URL(trimmed).hostname.toLowerCase();
|
|
4220
|
+
} catch {
|
|
4221
|
+
source = trimmed.toLowerCase();
|
|
4222
|
+
}
|
|
4223
|
+
if (!source || source === "unknown") {
|
|
4224
|
+
return "unknown";
|
|
4225
|
+
}
|
|
4226
|
+
return createHash("sha256").update(source).digest("hex").slice(0, 16);
|
|
4227
|
+
}
|
|
4228
|
+
async function loadCache(path) {
|
|
4229
|
+
const file = await readJsonFile(path);
|
|
4230
|
+
if (!file || file.version !== CACHE_VERSION || !isRecord(file.entries)) {
|
|
4231
|
+
return { version: CACHE_VERSION, entries: {} };
|
|
4232
|
+
}
|
|
4233
|
+
const entries = {};
|
|
4234
|
+
for (const [userId, rawEntry] of Object.entries(file.entries)) {
|
|
4235
|
+
if (!USER_ID_PATTERN.test(userId) || !isRecord(rawEntry)) {
|
|
4236
|
+
continue;
|
|
4237
|
+
}
|
|
4238
|
+
const fetchedAt = typeof rawEntry.fetched_at === "number" ? rawEntry.fetched_at : undefined;
|
|
4239
|
+
const user = isRecord(rawEntry.user) ? toCompactUser(rawEntry.user) : null;
|
|
4240
|
+
if (!fetchedAt || !user) {
|
|
4241
|
+
continue;
|
|
4242
|
+
}
|
|
4243
|
+
entries[userId] = { fetched_at: fetchedAt, user };
|
|
4244
|
+
}
|
|
4245
|
+
return {
|
|
4246
|
+
version: CACHE_VERSION,
|
|
4247
|
+
entries
|
|
4248
|
+
};
|
|
4249
|
+
}
|
|
4250
|
+
async function writeCache(path, file) {
|
|
4251
|
+
try {
|
|
4252
|
+
await writeJsonFile(path, file);
|
|
4253
|
+
} catch {}
|
|
4254
|
+
}
|
|
4255
|
+
function pruneExpiredEntries(file, now) {
|
|
4256
|
+
const next = {};
|
|
4257
|
+
for (const [userId, entry] of Object.entries(file.entries)) {
|
|
4258
|
+
if (now - entry.fetched_at >= USER_TTL_MS) {
|
|
4259
|
+
continue;
|
|
4260
|
+
}
|
|
4261
|
+
next[userId] = entry;
|
|
4262
|
+
}
|
|
4263
|
+
return { version: CACHE_VERSION, entries: next };
|
|
4264
|
+
}
|
|
4265
|
+
async function fetchUserById(client, userId) {
|
|
4266
|
+
try {
|
|
4267
|
+
const resp = await client.api("users.info", { user: userId });
|
|
4268
|
+
const user = isRecord(resp.user) ? resp.user : null;
|
|
4269
|
+
if (!user) {
|
|
4270
|
+
return;
|
|
4271
|
+
}
|
|
4272
|
+
return toCompactUser(user);
|
|
4273
|
+
} catch {
|
|
4274
|
+
return;
|
|
4275
|
+
}
|
|
4276
|
+
}
|
|
4277
|
+
function collectUserIdsFromUnknown(value, out) {
|
|
4278
|
+
if (typeof value === "string") {
|
|
4279
|
+
collectMentionUserIds(value, out);
|
|
4280
|
+
return;
|
|
4281
|
+
}
|
|
4282
|
+
if (Array.isArray(value)) {
|
|
4283
|
+
for (const item of value) {
|
|
4284
|
+
collectUserIdsFromUnknown(item, out);
|
|
4285
|
+
}
|
|
4286
|
+
return;
|
|
4287
|
+
}
|
|
4288
|
+
if (!isRecord(value)) {
|
|
4289
|
+
return;
|
|
4290
|
+
}
|
|
4291
|
+
for (const [key, child] of Object.entries(value)) {
|
|
4292
|
+
if ((key === "user" || key === "user_id") && typeof child === "string") {
|
|
4293
|
+
if (USER_ID_PATTERN.test(child)) {
|
|
4294
|
+
out.add(child);
|
|
4295
|
+
}
|
|
4296
|
+
continue;
|
|
4297
|
+
}
|
|
4298
|
+
if (key === "users") {
|
|
4299
|
+
for (const maybeUserId of asArray(child)) {
|
|
4300
|
+
const userId = String(maybeUserId);
|
|
4301
|
+
if (USER_ID_PATTERN.test(userId)) {
|
|
4302
|
+
out.add(userId);
|
|
4303
|
+
}
|
|
4304
|
+
}
|
|
4305
|
+
continue;
|
|
4306
|
+
}
|
|
4307
|
+
collectUserIdsFromUnknown(child, out);
|
|
4308
|
+
}
|
|
4309
|
+
}
|
|
4310
|
+
function collectUserIdsFromMessage(message, out, options) {
|
|
4311
|
+
if (message.user && USER_ID_PATTERN.test(message.user)) {
|
|
4312
|
+
out.add(message.user);
|
|
4313
|
+
}
|
|
4314
|
+
if (typeof message.text === "string") {
|
|
4315
|
+
collectMentionUserIds(message.text, out);
|
|
4316
|
+
}
|
|
4317
|
+
collectUserIdsFromUnknown(message.blocks, out);
|
|
4318
|
+
collectUserIdsFromUnknown(message.attachments, out);
|
|
4319
|
+
if (options.includeReactions) {
|
|
4320
|
+
collectUserIdsFromUnknown(message.reactions, out);
|
|
4321
|
+
}
|
|
4322
|
+
}
|
|
4323
|
+
function collectMentionUserIds(text, out) {
|
|
4324
|
+
USER_MENTION_PATTERN.lastIndex = 0;
|
|
4325
|
+
for (;; ) {
|
|
4326
|
+
const match = USER_MENTION_PATTERN.exec(text);
|
|
4327
|
+
if (!match) {
|
|
4328
|
+
break;
|
|
4329
|
+
}
|
|
4330
|
+
const userId = match[1] ?? "";
|
|
4331
|
+
if (USER_ID_PATTERN.test(userId)) {
|
|
4332
|
+
out.add(userId);
|
|
4333
|
+
}
|
|
4334
|
+
}
|
|
4335
|
+
}
|
|
4336
|
+
|
|
3930
4337
|
// src/cli/message-read-actions.ts
|
|
3931
4338
|
async function handleMessageGet(input) {
|
|
3932
4339
|
const target = parseMsgTarget(input.targetInput);
|
|
@@ -3946,8 +4353,25 @@ async function handleMessageGet(input) {
|
|
|
3946
4353
|
const thread2 = await getThreadSummary(client2, { channelId: ref2.channel_id, msg: msg2 });
|
|
3947
4354
|
const downloadedPaths2 = await downloadMessageFiles({ auth: auth2, messages: [msg2] });
|
|
3948
4355
|
const maxBodyChars2 = Number.parseInt(input.options.maxBodyChars, 10);
|
|
3949
|
-
const
|
|
3950
|
-
|
|
4356
|
+
const referencedUserIds2 = collectReferencedUserIds([msg2], {
|
|
4357
|
+
includeReactions: includeReactions2
|
|
4358
|
+
});
|
|
4359
|
+
const usersById2 = input.options.resolveUsers || input.options.refreshUsers ? await resolveUsersById({
|
|
4360
|
+
client: client2,
|
|
4361
|
+
workspaceUrl: ref2.workspace_url,
|
|
4362
|
+
userIds: referencedUserIds2,
|
|
4363
|
+
forceRefresh: Boolean(input.options.refreshUsers)
|
|
4364
|
+
}) : new Map;
|
|
4365
|
+
const message2 = toCompactMessage(msg2, {
|
|
4366
|
+
maxBodyChars: maxBodyChars2,
|
|
4367
|
+
includeReactions: includeReactions2,
|
|
4368
|
+
downloadedPaths: downloadedPaths2
|
|
4369
|
+
});
|
|
4370
|
+
return pruneEmpty({
|
|
4371
|
+
message: message2,
|
|
4372
|
+
thread: thread2,
|
|
4373
|
+
referenced_users: toReferencedUsers(referencedUserIds2, usersById2)
|
|
4374
|
+
});
|
|
3951
4375
|
}
|
|
3952
4376
|
const ts = input.options.ts?.trim();
|
|
3953
4377
|
if (!ts) {
|
|
@@ -3971,8 +4395,25 @@ async function handleMessageGet(input) {
|
|
|
3971
4395
|
const thread = await getThreadSummary(client, { channelId, msg });
|
|
3972
4396
|
const downloadedPaths = await downloadMessageFiles({ auth, messages: [msg] });
|
|
3973
4397
|
const maxBodyChars = Number.parseInt(input.options.maxBodyChars, 10);
|
|
3974
|
-
const
|
|
3975
|
-
|
|
4398
|
+
const referencedUserIds = collectReferencedUserIds([msg], {
|
|
4399
|
+
includeReactions
|
|
4400
|
+
});
|
|
4401
|
+
const usersById = input.options.resolveUsers || input.options.refreshUsers ? await resolveUsersById({
|
|
4402
|
+
client,
|
|
4403
|
+
workspaceUrl: ref.workspace_url,
|
|
4404
|
+
userIds: referencedUserIds,
|
|
4405
|
+
forceRefresh: Boolean(input.options.refreshUsers)
|
|
4406
|
+
}) : new Map;
|
|
4407
|
+
const message = toCompactMessage(msg, {
|
|
4408
|
+
maxBodyChars,
|
|
4409
|
+
includeReactions,
|
|
4410
|
+
downloadedPaths
|
|
4411
|
+
});
|
|
4412
|
+
return pruneEmpty({
|
|
4413
|
+
message,
|
|
4414
|
+
thread,
|
|
4415
|
+
referenced_users: toReferencedUsers(referencedUserIds, usersById)
|
|
4416
|
+
});
|
|
3976
4417
|
}
|
|
3977
4418
|
});
|
|
3978
4419
|
}
|
|
@@ -4005,8 +4446,18 @@ async function handleMessageList(input) {
|
|
|
4005
4446
|
});
|
|
4006
4447
|
const downloadedPaths2 = await downloadMessageFiles({ auth: auth2, messages: threadMessages2 });
|
|
4007
4448
|
const maxBodyChars2 = Number.parseInt(input.options.maxBodyChars, 10);
|
|
4449
|
+
const referencedUserIds2 = collectReferencedUserIds(threadMessages2, {
|
|
4450
|
+
includeReactions: includeReactions2
|
|
4451
|
+
});
|
|
4452
|
+
const usersById2 = input.options.resolveUsers || input.options.refreshUsers ? await resolveUsersById({
|
|
4453
|
+
client: client2,
|
|
4454
|
+
workspaceUrl: ref.workspace_url,
|
|
4455
|
+
userIds: referencedUserIds2,
|
|
4456
|
+
forceRefresh: Boolean(input.options.refreshUsers)
|
|
4457
|
+
}) : new Map;
|
|
4008
4458
|
return pruneEmpty({
|
|
4009
|
-
messages: threadMessages2.map((m) => toCompactMessage(m, { maxBodyChars: maxBodyChars2, includeReactions: includeReactions2, downloadedPaths: downloadedPaths2 })).map(toThreadListMessage)
|
|
4459
|
+
messages: threadMessages2.map((m) => toCompactMessage(m, { maxBodyChars: maxBodyChars2, includeReactions: includeReactions2, downloadedPaths: downloadedPaths2 })).map(toThreadListMessage),
|
|
4460
|
+
referenced_users: toReferencedUsers(referencedUserIds2, usersById2)
|
|
4010
4461
|
});
|
|
4011
4462
|
}
|
|
4012
4463
|
const { client, auth, workspace_url } = await input.ctx.getClientForWorkspace(workspaceUrl);
|
|
@@ -4036,9 +4487,19 @@ async function handleMessageList(input) {
|
|
|
4036
4487
|
});
|
|
4037
4488
|
const downloadedPaths2 = await downloadMessageFiles({ auth, messages: channelMessages });
|
|
4038
4489
|
const maxBodyChars2 = Number.parseInt(input.options.maxBodyChars, 10);
|
|
4490
|
+
const referencedUserIds2 = collectReferencedUserIds(channelMessages, {
|
|
4491
|
+
includeReactions: includeReactions2
|
|
4492
|
+
});
|
|
4493
|
+
const usersById2 = input.options.resolveUsers || input.options.refreshUsers ? await resolveUsersById({
|
|
4494
|
+
client,
|
|
4495
|
+
workspaceUrl: workspace_url ?? workspaceUrl ?? "",
|
|
4496
|
+
userIds: referencedUserIds2,
|
|
4497
|
+
forceRefresh: Boolean(input.options.refreshUsers)
|
|
4498
|
+
}) : new Map;
|
|
4039
4499
|
return pruneEmpty({
|
|
4040
4500
|
channel_id: channelId,
|
|
4041
|
-
messages: channelMessages.map((m) => toCompactMessage(m, { maxBodyChars: maxBodyChars2, includeReactions: includeReactions2, downloadedPaths: downloadedPaths2 }))
|
|
4501
|
+
messages: channelMessages.map((m) => toCompactMessage(m, { maxBodyChars: maxBodyChars2, includeReactions: includeReactions2, downloadedPaths: downloadedPaths2 })),
|
|
4502
|
+
referenced_users: toReferencedUsers(referencedUserIds2, usersById2)
|
|
4042
4503
|
});
|
|
4043
4504
|
}
|
|
4044
4505
|
if (hasReactionFilters) {
|
|
@@ -4063,8 +4524,18 @@ async function handleMessageList(input) {
|
|
|
4063
4524
|
});
|
|
4064
4525
|
const downloadedPaths = await downloadMessageFiles({ auth, messages: threadMessages });
|
|
4065
4526
|
const maxBodyChars = Number.parseInt(input.options.maxBodyChars, 10);
|
|
4527
|
+
const referencedUserIds = collectReferencedUserIds(threadMessages, {
|
|
4528
|
+
includeReactions
|
|
4529
|
+
});
|
|
4530
|
+
const usersById = input.options.resolveUsers || input.options.refreshUsers ? await resolveUsersById({
|
|
4531
|
+
client,
|
|
4532
|
+
workspaceUrl: workspace_url ?? workspaceUrl ?? "",
|
|
4533
|
+
userIds: referencedUserIds,
|
|
4534
|
+
forceRefresh: Boolean(input.options.refreshUsers)
|
|
4535
|
+
}) : new Map;
|
|
4066
4536
|
return pruneEmpty({
|
|
4067
|
-
messages: threadMessages.map((m) => toCompactMessage(m, { maxBodyChars, includeReactions, downloadedPaths })).map(toThreadListMessage)
|
|
4537
|
+
messages: threadMessages.map((m) => toCompactMessage(m, { maxBodyChars, includeReactions, downloadedPaths })).map(toThreadListMessage),
|
|
4538
|
+
referenced_users: toReferencedUsers(referencedUserIds, usersById)
|
|
4068
4539
|
});
|
|
4069
4540
|
}
|
|
4070
4541
|
});
|
|
@@ -6357,7 +6828,7 @@ function collectOptionValue(value, previous = []) {
|
|
|
6357
6828
|
}
|
|
6358
6829
|
function registerMessageCommand(input) {
|
|
6359
6830
|
const messageCmd = input.program.command("message").description("Read/write Slack messages (token-efficient JSON)");
|
|
6360
|
-
messageCmd.command("get", { isDefault: true }).description("Fetch a single Slack message (with thread summary if any)").argument("<target>", "Slack message URL, #channel, or channel ID").option("--workspace <url>", "Workspace selector (full URL or unique substring; needed when using #channel/channel id across multiple workspaces)").option("--ts <ts>", "Message ts (required when using #channel/channel id)").option("--thread-ts <ts>", "Thread root ts hint (useful for thread permalinks)").option("--max-body-chars <n>", "Max content characters to include (default 8000, -1 for unlimited)", "8000").option("--include-reactions", "Include reactions + reacting users").action(async (...args) => {
|
|
6831
|
+
messageCmd.command("get", { isDefault: true }).description("Fetch a single Slack message (with thread summary if any)").argument("<target>", "Slack message URL, #channel, or channel ID").option("--workspace <url>", "Workspace selector (full URL or unique substring; needed when using #channel/channel id across multiple workspaces)").option("--ts <ts>", "Message ts (required when using #channel/channel id)").option("--thread-ts <ts>", "Thread root ts hint (useful for thread permalinks)").option("--max-body-chars <n>", "Max content characters to include (default 8000, -1 for unlimited)", "8000").option("--include-reactions", "Include reactions + reacting users").option("--resolve-users", "Resolve user IDs to user profiles").option("--refresh-users", "Refresh user profile cache before resolving user IDs (implies --resolve-users)").action(async (...args) => {
|
|
6361
6832
|
const [targetInput, options] = args;
|
|
6362
6833
|
try {
|
|
6363
6834
|
const payload = await handleMessageGet({ ctx: input.ctx, targetInput, options });
|
|
@@ -6367,7 +6838,7 @@ function registerMessageCommand(input) {
|
|
|
6367
6838
|
process.exitCode = 1;
|
|
6368
6839
|
}
|
|
6369
6840
|
});
|
|
6370
|
-
messageCmd.command("list").description("List recent channel messages, or fetch a full thread").argument("<target>", "Slack message URL, #channel, or channel ID").option("--workspace <url>", "Workspace selector (full URL or unique substring; needed when using #channel/channel id across multiple workspaces)").option("--thread-ts <ts>", "Thread root ts (lists thread replies instead of channel history)").option("--ts <ts>", "Message ts (resolve message to its thread)").option("--limit <n>", "Max messages to return for channel history (default 25, max 200)").option("--oldest <ts>", "Only messages after this ts (channel history mode)").option("--latest <ts>", "Only messages before this ts (channel history mode)").option("--with-reaction <emoji>", "Only include messages with this reaction (repeatable; channel history mode; requires --oldest)", collectOptionValue, []).option("--without-reaction <emoji>", "Only include messages without this reaction (repeatable; channel history mode; requires --oldest)", collectOptionValue, []).option("--max-body-chars <n>", "Max content characters to include (default 8000, -1 for unlimited)", "8000").option("--include-reactions", "Include reactions + reacting users").action(async (...args) => {
|
|
6841
|
+
messageCmd.command("list").description("List recent channel messages, or fetch a full thread").argument("<target>", "Slack message URL, #channel, or channel ID").option("--workspace <url>", "Workspace selector (full URL or unique substring; needed when using #channel/channel id across multiple workspaces)").option("--thread-ts <ts>", "Thread root ts (lists thread replies instead of channel history)").option("--ts <ts>", "Message ts (resolve message to its thread)").option("--limit <n>", "Max messages to return for channel history (default 25, max 200)").option("--oldest <ts>", "Only messages after this ts (channel history mode)").option("--latest <ts>", "Only messages before this ts (channel history mode)").option("--with-reaction <emoji>", "Only include messages with this reaction (repeatable; channel history mode; requires --oldest)", collectOptionValue, []).option("--without-reaction <emoji>", "Only include messages without this reaction (repeatable; channel history mode; requires --oldest)", collectOptionValue, []).option("--max-body-chars <n>", "Max content characters to include (default 8000, -1 for unlimited)", "8000").option("--include-reactions", "Include reactions + reacting users").option("--resolve-users", "Resolve user IDs to user profiles").option("--refresh-users", "Refresh user profile cache before resolving user IDs (implies --resolve-users)").action(async (...args) => {
|
|
6371
6842
|
const [targetInput, options] = args;
|
|
6372
6843
|
try {
|
|
6373
6844
|
const payload = await handleMessageList({ ctx: input.ctx, targetInput, options });
|
|
@@ -6559,7 +7030,7 @@ async function channelTokenForSearch(client, channel) {
|
|
|
6559
7030
|
} catch {}
|
|
6560
7031
|
return null;
|
|
6561
7032
|
}
|
|
6562
|
-
async function
|
|
7033
|
+
async function resolveUserId2(client, input) {
|
|
6563
7034
|
const trimmed = input.trim();
|
|
6564
7035
|
if (!trimmed) {
|
|
6565
7036
|
return;
|
|
@@ -6747,7 +7218,7 @@ async function searchFilesViaSearchApi(client, input) {
|
|
|
6747
7218
|
}
|
|
6748
7219
|
async function searchFilesInChannelsFallback(client, input) {
|
|
6749
7220
|
const channelIds = await Promise.all(input.channels.map((c) => resolveChannelId(client, c)));
|
|
6750
|
-
const userId = input.user ? await
|
|
7221
|
+
const userId = input.user ? await resolveUserId2(client, input.user) : undefined;
|
|
6751
7222
|
const queryLower = input.query.trim().toLowerCase();
|
|
6752
7223
|
const ts_from = input.after ? dateToUnixSeconds(input.after, "start") : undefined;
|
|
6753
7224
|
const ts_to = input.before ? dateToUnixSeconds(input.before, "end") : undefined;
|
|
@@ -6845,7 +7316,7 @@ function passesFileContentTypeFilter(f, contentType) {
|
|
|
6845
7316
|
async function searchMessagesViaSearchApi(client, input) {
|
|
6846
7317
|
const matches = input.rawMatches;
|
|
6847
7318
|
if (matches.length === 0) {
|
|
6848
|
-
return [];
|
|
7319
|
+
return { messages: [] };
|
|
6849
7320
|
}
|
|
6850
7321
|
const messageRefs = [];
|
|
6851
7322
|
for (const m of matches) {
|
|
@@ -6869,6 +7340,7 @@ async function searchMessagesViaSearchApi(client, input) {
|
|
|
6869
7340
|
}
|
|
6870
7341
|
const downloadedPaths = {};
|
|
6871
7342
|
const downloadsDir = input.download ? await ensureDownloadsDir() : null;
|
|
7343
|
+
const resolvedMessages = [];
|
|
6872
7344
|
const out = [];
|
|
6873
7345
|
for (const ref of messageRefs) {
|
|
6874
7346
|
let full = null;
|
|
@@ -6907,21 +7379,36 @@ async function searchMessagesViaSearchApi(client, input) {
|
|
|
6907
7379
|
if (!passesContentTypeFilter(compact, input.contentType)) {
|
|
6908
7380
|
continue;
|
|
6909
7381
|
}
|
|
6910
|
-
|
|
7382
|
+
resolvedMessages.push(full);
|
|
7383
|
+
out.push(toSearchCompactMessage(compact, ref.permalink));
|
|
6911
7384
|
if (out.length >= input.limit) {
|
|
6912
7385
|
break;
|
|
6913
7386
|
}
|
|
6914
7387
|
}
|
|
6915
|
-
|
|
7388
|
+
const referencedUserIds = collectReferencedUserIds(resolvedMessages, {
|
|
7389
|
+
includeReactions: false
|
|
7390
|
+
});
|
|
7391
|
+
const shouldResolveUsers = input.resolveUsers || input.refreshUsers;
|
|
7392
|
+
const usersById = shouldResolveUsers ? await resolveUsersById({
|
|
7393
|
+
client,
|
|
7394
|
+
workspaceUrl: input.workspace_url ?? "",
|
|
7395
|
+
userIds: referencedUserIds,
|
|
7396
|
+
forceRefresh: Boolean(input.refreshUsers)
|
|
7397
|
+
}) : new Map;
|
|
7398
|
+
return {
|
|
7399
|
+
messages: out,
|
|
7400
|
+
referenced_users: toReferencedUsers(referencedUserIds, usersById)
|
|
7401
|
+
};
|
|
6916
7402
|
}
|
|
6917
7403
|
async function searchMessagesInChannelsFallback(client, input) {
|
|
6918
7404
|
const channelIds = await Promise.all(input.channels.map((c) => resolveChannelId(client, c)));
|
|
6919
7405
|
const queryLower = input.query.trim().toLowerCase();
|
|
6920
|
-
const userId = input.user ? await
|
|
7406
|
+
const userId = input.user ? await resolveUserId2(client, input.user) : undefined;
|
|
6921
7407
|
const afterSec = input.after ? dateToUnixSeconds(input.after, "start") : null;
|
|
6922
7408
|
const beforeSec = input.before ? dateToUnixSeconds(input.before, "end") : null;
|
|
6923
7409
|
const downloadsDir = input.download ? await ensureDownloadsDir() : null;
|
|
6924
7410
|
const downloadedPaths = {};
|
|
7411
|
+
const matchedSummaries = [];
|
|
6925
7412
|
const results = [];
|
|
6926
7413
|
for (const channelId of channelIds) {
|
|
6927
7414
|
let cursorLatest;
|
|
@@ -6969,9 +7456,22 @@ async function searchMessagesInChannelsFallback(client, input) {
|
|
|
6969
7456
|
if (!passesContentTypeFilter(compact, input.contentType)) {
|
|
6970
7457
|
continue;
|
|
6971
7458
|
}
|
|
6972
|
-
|
|
7459
|
+
matchedSummaries.push(summary);
|
|
7460
|
+
results.push(toSearchCompactMessage(compact));
|
|
6973
7461
|
if (results.length >= input.limit) {
|
|
6974
|
-
|
|
7462
|
+
const referencedUserIds2 = collectReferencedUserIds(matchedSummaries, {
|
|
7463
|
+
includeReactions: false
|
|
7464
|
+
});
|
|
7465
|
+
const usersById2 = await resolveUsersById({
|
|
7466
|
+
client,
|
|
7467
|
+
workspaceUrl: input.workspace_url ?? "",
|
|
7468
|
+
userIds: referencedUserIds2,
|
|
7469
|
+
forceRefresh: Boolean(input.refreshUsers)
|
|
7470
|
+
});
|
|
7471
|
+
return {
|
|
7472
|
+
messages: results,
|
|
7473
|
+
referenced_users: toReferencedUsers(referencedUserIds2, usersById2)
|
|
7474
|
+
};
|
|
6975
7475
|
}
|
|
6976
7476
|
}
|
|
6977
7477
|
if (!cursorLatest) {
|
|
@@ -6984,7 +7484,20 @@ async function searchMessagesInChannelsFallback(client, input) {
|
|
|
6984
7484
|
}
|
|
6985
7485
|
}
|
|
6986
7486
|
}
|
|
6987
|
-
|
|
7487
|
+
const referencedUserIds = collectReferencedUserIds(matchedSummaries, {
|
|
7488
|
+
includeReactions: false
|
|
7489
|
+
});
|
|
7490
|
+
const shouldResolveUsers = input.resolveUsers || input.refreshUsers;
|
|
7491
|
+
const usersById = shouldResolveUsers ? await resolveUsersById({
|
|
7492
|
+
client,
|
|
7493
|
+
workspaceUrl: input.workspace_url ?? "",
|
|
7494
|
+
userIds: referencedUserIds,
|
|
7495
|
+
forceRefresh: Boolean(input.refreshUsers)
|
|
7496
|
+
}) : new Map;
|
|
7497
|
+
return {
|
|
7498
|
+
messages: results,
|
|
7499
|
+
referenced_users: toReferencedUsers(referencedUserIds, usersById)
|
|
7500
|
+
};
|
|
6988
7501
|
}
|
|
6989
7502
|
function passesContentTypeFilter(m, contentType) {
|
|
6990
7503
|
if (contentType === "any") {
|
|
@@ -7008,9 +7521,9 @@ function passesContentTypeFilter(m, contentType) {
|
|
|
7008
7521
|
}
|
|
7009
7522
|
return true;
|
|
7010
7523
|
}
|
|
7011
|
-
function
|
|
7012
|
-
const {
|
|
7013
|
-
return rest;
|
|
7524
|
+
function toSearchCompactMessage(m, permalink) {
|
|
7525
|
+
const { thread_ts: _threadTs, ...rest } = m;
|
|
7526
|
+
return permalink ? { ...rest, permalink } : rest;
|
|
7014
7527
|
}
|
|
7015
7528
|
async function downloadFilesForMessage(input) {
|
|
7016
7529
|
for (const f of input.message.files ?? []) {
|
|
@@ -7102,8 +7615,9 @@ async function searchSlack(input) {
|
|
|
7102
7615
|
const out = {};
|
|
7103
7616
|
if (input.options.kind === "messages" || input.options.kind === "all") {
|
|
7104
7617
|
if (input.options.channels?.length) {
|
|
7105
|
-
|
|
7618
|
+
const messageResult = await searchMessagesInChannelsFallback(input.client, {
|
|
7106
7619
|
auth: input.auth,
|
|
7620
|
+
workspace_url: input.options.workspace_url,
|
|
7107
7621
|
query: input.options.query,
|
|
7108
7622
|
channels: input.options.channels,
|
|
7109
7623
|
user: input.options.user,
|
|
@@ -7112,11 +7626,15 @@ async function searchSlack(input) {
|
|
|
7112
7626
|
limit,
|
|
7113
7627
|
maxContentChars,
|
|
7114
7628
|
contentType,
|
|
7115
|
-
download
|
|
7629
|
+
download,
|
|
7630
|
+
resolveUsers: input.options.resolve_users,
|
|
7631
|
+
refreshUsers: input.options.refresh_users
|
|
7116
7632
|
});
|
|
7633
|
+
out.messages = messageResult.messages;
|
|
7634
|
+
out.referenced_users = messageResult.referenced_users;
|
|
7117
7635
|
} else {
|
|
7118
7636
|
const rawMatches = await searchMessagesRaw(input.client, { query: slackQuery, limit });
|
|
7119
|
-
|
|
7637
|
+
const messageResult = await searchMessagesViaSearchApi(input.client, {
|
|
7120
7638
|
auth: input.auth,
|
|
7121
7639
|
workspace_url: input.options.workspace_url,
|
|
7122
7640
|
slack_query: slackQuery,
|
|
@@ -7124,8 +7642,12 @@ async function searchSlack(input) {
|
|
|
7124
7642
|
maxContentChars,
|
|
7125
7643
|
contentType,
|
|
7126
7644
|
download,
|
|
7127
|
-
rawMatches
|
|
7645
|
+
rawMatches,
|
|
7646
|
+
resolveUsers: input.options.resolve_users,
|
|
7647
|
+
refreshUsers: input.options.refresh_users
|
|
7128
7648
|
});
|
|
7649
|
+
out.messages = messageResult.messages;
|
|
7650
|
+
out.referenced_users = messageResult.referenced_users;
|
|
7129
7651
|
}
|
|
7130
7652
|
}
|
|
7131
7653
|
if (input.options.kind === "files" || input.options.kind === "all") {
|
|
@@ -7156,7 +7678,7 @@ async function searchSlack(input) {
|
|
|
7156
7678
|
|
|
7157
7679
|
// src/cli/search-command.ts
|
|
7158
7680
|
function addSearchOptions(cmd) {
|
|
7159
|
-
return cmd.option("--workspace <url>", "Workspace selector (full URL or unique substring; needed when searching across multiple workspaces)").option("--channel <channel...>", "Channel filter (#name, name, or id). Repeatable.").option("--user <user>", "User filter (@name, name, or user id U...)").option("--after <date>", "Only results after YYYY-MM-DD").option("--before <date>", "Only results before YYYY-MM-DD").option("--content-type <type>", "Filter content type: any|text|image|snippet|file (default any)").option("--limit <n>", "Max results (default 20)", "20").option("--max-content-chars <n>", "Max message content characters (default 4000, -1 for unlimited)", "4000");
|
|
7681
|
+
return cmd.option("--workspace <url>", "Workspace selector (full URL or unique substring; needed when searching across multiple workspaces)").option("--channel <channel...>", "Channel filter (#name, name, or id). Repeatable.").option("--user <user>", "User filter (@name, name, or user id U...)").option("--after <date>", "Only results after YYYY-MM-DD").option("--before <date>", "Only results before YYYY-MM-DD").option("--content-type <type>", "Filter content type: any|text|image|snippet|file (default any)").option("--limit <n>", "Max results (default 20)", "20").option("--max-content-chars <n>", "Max message content characters (default 4000, -1 for unlimited)", "4000").option("--resolve-users", "Resolve user IDs to user profiles").option("--refresh-users", "Refresh user profile cache before resolving referenced users (implies --resolve-users)");
|
|
7160
7682
|
}
|
|
7161
7683
|
async function runSearch(input) {
|
|
7162
7684
|
const workspaceUrl = input.ctx.effectiveWorkspaceUrl(input.options.workspace);
|
|
@@ -7183,7 +7705,9 @@ async function runSearch(input) {
|
|
|
7183
7705
|
content_type: contentType,
|
|
7184
7706
|
limit,
|
|
7185
7707
|
max_content_chars: maxContentChars,
|
|
7186
|
-
download: true
|
|
7708
|
+
download: true,
|
|
7709
|
+
resolve_users: Boolean(input.options.resolveUsers || input.options.refreshUsers),
|
|
7710
|
+
refresh_users: Boolean(input.options.refreshUsers)
|
|
7187
7711
|
}
|
|
7188
7712
|
});
|
|
7189
7713
|
}
|
|
@@ -7227,13 +7751,13 @@ async function fetchLaterItems(client, options) {
|
|
|
7227
7751
|
const pageRawItems = asArray2(resp.saved_items).filter(isRecord5);
|
|
7228
7752
|
allRawItems.push(...pageRawItems);
|
|
7229
7753
|
const meta = isRecord5(resp.response_metadata) ? resp.response_metadata : null;
|
|
7230
|
-
nextCursor = meta ?
|
|
7754
|
+
nextCursor = meta ? getString5(meta.next_cursor) : undefined;
|
|
7231
7755
|
if (countsOnly) {
|
|
7232
7756
|
break;
|
|
7233
7757
|
}
|
|
7234
|
-
let filtered2 = allRawItems.filter((item) =>
|
|
7758
|
+
let filtered2 = allRawItems.filter((item) => getString5(item.item_type) === "message");
|
|
7235
7759
|
if (stateFilter !== "all") {
|
|
7236
|
-
filtered2 = filtered2.filter((item) =>
|
|
7760
|
+
filtered2 = filtered2.filter((item) => getString5(item.state) === stateFilter);
|
|
7237
7761
|
}
|
|
7238
7762
|
if (filtered2.length >= limit || !nextCursor) {
|
|
7239
7763
|
break;
|
|
@@ -7253,15 +7777,15 @@ async function fetchLaterItems(client, options) {
|
|
|
7253
7777
|
if (countsOnly) {
|
|
7254
7778
|
return result;
|
|
7255
7779
|
}
|
|
7256
|
-
let filtered = allRawItems.filter((item) =>
|
|
7780
|
+
let filtered = allRawItems.filter((item) => getString5(item.item_type) === "message");
|
|
7257
7781
|
if (stateFilter !== "all") {
|
|
7258
|
-
filtered = filtered.filter((item) =>
|
|
7782
|
+
filtered = filtered.filter((item) => getString5(item.state) === stateFilter);
|
|
7259
7783
|
}
|
|
7260
7784
|
filtered = filtered.slice(0, limit);
|
|
7261
7785
|
result.items = await Promise.all(filtered.map(async (item) => {
|
|
7262
|
-
const channelId =
|
|
7263
|
-
const ts =
|
|
7264
|
-
const state =
|
|
7786
|
+
const channelId = getString5(item.item_id) ?? "";
|
|
7787
|
+
const ts = getString5(item.ts) ?? "";
|
|
7788
|
+
const state = getString5(item.state) ?? "in_progress";
|
|
7265
7789
|
const dateSaved = getNumber3(item.date_created) ?? 0;
|
|
7266
7790
|
const dateCompleted = getNumber3(item.date_completed);
|
|
7267
7791
|
let channelName;
|
|
@@ -7272,15 +7796,15 @@ async function fetchLaterItems(client, options) {
|
|
|
7272
7796
|
});
|
|
7273
7797
|
const ch = isRecord5(info.channel) ? info.channel : null;
|
|
7274
7798
|
if (ch) {
|
|
7275
|
-
channelName =
|
|
7799
|
+
channelName = getString5(ch.name) ?? getString5(ch.name_normalized) ?? undefined;
|
|
7276
7800
|
if (ch.is_im && !channelName) {
|
|
7277
|
-
const userId =
|
|
7801
|
+
const userId = getString5(ch.user);
|
|
7278
7802
|
if (userId) {
|
|
7279
7803
|
try {
|
|
7280
7804
|
const userInfo = await client.api("users.info", { user: userId });
|
|
7281
7805
|
const u = isRecord5(userInfo.user) ? userInfo.user : null;
|
|
7282
7806
|
const profile = u && isRecord5(u.profile) ? u.profile : null;
|
|
7283
|
-
channelName =
|
|
7807
|
+
channelName = getString5(profile?.display_name) || getString5(u?.real_name) || getString5(u?.name) || undefined;
|
|
7284
7808
|
} catch {}
|
|
7285
7809
|
}
|
|
7286
7810
|
}
|
|
@@ -7295,18 +7819,18 @@ async function fetchLaterItems(client, options) {
|
|
|
7295
7819
|
limit: 1
|
|
7296
7820
|
});
|
|
7297
7821
|
const msgs = asArray2(history.messages).filter(isRecord5);
|
|
7298
|
-
const msg = msgs.find((m) =>
|
|
7822
|
+
const msg = msgs.find((m) => getString5(m.ts) === ts);
|
|
7299
7823
|
if (msg) {
|
|
7300
7824
|
const rendered = renderSlackMessageContent(msg);
|
|
7301
7825
|
const content = maxBodyChars >= 0 && rendered.length > maxBodyChars ? `${rendered.slice(0, maxBodyChars)}
|
|
7302
7826
|
…` : rendered;
|
|
7303
7827
|
message = {
|
|
7304
|
-
author:
|
|
7305
|
-
user_id:
|
|
7306
|
-
bot_id:
|
|
7828
|
+
author: getString5(msg.user) || getString5(msg.bot_id) ? {
|
|
7829
|
+
user_id: getString5(msg.user) ?? undefined,
|
|
7830
|
+
bot_id: getString5(msg.bot_id) ?? undefined
|
|
7307
7831
|
} : undefined,
|
|
7308
7832
|
content: content || undefined,
|
|
7309
|
-
thread_ts:
|
|
7833
|
+
thread_ts: getString5(msg.thread_ts) ?? undefined,
|
|
7310
7834
|
reply_count: getNumber3(msg.reply_count) ?? undefined
|
|
7311
7835
|
};
|
|
7312
7836
|
}
|
|
@@ -7404,7 +7928,7 @@ function isRecord5(value) {
|
|
|
7404
7928
|
function asArray2(value) {
|
|
7405
7929
|
return Array.isArray(value) ? value : [];
|
|
7406
7930
|
}
|
|
7407
|
-
function
|
|
7931
|
+
function getString5(value) {
|
|
7408
7932
|
return typeof value === "string" ? value : undefined;
|
|
7409
7933
|
}
|
|
7410
7934
|
function getNumber3(value) {
|
|
@@ -7622,22 +8146,22 @@ async function fetchUnreads(client, options) {
|
|
|
7622
8146
|
});
|
|
7623
8147
|
const ch = isRecord6(info.channel) ? info.channel : null;
|
|
7624
8148
|
if (ch) {
|
|
7625
|
-
name =
|
|
8149
|
+
name = getString6(ch.name) ?? getString6(ch.name_normalized) ?? undefined;
|
|
7626
8150
|
if (ch.is_im) {
|
|
7627
8151
|
type = "dm";
|
|
7628
|
-
const userId =
|
|
8152
|
+
const userId = getString6(ch.user);
|
|
7629
8153
|
if (userId && !name) {
|
|
7630
8154
|
try {
|
|
7631
8155
|
const userInfo = await client.api("users.info", { user: userId });
|
|
7632
8156
|
const u = isRecord6(userInfo.user) ? userInfo.user : null;
|
|
7633
8157
|
const profile = u && isRecord6(u.profile) ? u.profile : null;
|
|
7634
|
-
name =
|
|
8158
|
+
name = getString6(profile?.display_name) || getString6(u?.real_name) || getString6(u?.name) || undefined;
|
|
7635
8159
|
} catch {}
|
|
7636
8160
|
}
|
|
7637
8161
|
} else if (ch.is_mpim) {
|
|
7638
8162
|
type = "mpim";
|
|
7639
8163
|
} else if (ch.is_group || ch.is_private) {
|
|
7640
|
-
type = "
|
|
8164
|
+
type = "channel";
|
|
7641
8165
|
} else {
|
|
7642
8166
|
type = "channel";
|
|
7643
8167
|
}
|
|
@@ -7659,7 +8183,7 @@ async function fetchUnreads(client, options) {
|
|
|
7659
8183
|
let msgs = asArray3(history.messages).filter(isRecord6);
|
|
7660
8184
|
if (skipSystem) {
|
|
7661
8185
|
msgs = msgs.filter((m) => {
|
|
7662
|
-
const subtype =
|
|
8186
|
+
const subtype = getString6(m.subtype);
|
|
7663
8187
|
if (!subtype) {
|
|
7664
8188
|
return true;
|
|
7665
8189
|
}
|
|
@@ -7693,13 +8217,13 @@ async function fetchUnreads(client, options) {
|
|
|
7693
8217
|
const content = maxBodyChars >= 0 && rendered.length > maxBodyChars ? `${rendered.slice(0, maxBodyChars)}
|
|
7694
8218
|
...` : rendered;
|
|
7695
8219
|
return {
|
|
7696
|
-
ts:
|
|
7697
|
-
author:
|
|
7698
|
-
user_id:
|
|
7699
|
-
bot_id:
|
|
8220
|
+
ts: getString6(m.ts) ?? "",
|
|
8221
|
+
author: getString6(m.user) || getString6(m.bot_id) ? {
|
|
8222
|
+
user_id: getString6(m.user) ?? undefined,
|
|
8223
|
+
bot_id: getString6(m.bot_id) ?? undefined
|
|
7700
8224
|
} : undefined,
|
|
7701
8225
|
content: content || undefined,
|
|
7702
|
-
thread_ts:
|
|
8226
|
+
thread_ts: getString6(m.thread_ts) ?? undefined,
|
|
7703
8227
|
reply_count: getNumber4(m.reply_count) ?? undefined
|
|
7704
8228
|
};
|
|
7705
8229
|
});
|
|
@@ -7737,7 +8261,7 @@ function isRecord6(value) {
|
|
|
7737
8261
|
function asArray3(value) {
|
|
7738
8262
|
return Array.isArray(value) ? value : [];
|
|
7739
8263
|
}
|
|
7740
|
-
function
|
|
8264
|
+
function getString6(value) {
|
|
7741
8265
|
return typeof value === "string" ? value : undefined;
|
|
7742
8266
|
}
|
|
7743
8267
|
function getNumber4(value) {
|
|
@@ -7771,14 +8295,14 @@ function registerUnreadsCommand(input) {
|
|
|
7771
8295
|
|
|
7772
8296
|
// src/lib/update.ts
|
|
7773
8297
|
import { execSync as execSync2 } from "node:child_process";
|
|
7774
|
-
import { createHash } from "node:crypto";
|
|
8298
|
+
import { createHash as createHash2 } from "node:crypto";
|
|
7775
8299
|
import { chmod, copyFile as copyFile2, mkdir as mkdir5, readFile as readFile7, rename, rm as rm3, writeFile as writeFile4 } from "node:fs/promises";
|
|
7776
8300
|
import { tmpdir as tmpdir5 } from "node:os";
|
|
7777
|
-
import { basename as basename3, join as
|
|
8301
|
+
import { basename as basename3, join as join14 } from "node:path";
|
|
7778
8302
|
var REPO = "stablyai/agent-slack";
|
|
7779
8303
|
var CHECK_INTERVAL_MS = 24 * 60 * 60 * 1000;
|
|
7780
8304
|
function getCachePath() {
|
|
7781
|
-
return
|
|
8305
|
+
return join14(getAppDir(), "update-check.json");
|
|
7782
8306
|
}
|
|
7783
8307
|
function compareSemver(a, b) {
|
|
7784
8308
|
const pa = a.replace(/^v/, "").split(".").map(Number);
|
|
@@ -7874,16 +8398,16 @@ function detectPlatformAsset() {
|
|
|
7874
8398
|
}
|
|
7875
8399
|
async function sha256(filePath) {
|
|
7876
8400
|
const data = await readFile7(filePath);
|
|
7877
|
-
return
|
|
8401
|
+
return createHash2("sha256").update(data).digest("hex");
|
|
7878
8402
|
}
|
|
7879
8403
|
async function performUpdate(latest) {
|
|
7880
8404
|
const asset = detectPlatformAsset();
|
|
7881
8405
|
const tag = `v${latest}`;
|
|
7882
8406
|
const baseUrl = `https://github.com/${REPO}/releases/download/${tag}`;
|
|
7883
|
-
const tmp =
|
|
8407
|
+
const tmp = join14(tmpdir5(), `agent-slack-update-${Date.now()}`);
|
|
7884
8408
|
await mkdir5(tmp, { recursive: true });
|
|
7885
|
-
const binTmp =
|
|
7886
|
-
const sumsTmp =
|
|
8409
|
+
const binTmp = join14(tmp, asset);
|
|
8410
|
+
const sumsTmp = join14(tmp, "checksums-sha256.txt");
|
|
7887
8411
|
try {
|
|
7888
8412
|
const [binResp, sumsResp] = await Promise.all([
|
|
7889
8413
|
fetch(`${baseUrl}/${asset}`, { signal: AbortSignal.timeout(120000) }),
|
|
@@ -7907,6 +8431,16 @@ async function performUpdate(latest) {
|
|
|
7907
8431
|
if (actual !== expected) {
|
|
7908
8432
|
return { success: false, message: `Checksum mismatch: expected ${expected}, got ${actual}` };
|
|
7909
8433
|
}
|
|
8434
|
+
if (process.platform === "darwin") {
|
|
8435
|
+
try {
|
|
8436
|
+
execSync2(`codesign --remove-signature ${JSON.stringify(binTmp)}`, {
|
|
8437
|
+
stdio: "ignore"
|
|
8438
|
+
});
|
|
8439
|
+
execSync2(`codesign --sign - ${JSON.stringify(binTmp)}`, {
|
|
8440
|
+
stdio: "ignore"
|
|
8441
|
+
});
|
|
8442
|
+
} catch {}
|
|
8443
|
+
}
|
|
7910
8444
|
const currentBin = process.execPath;
|
|
7911
8445
|
const backupPath = `${currentBin}.bak`;
|
|
7912
8446
|
await rename(currentBin, backupPath);
|
|
@@ -7994,194 +8528,6 @@ function registerUpdateCommand(input) {
|
|
|
7994
8528
|
});
|
|
7995
8529
|
}
|
|
7996
8530
|
|
|
7997
|
-
// src/slack/users.ts
|
|
7998
|
-
async function listUsers(client, options) {
|
|
7999
|
-
const limit = Math.min(Math.max(options?.limit ?? 200, 1), 1000);
|
|
8000
|
-
const includeBots = options?.includeBots ?? false;
|
|
8001
|
-
let next_cursor;
|
|
8002
|
-
const [out, dmMap] = await Promise.all([
|
|
8003
|
-
(async () => {
|
|
8004
|
-
const users = [];
|
|
8005
|
-
let cursor = options?.cursor;
|
|
8006
|
-
while (users.length < limit) {
|
|
8007
|
-
const pageSize = Math.min(200, limit - users.length);
|
|
8008
|
-
const resp = await client.api("users.list", { limit: pageSize, cursor });
|
|
8009
|
-
const members = asArray(resp.members).filter(isRecord);
|
|
8010
|
-
for (const m of members) {
|
|
8011
|
-
const id = getString(m.id);
|
|
8012
|
-
if (!id) {
|
|
8013
|
-
continue;
|
|
8014
|
-
}
|
|
8015
|
-
if (!includeBots && m.is_bot) {
|
|
8016
|
-
continue;
|
|
8017
|
-
}
|
|
8018
|
-
users.push(toCompactUser(m));
|
|
8019
|
-
if (users.length >= limit) {
|
|
8020
|
-
break;
|
|
8021
|
-
}
|
|
8022
|
-
}
|
|
8023
|
-
const meta = isRecord(resp.response_metadata) ? resp.response_metadata : null;
|
|
8024
|
-
const next = meta ? getString(meta.next_cursor) : undefined;
|
|
8025
|
-
if (!next) {
|
|
8026
|
-
break;
|
|
8027
|
-
}
|
|
8028
|
-
cursor = next;
|
|
8029
|
-
next_cursor = next;
|
|
8030
|
-
}
|
|
8031
|
-
return users;
|
|
8032
|
-
})(),
|
|
8033
|
-
fetchDmMap(client)
|
|
8034
|
-
]);
|
|
8035
|
-
for (const u of out) {
|
|
8036
|
-
const dmId = dmMap.get(u.id);
|
|
8037
|
-
if (dmId) {
|
|
8038
|
-
u.dm_id = dmId;
|
|
8039
|
-
}
|
|
8040
|
-
}
|
|
8041
|
-
return { users: out, next_cursor };
|
|
8042
|
-
}
|
|
8043
|
-
async function getUser(client, input) {
|
|
8044
|
-
const trimmed = input.trim();
|
|
8045
|
-
if (!trimmed) {
|
|
8046
|
-
throw new Error("User is empty");
|
|
8047
|
-
}
|
|
8048
|
-
const userId = await resolveUserId2(client, trimmed);
|
|
8049
|
-
if (!userId) {
|
|
8050
|
-
throw new Error(`Could not resolve user: ${input}`);
|
|
8051
|
-
}
|
|
8052
|
-
const resp = await client.api("users.info", { user: userId });
|
|
8053
|
-
const u = isRecord(resp.user) ? resp.user : null;
|
|
8054
|
-
if (!u || !getString(u.id)) {
|
|
8055
|
-
throw new Error("users.info returned no user");
|
|
8056
|
-
}
|
|
8057
|
-
return toCompactUser(u);
|
|
8058
|
-
}
|
|
8059
|
-
async function resolveUserId2(client, input) {
|
|
8060
|
-
const trimmed = input.trim();
|
|
8061
|
-
if (/^U[A-Z0-9]{8,}$/.test(trimmed)) {
|
|
8062
|
-
return trimmed;
|
|
8063
|
-
}
|
|
8064
|
-
const looksLikeEmail = /^[^@\s]+@[^@\s]+\.[^@\s]+$/.test(trimmed) && !trimmed.startsWith("@");
|
|
8065
|
-
if (looksLikeEmail) {
|
|
8066
|
-
try {
|
|
8067
|
-
const byEmail = await client.api("users.lookupByEmail", { email: trimmed });
|
|
8068
|
-
const user = isRecord(byEmail.user) ? byEmail.user : null;
|
|
8069
|
-
const userId = user ? getString(user.id) : undefined;
|
|
8070
|
-
if (userId) {
|
|
8071
|
-
return userId;
|
|
8072
|
-
}
|
|
8073
|
-
} catch {}
|
|
8074
|
-
}
|
|
8075
|
-
const handle = trimmed.startsWith("@") ? trimmed.slice(1) : trimmed;
|
|
8076
|
-
if (!handle) {
|
|
8077
|
-
return null;
|
|
8078
|
-
}
|
|
8079
|
-
let cursor;
|
|
8080
|
-
for (;; ) {
|
|
8081
|
-
const resp = await client.api("users.list", { limit: 200, cursor });
|
|
8082
|
-
const members = asArray(resp.members).filter(isRecord);
|
|
8083
|
-
const found = members.find((m) => {
|
|
8084
|
-
if (getString(m.name) === handle) {
|
|
8085
|
-
return true;
|
|
8086
|
-
}
|
|
8087
|
-
if (looksLikeEmail) {
|
|
8088
|
-
const profile = isRecord(m.profile) ? m.profile : null;
|
|
8089
|
-
const email = profile ? getString(profile.email) : undefined;
|
|
8090
|
-
return Boolean(email) && email?.toLowerCase() === trimmed.toLowerCase();
|
|
8091
|
-
}
|
|
8092
|
-
return false;
|
|
8093
|
-
});
|
|
8094
|
-
if (found) {
|
|
8095
|
-
const id = getString(found.id);
|
|
8096
|
-
if (id) {
|
|
8097
|
-
return id;
|
|
8098
|
-
}
|
|
8099
|
-
}
|
|
8100
|
-
const meta = isRecord(resp.response_metadata) ? resp.response_metadata : null;
|
|
8101
|
-
const next = meta ? getString(meta.next_cursor) : undefined;
|
|
8102
|
-
if (!next) {
|
|
8103
|
-
break;
|
|
8104
|
-
}
|
|
8105
|
-
cursor = next;
|
|
8106
|
-
}
|
|
8107
|
-
return null;
|
|
8108
|
-
}
|
|
8109
|
-
async function fetchDmMap(client) {
|
|
8110
|
-
const map = new Map;
|
|
8111
|
-
let cursor;
|
|
8112
|
-
for (;; ) {
|
|
8113
|
-
const resp = await client.api("conversations.list", {
|
|
8114
|
-
types: "im",
|
|
8115
|
-
limit: 200,
|
|
8116
|
-
cursor
|
|
8117
|
-
});
|
|
8118
|
-
const channels = asArray(resp.channels).filter(isRecord);
|
|
8119
|
-
for (const ch of channels) {
|
|
8120
|
-
const id = getString(ch.id);
|
|
8121
|
-
const user = getString(ch.user);
|
|
8122
|
-
if (id && user) {
|
|
8123
|
-
map.set(user, id);
|
|
8124
|
-
}
|
|
8125
|
-
}
|
|
8126
|
-
const meta = isRecord(resp.response_metadata) ? resp.response_metadata : null;
|
|
8127
|
-
const next = meta ? getString(meta.next_cursor) : undefined;
|
|
8128
|
-
if (!next) {
|
|
8129
|
-
break;
|
|
8130
|
-
}
|
|
8131
|
-
cursor = next;
|
|
8132
|
-
}
|
|
8133
|
-
return map;
|
|
8134
|
-
}
|
|
8135
|
-
async function getDmChannelForUsers(client, inputs) {
|
|
8136
|
-
if (!inputs || inputs.length === 0) {
|
|
8137
|
-
throw new Error("At least one user is required");
|
|
8138
|
-
}
|
|
8139
|
-
if (inputs.length > 8) {
|
|
8140
|
-
throw new Error("Slack supports a maximum of 8 users in a group DM");
|
|
8141
|
-
}
|
|
8142
|
-
const userIds = [];
|
|
8143
|
-
for (const input of inputs) {
|
|
8144
|
-
const trimmed = input.trim();
|
|
8145
|
-
if (!trimmed) {
|
|
8146
|
-
continue;
|
|
8147
|
-
}
|
|
8148
|
-
const userId = await resolveUserId2(client, trimmed);
|
|
8149
|
-
if (!userId) {
|
|
8150
|
-
throw new Error(`Could not resolve user: ${input}`);
|
|
8151
|
-
}
|
|
8152
|
-
userIds.push(userId);
|
|
8153
|
-
}
|
|
8154
|
-
if (userIds.length === 0) {
|
|
8155
|
-
throw new Error("No valid users provided");
|
|
8156
|
-
}
|
|
8157
|
-
const resp = await client.api("conversations.open", { users: userIds.join(",") });
|
|
8158
|
-
const channel = isRecord(resp.channel) ? resp.channel : null;
|
|
8159
|
-
const channelId = channel ? getString(channel.id) : null;
|
|
8160
|
-
if (!channelId) {
|
|
8161
|
-
throw new Error("conversations.open returned no channel");
|
|
8162
|
-
}
|
|
8163
|
-
const channelType = channelId.startsWith("D") ? "dm" : "group_dm";
|
|
8164
|
-
return {
|
|
8165
|
-
user_ids: userIds,
|
|
8166
|
-
dm_channel_id: channelId,
|
|
8167
|
-
channel_type: channelType
|
|
8168
|
-
};
|
|
8169
|
-
}
|
|
8170
|
-
function toCompactUser(u) {
|
|
8171
|
-
const profile = isRecord(u.profile) ? u.profile : {};
|
|
8172
|
-
return {
|
|
8173
|
-
id: getString(u.id) ?? "",
|
|
8174
|
-
name: getString(u.name) ?? undefined,
|
|
8175
|
-
real_name: getString(u.real_name) ?? getString(profile.real_name) ?? undefined,
|
|
8176
|
-
display_name: getString(profile.display_name) ?? undefined,
|
|
8177
|
-
email: getString(profile.email) ?? undefined,
|
|
8178
|
-
title: getString(profile.title) ?? undefined,
|
|
8179
|
-
tz: getString(u.tz) ?? undefined,
|
|
8180
|
-
is_bot: typeof u.is_bot === "boolean" ? u.is_bot : undefined,
|
|
8181
|
-
deleted: typeof u.deleted === "boolean" ? u.deleted : undefined
|
|
8182
|
-
};
|
|
8183
|
-
}
|
|
8184
|
-
|
|
8185
8531
|
// src/cli/user-command.ts
|
|
8186
8532
|
function registerUserCommand(input) {
|
|
8187
8533
|
const userCmd = input.program.command("user").description("Workspace user directory");
|
|
@@ -8366,7 +8712,7 @@ function registerChannelCommand(input) {
|
|
|
8366
8712
|
}
|
|
8367
8713
|
let userId;
|
|
8368
8714
|
if (options.user) {
|
|
8369
|
-
const resolvedUserId = await
|
|
8715
|
+
const resolvedUserId = await resolveUserId(client, options.user);
|
|
8370
8716
|
if (!resolvedUserId) {
|
|
8371
8717
|
throw new Error(`Could not resolve user: ${options.user}`);
|
|
8372
8718
|
}
|
|
@@ -8449,7 +8795,7 @@ function registerChannelCommand(input) {
|
|
|
8449
8795
|
const resolvedUserIds = [];
|
|
8450
8796
|
const unresolvedUsers = [];
|
|
8451
8797
|
for (const userInput of userInputs) {
|
|
8452
|
-
const userId = await
|
|
8798
|
+
const userId = await resolveUserId(client, userInput);
|
|
8453
8799
|
if (!userId) {
|
|
8454
8800
|
unresolvedUsers.push(userInput);
|
|
8455
8801
|
continue;
|
|
@@ -8810,5 +9156,5 @@ if (subcommand && subcommand !== "update") {
|
|
|
8810
9156
|
backgroundUpdateCheck();
|
|
8811
9157
|
}
|
|
8812
9158
|
|
|
8813
|
-
//# debugId=
|
|
9159
|
+
//# debugId=DD5B850D326A863A64756E2164756E21
|
|
8814
9160
|
//# sourceMappingURL=index.js.map
|