agent-messenger 2.6.1 → 2.6.3

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 (78) hide show
  1. package/.claude-plugin/plugin.json +1 -1
  2. package/dist/package.json +1 -1
  3. package/dist/src/platforms/channeltalk/cli.js +1 -1
  4. package/dist/src/platforms/channeltalk/cli.js.map +1 -1
  5. package/dist/src/platforms/channeltalk/client.js +1 -1
  6. package/dist/src/platforms/channeltalk/client.js.map +1 -1
  7. package/dist/src/platforms/channeltalk/commands/auth.d.ts +2 -0
  8. package/dist/src/platforms/channeltalk/commands/auth.d.ts.map +1 -1
  9. package/dist/src/platforms/channeltalk/commands/auth.js +9 -3
  10. package/dist/src/platforms/channeltalk/commands/auth.js.map +1 -1
  11. package/dist/src/platforms/discord/client.js +1 -1
  12. package/dist/src/platforms/discord/client.js.map +1 -1
  13. package/dist/src/platforms/discord/commands/auth.d.ts +1 -0
  14. package/dist/src/platforms/discord/commands/auth.d.ts.map +1 -1
  15. package/dist/src/platforms/discord/commands/auth.js +6 -3
  16. package/dist/src/platforms/discord/commands/auth.js.map +1 -1
  17. package/dist/src/platforms/slack/cli.js +1 -1
  18. package/dist/src/platforms/slack/cli.js.map +1 -1
  19. package/dist/src/platforms/slack/client.js +1 -1
  20. package/dist/src/platforms/slack/client.js.map +1 -1
  21. package/dist/src/platforms/slack/commands/auth.d.ts +1 -0
  22. package/dist/src/platforms/slack/commands/auth.d.ts.map +1 -1
  23. package/dist/src/platforms/slack/commands/auth.js +8 -5
  24. package/dist/src/platforms/slack/commands/auth.js.map +1 -1
  25. package/dist/src/platforms/teams/client.js +1 -1
  26. package/dist/src/platforms/teams/client.js.map +1 -1
  27. package/dist/src/platforms/teams/commands/auth.d.ts +1 -0
  28. package/dist/src/platforms/teams/commands/auth.d.ts.map +1 -1
  29. package/dist/src/platforms/teams/commands/auth.js +12 -7
  30. package/dist/src/platforms/teams/commands/auth.js.map +1 -1
  31. package/dist/src/platforms/webex/client.d.ts +3 -0
  32. package/dist/src/platforms/webex/client.d.ts.map +1 -1
  33. package/dist/src/platforms/webex/client.js +6 -0
  34. package/dist/src/platforms/webex/client.js.map +1 -1
  35. package/dist/src/platforms/webex/commands/snapshot.d.ts +0 -3
  36. package/dist/src/platforms/webex/commands/snapshot.d.ts.map +1 -1
  37. package/dist/src/platforms/webex/commands/snapshot.js +9 -47
  38. package/dist/src/platforms/webex/commands/snapshot.js.map +1 -1
  39. package/docs/content/docs/cli/webex.mdx +3 -11
  40. package/package.json +1 -1
  41. package/skills/agent-channeltalk/SKILL.md +3 -3
  42. package/skills/agent-channeltalk/references/authentication.md +3 -3
  43. package/skills/agent-channeltalk/templates/monitor-chat.sh +1 -1
  44. package/skills/agent-channeltalk/templates/post-message.sh +2 -2
  45. package/skills/agent-channeltalk/templates/workspace-summary.sh +1 -1
  46. package/skills/agent-channeltalkbot/SKILL.md +1 -1
  47. package/skills/agent-discord/SKILL.md +1 -1
  48. package/skills/agent-discordbot/SKILL.md +1 -1
  49. package/skills/agent-instagram/SKILL.md +1 -1
  50. package/skills/agent-kakaotalk/SKILL.md +1 -1
  51. package/skills/agent-line/SKILL.md +1 -1
  52. package/skills/agent-slack/SKILL.md +1 -1
  53. package/skills/agent-slack/references/authentication.md +3 -3
  54. package/skills/agent-slackbot/SKILL.md +1 -1
  55. package/skills/agent-teams/SKILL.md +1 -1
  56. package/skills/agent-telegram/SKILL.md +1 -1
  57. package/skills/agent-webex/SKILL.md +6 -14
  58. package/skills/agent-webex/references/common-patterns.md +3 -32
  59. package/skills/agent-wechatbot/SKILL.md +1 -1
  60. package/skills/agent-whatsapp/SKILL.md +1 -1
  61. package/skills/agent-whatsappbot/SKILL.md +1 -1
  62. package/src/platforms/channeltalk/cli.ts +1 -1
  63. package/src/platforms/channeltalk/client.ts +1 -1
  64. package/src/platforms/channeltalk/commands/auth.test.ts +4 -2
  65. package/src/platforms/channeltalk/commands/auth.ts +11 -3
  66. package/src/platforms/discord/client.ts +1 -1
  67. package/src/platforms/discord/commands/auth.test.ts +5 -0
  68. package/src/platforms/discord/commands/auth.ts +7 -3
  69. package/src/platforms/slack/cli.ts +1 -1
  70. package/src/platforms/slack/client.ts +1 -1
  71. package/src/platforms/slack/commands/auth.test.ts +31 -6
  72. package/src/platforms/slack/commands/auth.ts +9 -5
  73. package/src/platforms/teams/client.ts +1 -1
  74. package/src/platforms/teams/commands/auth.test.ts +5 -0
  75. package/src/platforms/teams/commands/auth.ts +14 -7
  76. package/src/platforms/webex/client.ts +10 -0
  77. package/src/platforms/webex/commands/snapshot.test.ts +13 -41
  78. package/src/platforms/webex/commands/snapshot.ts +10 -61
