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/dist/cli.js +71 -64
- package/package.json +1 -1
- package/ts/auth.ts +23 -0
- package/ts/cli.ts +15 -0
- package/ts/profiles.ts +4 -4
- package/ts/slack-app.ts +27 -4
- package/ts/slack.ts +16 -4
package/package.json
CHANGED
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
|
|
6
|
-
// Global (home): ~/.slack-cli/workspace — set with: slack
|
|
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
|
|
266
|
-
` Select globally: slack
|
|
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
|
-
/**
|
|
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
|
-
|
|
282
|
-
|
|
283
|
-
|
|
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
|
|
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
|
|
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
|
-
`
|
|
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}`);
|