slack-term 1.26.0 → 1.26.2

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 (3) hide show
  1. package/dist/cli.js +62 -62
  2. package/package.json +2 -1
  3. package/ts/cli.ts +33 -16
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "slack-term",
3
- "version": "1.26.0",
3
+ "version": "1.26.2",
4
4
  "repository": {
5
5
  "type": "git",
6
6
  "url": "https://github.com/snomiao/slack-term.git"
@@ -17,6 +17,7 @@
17
17
  "@types/node": "^22",
18
18
  "@types/yargs": "^17.0.35",
19
19
  "@typescript/native-preview": "^7.0.0-dev.20260707.2",
20
+ "@vitest/coverage-istanbul": "^4.1.10",
20
21
  "@vitest/coverage-v8": "^4.1.4",
21
22
  "semantic-release": "^24",
22
23
  "typescript": "^5.6",
package/ts/cli.ts CHANGED
@@ -1224,14 +1224,27 @@ interface SendArgs {
1224
1224
  // Slack does not notify you about messages you sent to yourself, so an
1225
1225
  // escalation DM via `send @me` (or @your-own-handle) is delivered but never
1226
1226
  // surfaces. Returns true when ref names the token's own user.
1227
- async function isSelfDm(token: string, ref: string, cookie?: string): Promise<boolean> {
1228
- if (!ref.startsWith("@")) return false;
1229
- const name = ref.slice(1).toLowerCase().replace(/[^a-z0-9]/g, "");
1230
- if (name === "me" || name === "you") return true;
1227
+ /** Is `channelId` the token owner's DM with themselves?
1228
+ *
1229
+ * Decided on the RESOLVED channel rather than the target string. Matching the
1230
+ * target text only catches the spellings someone thought of (`@me`, the exact
1231
+ * handle) and misses every other way the same conversation gets addressed — a
1232
+ * display name, `--user-id`, `--channel-id`, a permalink. Slack's self-DM is an
1233
+ * IM whose counterparty is you, which is true regardless of how it was named.
1234
+ *
1235
+ * Fail-soft: an unreadable channel returns false, so the send is never blocked
1236
+ * by a lookup failure. Only asked for `D…` ids, so channel sends pay nothing. */
1237
+ async function isSelfDmChannel(
1238
+ token: string,
1239
+ channelId: string,
1240
+ selfUserId: string | undefined,
1241
+ cookie?: string,
1242
+ ): Promise<boolean> {
1243
+ if (!selfUserId || !channelId.startsWith("D")) return false;
1231
1244
  try {
1232
- const self = await authTest(token, cookie);
1233
- const selfName = (self.user ?? "").toLowerCase().replace(/[^a-z0-9]/g, "");
1234
- return selfName !== "" && selfName === name;
1245
+ const info = asRecord((await conversationInfo(token, channelId, cookie)) as Json);
1246
+ const ch = asRecord(info.channel);
1247
+ return ch.is_im === true && ch.user === selfUserId;
1235
1248
  } catch {
1236
1249
  return false;
1237
1250
  }
@@ -1245,20 +1258,24 @@ async function cmdSend(token: string, args: SendArgs): Promise<void> {
1245
1258
  // --as-bot, the user token otherwise.
1246
1259
  const getSelf = selfLookup(token, cookie);
1247
1260
 
1248
- // Guard the self-DM footgun before doing anything else, unless sending as the
1249
- // bot (which delivers a notifiable DM from a different identity).
1250
- if (!args.asBot && !args.channelId && !args.userId && await isSelfDm(token, ref, cookie)) {
1251
- console.error(
1252
- `Warning: "${ref}" is a DM to yourself — Slack will NOT notify you of your own message.\n` +
1253
- ` To reach yourself with a notification, send as the bot: slack send '${ref}' '...' --as-bot`,
1254
- );
1255
- }
1256
-
1257
1261
  let channelId: string;
1258
1262
  if (args.channelId) channelId = args.channelId;
1259
1263
  else if (args.userId) channelId = await openDm(token, args.userId, cookie);
1260
1264
  else channelId = await resolveChannel(token, ref, cookie);
1261
1265
 
1266
+ // Self-DM footgun: Slack never notifies you about a message you sent, so a DM
1267
+ // to yourself is delivered and then silently never surfaces — the worst shape
1268
+ // for an escalation ("I told you" / nobody saw it). Checked after resolution
1269
+ // so it fires however the DM was addressed: @me, a handle, a display name,
1270
+ // --user-id, --channel-id, or a permalink. --as-bot is exempt: that posts as
1271
+ // the app, a different identity, which does notify you.
1272
+ if (!args.asBot && await isSelfDmChannel(token, channelId, (await getSelf())?.userId, cookie)) {
1273
+ console.error(
1274
+ `Warning: "${args.target}" is a DM to yourself — Slack will NOT notify you of your own message.\n` +
1275
+ ` To reach yourself with a notification, send as the bot: slack send '${args.target}' '...' --as-bot`,
1276
+ );
1277
+ }
1278
+
1262
1279
  // Convert @handle / @名前 tokens to <@USERID> before hashing/sending so the
1263
1280
  // safety gate covers exactly what will be posted. Unresolved tokens stay as
1264
1281
  // text. The detailed report drives the confirm-gate mention preview below.