agent-messenger 2.1.0 → 2.3.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.
Files changed (217) hide show
  1. package/.claude-plugin/plugin.json +1 -1
  2. package/.env.template +35 -17
  3. package/README.md +7 -7
  4. package/bun.lock +31 -7
  5. package/dist/package.json +5 -3
  6. package/dist/src/platforms/channeltalk/commands/auth.d.ts.map +1 -1
  7. package/dist/src/platforms/channeltalk/commands/auth.js +35 -28
  8. package/dist/src/platforms/channeltalk/commands/auth.js.map +1 -1
  9. package/dist/src/platforms/channeltalk/ensure-auth.js +6 -6
  10. package/dist/src/platforms/channeltalk/ensure-auth.js.map +1 -1
  11. package/dist/src/platforms/channeltalk/token-extractor.d.ts +23 -1
  12. package/dist/src/platforms/channeltalk/token-extractor.d.ts.map +1 -1
  13. package/dist/src/platforms/channeltalk/token-extractor.js +299 -29
  14. package/dist/src/platforms/channeltalk/token-extractor.js.map +1 -1
  15. package/dist/src/platforms/discord/commands/auth.d.ts.map +1 -1
  16. package/dist/src/platforms/discord/commands/auth.js +57 -49
  17. package/dist/src/platforms/discord/commands/auth.js.map +1 -1
  18. package/dist/src/platforms/discord/ensure-auth.js +3 -3
  19. package/dist/src/platforms/discord/ensure-auth.js.map +1 -1
  20. package/dist/src/platforms/discord/token-extractor.d.ts +6 -1
  21. package/dist/src/platforms/discord/token-extractor.d.ts.map +1 -1
  22. package/dist/src/platforms/discord/token-extractor.js +167 -14
  23. package/dist/src/platforms/discord/token-extractor.js.map +1 -1
  24. package/dist/src/platforms/instagram/client.d.ts +2 -0
  25. package/dist/src/platforms/instagram/client.d.ts.map +1 -1
  26. package/dist/src/platforms/instagram/client.js +2 -2
  27. package/dist/src/platforms/instagram/client.js.map +1 -1
  28. package/dist/src/platforms/instagram/commands/auth.d.ts.map +1 -1
  29. package/dist/src/platforms/instagram/commands/auth.js +107 -14
  30. package/dist/src/platforms/instagram/commands/auth.js.map +1 -1
  31. package/dist/src/platforms/instagram/ensure-auth.d.ts.map +1 -1
  32. package/dist/src/platforms/instagram/ensure-auth.js +57 -11
  33. package/dist/src/platforms/instagram/ensure-auth.js.map +1 -1
  34. package/dist/src/platforms/instagram/index.d.ts +1 -0
  35. package/dist/src/platforms/instagram/index.d.ts.map +1 -1
  36. package/dist/src/platforms/instagram/index.js +1 -0
  37. package/dist/src/platforms/instagram/index.js.map +1 -1
  38. package/dist/src/platforms/instagram/token-extractor.d.ts +44 -0
  39. package/dist/src/platforms/instagram/token-extractor.d.ts.map +1 -0
  40. package/dist/src/platforms/instagram/token-extractor.js +407 -0
  41. package/dist/src/platforms/instagram/token-extractor.js.map +1 -0
  42. package/dist/src/platforms/kakaotalk/client.d.ts.map +1 -1
  43. package/dist/src/platforms/kakaotalk/client.js +2 -1
  44. package/dist/src/platforms/kakaotalk/client.js.map +1 -1
  45. package/dist/src/platforms/kakaotalk/commands/auth.d.ts.map +1 -1
  46. package/dist/src/platforms/kakaotalk/commands/auth.js +14 -13
  47. package/dist/src/platforms/kakaotalk/commands/auth.js.map +1 -1
  48. package/dist/src/platforms/kakaotalk/protocol/connection.d.ts.map +1 -1
  49. package/dist/src/platforms/kakaotalk/protocol/connection.js +2 -1
  50. package/dist/src/platforms/kakaotalk/protocol/connection.js.map +1 -1
  51. package/dist/src/platforms/line/client.d.ts.map +1 -1
  52. package/dist/src/platforms/line/client.js +36 -9
  53. package/dist/src/platforms/line/client.js.map +1 -1
  54. package/dist/src/platforms/line/commands/auth.d.ts.map +1 -1
  55. package/dist/src/platforms/line/commands/auth.js +6 -5
  56. package/dist/src/platforms/line/commands/auth.js.map +1 -1
  57. package/dist/src/platforms/slack/commands/auth.d.ts.map +1 -1
  58. package/dist/src/platforms/slack/commands/auth.js +11 -10
  59. package/dist/src/platforms/slack/commands/auth.js.map +1 -1
  60. package/dist/src/platforms/slack/token-extractor.d.ts +9 -0
  61. package/dist/src/platforms/slack/token-extractor.d.ts.map +1 -1
  62. package/dist/src/platforms/slack/token-extractor.js +300 -23
  63. package/dist/src/platforms/slack/token-extractor.js.map +1 -1
  64. package/dist/src/platforms/teams/commands/auth.d.ts.map +1 -1
  65. package/dist/src/platforms/teams/commands/auth.js +9 -8
  66. package/dist/src/platforms/teams/commands/auth.js.map +1 -1
  67. package/dist/src/platforms/teams/ensure-auth.d.ts.map +1 -1
  68. package/dist/src/platforms/teams/ensure-auth.js +2 -1
  69. package/dist/src/platforms/teams/ensure-auth.js.map +1 -1
  70. package/dist/src/platforms/teams/token-extractor.d.ts +5 -0
  71. package/dist/src/platforms/teams/token-extractor.d.ts.map +1 -1
  72. package/dist/src/platforms/teams/token-extractor.js +161 -29
  73. package/dist/src/platforms/teams/token-extractor.js.map +1 -1
  74. package/dist/src/platforms/telegram/client.d.ts.map +1 -1
  75. package/dist/src/platforms/telegram/client.js +25 -7
  76. package/dist/src/platforms/telegram/client.js.map +1 -1
  77. package/dist/src/platforms/telegram/commands/auth.d.ts.map +1 -1
  78. package/dist/src/platforms/telegram/commands/auth.js +6 -5
  79. package/dist/src/platforms/telegram/commands/auth.js.map +1 -1
  80. package/dist/src/platforms/webex/client.d.ts +12 -0
  81. package/dist/src/platforms/webex/client.d.ts.map +1 -1
  82. package/dist/src/platforms/webex/client.js +168 -1
  83. package/dist/src/platforms/webex/client.js.map +1 -1
  84. package/dist/src/platforms/webex/commands/auth.d.ts +4 -0
  85. package/dist/src/platforms/webex/commands/auth.d.ts.map +1 -1
  86. package/dist/src/platforms/webex/commands/auth.js +50 -4
  87. package/dist/src/platforms/webex/commands/auth.js.map +1 -1
  88. package/dist/src/platforms/webex/credential-manager.js +1 -1
  89. package/dist/src/platforms/webex/credential-manager.js.map +1 -1
  90. package/dist/src/platforms/webex/encryption.d.ts +10 -0
  91. package/dist/src/platforms/webex/encryption.d.ts.map +1 -0
  92. package/dist/src/platforms/webex/encryption.js +49 -0
  93. package/dist/src/platforms/webex/encryption.js.map +1 -0
  94. package/dist/src/platforms/webex/ensure-auth.d.ts.map +1 -1
  95. package/dist/src/platforms/webex/ensure-auth.js +25 -5
  96. package/dist/src/platforms/webex/ensure-auth.js.map +1 -1
  97. package/dist/src/platforms/webex/index.d.ts +2 -0
  98. package/dist/src/platforms/webex/index.d.ts.map +1 -1
  99. package/dist/src/platforms/webex/index.js +1 -0
  100. package/dist/src/platforms/webex/index.js.map +1 -1
  101. package/dist/src/platforms/webex/token-extractor.d.ts +29 -0
  102. package/dist/src/platforms/webex/token-extractor.d.ts.map +1 -0
  103. package/dist/src/platforms/webex/token-extractor.js +393 -0
  104. package/dist/src/platforms/webex/token-extractor.js.map +1 -0
  105. package/dist/src/platforms/webex/types.d.ts +8 -1
  106. package/dist/src/platforms/webex/types.d.ts.map +1 -1
  107. package/dist/src/platforms/webex/types.js +4 -1
  108. package/dist/src/platforms/webex/types.js.map +1 -1
  109. package/dist/src/platforms/whatsapp/client.d.ts.map +1 -1
  110. package/dist/src/platforms/whatsapp/client.js +6 -2
  111. package/dist/src/platforms/whatsapp/client.js.map +1 -1
  112. package/dist/src/shared/utils/derived-key-cache.d.ts +1 -1
  113. package/dist/src/shared/utils/derived-key-cache.d.ts.map +1 -1
  114. package/dist/src/shared/utils/error-handler.d.ts +1 -1
  115. package/dist/src/shared/utils/error-handler.d.ts.map +1 -1
  116. package/dist/src/shared/utils/error-handler.js +3 -2
  117. package/dist/src/shared/utils/error-handler.js.map +1 -1
  118. package/dist/src/shared/utils/stderr.d.ts +5 -0
  119. package/dist/src/shared/utils/stderr.d.ts.map +1 -0
  120. package/dist/src/shared/utils/stderr.js +18 -0
  121. package/dist/src/shared/utils/stderr.js.map +1 -0
  122. package/docs/content/docs/cli/channeltalk.mdx +7 -7
  123. package/docs/content/docs/cli/discord.mdx +3 -3
  124. package/docs/content/docs/cli/instagram.mdx +28 -6
  125. package/docs/content/docs/cli/slack.mdx +2 -2
  126. package/docs/content/docs/cli/teams.mdx +6 -4
  127. package/docs/content/docs/cli/webex.mdx +32 -11
  128. package/e2e/README.md +132 -8
  129. package/e2e/channeltalk.e2e.test.ts +2 -7
  130. package/e2e/channeltalkbot.e2e.test.ts +2 -6
  131. package/e2e/config.ts +172 -10
  132. package/e2e/helpers.ts +7 -0
  133. package/e2e/instagram.e2e.test.ts +97 -0
  134. package/e2e/kakaotalk.e2e.test.ts +74 -0
  135. package/e2e/line.e2e.test.ts +92 -0
  136. package/e2e/teams.e2e.test.ts +46 -1
  137. package/e2e/telegram.e2e.test.ts +84 -0
  138. package/e2e/webex.e2e.test.ts +190 -0
  139. package/e2e/whatsapp.e2e.test.ts +90 -0
  140. package/e2e/whatsappbot.e2e.test.ts +78 -0
  141. package/package.json +5 -3
  142. package/skills/agent-channeltalk/SKILL.md +9 -9
  143. package/skills/agent-channeltalk/references/authentication.md +21 -18
  144. package/skills/agent-channeltalkbot/SKILL.md +1 -1
  145. package/skills/agent-discord/SKILL.md +5 -5
  146. package/skills/agent-discord/references/authentication.md +8 -8
  147. package/skills/agent-discordbot/SKILL.md +1 -1
  148. package/skills/agent-instagram/SKILL.md +51 -9
  149. package/skills/agent-instagram/references/authentication.md +35 -3
  150. package/skills/agent-kakaotalk/SKILL.md +1 -1
  151. package/skills/agent-line/SKILL.md +1 -1
  152. package/skills/agent-slack/SKILL.md +5 -5
  153. package/skills/agent-slack/references/authentication.md +8 -8
  154. package/skills/agent-slackbot/SKILL.md +1 -1
  155. package/skills/agent-teams/SKILL.md +6 -6
  156. package/skills/agent-teams/references/authentication.md +8 -8
  157. package/skills/agent-telegram/SKILL.md +1 -1
  158. package/skills/agent-webex/SKILL.md +35 -15
  159. package/skills/agent-webex/references/authentication.md +63 -9
  160. package/skills/agent-webex/references/common-patterns.md +6 -3
  161. package/skills/agent-whatsapp/SKILL.md +1 -1
  162. package/skills/agent-whatsappbot/SKILL.md +1 -1
  163. package/src/platforms/channeltalk/commands/auth.test.ts +5 -5
  164. package/src/platforms/channeltalk/commands/auth.ts +38 -32
  165. package/src/platforms/channeltalk/ensure-auth.test.ts +6 -6
  166. package/src/platforms/channeltalk/ensure-auth.ts +6 -6
  167. package/src/platforms/channeltalk/token-extractor.test.ts +182 -15
  168. package/src/platforms/channeltalk/token-extractor.ts +344 -30
  169. package/src/platforms/discord/commands/auth.test.ts +3 -3
  170. package/src/platforms/discord/commands/auth.ts +58 -54
  171. package/src/platforms/discord/ensure-auth.test.ts +3 -3
  172. package/src/platforms/discord/ensure-auth.ts +3 -3
  173. package/src/platforms/discord/token-extractor.test.ts +199 -27
  174. package/src/platforms/discord/token-extractor.ts +190 -17
  175. package/src/platforms/instagram/client.ts +2 -2
  176. package/src/platforms/instagram/commands/auth.ts +133 -14
  177. package/src/platforms/instagram/ensure-auth.ts +63 -12
  178. package/src/platforms/instagram/index.ts +1 -0
  179. package/src/platforms/instagram/token-extractor.test.ts +424 -0
  180. package/src/platforms/instagram/token-extractor.ts +478 -0
  181. package/src/platforms/kakaotalk/client.ts +3 -1
  182. package/src/platforms/kakaotalk/commands/auth.ts +14 -13
  183. package/src/platforms/kakaotalk/protocol/connection.ts +3 -1
  184. package/src/platforms/line/client.ts +39 -14
  185. package/src/platforms/line/commands/auth.ts +7 -6
  186. package/src/platforms/slack/cli.test.ts +6 -5
  187. package/src/platforms/slack/commands/auth.test.ts +11 -7
  188. package/src/platforms/slack/commands/auth.ts +11 -10
  189. package/src/platforms/slack/token-extractor.test.ts +98 -1
  190. package/src/platforms/slack/token-extractor.ts +338 -26
  191. package/src/platforms/teams/commands/auth.ts +9 -8
  192. package/src/platforms/teams/ensure-auth.ts +3 -1
  193. package/src/platforms/teams/token-extractor.test.ts +136 -17
  194. package/src/platforms/teams/token-extractor.ts +182 -31
  195. package/src/platforms/telegram/client.test.ts +134 -0
  196. package/src/platforms/telegram/client.ts +27 -6
  197. package/src/platforms/telegram/commands/auth.ts +6 -5
  198. package/src/platforms/webex/client.test.ts +314 -0
  199. package/src/platforms/webex/client.ts +231 -1
  200. package/src/platforms/webex/commands/auth.ts +71 -4
  201. package/src/platforms/webex/commands/member.test.ts +10 -1
  202. package/src/platforms/webex/commands/message.test.ts +9 -5
  203. package/src/platforms/webex/commands/snapshot.test.ts +13 -4
  204. package/src/platforms/webex/commands/space.test.ts +12 -2
  205. package/src/platforms/webex/credential-manager.ts +1 -1
  206. package/src/platforms/webex/encryption.ts +53 -0
  207. package/src/platforms/webex/ensure-auth.test.ts +4 -0
  208. package/src/platforms/webex/ensure-auth.ts +27 -4
  209. package/src/platforms/webex/index.ts +2 -0
  210. package/src/platforms/webex/token-extractor.test.ts +327 -0
  211. package/src/platforms/webex/token-extractor.ts +460 -0
  212. package/src/platforms/webex/types.ts +8 -2
  213. package/src/platforms/webex/typings/node-jose.d.ts +27 -0
  214. package/src/platforms/whatsapp/client.ts +11 -7
  215. package/src/shared/utils/derived-key-cache.ts +1 -1
  216. package/src/shared/utils/error-handler.ts +4 -2
  217. package/src/shared/utils/stderr.ts +22 -0