@@ -44,7 +44,7 @@ VALID=$(echo "$AUTH_STATUS" | jq -r '.valid // false')
44
44
 
45
45
  if [ "$VALID" != "true" ]; then
46
46
  echo -e "${RED}Not authenticated!${NC}" >&2
47
- echo "Make sure Channel Talk desktop app is installed and you're logged in." >&2
47
+ echo "Make sure Channel Talk is logged in via the desktop app or a supported Chromium browser." >&2
48
48
  echo "Then run: agent-channeltalk auth extract" >&2
49
49
  exit 1
50
50
  fi
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  name: agent-channeltalkbot
3
3
  description: Interact with Channel Talk workspaces using API credentials - send messages, read chats, manage groups and bots
4
- version: 2.6.1
4
+ version: 2.6.3
5
5
  allowed-tools: Bash(agent-channeltalkbot:*)
6
6
  metadata:
7
7
  openclaw:
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  name: agent-discord
3
3
  description: Interact with Discord servers - send messages, read channels, manage reactions
4
- version: 2.6.1
4
+ version: 2.6.3
5
5
  allowed-tools: Bash(agent-discord:*)
6
6
  metadata:
7
7
  openclaw:
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  name: agent-discordbot
3
3
  description: Interact with Discord servers using bot tokens - send messages, read channels, manage reactions
4
- version: 2.6.1
4
+ version: 2.6.3
5
5
  allowed-tools: Bash(agent-discordbot:*)
6
6
  metadata:
7
7
  openclaw:
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  name: agent-instagram
3
3
  description: Interact with Instagram DMs - send messages, read conversations, manage accounts
4
- version: 2.6.1
4
+ version: 2.6.3
5
5
  allowed-tools: Bash(agent-instagram:*)
6
6
  metadata:
7
7
  openclaw:
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  name: agent-kakaotalk
3
3
  description: Interact with KakaoTalk - send messages, read chats, manage conversations
4
- version: 2.6.1
4
+ version: 2.6.3
5
5
  allowed-tools: Bash(agent-kakaotalk:*)
6
6
  metadata:
7
7
  openclaw:
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  name: agent-line
3
3
  description: Interact with LINE - send messages, read chats, manage conversations
4
- version: 2.6.1
4
+ version: 2.6.3
5
5
  allowed-tools: Bash(agent-line:*)
6
6
  metadata:
7
7
  openclaw:
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  name: agent-slack
3
3
  description: Interact with Slack workspaces - send messages, read channels, manage reactions
4
- version: 2.6.1
4
+ version: 2.6.3
5
5
  allowed-tools: Bash(agent-slack:*)
6
6
  metadata:
7
7
  openclaw:
@@ -243,11 +243,11 @@ This shows:
243
243
 
244
244
  ### "No workspaces found"
245
245
 
