slack-term 1.21.0 → 1.21.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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "slack-term",
3
- "version": "1.21.0",
3
+ "version": "1.21.2",
4
4
  "repository": {
5
5
  "type": "git",
6
6
  "url": "https://github.com/snomiao/slack-term.git"
package/ts/auth.ts CHANGED
@@ -263,6 +263,29 @@ export async function cmdAuthChrome(opts: { workspace?: string } = {}): Promise<
263
263
  }
264
264
  }
265
265
 
266
+ // A Chrome xoxd session cookie only augments a desktop *user* session token (xoxc-); it has
267
+ // no effect on a bot token (xoxb-). Attaching it to a bot profile silently does nothing and
268
+ // user-level actions (tail @user, DMs, users.list) still fail with missing_scope /
269
+ // cannot_dm_bot. Stop early with a pointer to a user-token workspace instead.
270
+ const selected = profiles.find((p) => p.name === profileName)!;
271
+ if (selected.profile.token.startsWith("xoxb-")) {
272
+ console.error(
273
+ `\nWorkspace "${profileName}" uses a bot token (xoxb-). A Chrome session cookie only\n` +
274
+ `augments a user session token (xoxc-) — it has no effect on a bot token, so user-level\n` +
275
+ `actions (tail @user, DMs, listing users) would still fail.`,
276
+ );
277
+ const userProfiles = profiles.filter(
278
+ (p) => p.profile.token.startsWith("xoxc-") || p.profile.token.startsWith("xoxp-"),
279
+ );
280
+ if (userProfiles.length > 0) {
281
+ console.error(` Target a user-token workspace instead: ${userProfiles.map((p) => p.name).join(", ")}`);
282
+ console.error(` slack auth chrome -w ${userProfiles[0]!.name}`);
283
+ } else {
284
+ console.error(` Import your Slack desktop user session instead: slack auth login`);
285
+ }
286
+ process.exit(1);
287
+ }
288
+
266
289
  console.log("Scanning Chrome profiles for Slack session...");
267
290
  console.log("macOS may show a dialog asking for your login password — click Allow.");
268
291
 