@@ -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.1.0
4
+ version: 2.3.0
5
5
  allowed-tools: Bash(agent-webex:*)
6
6
  metadata:
7
7
  openclaw:
@@ -16,12 +16,15 @@ metadata:
16
16
 
17
17
  # Agent Webex
18
18
 
19
- A TypeScript CLI tool that enables AI agents and humans to interact with Cisco Webex through a simple command interface. Uses OAuth Device Grant flow, zero configuration required.
19
+ A TypeScript CLI tool that enables AI agents and humans to interact with Cisco Webex through a simple command interface. Supports browser token extraction (zero-config, sends as you) and OAuth Device Grant flow.
20
20
 
21
21
  ## Quick Start
22
22
 
23
23
  ```bash
24
- # Log in (opens browser automatically)
24
+ # Extract token from browser (Chrome, Edge, Arc, Brave) — messages appear as you
25
+ agent-webex auth extract
26
+
27
+ # Or: Log in via OAuth Device Grant (opens browser, messages show "via agent-messenger")
25
28
  agent-webex auth login
26
29
 
27
30
  # Get workspace snapshot
@@ -36,10 +39,35 @@ agent-webex space list
36
39
 
37
40
  ## Authentication
38
41
 
39
- Webex uses OAuth Device Grant flow with built-in Integration credentials. No tokens to copy, no developer portal setup needed.
42
+ Webex supports two authentication methods:
43
+
44
+ 1. **Browser token extraction** (recommended): Extracts your first-party token from a Chromium browser where you're logged into web.webex.com. Messages appear as you — no "via" label.
45
+ 2. **OAuth Device Grant**: Opens a browser for you to authorize. Messages show "via agent-messenger" label.
46
+
47
+ ### Browser Token Extraction (Recommended)
48
+
49
+ `agent-webex auth extract` reads your Webex session token from Chrome, Edge, Arc, or Brave. You must be logged into web.webex.com in one of these browsers. No configuration needed.
50
+
51
+ ```bash
52
+ # Extract token from browser — messages appear as you
53
+ agent-webex auth extract
54
+
55
+ # With debug output
56
+ agent-webex auth extract --debug
57
+ ```
58
+
59
+ **Supported browsers**: Chrome, Chrome Canary, Edge, Arc, Brave, Vivaldi, Chromium
60
+
61
+ **How it works**: The Webex web client stores its authentication token in the browser's localStorage. This CLI reads it directly from the browser's LevelDB files — no browser automation, no password prompts. The token is stored locally in `~/.config/agent-messenger/`.
62
+
63
+ **When to re-extract**: Browser tokens expire. When your token expires, re-run `agent-webex auth extract` or let auto-extraction handle it (the CLI attempts extraction automatically on each run).
64
+
65
+ ### OAuth Device Grant (Fallback)
40
66
 
41
67
  `agent-webex auth login` starts the Device Grant flow: it displays a verification URL and user code, then opens the browser. You enter the code at the verification page and approve access. The CLI polls for the token automatically. Access and refresh tokens are stored locally, and the access token auto-refreshes via the refresh token.
42
68
 
69
+ Note: Messages sent via OAuth Device Grant show "via agent-messenger" because the token is associated with a third-party Webex Integration.
70
+
43
71
  Optionally, pass `--token <bot-token>` for bot token auth. Or pass `--client-id <id> --client-secret <secret>` to use your own Webex Integration credentials instead of the built-in ones.
44
72
 
45
73
  Env vars `AGENT_WEBEX_CLIENT_ID` / `AGENT_WEBEX_CLIENT_SECRET` can also override the built-in credentials.
@@ -61,22 +89,14 @@ agent-webex auth status
61
89
  agent-webex auth logout
62
90
  ```