246
- **Cause**: Not logged into any workspaces in Slack desktop app
246
+ **Cause**: Not logged into any workspaces in the Slack desktop app or a supported Chromium browser
247
247
 
248
248
  **Solution**:
249
249
 
250
- 1. Open Slack desktop app
250
+ 1. Open Slack desktop app or sign in at app.slack.com in a supported Chromium browser (Chrome, Edge, Arc, Brave)
251
251
  2. Sign in to at least one workspace
252
252
  3. Run `agent-slack auth extract` again
253
253
 
@@ -281,7 +281,7 @@ agent-slack auth status
281
281
 
282
282
  **Solution**:
283
283
 
284
- 1. Open Slack desktop app
284
+ 1. Open Slack desktop app or app.slack.com in a supported Chromium browser
285
285
  2. Make sure you're logged in (send a message to verify)
286
286
  3. Run `agent-slack auth extract --debug` to see details
287
287
  4. If issues persist, try logging out and back into Slack
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  name: agent-slackbot
3
3
  description: Interact with Slack workspaces using bot tokens - send messages, read channels, manage reactions
4
- version: 2.6.1
4
+ version: 2.6.3
5
5
  allowed-tools: Bash(agent-slackbot:*)
6
6
  metadata:
7
7
  openclaw:
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  name: agent-teams
3
3
  description: Interact with Microsoft Teams - send messages, read channels, manage reactions
4
- version: 2.6.1
4
+ version: 2.6.3
5
5
  allowed-tools: Bash(agent-teams:*)
6
6
  metadata:
7
7
  openclaw:
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  name: agent-telegram
3
3
  description: Interact with Telegram through TDLib - authenticate, inspect chats, and send messages
4
- version: 2.6.1
4
+ version: 2.6.3
5
5
  allowed-tools: Bash(agent-telegram:*)
6
6
  ---
7
7
 
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  name: agent-webex
3
3
  description: Interact with Cisco Webex - send messages, read spaces, manage memberships
4
- version: 2.6.1
4
+ version: 2.6.3
5
5
  allowed-tools: Bash(agent-webex:*)
6
6
  metadata:
7
7
  openclaw:
@@ -116,7 +116,7 @@ At the **start of every task**, read `~/.config/agent-messenger/MEMORY.md` using
116
116
  After discovering useful information, update `~/.config/agent-messenger/MEMORY.md` using the `Write` tool. Write triggers include:
117
117
 
118
118
  - After discovering space IDs and titles (from `space list`, `snapshot`, etc.)
119
- - After discovering member IDs and names (from `member list`, `snapshot`, etc.)
119
+ - After discovering member IDs and names (from `member list`, etc.)
120
120
  - After the user gives you an alias or preference ("call this the standup space", "my main space is X")
121
121
  - After discovering space structure (group vs direct spaces)
122
122
 
@@ -247,25 +247,17 @@ agent-webex member list <space-id> --limit 100
247
247
 
248
248
  ### Snapshot Command
249
249
 
250
- Get comprehensive workspace state for AI agents:
250
+ Get workspace spaces overview for AI agents:
251
251
 
252
252
  ```bash
253
- # Full snapshot
254
253
  agent-webex snapshot
255
-
256
- # Filtered snapshots
257
- agent-webex snapshot --spaces-only
258
- agent-webex snapshot --members-only
259
-
260
- # Limit messages per space
261
- agent-webex snapshot --limit 10
262
254
  ```
263
255
 
264
256
  Returns JSON with:
265
257
 
266
- - Spaces (id, title, type, created)
267
- - Recent messages (id, text, personEmail, created)
268
- - Members (id, personDisplayName, personEmail)
258
+ - Spaces (id, title, type, lastActivity) — only spaces you're a member of
259
+
260
+ For messages or members, use `message list <space-id>` or `member list <space-id>`.
269
261
 
270
262
  ## Output Format
271
263
 
@@ -323,9 +323,9 @@ echo "Found: $(echo "$MATCH" | jq -r '.personDisplayName') ($(echo "$MATCH" | jq
323
323
 
324
324
  ## Snapshot Patterns
325
325
 
326
- ### Pattern 19: Full Workspace Snapshot
326
+ ### Pattern 19: Workspace Snapshot
327
327
 
328
- **Use case**: Get complete workspace state for AI context
328
+ **Use case**: Get spaces overview for AI context
329
329
 
