slack-term 1.18.0 → 1.19.1
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/cli.js +59 -59
- package/package.json +1 -1
- package/ts/cli.ts +52 -0
- package/ts/format.ts +4 -2
- package/ts/slack.ts +25 -0
package/package.json
CHANGED
package/ts/cli.ts
CHANGED
|
@@ -17,6 +17,8 @@ import {
|
|
|
17
17
|
authTest,
|
|
18
18
|
authTestSession,
|
|
19
19
|
conversationInfoSession,
|
|
20
|
+
createChannel,
|
|
21
|
+
inviteToChannel,
|
|
20
22
|
createDraft,
|
|
21
23
|
deleteDraft,
|
|
22
24
|
updateDraft,
|
|
@@ -1128,6 +1130,56 @@ async function main(): Promise<void> {
|
|
|
1128
1130
|
console.log(`private: ${ch.is_private === true}`);
|
|
1129
1131
|
},
|
|
1130
1132
|
)
|
|
1133
|
+
.command(
|
|
1134
|
+
["create <name>", "new <name>"],
|
|
1135
|
+
"Create a channel (confirm-hash safety gate)",
|
|
1136
|
+
(y2) => y2
|
|
1137
|
+
.positional("name", { type: "string", demandOption: true, describe: "Channel name (Slack lowercases it; no spaces)" })
|
|
1138
|
+
.option("private", { type: "boolean", default: false, describe: "Create a private channel" })
|
|
1139
|
+
.option("invite", { type: "string", array: true, default: [], describe: "Users to invite after creating (@handle or Uxxxx, repeatable)" })
|
|
1140
|
+
.option("code", { type: "string", describe: "Safety hash to confirm create" }),
|
|
1141
|
+
async (argv) => {
|
|
1142
|
+
const token = tok(argv as W);
|
|
1143
|
+
// Slack lowercases and strips the leading #; normalize for preview + code.
|
|
1144
|
+
const name = argv.name!.replace(/^#/, "").toLowerCase();
|
|
1145
|
+
const isPrivate = argv.private === true;
|
|
1146
|
+
const invites = (argv.invite as string[]).filter(Boolean);
|
|
1147
|
+
const code = safetyCode(name, String(isPrivate), invites.join(","));
|
|
1148
|
+
if (argv.code !== code) requireCode(argv.code, code, [
|
|
1149
|
+
`--- Creating channel -------------------------`,
|
|
1150
|
+
` name: ${isPrivate ? "🔒 " : "#"}${name}`,
|
|
1151
|
+
` private: ${isPrivate}`,
|
|
1152
|
+
...(invites.length ? [` invite: ${invites.join(", ")}`] : []),
|
|
1153
|
+
`--------------------------------────────────`,
|
|
1154
|
+
]);
|
|
1155
|
+
let created: { id: string; name: string };
|
|
1156
|
+
try {
|
|
1157
|
+
created = await createChannel(token, name, isPrivate);
|
|
1158
|
+
} catch (e: unknown) {
|
|
1159
|
+
console.error(e instanceof Error ? e.message : String(e));
|
|
1160
|
+
process.exit(1);
|
|
1161
|
+
}
|
|
1162
|
+
console.log(`✓ Created ${isPrivate ? "🔒 " : "#"}${created.name} (${created.id})`);
|
|
1163
|
+
if (invites.length) {
|
|
1164
|
+
const ids: string[] = [];
|
|
1165
|
+
for (const ref of invites) {
|
|
1166
|
+
try {
|
|
1167
|
+
ids.push(ref.startsWith("U") || ref.startsWith("W") ? ref : await resolveUserId(token, ref));
|
|
1168
|
+
} catch (e: unknown) {
|
|
1169
|
+
console.error(` ! could not resolve ${ref}: ${e instanceof Error ? e.message : String(e)}`);
|
|
1170
|
+
}
|
|
1171
|
+
}
|
|
1172
|
+
if (ids.length) {
|
|
1173
|
+
try {
|
|
1174
|
+
await inviteToChannel(token, created.id, ids);
|
|
1175
|
+
console.log(`✓ Invited ${ids.length} member${ids.length === 1 ? "" : "s"}`);
|
|
1176
|
+
} catch (e: unknown) {
|
|
1177
|
+
console.error(` ! invite failed: ${e instanceof Error ? e.message : String(e)}`);
|
|
1178
|
+
}
|
|
1179
|
+
}
|
|
1180
|
+
}
|
|
1181
|
+
},
|
|
1182
|
+
)
|
|
1131
1183
|
.demandCommand(1, "")
|
|
1132
1184
|
.showHelpOnFail(true),
|
|
1133
1185
|
)
|
package/ts/format.ts
CHANGED
|
@@ -3,11 +3,13 @@
|
|
|
3
3
|
import { listConversationMembers, listUsers, userInfo, userName, type Json } from "./slack.ts";
|
|
4
4
|
|
|
5
5
|
/** Match an `@handle` token at a word boundary, capturing the handle.
|
|
6
|
-
* - The negative lookbehind keeps `@` inside emails (`a@b.com`) from matching
|
|
6
|
+
* - The negative lookbehind keeps `@` inside emails (`a@b.com`) from matching,
|
|
7
|
+
* and the `<` keeps already-encoded mentions (`<@U0123>`) from being picked up
|
|
8
|
+
* as a handle named after the user ID (Slack resolves those natively).
|
|
7
9
|
* - Each `.` must be followed by more handle chars, so a trailing sentence dot
|
|
8
10
|
* (`thanks @taku.`) is left out of the capture. */
|
|
9
11
|
function mentionRe(): RegExp {
|
|
10
|
-
return /(?<![A-Za-z0-9._
|
|
12
|
+
return /(?<![A-Za-z0-9._@<-])@([A-Za-z0-9_-]+(?:\.[A-Za-z0-9_-]+)*)/g;
|
|
11
13
|
}
|
|
12
14
|
|
|
13
15
|
/** Lowercase + strip hyphens/underscores/whitespace for loose handle matching. */
|
package/ts/slack.ts
CHANGED
|
@@ -314,6 +314,31 @@ export async function deleteMessage(
|
|
|
314
314
|
await post(token, "chat.delete", { channel, ts });
|
|
315
315
|
}
|
|
316
316
|
|
|
317
|
+
// Create a public (or private) channel via conversations.create. Slack
|
|
318
|
+
// lowercases the name and rejects spaces/most punctuation; the raw API error
|
|
319
|
+
// (e.g. name_taken, invalid_name_specials) surfaces to the caller. Returns the
|
|
320
|
+
// new channel's { id, name }.
|
|
321
|
+
export async function createChannel(
|
|
322
|
+
token: string,
|
|
323
|
+
name: string,
|
|
324
|
+
isPrivate = false,
|
|
325
|
+
): Promise<{ id: string; name: string }> {
|
|
326
|
+
const resp = (await post(token, "conversations.create", {
|
|
327
|
+
name,
|
|
328
|
+
is_private: isPrivate,
|
|
329
|
+
})) as { channel?: { id?: string; name?: string } };
|
|
330
|
+
return { id: resp.channel?.id ?? "", name: resp.channel?.name ?? name };
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
// Invite users to a channel via conversations.invite (up to ~1000 ids).
|
|
334
|
+
export async function inviteToChannel(
|
|
335
|
+
token: string,
|
|
336
|
+
channel: string,
|
|
337
|
+
userIds: string[],
|
|
338
|
+
): Promise<void> {
|
|
339
|
+
await post(token, "conversations.invite", { channel, users: userIds.join(",") });
|
|
340
|
+
}
|
|
341
|
+
|
|
317
342
|
export async function listConversations(token: string): Promise<Json> {
|
|
318
343
|
const allChannels: Json[] = [];
|
|
319
344
|
let cursor = "";
|