63
91
 
64
- ### How Login Works
65
-
66
- 1. Run `agent-webex auth login`
67
- 2. CLI requests a device code from Webex
68
- 3. Browser opens to Webex verification page
69
- 4. Enter the displayed code and sign in
70
- 5. CLI automatically detects approval and stores tokens
71
- 6. Access token auto-refreshes via refresh token
72
-
73
92
  ### Token Types
74
93
 
75
- - **OAuth Device Grant (default)**: Zero-config login. Access token auto-refreshes. Built-in Integration credentials used unless overridden.
94
+ - **Extracted (browser)**: First-party token from web.webex.com. Messages appear as you. Requires re-extraction when expired.
95
+ - **OAuth Device Grant**: Zero-config login. Access token auto-refreshes. Messages show "via agent-messenger".
76
96
  - **Bot Token**: Pass via `--token` flag. Never expires. Best for CI/CD.
77
97
  - **Custom Integration**: Pass `--client-id` + `--client-secret` or set env vars for your own Webex Integration.
78
98
 
79
- **IMPORTANT**: NEVER guide the user to open a web browser, use DevTools, or manually copy tokens from a browser's network inspector. Always use `agent-webex auth login` for interactive authentication.
99
+ **IMPORTANT**: NEVER guide the user to open a web browser, use DevTools, or manually copy tokens from a browser's network inspector. Always use `agent-webex auth extract` or `agent-webex auth login` for authentication.
80
100
 