package/ts/cli.ts CHANGED
@@ -1297,6 +1297,21 @@ async function main(): Promise<void> {
1297
1297
 
1298
1298
  await yargs(hideBin(process.argv))
1299
1299
  .scriptName("slack")
1300
+ // A thrown handler error (e.g. a Slack API failure) is a runtime error, not a usage
1301
+ // mistake — print just the clean one-line message, never the command's --help block or a
1302
+ // minified source stack. Reserve the usage/help output for actual argument-parse errors
1303
+ // (err is undefined then). showHelpOnFail(false) stops yargs' default help dump.
1304
+ .showHelpOnFail(false)
1305
+ .fail((msg, err, y) => {
1306
+ if (err) {
1307
+ console.error(err.message);
1308
+ process.exit(1);
1309
+ }
1310
+ console.error(msg);
1311
+ console.error("");
1312
+ y.showHelp();
1313
+ process.exit(1);
1314
+ })
1300
1315
  .option("workspace", { alias: "w", type: "string", describe: "Workspace name" })
1301
1316
  .middleware(async (argv) => {
1302
1317
  const cmd = String((argv._ ?? [])[0] ?? "");
package/ts/profiles.ts CHANGED
@@ -2,8 +2,8 @@
2
2
  // Profiles are stored in ~/.config/slack-cli/profiles.json.
3
3
  //
4
4
  // Workspace selection uses lockfiles:
5
- // Local (cwd): .slack-cli/workspace — set with: slack workspace use <name>
6
- // Global (home): ~/.slack-cli/workspace — set with: slack workspace use -g <name>
5
+ // Local (cwd): .slack-cli/workspace — set with: slack auth use <name>
6
+ // Global (home): ~/.slack-cli/workspace — set with: slack auth use -g <name>
7
7
  //
8
8
  // Token resolution order (no --workspace flag):
9
9
  // 1. process.env SLACK_TOKEN or SLACK_BOT_TOKEN
@@ -262,8 +262,8 @@ export function resolveToken(workspaceFlag?: string): string {
262
262
  if (names.length > 0) {
263
263
  throw new Error(
264
264
  `Workspace not selected (${names.join(", ")} available).\n` +
265
- ` Select locally: slack workspace use <name> (writes .slack-cli/workspace)\n` +
266
- ` Select globally: slack workspace use -g <name> (writes ~/.slack-cli/workspace)`,
265
+ ` Select locally: slack auth use <name> (writes .slack-cli/workspace)\n` +
266
+ ` Select globally: slack auth use -g <name> (writes ~/.slack-cli/workspace)`,
267
267
  );
268
268
  }
269
269
 
package/ts/slack-app.ts CHANGED
@@ -271,16 +271,39 @@ export type ChromeCookieCandidate = {
271
271
  cookie: string; // decrypted xoxd-...
272
272
  };
273
273
 
274
- /** Read the display name for a Chrome profile from its Preferences JSON. */
274
+ /**
275
+ * Read a human-friendly display name (nickname + email) for a Chrome profile so a bare
276
+ * "Default"/"Profile N" is never shown alone.
277
+ *
278
+ * Prefers Chrome's `Local State` → profile.info_cache, which reliably carries both the
279
+ * nickname (`name`) and account email (`user_name`); the per-profile Preferences file
280
+ * often has neither. Only nickname + email are surfaced — the gaia real name is never read.
281
+ */
275
282
  function chromeProfileName(userDataDir: string, profileDir: string): string {
283
+ const label = (name: string, email: string): string => {
284
+ if (name && email) return `${name} (${email})`;
285
+ return name || email || profileDir;
286
+ };
287
+ try {
288
+ const localState = JSON.parse(
289
+ readFileSync(join(userDataDir, "Local State"), "utf8"),
290
+ ) as { profile?: { info_cache?: Record<string, { name?: string; user_name?: string }> } };
291
+ const info = localState.profile?.info_cache?.[profileDir];
292
+ if (info && (info.name || info.user_name)) {
293
+ return label(info.name ?? "", info.user_name ?? "");
294
+ }
295
+ } catch {
296
+ // fall through to Preferences
297
+ }
276
298
  try {
277
299
  const prefs = JSON.parse(
278
300
  readFileSync(join(userDataDir, profileDir, "Preferences"), "utf8"),
279
301
  ) as Record<string, unknown>;
280
302
  const profile = prefs.profile as Record<string, unknown> | undefined;
281
- const name = (profile?.name as string | undefined) ?? "";
282
- const email = (profile?.user_name as string | undefined) ?? "";
283
- return email ? `${name} (${email})` : name || profileDir;
303
+ return label(
304
+ (profile?.name as string | undefined) ?? "",
305
+ (profile?.user_name as string | undefined) ?? "",
306
+ );
284
307
  } catch {
285
308
  return profileDir;
286
309
  }
package/ts/slack.ts CHANGED
@@ -44,7 +44,20 @@ async function call(token: string, method: string, init: RequestInit, cookie?: s
44
44
  throw new Error(
45
45
  `Desktop app token (xoxc-) is not accepted by the public Slack API.\n` +
46
46
  `Replace it with an xoxp- user token:\n` +
47
- ` slack workspace set-token <name> <xoxp-token>`,
47
+ ` slack auth token`,
48
+ );
49
+ }
50
+ // Bot tokens (xoxb-) can't act as a user: they lack user scopes (missing_scope) and can't
51
+ // open a DM with themselves (cannot_dm_bot, e.g. `tail @you`). Point at a user-token workspace.
52
+ if ((err === "missing_scope" || err === "cannot_dm_bot") && token.startsWith("xoxb-")) {
53
+ const why = err === "cannot_dm_bot"
54
+ ? `you're authenticated as a bot, so "@you" is the bot itself and it can't DM itself`
55
+ : `this bot token lacks the user scope this action needs`;
56
+ throw new Error(
57
+ `Slack error on ${method}: ${err} — ${why}.\n` +
58
+ `Tailing/DMing people and listing users need a user session, not a bot token.\n` +
59
+ ` Switch workspace: slack auth ls then slack auth use <name>\n` +
60
+ ` Or import your Slack desktop session: slack auth login`,
48
61
  );
49
62
  }
50
63
  throw new Error(`Slack error on ${method}: ${err}`);
@@ -77,14 +90,13 @@ async function callSession(token: string, method: string, init: RequestInit, coo
77
90
  if ((err === "invalid_auth" || err === "not_authed") && !token.startsWith("xoxc-")) {
78
91
  throw new Error(
79
92
  `The draft API requires a desktop app session token (xoxc-).\n` +
80
- `Import from Slack desktop: slack workspace import`,
93
+ `Import from Slack desktop: slack auth login`,
81
94
  );
82
95
  }
83
96
  if ((err === "invalid_auth" || err === "not_authed") && !cookie) {
84
97
  throw new Error(
85
98
  `drafts.list also requires the xoxd session cookie.\n` +
86
- `Set it with: slack workspace set-cookie <workspace-name> <xoxd-value>\n` +
87
- `Get xoxd from browser: DevTools → Application → Cookies → slack.com → d`,
99
+ `Attach it with: slack auth chrome (macOS) or slack auth firefox`,
88
100
  );
89
101
  }
90
102
  throw new Error(`Slack error on ${method}: ${err}`);