330
330
  ```bash
331
331
  #!/bin/bash
@@ -339,36 +339,7 @@ echo "Total spaces: $SPACE_COUNT"
339
339
  echo "$SNAPSHOT" | jq -r '.spaces[] | " \(.title) (\(.type))"'
340
340
  ```
341
341
 
342
- ### Pattern 20: Spaces-Only Snapshot
343
-
344
- **Use case**: Quick overview without messages or members
345
-
346
- ```bash
347
- #!/bin/bash
348
-
349
- agent-webex snapshot --spaces-only
350
- ```
351
-
352
- ### Pattern 21: Members-Only Snapshot
353
-
354
- **Use case**: Get member lists across all spaces
355
-
356
- ```bash
357
- #!/bin/bash
358
-
359
- agent-webex snapshot --members-only
360
- ```
361
-
362
- ### Pattern 22: Snapshot with Message Limit
363
-
364
- **Use case**: Control how many messages per space
365
-
366
- ```bash
367
- #!/bin/bash
368
-
369
- # Get snapshot with last 5 messages per space
370
- agent-webex snapshot --limit 5
371
- ```
342
+ **When to use**: Quick workspace overview to discover space IDs and titles. Use `message list <space-id>` or `member list <space-id>` for details.
372
343
 
373
344
  ## Pipeline Patterns
374
345
 
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  name: agent-wechatbot
3
3
  description: Interact with WeChat Official Account using API credentials - send messages, manage templates, list followers
4
- version: 2.6.1
4
+ version: 2.6.3
5
5
  allowed-tools: Bash(agent-wechatbot:*)
6
6
  metadata:
7
7
  openclaw:
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  name: agent-whatsapp
3
3
  description: Interact with WhatsApp - send messages, read chats, manage conversations
4
- version: 2.6.1
4
+ version: 2.6.3
5
5
  allowed-tools: Bash(agent-whatsapp:*)
6
6
  metadata:
7
7
  openclaw:
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  name: agent-whatsappbot
3
3
  description: Interact with WhatsApp using Cloud API credentials - send messages, manage templates
4
- version: 2.6.1
4
+ version: 2.6.3
5
5
  allowed-tools: Bash(agent-whatsappbot:*)
6
6
  metadata:
7
7
  openclaw:
@@ -29,7 +29,7 @@ const program = new Command()
29
29
 
30
30
  program
31
31
  .name('agent-channeltalk')
32
- .description('CLI tool for Channel Talk using extracted desktop app credentials')
32
+ .description('CLI tool for Channel Talk using extracted desktop app or supported Chromium browser credentials')
33
33
  .version(pkg.version)
34
34
  .option('--pretty', 'Pretty-print JSON output')
35
35
  .option('--workspace <id>', 'Workspace ID to use')
@@ -44,7 +44,7 @@ export class ChannelClient {
44
44
  const creds = await new ChannelCredentialManager().getCredentials()
45
45
  if (!creds) {
46
46
  throw new ChannelError(
47
- 'No Channel Talk credentials found. Make sure Channel Talk desktop app is installed and logged in.',
47
+ 'No Channel Talk credentials found. Make sure Channel Talk is logged in to the desktop app or a supported Chromium browser.',
48
48
  'no_credentials',
49
49
  )
50
50
  }
@@ -26,6 +26,8 @@ const mockExtract = mock(() =>
26
26
  import {
27
27
  clearAction,
28
28
  extractAction,
29
+ getNoChannelTalkCredentialsMessage,
30
+ getNoValidChannelTalkCredentialsMessage,
29
31
  listAction,
30
32
  removeAction,
31
33
  resetChannelAuthCommandDependenciesForTesting,
@@ -182,7 +184,7 @@ describe('channel auth commands', () => {
182
184
  const result = await extractAction()
183
185
 
184
186
  expect(result).toEqual({
185
- error: 'No credentials. Make sure Channel Talk desktop app is installed and logged in.',
187
+ error: getNoChannelTalkCredentialsMessage(),
186
188
  })
187
189
  })
188
190
 
@@ -192,7 +194,7 @@ describe('channel auth commands', () => {
192
194
  const result = await extractAction()
193
195
 
194
196
  expect(result).toEqual({
195
- error: 'No valid credentials found. Make sure Channel Talk desktop app or browser is logged in.',
197
+ error: getNoValidChannelTalkCredentialsMessage(),
196
198
  })
197
199
  })
198
200
  })
@@ -84,7 +84,7 @@ export async function extractAction(options: ActionOptions = {}): Promise<Extrac
84
84
 
85
85
  if (extracted.length === 0) {
86
86
  return {
87
- error: 'No credentials. Make sure Channel Talk desktop app is installed and logged in.',
87
+ error: getNoChannelTalkCredentialsMessage(),
88
88
  }
89
89
  }
90
90
 
@@ -126,12 +126,20 @@ export async function extractAction(options: ActionOptions = {}): Promise<Extrac
126
126
  }