81
101
  For detailed token management, see [references/authentication.md](references/authentication.md).
82
102
 
@@ -2,17 +2,41 @@
2
2
 
3
3
  ## Overview
4
4
 
5
- agent-webex supports three authentication methods against the Webex REST API (`https://webexapis.com/v1`):
5
+ agent-webex supports four authentication methods against the Webex REST API (`https://webexapis.com/v1`):
6
6
 
7
- 1. **OAuth Device Grant** (default): Zero-config. Run `auth login`, approve in browser, done. Tokens refresh automatically.
8
- 2. **Bot Token**: Pass via `auth login --token`. Never expires. Best for CI/CD.
9
- 3. **Personal Access Token (PAT)**: Pass via `auth login --token`. Expires in 12 hours. For quick testing.
7
+ 1. **Browser Token Extraction**: Extracts your first-party token and cached encryption keys from a Chromium browser where you're logged into web.webex.com. Supports all operations including encrypted messaging via the internal API. Zero-config.
8
+ 2. **OAuth Device Grant** (recommended for messaging): Zero-config. Run `auth login`, approve in browser, done. Tokens refresh automatically. Supports all operations including sending messages (shows "via agent-messenger").
9
+ 3. **Bot Token**: Pass via `auth login --token`. Never expires. Best for CI/CD.
10
+ 4. **Personal Access Token (PAT)**: Pass via `auth login --token`. Expires in 12 hours. For quick testing.
10
11
 
