slack-term 1.18.0 → 1.19.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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "slack-term",
3
- "version": "1.18.0",
3
+ "version": "1.19.0",
4
4
  "repository": {
5
5
  "type": "git",
6
6
  "url": "https://github.com/snomiao/slack-term.git"
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/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 = "";