127
127
  }
128
128
 
129
- return { error: 'No valid credentials found. Make sure Channel Talk desktop app or browser is logged in.' }
129
+ return { error: getNoValidChannelTalkCredentialsMessage() }
130
130
  } catch (error: unknown) {
131
131
  return { error: (error as Error).message }
132
132
  }
133
133
  }
134
134
 
135
+ export function getNoChannelTalkCredentialsMessage(): string {
136
+ return 'No credentials. Make sure Channel Talk is logged in to the desktop app or a supported Chromium browser.'
137
+ }
138
+
139
+ export function getNoValidChannelTalkCredentialsMessage(): string {
140
+ return 'No valid credentials found. Make sure Channel Talk is logged in to the desktop app or a supported Chromium browser.'
141
+ }
142
+
135
143
  export async function statusAction(options: ActionOptions = {}): Promise<StatusResult> {
136
144
  try {
137
145
  const credManager = options._credManager ?? createCredentialManager()
@@ -246,7 +254,7 @@ export function createAuthCommand(): Command {
246
254
  .description('Authentication commands')
247
255
  .addCommand(
248
256
  new Command('extract')
249
- .description('Extract cookies from Channel Talk desktop app')
257
+ .description('Extract cookies from Channel Talk desktop app or a supported Chromium browser')
250
258
  .option('--pretty', 'Pretty print JSON output')
251
259
  .action(async (opts: { pretty?: boolean }) => {
252
260
  cliOutput(await extractAction(opts), opts.pretty)
@@ -59,7 +59,7 @@ export class DiscordClient {
59
59
  const token = await credManager.getToken()
60
60
  if (!token) {
61
61
  throw new DiscordError(
62
- 'No Discord credentials found. Make sure Discord desktop app is installed and logged in.',
62
+ 'No Discord credentials found. Make sure Discord is logged in to the desktop app or a supported Chromium browser.',
63
63
  'no_credentials',
64
64
  )
65
65
  }
@@ -1,5 +1,6 @@
1
1
  import { afterEach, beforeEach, expect, spyOn, test } from 'bun:test'
2
2
 
3
+ import { getNoDiscordTokenFoundMessage } from './auth'
3
4
  import { DiscordClient } from '../client'
4
5
  import { DiscordCredentialManager } from '../credential-manager'
5
6
  import { DiscordTokenExtractor } from '../token-extractor'
@@ -82,3 +83,7 @@ test('status: returns auth state', async () => {
82
83
  expect(config.token).toBeNull()
83
84
  expect(config.current_server).toBeNull()
84
85
  })
86
+
87
+ test('no-token message mentions desktop app and browser fallback', () => {
88
+ expect(getNoDiscordTokenFoundMessage()).toContain('desktop app or a supported Chromium browser')
89
+ })
@@ -39,7 +39,7 @@ export async function extractAction(options: { pretty?: boolean; debug?: boolean
39
39
  console.log(
40
40
  formatOutput(
41
41
  {
42
- error: 'No Discord token found. Make sure Discord desktop app is installed and logged in.',
42
+ error: getNoDiscordTokenFoundMessage(),
43
43
  hint: options.debug ? undefined : 'Run with --debug for more info.',
44
44
  },
45
45
  options.pretty,
@@ -121,7 +121,7 @@ export async function extractAction(options: { pretty?: boolean; debug?: boolean
121
121
  formatOutput(
122
122
  {
123
123
  error: 'No usable Discord token found. Tokens may be expired or have no servers.',
124
- hint: 'Make sure Discord is logged in and you are a member of at least one server.',
124
+ hint: 'Make sure Discord is logged in to the desktop app or a supported Chromium browser, and that you are a member of at least one server.',
125
125
  },
126
126
  options.pretty,
127
127
  ),
@@ -184,11 +184,15 @@ export async function statusAction(options: { pretty?: boolean }): Promise<void>
184
184
  }
185
185
  }
186
186
 
187
+ export function getNoDiscordTokenFoundMessage(): string {
188
+ return 'No Discord token found. Make sure Discord is logged in to the desktop app or a supported Chromium browser.'
189
+ }
190
+
187
191
  export const authCommand = new Command('auth')
188
192
  .description('Authentication commands')
189
193
  .addCommand(
190
194
  new Command('extract')
191
- .description('Extract token from Discord desktop app')
195
+ .description('Extract token from Discord desktop app or a supported Chromium browser')
192
196
  .option('--pretty', 'Pretty print JSON output')
193
197
  .option('--debug', 'Show debug output for troubleshooting')
194
198
  .action(extractAction),
@@ -40,7 +40,7 @@ const program = new Command()
40
40
 
41
41
  program
42
42
  .name('agent-slack')
43
- .description('CLI tool for Slack communication with token extraction from Slack desktop app')
43
+ .description('CLI tool for Slack communication with token extraction from the desktop app or a supported Chromium browser')
44
44
  .version(pkg.version)
45
45
  .option('--workspace <id>', 'Use specific workspace')
46
46
 
@@ -62,7 +62,7 @@ export class SlackClient {
62
62
  const workspace = await credManager.getWorkspace()
63
63
  if (!workspace) {
64
64
  throw new SlackError(
65
- 'No workspace credentials found. Make sure Slack desktop app is installed and logged in.',
65
+ 'No workspace credentials found. Make sure Slack is logged in in the desktop app or a supported Chromium browser.',
66
66
  'no_credentials',
67
67
  )
68
68
  }
@@ -3,7 +3,11 @@ import { mkdirSync, rmSync } from 'node:fs'
3
3
  import { homedir } from 'node:os'
4
4
  import { join } from 'node:path'
5
5
 
6
- import { formatCredentialDebug, getExtractionErrorMessage } from '@/platforms/slack/commands/auth'
6
+ import {
7
+ formatCredentialDebug,
8
+ getExtractionErrorMessage,
9
+ getNoWorkspacesFoundMessage,
10
+ } from '@/platforms/slack/commands/auth'
7
11
  import { CredentialManager } from '@/platforms/slack/credential-manager'
8
12
  import { type ExtractedWorkspace, TokenExtractor } from '@/platforms/slack/token-extractor'
9
13
 
@@ -402,23 +406,44 @@ describe('formatCredentialDebug', () => {
402
406
 
403
407
  describe('getExtractionErrorMessage', () => {
404
408
  test('returns cookie failure message for missing_cookie', () => {
405
- expect(getExtractionErrorMessage(['missing_cookie'])).toContain('Cookie extraction failed')
409
+ const message = getExtractionErrorMessage(['missing_cookie'])
410
+
411
+ expect(message).toContain('Cookie extraction failed')
412
+ expect(message).toContain('desktop app or a supported Chromium browser')
406
413
  })
407
414
 
408
415
  test('returns session expired message for invalid_auth', () => {
409
- expect(getExtractionErrorMessage(['invalid_auth'])).toContain('session has expired')
416
+ const message = getExtractionErrorMessage(['invalid_auth'])
417
+
418
+ expect(message).toContain('session has expired')
419
+ expect(message).toContain('desktop app or a supported Chromium browser')
410
420
  })
411
421
 
412
422
  test('prioritizes missing_cookie over invalid_auth', () => {
413
- expect(getExtractionErrorMessage(['invalid_auth', 'missing_cookie'])).toContain('Cookie extraction failed')
423
+ const message = getExtractionErrorMessage(['invalid_auth', 'missing_cookie'])
424
+
425
+ expect(message).toContain('Cookie extraction failed')
426
+ expect(message).toContain('desktop app or a supported Chromium browser')
414
427
  })
415
428
 
416
429
  test('returns generic message for unknown error codes', () => {
417
- expect(getExtractionErrorMessage(['unknown_error'])).toContain('Extracted tokens are invalid')
430
+ const message = getExtractionErrorMessage(['unknown_error'])
431
+
432
+ expect(message).toContain('Extracted tokens are invalid')
433
+ expect(message).toContain('desktop app or a supported Chromium browser')
418
434
  })
419
435
 
420
436
  test('returns generic message for empty failure list', () => {
421
- expect(getExtractionErrorMessage([])).toContain('Extracted tokens are invalid')
437
+ const message = getExtractionErrorMessage([])
438
+
439
+ expect(message).toContain('Extracted tokens are invalid')
440
+ expect(message).toContain('desktop app or a supported Chromium browser')
441
+ })
442
+ })
443
+
444
+ describe('getNoWorkspacesFoundMessage', () => {
445
+ test('mentions desktop app and browser fallback', () => {
446
+ expect(getNoWorkspacesFoundMessage()).toContain('desktop app or a supported Chromium browser')
422
447
  })
423
448
  })
424
449
 
@@ -61,7 +61,7 @@ async function extractAction(options: {
61
61
  console.log(
62
62
  formatOutput(
63
63
  {
64
- error: 'No workspaces found. Make sure Slack desktop app is installed and logged in.',
64
+ error: getNoWorkspacesFoundMessage(),
65
65
  hint: options.debug ? undefined : 'Run with --debug for more info.',
66
66
  },
67
67
  options.pretty,
@@ -227,19 +227,23 @@ async function statusAction(options: { pretty?: boolean }): Promise<void> {
227
227
 
228
228
  export function getExtractionErrorMessage(failureReasons: string[]): string {
229
229
  if (failureReasons.includes('missing_cookie')) {
230
- return 'Cookie extraction failed. Make sure the Slack desktop app is installed and grant Keychain access when prompted.'
230
+ return 'Cookie extraction failed. Grant Keychain access when prompted, and make sure you are signed into Slack in the desktop app or a supported Chromium browser.'
231
231
  }
232
232
  if (failureReasons.includes('invalid_auth')) {
233
- return 'Slack session has expired. Sign into the Slack desktop app, wait a few seconds, then re-run this command.'
233
+ return 'Slack session has expired. Sign into Slack in the desktop app or a supported Chromium browser, wait a few seconds, then re-run this command.'
234
234
  }
235
- return 'Extracted tokens are invalid. Make sure you are logged into the Slack desktop app.'
235
+ return 'Extracted tokens are invalid. Make sure you are logged into Slack in the desktop app or a supported Chromium browser.'
236
+ }
237
+
238
+ export function getNoWorkspacesFoundMessage(): string {
239
+ return 'No workspaces found. Make sure you are logged into Slack in the desktop app or a supported Chromium browser.'
236
240
  }
237
241
 
238
242
  export const authCommand = new Command('auth')
239
243
  .description('Authentication commands')
240
244
  .addCommand(
241
245
  new Command('extract')
242
- .description('Extract tokens from Slack desktop app')
246
+ .description('Extract tokens from Slack desktop app or a supported Chromium browser')
243
247
  .option('--pretty', 'Pretty print JSON output')
244
248
  .option('--debug', 'Show debug output for troubleshooting')
245
249
  .option('--unsafely-show-secrets', 'Show full token and cookie values in debug output')
@@ -39,7 +39,7 @@ export class TeamsClient {
39
39
  const creds = await credManager.getTokenWithExpiry()
40
40
  if (!creds) {
41
41
  throw new TeamsError(
42
- 'No Teams credentials found. Make sure Microsoft Teams desktop app is installed and logged in.',
42
+ 'No Teams credentials found. Make sure Microsoft Teams is logged in via the desktop app or a supported Chromium browser.',
43
43
  'no_credentials',
44
44
  )
45
45
  }
@@ -1,5 +1,6 @@
1
1
  import { afterEach, beforeEach, expect, spyOn, test } from 'bun:test'
2
2
 
3
+ import { getNoTeamsTokenFoundMessage } from './auth'
3
4
  import { TeamsClient } from '../client'
4
5
  import { TeamsCredentialManager } from '../credential-manager'
5
6
  import { TeamsTokenExtractor } from '../token-extractor'
@@ -89,3 +90,7 @@ test('status: checks token expiry', async () => {
89
90
  const isExpired = await credManager.isTokenExpired()
90
91
  expect(isExpired).toBe(false)
91
92
  })
93
+
94
+ test('no-token message mentions desktop app and browser fallback', () => {
95
+ expect(getNoTeamsTokenFoundMessage()).toContain('desktop app or a supported Chromium browser')
96
+ })
@@ -45,7 +45,7 @@ export async function extractAction(options: { pretty?: boolean; debug?: boolean
45
45
  console.log(
46
46
  formatOutput(
47
47
  {
48
- error: 'No Teams token found. Make sure Microsoft Teams desktop app is installed and logged in.',
48
+ error: getNoTeamsTokenFoundMessage(),
49
49
  hint: 'Run with --token <token> to manually provide a token, or --debug for more info.',
50
50
  },
51
51
  options.pretty,
@@ -116,8 +116,8 @@ export async function extractAction(options: { pretty?: boolean; debug?: boolean
116
116
  {
117
117
  error: `Token validation failed: ${errorMessage}`,
118
118
  hint: is401
119
- ? 'Token expired. Open Microsoft Teams, send a message to refresh your session, then run "auth extract" again.'
120
- : 'Make sure Microsoft Teams desktop app is running and you are logged in.',
119
+ ? 'Token expired. Open Microsoft Teams in the desktop app or a supported Chromium browser, send a message to refresh your session, then run "auth extract" again.'
120
+ : 'Make sure Microsoft Teams is running and you are logged in via the desktop app or a supported Chromium browser.',
121
121
  },
122
122
  options.pretty,
123
123
  ),
@@ -130,7 +130,10 @@ export async function extractAction(options: { pretty?: boolean; debug?: boolean
130
130
  if (Object.keys(config.accounts).length === 0) {
131
131
  console.log(
132
132
  formatOutput(
133
- { error: 'All extracted tokens failed validation. Make sure Microsoft Teams is running and logged in.' },
133
+ {
134
+ error:
135
+ 'All extracted tokens failed validation. Make sure Microsoft Teams is running and you are logged in via the desktop app or a supported Chromium browser.',
136
+ },
134
137
  options.pretty,
135
138
  ),
136
139
  )
@@ -229,8 +232,8 @@ async function extractManualToken(token: string, options: { pretty?: boolean; de
229
232
  {
230
233
  error: `Token validation failed: ${errorMessage}`,
231
234
  hint: is401
232
- ? 'Token expired. Open Microsoft Teams, send a message to refresh your session, then run "auth extract" again.'
233
- : 'Make sure Microsoft Teams desktop app is running and you are logged in.',
235
+ ? 'Token expired. Open Microsoft Teams in the desktop app or a supported Chromium browser, send a message to refresh your session, then run "auth extract" again.'
236
+ : 'Make sure Microsoft Teams is running and you are logged in via the desktop app or a supported Chromium browser.',
234
237
  },
235
238
  options.pretty,
236
239
  ),
@@ -239,6 +242,10 @@ async function extractManualToken(token: string, options: { pretty?: boolean; de
239
242
  }
240
243
  }
241
244
 
245
+ export function getNoTeamsTokenFoundMessage(): string {
246
+ return 'No Teams token found. Make sure you are logged in to Microsoft Teams via the desktop app or a supported Chromium browser.'
247
+ }
248
+
242
249
  export async function logoutAction(options: { pretty?: boolean }): Promise<void> {
243
250
  try {
244
251
  const credManager = new TeamsCredentialManager()
@@ -361,7 +368,7 @@ export const authCommand = new Command('auth')
361
368
  .description('Authentication commands')
362
369
  .addCommand(
363
370
  new Command('extract')
364
- .description('Extract token from Microsoft Teams desktop app')
371
+ .description('Extract token from Microsoft Teams desktop app or a supported Chromium browser')
365
372
  .option('--pretty', 'Pretty print JSON output')
366
373
  .option('--debug', 'Show debug output for troubleshooting')
367
374
  .option('--token <token>', 'Manually provide a token (bypasses auto-extraction)')
@@ -438,6 +438,16 @@ export class WebexClient {
438
438
  return data.items
439
439
  }
440
440
 
441
+ async listMyMemberships(options?: { max?: number }): Promise<WebexMembership[]> {
442
+ const params = new URLSearchParams()
443
+ params.set('max', String(options?.max ?? 100))
444
+ const data = await this.request<{ items: WebexMembership[] }>(
445
+ 'GET',
446
+ `/memberships?${params}`,
447
+ )
448
+ return data.items
449
+ }
450
+
441
451
  async listMemberships(
442
452
  roomId: string,
443
453
  options?: { max?: number },