11
12
  ## Token Types
12
13
 
13
- ### OAuth Device Grant (default)
14
+ ### Browser Token Extraction
14
15
 
15
- The primary authentication method. No credentials to copy, no developer portal setup required.
16
+ Extracts your first-party Webex session token from a Chromium-based browser where you're logged into web.webex.com. Supports full messaging with end-to-end encryption. The extracted token uses Webex's internal conversation API for sending messages. Encryption keys are also extracted from the browser's cached KMS key store, enabling client-side JWE encryption so messages appear as encrypted in the Webex client.
17
+
18
+ - **How it works**: Run `agent-webex auth extract`. The CLI scans Chromium browser profiles for Webex localStorage data (LevelDB files). It finds the `webex-storage` key containing `Credentials.@.supertoken` and extracts the access token. It also extracts `userId` from the Device namespace and cached KMS encryption keys from the unbounded storage — these keys enable end-to-end encrypted messaging via the internal API. No browser automation, no password prompts.
19
+ - **Supported browsers**: Chrome, Chrome Canary, Edge, Arc, Brave, Vivaldi, Chromium
20
+ - **Token lifetime**: Depends on Webex session policy (typically hours to days). Re-extract when expired.
21
+ - **Auto-extraction**: The CLI attempts browser extraction automatically when no valid token is stored, so you often don't need to run `auth extract` manually.
22
+ - **End-to-end encryption**: When encryption keys are found in the browser's cache, messages are encrypted client-side (JWE with AES-256-GCM) before sending via the internal conversation API. This ensures messages appear as encrypted in the Webex client. If no keys are found (e.g., the conversation hasn't been opened in the browser), messages fall back to plaintext.
23
+ - **Best for**: Interactive use, sending messages as yourself without the "via" label
24
+
25
+ ```bash
26
+ # Extract token from browser
27
+ agent-webex auth extract
28
+
29
+ # With debug output
30
+ agent-webex auth extract --debug
31
+ ```
32
+
33
+ **Requirements**: You must be logged into web.webex.com in a supported Chromium browser. The browser does not need to be running — the CLI reads directly from on-disk LevelDB files.
34
+
35
+ **Limitations**: Direct messages (`message dm`) require an existing conversation with the recipient. The extracted token cannot create new 1:1 conversations — start one from the Webex app first, then use the CLI.
36
+
37
+ ### OAuth Device Grant
38
+
39
+ The fallback authentication method when browser extraction is unavailable. No credentials to copy, no developer portal setup required.
16
40
 
17
41
  - **How it works**: Run `agent-webex auth login`. The CLI requests a device code from Webex, opens your browser, and waits for you to approve. Once approved, access and refresh tokens are stored automatically.
18
42
  - **Access token lifetime**: 14 days
@@ -56,7 +80,10 @@ agent-webex auth login --token "YOUR_PAT_HERE"
56
80
  ## Logging In
57
81
 
58
82
  ```bash
59
- # Device Grant (default, zero-config)
83
+ # Browser extraction (recommended — messages appear as you)
84
+ agent-webex auth extract
85
+
86
+ # Device Grant (fallback — messages show "via agent-messenger")
60
87
  agent-webex auth login
61
88
 
62
89
  # With custom Integration credentials
@@ -69,6 +96,8 @@ agent-webex auth login --token <bot-token>
69
96
  agent-webex auth login --token <pat>
70
97
  ```
71
98
 
99
+ When using `auth extract`, the CLI reads your Webex session from the browser's LevelDB storage. No prompts, no browser automation.
100
+
72
101
  When using `--token`, the CLI validates the token against the Webex API before saving. If validation fails, you'll see an error and the token won't be stored.
73
102
 
74
103
  When using Device Grant, the CLI prints a URL and code, opens your browser, then polls until you approve (or the code expires).
@@ -118,6 +147,17 @@ This removes the stored credentials from disk.
118
147
 
119
148
  ### Format
120
149
 
150
+ Extracted credentials (from `auth extract`):
151
+
152
+ ```json
153
+ {
154
+ "accessToken": "...",
155
+ "refreshToken": "...",
156
+ "expiresAt": 1234567890,
157
+ "tokenType": "extracted"
158
+ }
159
+ ```
160
+
121
161
  OAuth credentials (from Device Grant):
122
162
 
123
163
  ```json
@@ -155,6 +195,19 @@ Manual credentials (from `--token`):
155
195
 
156
196
  ## Token Lifecycle
157
197
 
198
+ ### Browser Token Extraction
199
+
200
+ ```
201
+ auth extract -> Scan browser LevelDB -> Extract supertoken -> Access token (session-based)
202
+ |
203
+ Token expires
204
+ |
205
+ Re-run "auth extract"
206
+ (or auto-extraction on next CLI run)
207
+ ```
208
+
209
+ Browser-extracted tokens have no refresh mechanism — when they expire, re-extract from the browser (where your active session keeps them fresh). The CLI attempts auto-extraction on each run, so manual re-extraction is rarely needed.
210
+
158
211
  ### OAuth Device Grant
159
212
 
160
213
  ```
@@ -274,8 +327,9 @@ With a valid token, agent-webex has the same permissions as the token owner:
274
327
 
275
328
  ### Best Practices
276
329
 
277
- 1. **Use Device Grant for interactive work**: Zero-config, auto-refreshing, scoped access
278
- 2. **Use bot tokens for automation**: They don't expire and have scoped access
330
+ 1. **Use browser extraction for interactive work**: Zero-config, messages appear as you, no "via" label
331
+ 2. **Use Device Grant as fallback**: When browser extraction isn't available (no Chromium browser, headless server)
332
+ 3. **Use bot tokens for automation**: They don't expire and have scoped access
279
333
  3. **Protect credentials.json**: Never commit to version control
280
334
  4. **Rotate PATs regularly**: Don't reuse expired tokens. Generate fresh ones
281
335
  5. **Revoke compromised tokens**: Regenerate bot tokens at https://developer.webex.com/my-apps if compromised
@@ -8,14 +8,17 @@ This guide covers typical workflows for AI agents interacting with Cisco Webex u
8
8
 
9
9
  ## Auth Patterns
10
10
 
11
- ### Pattern 1: Log In
11
+ ### Pattern 1: Authenticate
12
12
 
13
13
  **Use case**: First-time setup or token renewal
14
14
 
15
15
  ```bash
16
16
  #!/bin/bash
17
17
 
18
- # Default: Device Grant (zero-config, opens browser)
18
+ # Recommended: Browser extraction (zero-config, sends as you, no "via" label)
19
+ agent-webex auth extract
20
+
21
+ # Fallback: Device Grant (zero-config, opens browser, shows "via agent-messenger")
19
22
  agent-webex auth login
20
23
 
21
24
  # With a bot token (never expires, for CI/CD)
@@ -25,7 +28,7 @@ agent-webex auth login --token "YOUR_BOT_TOKEN_HERE"
25
28
  agent-webex auth login --token "YOUR_PAT_HERE"
26
29
  ```
27
30
 
28
- **When to use**: Before any other command, if not already authenticated.
31
+ **When to use**: Before any other command, if not already authenticated. Browser extraction is preferred — it auto-runs when no valid token is stored. It also extracts cached KMS encryption keys from the browser, enabling end-to-end encrypted messaging via the internal API.
29
32
 
30
33
  ### Pattern 2: Check Auth Status
31
34
 
@@ -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.1.0
4
+ version: 2.3.0
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.1.0
4
+ version: 2.3.0
5
5
  allowed-tools: Bash(agent-whatsappbot:*)
6
6
  metadata:
7
7
  openclaw:
@@ -19,8 +19,8 @@ const mockListChannels = mock(() =>
19
19
  { id: 'ws-2', name: 'Workspace 2' },
20
20
  ]),
21
21
  )
22
- const mockExtract = mock<() => Promise<{ accountCookie: string; sessionCookie: string } | null>>(() =>
23
- Promise.resolve({ accountCookie: 'fresh-account', sessionCookie: 'fresh-session' }),
22
+ const mockExtract = mock(() =>
23
+ Promise.resolve([{ accountCookie: 'fresh-account', sessionCookie: 'fresh-session' }]),
24
24
  )
25
25
 
26
26
  import {
@@ -113,7 +113,7 @@ describe('channel auth commands', () => {
113
113
  { id: 'ws-2', name: 'Workspace 2' },
114
114
  ]),
115
115
  )
116
- mockExtract.mockImplementation(() => Promise.resolve({ accountCookie: 'fresh-account', sessionCookie: 'fresh-session' }))
116
+ mockExtract.mockImplementation(() => Promise.resolve([{ accountCookie: 'fresh-account', sessionCookie: 'fresh-session' }]))
117
117
  })
118
118
 
119
119
  describe('extractAction', () => {
@@ -177,7 +177,7 @@ describe('channel auth commands', () => {
177
177
  })
178
178
 
179
179
  test('returns error when token extraction fails', async () => {
180
- mockExtract.mockImplementation(() => Promise.resolve(null))
180
+ mockExtract.mockImplementation(() => Promise.resolve([]))
181
181
 
182
182
  const result = await extractAction()
183
183
 
@@ -192,7 +192,7 @@ describe('channel auth commands', () => {
192
192
  const result = await extractAction()
193
193
 
194
194
  expect(result).toEqual({
195
- error: 'No workspaces found for this account.',
195
+ error: 'No valid credentials found. Make sure Channel Talk desktop app or browser is logged in.',
196
196
  })
197
197
  })
198
198
  })
@@ -82,45 +82,51 @@ export async function extractAction(options: ActionOptions = {}): Promise<Extrac
82
82
  const extractor = createTokenExtractor()
83
83
  const extracted = await extractor.extract()
84
84
 
85
- if (!extracted) {
85
+ if (extracted.length === 0) {
86
86
  return {
87
87
  error: 'No credentials. Make sure Channel Talk desktop app is installed and logged in.',
88
88
  }
89
89
  }
90
90
 
91
- const client = await createChannelClient(extracted.accountCookie, extracted.sessionCookie)
92
- const account = await client.getAccount()
93
- const channels = await client.listChannels()
94
-
95
- if (channels.length === 0) {
96
- return { error: 'No workspaces found for this account.' }
97
- }
98
-
99
- const previousCurrent = await credManager.getCredentials()
100
-
101
- for (const channel of channels) {
102
- await credManager.setCredentials({
103
- workspace_id: channel.id,
104
- workspace_name: channel.name,
105
- account_id: account.id,
106
- account_name: account.name,
107
- account_cookie: extracted.accountCookie,
108
- session_cookie: extracted.sessionCookie,
109
- })
91
+ for (const cookies of extracted) {
92
+ try {
93
+ const client = await createChannelClient(cookies.accountCookie, cookies.sessionCookie)
94
+ const account = await client.getAccount()
95
+ const channels = await client.listChannels()
96
+
97
+ if (channels.length === 0) continue
98
+
99
+ const previousCurrent = await credManager.getCredentials()
100
+
101
+ for (const channel of channels) {
102
+ await credManager.setCredentials({
103
+ workspace_id: channel.id,
104
+ workspace_name: channel.name,
105
+ account_id: account.id,
106
+ account_name: account.name,
107
+ account_cookie: cookies.accountCookie,
108
+ session_cookie: cookies.sessionCookie,
109
+ })
110
+ }
111
+
112
+ const previousStillExists = previousCurrent && channels.some((ch) => ch.id === previousCurrent.workspace_id)
113
+ const currentId = previousStillExists ? previousCurrent.workspace_id : channels[0].id
114
+ await credManager.setCurrent(currentId)
115
+
116
+ return {
117
+ success: true,
118
+ workspaces: channels.map((ch) => ({
119
+ workspace_id: ch.id,
120
+ workspace_name: ch.name,
121
+ })),
122
+ current_workspace_id: currentId,
123
+ }
124
+ } catch {
125
+ continue
126
+ }
110
127
  }
111
128
 
112
- const previousStillExists = previousCurrent && channels.some((ch) => ch.id === previousCurrent.workspace_id)
113
- const currentId = previousStillExists ? previousCurrent.workspace_id : channels[0].id
114
- await credManager.setCurrent(currentId)
115
-
116
- return {
117
- success: true,
118
- workspaces: channels.map((ch) => ({
119
- workspace_id: ch.id,
120
- workspace_name: ch.name,
121
- })),
122
- current_workspace_id: currentId,
123
- }
129
+ return { error: 'No valid credentials found. Make sure Channel Talk desktop app or browser is logged in.' }
124
130
  } catch (error: unknown) {
125
131
  return { error: (error as Error).message }
126
132
  }
@@ -17,7 +17,7 @@ const mockGetCredentials = mock<() => Promise<
17
17
  >>(() => Promise.resolve(null))
18
18
  const mockSetCredentials = mock(() => Promise.resolve())
19
19
  const mockSetCurrent = mock(() => Promise.resolve(true))
20
- const mockExtract = mock(() => Promise.resolve(null))
20
+ const mockExtract = mock(() => Promise.resolve([]))
21
21
  const mockGetAccount = mock(() => Promise.resolve({ id: 'acct-1', name: 'Alice' }))
22
22
  const mockListChannels = mock(() => Promise.resolve([{ id: 'ws-1', name: 'Workspace 1' }]))
23
23
 
@@ -58,17 +58,17 @@ describe('ensureChannelAuth', () => {
58
58
  mockGetCredentials.mockImplementation(() => Promise.resolve(null))
59
59
  mockSetCredentials.mockImplementation(() => Promise.resolve())
60
60
  mockSetCurrent.mockImplementation(() => Promise.resolve(true))
61
- mockExtract.mockImplementation(() => Promise.resolve(null))
61
+ mockExtract.mockImplementation(() => Promise.resolve([]))
62
62
  mockGetAccount.mockImplementation(() => Promise.resolve({ id: 'acct-1', name: 'Alice' }))
63
63
  mockListChannels.mockImplementation(() => Promise.resolve([{ id: 'ws-1', name: 'Workspace 1' }]))
64
64
  })
65
65
 
66
66
  test('extracts and saves workspaces when no credentials exist', async () => {
67
67
  mockExtract.mockImplementation(() =>
68
- Promise.resolve({
68
+ Promise.resolve([{
69
69
  accountCookie: 'account-cookie',
70
70
  sessionCookie: 'session-cookie',
71
- }),
71
+ }]),
72
72
  )
73
73
  mockListChannels.mockImplementation(() =>
74
74
  Promise.resolve([
@@ -128,10 +128,10 @@ describe('ensureChannelAuth', () => {
128
128
  )
129
129
  mockGetAccount.mockImplementationOnce(() => Promise.reject(new Error('Unauthorized')))
130
130
  mockExtract.mockImplementation(() =>
131
- Promise.resolve({
131
+ Promise.resolve([{
132
132
  accountCookie: 'fresh-account',
133
133
  sessionCookie: 'fresh-session',
134
- }),
134
+ }]),
135
135
  )
136
136
 
137
137
  await ensureChannelAuth()
@@ -58,11 +58,11 @@ export async function ensureChannelAuth(): Promise<void> {
58
58
 
59
59
  const extractor = createTokenExtractor()
60
60
  const extracted = await extractor.extract()
61
- if (!extracted) {
61
+ if (extracted.length === 0) {
62
62
  return
63
63
  }
64
64
 
65
- const client = await createChannelClient(extracted.accountCookie, extracted.sessionCookie)
65
+ const client = await createChannelClient(extracted[0].accountCookie, extracted[0].sessionCookie)
66
66
  const account = await client.getAccount()
67
67
  const channels = await client.listChannels()
68
68
  if (channels.length === 0) {
@@ -76,8 +76,8 @@ export async function ensureChannelAuth(): Promise<void> {
76
76
  workspace_name: currentChannel.name,
77
77
  account_id: account.id,
78
78
  account_name: account.name,
79
- account_cookie: extracted.accountCookie,
80
- session_cookie: extracted.sessionCookie,
79
+ account_cookie: extracted[0].accountCookie,
80
+ session_cookie: extracted[0].sessionCookie,
81
81
  })
82
82
 
83
83
  for (const channel of otherChannels) {
@@ -86,8 +86,8 @@ export async function ensureChannelAuth(): Promise<void> {
86
86
  workspace_name: channel.name,
87
87
  account_id: account.id,
88
88
  account_name: account.name,
89
- account_cookie: extracted.accountCookie,
90
- session_cookie: extracted.sessionCookie,
89
+ account_cookie: extracted[0].accountCookie,
90
+ session_cookie: extracted[0].sessionCookie,
91
91
  })
92
92
  }
93
93