agent-messenger 2.0.0 → 2.2.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 (272) hide show
  1. package/.claude-plugin/marketplace.json +14 -1
  2. package/.claude-plugin/plugin.json +4 -2
  3. package/.env.template +35 -17
  4. package/README.md +37 -33
  5. package/bun.lock +6 -6
  6. package/dist/package.json +11 -3
  7. package/dist/src/cli.d.ts.map +1 -1
  8. package/dist/src/cli.js +3 -0
  9. package/dist/src/cli.js.map +1 -1
  10. package/dist/src/platforms/channeltalk/commands/auth.d.ts.map +1 -1
  11. package/dist/src/platforms/channeltalk/commands/auth.js +35 -28
  12. package/dist/src/platforms/channeltalk/commands/auth.js.map +1 -1
  13. package/dist/src/platforms/channeltalk/ensure-auth.js +6 -6
  14. package/dist/src/platforms/channeltalk/ensure-auth.js.map +1 -1
  15. package/dist/src/platforms/channeltalk/token-extractor.d.ts +23 -1
  16. package/dist/src/platforms/channeltalk/token-extractor.d.ts.map +1 -1
  17. package/dist/src/platforms/channeltalk/token-extractor.js +299 -29
  18. package/dist/src/platforms/channeltalk/token-extractor.js.map +1 -1
  19. package/dist/src/platforms/discord/commands/auth.d.ts.map +1 -1
  20. package/dist/src/platforms/discord/commands/auth.js +57 -49
  21. package/dist/src/platforms/discord/commands/auth.js.map +1 -1
  22. package/dist/src/platforms/discord/ensure-auth.js +3 -3
  23. package/dist/src/platforms/discord/ensure-auth.js.map +1 -1
  24. package/dist/src/platforms/discord/token-extractor.d.ts +6 -1
  25. package/dist/src/platforms/discord/token-extractor.d.ts.map +1 -1
  26. package/dist/src/platforms/discord/token-extractor.js +167 -14
  27. package/dist/src/platforms/discord/token-extractor.js.map +1 -1
  28. package/dist/src/platforms/instagram/client.d.ts +2 -0
  29. package/dist/src/platforms/instagram/client.d.ts.map +1 -1
  30. package/dist/src/platforms/instagram/client.js +2 -2
  31. package/dist/src/platforms/instagram/client.js.map +1 -1
  32. package/dist/src/platforms/instagram/commands/auth.d.ts.map +1 -1
  33. package/dist/src/platforms/instagram/commands/auth.js +107 -14
  34. package/dist/src/platforms/instagram/commands/auth.js.map +1 -1
  35. package/dist/src/platforms/instagram/ensure-auth.d.ts.map +1 -1
  36. package/dist/src/platforms/instagram/ensure-auth.js +57 -11
  37. package/dist/src/platforms/instagram/ensure-auth.js.map +1 -1
  38. package/dist/src/platforms/instagram/index.d.ts +1 -0
  39. package/dist/src/platforms/instagram/index.d.ts.map +1 -1
  40. package/dist/src/platforms/instagram/index.js +1 -0
  41. package/dist/src/platforms/instagram/index.js.map +1 -1
  42. package/dist/src/platforms/instagram/token-extractor.d.ts +44 -0
  43. package/dist/src/platforms/instagram/token-extractor.d.ts.map +1 -0
  44. package/dist/src/platforms/instagram/token-extractor.js +407 -0
  45. package/dist/src/platforms/instagram/token-extractor.js.map +1 -0
  46. package/dist/src/platforms/kakaotalk/client.d.ts.map +1 -1
  47. package/dist/src/platforms/kakaotalk/client.js +2 -1
  48. package/dist/src/platforms/kakaotalk/client.js.map +1 -1
  49. package/dist/src/platforms/kakaotalk/commands/auth.d.ts.map +1 -1
  50. package/dist/src/platforms/kakaotalk/commands/auth.js +14 -13
  51. package/dist/src/platforms/kakaotalk/commands/auth.js.map +1 -1
  52. package/dist/src/platforms/kakaotalk/protocol/connection.d.ts.map +1 -1
  53. package/dist/src/platforms/kakaotalk/protocol/connection.js +2 -1
  54. package/dist/src/platforms/kakaotalk/protocol/connection.js.map +1 -1
  55. package/dist/src/platforms/line/commands/auth.d.ts.map +1 -1
  56. package/dist/src/platforms/line/commands/auth.js +6 -5
  57. package/dist/src/platforms/line/commands/auth.js.map +1 -1
  58. package/dist/src/platforms/slack/commands/auth.d.ts.map +1 -1
  59. package/dist/src/platforms/slack/commands/auth.js +11 -10
  60. package/dist/src/platforms/slack/commands/auth.js.map +1 -1
  61. package/dist/src/platforms/slack/token-extractor.d.ts +9 -0
  62. package/dist/src/platforms/slack/token-extractor.d.ts.map +1 -1
  63. package/dist/src/platforms/slack/token-extractor.js +300 -23
  64. package/dist/src/platforms/slack/token-extractor.js.map +1 -1
  65. package/dist/src/platforms/teams/commands/auth.d.ts.map +1 -1
  66. package/dist/src/platforms/teams/commands/auth.js +9 -8
  67. package/dist/src/platforms/teams/commands/auth.js.map +1 -1
  68. package/dist/src/platforms/teams/ensure-auth.d.ts.map +1 -1
  69. package/dist/src/platforms/teams/ensure-auth.js +2 -1
  70. package/dist/src/platforms/teams/ensure-auth.js.map +1 -1
  71. package/dist/src/platforms/teams/token-extractor.d.ts +5 -0
  72. package/dist/src/platforms/teams/token-extractor.d.ts.map +1 -1
  73. package/dist/src/platforms/teams/token-extractor.js +161 -29
  74. package/dist/src/platforms/teams/token-extractor.js.map +1 -1
  75. package/dist/src/platforms/telegram/client.d.ts.map +1 -1
  76. package/dist/src/platforms/telegram/client.js +25 -7
  77. package/dist/src/platforms/telegram/client.js.map +1 -1
  78. package/dist/src/platforms/telegram/commands/auth.d.ts.map +1 -1
  79. package/dist/src/platforms/telegram/commands/auth.js +6 -5
  80. package/dist/src/platforms/telegram/commands/auth.js.map +1 -1
  81. package/dist/src/platforms/webex/app-config.d.ts +7 -0
  82. package/dist/src/platforms/webex/app-config.d.ts.map +1 -0
  83. package/dist/src/platforms/webex/app-config.js +20 -0
  84. package/dist/src/platforms/webex/app-config.js.map +1 -0
  85. package/dist/src/platforms/webex/cli.d.ts +5 -0
  86. package/dist/src/platforms/webex/cli.d.ts.map +1 -0
  87. package/dist/src/platforms/webex/cli.js +32 -0
  88. package/dist/src/platforms/webex/cli.js.map +1 -0
  89. package/dist/src/platforms/webex/client.d.ts +55 -0
  90. package/dist/src/platforms/webex/client.d.ts.map +1 -0
  91. package/dist/src/platforms/webex/client.js +299 -0
  92. package/dist/src/platforms/webex/client.js.map +1 -0
  93. package/dist/src/platforms/webex/commands/auth.d.ts +19 -0
  94. package/dist/src/platforms/webex/commands/auth.d.ts.map +1 -0
  95. package/dist/src/platforms/webex/commands/auth.js +166 -0
  96. package/dist/src/platforms/webex/commands/auth.js.map +1 -0
  97. package/dist/src/platforms/webex/commands/index.d.ts +6 -0
  98. package/dist/src/platforms/webex/commands/index.d.ts.map +1 -0
  99. package/dist/src/platforms/webex/commands/index.js +6 -0
  100. package/dist/src/platforms/webex/commands/index.js.map +1 -0
  101. package/dist/src/platforms/webex/commands/member.d.ts +7 -0
  102. package/dist/src/platforms/webex/commands/member.d.ts.map +1 -0
  103. package/dist/src/platforms/webex/commands/member.js +34 -0
  104. package/dist/src/platforms/webex/commands/member.js.map +1 -0
  105. package/dist/src/platforms/webex/commands/message.d.ts +26 -0
  106. package/dist/src/platforms/webex/commands/message.d.ts.map +1 -0
  107. package/dist/src/platforms/webex/commands/message.js +153 -0
  108. package/dist/src/platforms/webex/commands/message.js.map +1 -0
  109. package/dist/src/platforms/webex/commands/snapshot.d.ts +9 -0
  110. package/dist/src/platforms/webex/commands/snapshot.d.ts.map +1 -0
  111. package/dist/src/platforms/webex/commands/snapshot.js +72 -0
  112. package/dist/src/platforms/webex/commands/snapshot.js.map +1 -0
  113. package/dist/src/platforms/webex/commands/space.d.ts +11 -0
  114. package/dist/src/platforms/webex/commands/space.d.ts.map +1 -0
  115. package/dist/src/platforms/webex/commands/space.js +59 -0
  116. package/dist/src/platforms/webex/commands/space.js.map +1 -0
  117. package/dist/src/platforms/webex/credential-manager.d.ts +23 -0
  118. package/dist/src/platforms/webex/credential-manager.d.ts.map +1 -0
  119. package/dist/src/platforms/webex/credential-manager.js +148 -0
  120. package/dist/src/platforms/webex/credential-manager.js.map +1 -0
  121. package/dist/src/platforms/webex/ensure-auth.d.ts +2 -0
  122. package/dist/src/platforms/webex/ensure-auth.d.ts.map +1 -0
  123. package/dist/src/platforms/webex/ensure-auth.js +36 -0
  124. package/dist/src/platforms/webex/ensure-auth.js.map +1 -0
  125. package/dist/src/platforms/webex/index.d.ts +8 -0
  126. package/dist/src/platforms/webex/index.d.ts.map +1 -0
  127. package/dist/src/platforms/webex/index.js +6 -0
  128. package/dist/src/platforms/webex/index.js.map +1 -0
  129. package/dist/src/platforms/webex/token-extractor.d.ts +28 -0
  130. package/dist/src/platforms/webex/token-extractor.d.ts.map +1 -0
  131. package/dist/src/platforms/webex/token-extractor.js +344 -0
  132. package/dist/src/platforms/webex/token-extractor.js.map +1 -0
  133. package/dist/src/platforms/webex/types.d.ts +127 -0
  134. package/dist/src/platforms/webex/types.d.ts.map +1 -0
  135. package/dist/src/platforms/webex/types.js +64 -0
  136. package/dist/src/platforms/webex/types.js.map +1 -0
  137. package/dist/src/platforms/whatsapp/client.d.ts.map +1 -1
  138. package/dist/src/platforms/whatsapp/client.js +6 -2
  139. package/dist/src/platforms/whatsapp/client.js.map +1 -1
  140. package/dist/src/shared/utils/derived-key-cache.d.ts +1 -1
  141. package/dist/src/shared/utils/derived-key-cache.d.ts.map +1 -1
  142. package/dist/src/shared/utils/error-handler.d.ts +1 -1
  143. package/dist/src/shared/utils/error-handler.d.ts.map +1 -1
  144. package/dist/src/shared/utils/error-handler.js +3 -2
  145. package/dist/src/shared/utils/error-handler.js.map +1 -1
  146. package/dist/src/shared/utils/stderr.d.ts +5 -0
  147. package/dist/src/shared/utils/stderr.d.ts.map +1 -0
  148. package/dist/src/shared/utils/stderr.js +18 -0
  149. package/dist/src/shared/utils/stderr.js.map +1 -0
  150. package/dist/src/tui/adapters/webex-adapter.d.ts +14 -0
  151. package/dist/src/tui/adapters/webex-adapter.d.ts.map +1 -0
  152. package/dist/src/tui/adapters/webex-adapter.js +79 -0
  153. package/dist/src/tui/adapters/webex-adapter.js.map +1 -0
  154. package/dist/src/tui/app.d.ts.map +1 -1
  155. package/dist/src/tui/app.js +2 -0
  156. package/dist/src/tui/app.js.map +1 -1
  157. package/docs/content/docs/cli/channeltalk.mdx +7 -7
  158. package/docs/content/docs/cli/discord.mdx +3 -3
  159. package/docs/content/docs/cli/instagram.mdx +28 -6
  160. package/docs/content/docs/cli/meta.json +1 -0
  161. package/docs/content/docs/cli/slack.mdx +2 -2
  162. package/docs/content/docs/cli/teams.mdx +6 -4
  163. package/docs/content/docs/cli/webex.mdx +310 -0
  164. package/docs/content/docs/sdk/meta.json +1 -1
  165. package/docs/content/docs/sdk/webex.mdx +260 -0
  166. package/docs/content/docs/tui.mdx +4 -3
  167. package/docs/src/app/page.tsx +2 -2
  168. package/e2e/README.md +132 -8
  169. package/e2e/channeltalk.e2e.test.ts +2 -7
  170. package/e2e/channeltalkbot.e2e.test.ts +2 -6
  171. package/e2e/config.ts +172 -10
  172. package/e2e/helpers.ts +7 -0
  173. package/e2e/instagram.e2e.test.ts +97 -0
  174. package/e2e/kakaotalk.e2e.test.ts +74 -0
  175. package/e2e/line.e2e.test.ts +92 -0
  176. package/e2e/teams.e2e.test.ts +46 -1
  177. package/e2e/telegram.e2e.test.ts +84 -0
  178. package/e2e/webex.e2e.test.ts +190 -0
  179. package/e2e/whatsapp.e2e.test.ts +90 -0
  180. package/e2e/whatsappbot.e2e.test.ts +78 -0
  181. package/package.json +11 -3
  182. package/skills/agent-channeltalk/SKILL.md +9 -9
  183. package/skills/agent-channeltalk/references/authentication.md +21 -18
  184. package/skills/agent-channeltalkbot/SKILL.md +1 -1
  185. package/skills/agent-discord/SKILL.md +5 -5
  186. package/skills/agent-discord/references/authentication.md +8 -8
  187. package/skills/agent-discordbot/SKILL.md +1 -1
  188. package/skills/agent-instagram/SKILL.md +51 -9
  189. package/skills/agent-instagram/references/authentication.md +35 -3
  190. package/skills/agent-kakaotalk/SKILL.md +1 -1
  191. package/skills/agent-line/SKILL.md +1 -1
  192. package/skills/agent-slack/SKILL.md +5 -5
  193. package/skills/agent-slack/references/authentication.md +8 -8
  194. package/skills/agent-slackbot/SKILL.md +1 -1
  195. package/skills/agent-teams/SKILL.md +6 -6
  196. package/skills/agent-teams/references/authentication.md +8 -8
  197. package/skills/agent-telegram/SKILL.md +1 -1
  198. package/skills/agent-webex/SKILL.md +406 -0
  199. package/skills/agent-webex/references/authentication.md +371 -0
  200. package/skills/agent-webex/references/common-patterns.md +726 -0
  201. package/skills/agent-webex/templates/monitor-space.sh +165 -0
  202. package/skills/agent-webex/templates/post-message.sh +170 -0
  203. package/skills/agent-whatsapp/SKILL.md +1 -1
  204. package/skills/agent-whatsappbot/SKILL.md +1 -1
  205. package/src/cli.ts +4 -0
  206. package/src/platforms/channeltalk/commands/auth.test.ts +5 -5
  207. package/src/platforms/channeltalk/commands/auth.ts +38 -32
  208. package/src/platforms/channeltalk/ensure-auth.test.ts +6 -6
  209. package/src/platforms/channeltalk/ensure-auth.ts +6 -6
  210. package/src/platforms/channeltalk/token-extractor.test.ts +182 -15
  211. package/src/platforms/channeltalk/token-extractor.ts +344 -30
  212. package/src/platforms/discord/commands/auth.test.ts +3 -3
  213. package/src/platforms/discord/commands/auth.ts +58 -54
  214. package/src/platforms/discord/ensure-auth.test.ts +3 -3
  215. package/src/platforms/discord/ensure-auth.ts +3 -3
  216. package/src/platforms/discord/token-extractor.test.ts +199 -27
  217. package/src/platforms/discord/token-extractor.ts +190 -17
  218. package/src/platforms/instagram/client.ts +2 -2
  219. package/src/platforms/instagram/commands/auth.ts +133 -14
  220. package/src/platforms/instagram/ensure-auth.ts +63 -12
  221. package/src/platforms/instagram/index.ts +1 -0
  222. package/src/platforms/instagram/token-extractor.test.ts +424 -0
  223. package/src/platforms/instagram/token-extractor.ts +478 -0
  224. package/src/platforms/kakaotalk/client.ts +3 -1
  225. package/src/platforms/kakaotalk/commands/auth.ts +14 -13
  226. package/src/platforms/kakaotalk/protocol/connection.ts +3 -1
  227. package/src/platforms/line/commands/auth.ts +7 -6
  228. package/src/platforms/slack/cli.test.ts +6 -5
  229. package/src/platforms/slack/commands/auth.test.ts +11 -7
  230. package/src/platforms/slack/commands/auth.ts +11 -10
  231. package/src/platforms/slack/token-extractor.test.ts +98 -1
  232. package/src/platforms/slack/token-extractor.ts +338 -26
  233. package/src/platforms/teams/commands/auth.ts +9 -8
  234. package/src/platforms/teams/ensure-auth.ts +3 -1
  235. package/src/platforms/teams/token-extractor.test.ts +136 -17
  236. package/src/platforms/teams/token-extractor.ts +182 -31
  237. package/src/platforms/telegram/client.test.ts +134 -0
  238. package/src/platforms/telegram/client.ts +27 -6
  239. package/src/platforms/telegram/commands/auth.ts +6 -5
  240. package/src/platforms/webex/app-config.test.ts +98 -0
  241. package/src/platforms/webex/app-config.ts +31 -0
  242. package/src/platforms/webex/cli.test.ts +58 -0
  243. package/src/platforms/webex/cli.ts +39 -0
  244. package/src/platforms/webex/client.test.ts +743 -0
  245. package/src/platforms/webex/client.ts +405 -0
  246. package/src/platforms/webex/commands/auth.test.ts +222 -0
  247. package/src/platforms/webex/commands/auth.ts +243 -0
  248. package/src/platforms/webex/commands/index.ts +5 -0
  249. package/src/platforms/webex/commands/member.test.ts +112 -0
  250. package/src/platforms/webex/commands/member.ts +45 -0
  251. package/src/platforms/webex/commands/message.test.ts +235 -0
  252. package/src/platforms/webex/commands/message.ts +204 -0
  253. package/src/platforms/webex/commands/snapshot.test.ts +105 -0
  254. package/src/platforms/webex/commands/snapshot.ts +91 -0
  255. package/src/platforms/webex/commands/space.test.ts +216 -0
  256. package/src/platforms/webex/commands/space.ts +74 -0
  257. package/src/platforms/webex/credential-manager.test.ts +314 -0
  258. package/src/platforms/webex/credential-manager.ts +197 -0
  259. package/src/platforms/webex/ensure-auth.test.ts +89 -0
  260. package/src/platforms/webex/ensure-auth.ts +38 -0
  261. package/src/platforms/webex/index.test.ts +25 -0
  262. package/src/platforms/webex/index.ts +19 -0
  263. package/src/platforms/webex/token-extractor.test.ts +327 -0
  264. package/src/platforms/webex/token-extractor.ts +393 -0
  265. package/src/platforms/webex/types.test.ts +307 -0
  266. package/src/platforms/webex/types.ts +129 -0
  267. package/src/platforms/whatsapp/client.ts +11 -7
  268. package/src/shared/utils/derived-key-cache.ts +1 -1
  269. package/src/shared/utils/error-handler.ts +4 -2
  270. package/src/shared/utils/stderr.ts +22 -0
  271. package/src/tui/adapters/webex-adapter.ts +103 -0
  272. package/src/tui/app.ts +2 -0
@@ -0,0 +1,165 @@
1
+ #!/bin/bash
2
+ #
3
+ # monitor-space.sh - Monitor a Webex space for new messages
4
+ #
5
+ # Usage:
6
+ # ./monitor-space.sh <space-id> [interval]
7
+ #
8
+ # Arguments:
9
+ # space-id - Space ID to monitor (use 'space list' to find IDs)
10
+ # interval - Polling interval in seconds (default: 10)
11
+ #
12
+ # Example:
13
+ # ./monitor-space.sh "Y2lzY29zcGFyazovL..."
14
+ # ./monitor-space.sh "Y2lzY29zcGFyazovL..." 5
15
+
16
+ set -euo pipefail
17
+
18
+ if [ $# -lt 1 ]; then
19
+ echo "Usage: $0 <space-id> [interval]"
20
+ echo ""
21
+ echo "Examples:"
22
+ echo " $0 'Y2lzY29zcGFyazovL...' # Monitor space, poll every 10s"
23
+ echo " $0 'Y2lzY29zcGFyazovL...' 5 # Monitor space, poll every 5s"
24
+ echo ""
25
+ echo "To find space IDs, run: agent-webex space list"
26
+ exit 1
27
+ fi
28
+
29
+ SPACE_ID="$1"
30
+ INTERVAL="${2:-10}"
31
+
32
+ RED='\033[0;31m'
33
+ GREEN='\033[0;32m'
34
+ YELLOW='\033[1;33m'
35
+ BLUE='\033[0;34m'
36
+ NC='\033[0m'
37
+
38
+ LAST_ID=""
39
+ FIRST_RUN=true
40
+
41
+ format_time() {
42
+ local ts=$1
43
+ if command -v gdate &> /dev/null; then
44
+ gdate -d "$ts" "+%Y-%m-%d %H:%M:%S" 2>/dev/null || echo "$ts"
45
+ else
46
+ date -d "$ts" "+%Y-%m-%d %H:%M:%S" 2>/dev/null || echo "$ts"
47
+ fi
48
+ }
49
+
50
+ truncate_text() {
51
+ local text=$1
52
+ local max_length=100
53
+
54
+ if [ ${#text} -gt $max_length ]; then
55
+ echo "${text:0:$max_length}..."
56
+ else
57
+ echo "$text"
58
+ fi
59
+ }
60
+
61
+ check_messages() {
62
+ MESSAGES=$(agent-webex message list "$SPACE_ID" --limit 1 2>&1)
63
+
64
+ if echo "$MESSAGES" | jq -e '.error' > /dev/null 2>&1; then
65
+ ERROR_MSG=$(echo "$MESSAGES" | jq -r '.error // "Unknown error"')
66
+ echo -e "${RED}Error: $ERROR_MSG${NC}"
67
+
68
+ if echo "$ERROR_MSG" | grep -Eqi "401|unauthorized"; then
69
+ echo -e "${RED}Token expired or invalid. Get a new token from https://developer.webex.com${NC}"
70
+ exit 1
71
+ fi
72
+
73
+ return 1
74
+ fi
75
+
76
+ LATEST_ID=$(echo "$MESSAGES" | jq -r '.[0].id // ""')
77
+
78
+ if [ -z "$LATEST_ID" ]; then
79
+ if [ "$FIRST_RUN" = true ]; then
80
+ echo -e "${YELLOW}No messages in space yet${NC}"
81
+ fi
82
+ FIRST_RUN=false
83
+ return 0
84
+ fi
85
+
86
+ if [ "$LATEST_ID" != "$LAST_ID" ]; then
87
+ if [ "$FIRST_RUN" = false ] && [ -n "$LAST_ID" ]; then
88
+ TEXT=$(echo "$MESSAGES" | jq -r '.[0].text // ""')
89
+ AUTHOR=$(echo "$MESSAGES" | jq -r '.[0].personEmail // "Unknown"')
90
+ TIMESTAMP=$(echo "$MESSAGES" | jq -r '.[0].created // ""')
91
+
92
+ TIME=$(format_time "$TIMESTAMP")
93
+
94
+ echo ""
95
+ echo -e "${GREEN}----------------------------------------------${NC}"
96
+ echo -e "${BLUE}New message in space${NC}"
97
+ echo -e "${GREEN}----------------------------------------------${NC}"
98
+ echo -e "Time: $TIME"
99
+ echo -e "From: $AUTHOR"
100
+ echo -e "Message: $(truncate_text "$TEXT")"
101
+ echo -e "${GREEN}----------------------------------------------${NC}"
102
+
103
+ # Uncomment to auto-respond to keywords:
104
+ # if echo "$TEXT" | grep -qi "status"; then
105
+ # agent-webex message send "$SPACE_ID" "All systems operational."
106
+ # fi
107
+ fi
108
+
109
+ LAST_ID="$LATEST_ID"
110
+ fi
111
+
112
+ FIRST_RUN=false
113
+ return 0
114
+ }
115
+
116
+ if ! command -v agent-webex &> /dev/null; then
117
+ echo -e "${RED}Error: agent-webex not found${NC}"
118
+ echo ""
119
+ echo "Install it with:"
120
+ echo " npm install -g agent-messenger"
121
+ exit 1
122
+ fi
123
+
124
+ echo "Checking authentication..."
125
+ AUTH_STATUS=$(agent-webex auth status 2>&1)
126
+
127
+ if echo "$AUTH_STATUS" | jq -e '.error' > /dev/null 2>&1; then
128
+ echo -e "${RED}Not authenticated!${NC}"
129
+ echo ""
130
+ echo "Run this to authenticate:"
131
+ echo " agent-webex auth login --token <token>"
132
+ echo ""
133
+ echo "Get a token at: https://developer.webex.com/docs/getting-started"
134
+ exit 1
135
+ fi
136
+
137
+ USER_NAME=$(echo "$AUTH_STATUS" | jq -r '.displayName // "Unknown"')
138
+ echo -e "${GREEN}Authenticated as: $USER_NAME${NC}"
139
+ echo ""
140
+
141
+ echo "Verifying space..."
142
+ SPACE_INFO=$(agent-webex space info "$SPACE_ID" 2>&1)
143
+
144
+ if echo "$SPACE_INFO" | jq -e '.error' > /dev/null 2>&1; then
145
+ echo -e "${RED}Space '$SPACE_ID' not found${NC}"
146
+ echo ""
147
+ echo "List available spaces with:"
148
+ echo " agent-webex space list"
149
+ exit 1
150
+ fi
151
+
152
+ SPACE_TITLE=$(echo "$SPACE_INFO" | jq -r '.title // "Unknown"')
153
+ echo -e "${GREEN}Monitoring: $SPACE_TITLE ($SPACE_ID)${NC}"
154
+ echo ""
155
+
156
+ echo -e "${YELLOW}Monitoring for new messages (polling every ${INTERVAL}s)...${NC}"
157
+ echo -e "${YELLOW}Press Ctrl+C to stop${NC}"
158
+ echo ""
159
+
160
+ trap 'echo -e "\n${YELLOW}Monitoring stopped${NC}"; exit 0' INT
161
+
162
+ while true; do
163
+ check_messages
164
+ sleep "$INTERVAL"
165
+ done
@@ -0,0 +1,170 @@
1
+ #!/bin/bash
2
+ #
3
+ # post-message.sh - Send a message to a Webex space with error handling
4
+ #
5
+ # Usage:
6
+ # ./post-message.sh <space-id> <message>
7
+ # ./post-message.sh --space-title <title> <message>
8
+ #
9
+ # Example:
10
+ # ./post-message.sh "Y2lzY29zcGFyazovL..." "Hello from script!"
11
+ # ./post-message.sh --space-title Engineering "Deployment completed"
12
+
13
+ set -euo pipefail
14
+
15
+ # Colors for output
16
+ RED='\033[0;31m'
17
+ GREEN='\033[0;32m'
18
+ YELLOW='\033[1;33m'
19
+ NC='\033[0m' # No Color
20
+
21
+ # Parse arguments
22
+ SPACE_ID=""
23
+ SPACE_TITLE=""
24
+ MESSAGE=""
25
+
26
+ if [ "$1" = "--space-title" ]; then
27
+ if [ $# -lt 3 ]; then
28
+ echo "Usage: $0 --space-title <title> <message>"
29
+ echo ""
30
+ echo "Example:"
31
+ echo " $0 --space-title Engineering 'Build completed'"
32
+ exit 1
33
+ fi
34
+ SPACE_TITLE="$2"
35
+ MESSAGE="$3"
36
+ elif [ $# -lt 2 ]; then
37
+ echo "Usage: $0 <space-id> <message>"
38
+ echo " $0 --space-title <title> <message>"
39
+ echo ""
40
+ echo "Examples:"
41
+ echo " $0 'Y2lzY29zcGFyazovL...' 'Hello world!'"
42
+ echo " $0 --space-title Engineering 'Build completed'"
43
+ exit 1
44
+ else
45
+ SPACE_ID="$1"
46
+ MESSAGE="$2"
47
+ fi
48
+
49
+ # Function to send message with retry logic
50
+ send_message() {
51
+ local space_id=$1
52
+ local message=$2
53
+ local max_attempts=3
54
+ local attempt=1
55
+
56
+ while [ $attempt -le $max_attempts ]; do
57
+ echo -e "${YELLOW}Attempt $attempt/$max_attempts...${NC}"
58
+
59
+ # Send message and capture result
60
+ RESULT=$(agent-webex message send "$space_id" "$message" 2>&1)
61
+
62
+ # Check if successful (has an 'id' field)
63
+ if echo "$RESULT" | jq -e '.id' > /dev/null 2>&1; then
64
+ echo -e "${GREEN}Message sent successfully!${NC}"
65
+
66
+ MSG_ID=$(echo "$RESULT" | jq -r '.id')
67
+
68
+ echo ""
69
+ echo "Message details:"
70
+ echo " Space: $space_id"
71
+ echo " Message ID: $MSG_ID"
72
+
73
+ return 0
74
+ fi
75
+
76
+ # Extract error information
77
+ if echo "$RESULT" | jq -e '.error' > /dev/null 2>&1; then
78
+ ERROR_MSG=$(echo "$RESULT" | jq -r '.error // "Unknown error"')
79
+ echo -e "${RED}Failed: $ERROR_MSG${NC}"
80
+
81
+ # Don't retry on auth errors
82
+ if echo "$ERROR_MSG" | grep -Eqi "401|unauthorized|not authenticated"; then
83
+ echo ""
84
+ echo "Not authenticated. Run:"
85
+ echo " agent-webex auth login --token <token>"
86
+ return 1
87
+ fi
88
+
89
+ # Don't retry on not-found errors
90
+ if echo "$ERROR_MSG" | grep -qi "not found"; then
91
+ echo ""
92
+ echo "Space '$space_id' not found. Check space ID."
93
+ echo "List spaces with: agent-webex space list"
94
+ return 1
95
+ fi
96
+ else
97
+ echo -e "${RED}Unexpected error: $RESULT${NC}"
98
+ fi
99
+
100
+ # Exponential backoff before retry
101
+ if [ $attempt -lt $max_attempts ]; then
102
+ SLEEP_TIME=$((attempt * 2))
103
+ echo "Retrying in ${SLEEP_TIME}s..."
104
+ sleep $SLEEP_TIME
105
+ fi
106
+
107
+ attempt=$((attempt + 1))
108
+ done
109
+
110
+ echo -e "${RED}Failed after $max_attempts attempts${NC}"
111
+ return 1
112
+ }
113
+
114
+ # Check if agent-webex is installed
115
+ if ! command -v agent-webex &> /dev/null; then
116
+ echo -e "${RED}Error: agent-webex not found${NC}"
117
+ echo ""
118
+ echo "Install it with:"
119
+ echo " npm install -g agent-messenger"
120
+ exit 1
121
+ fi
122
+
123
+ # Check authentication
124
+ echo "Checking authentication..."
125
+ AUTH_STATUS=$(agent-webex auth status 2>&1)
126
+
127
+ if echo "$AUTH_STATUS" | jq -e '.error' > /dev/null 2>&1; then
128
+ echo -e "${RED}Not authenticated!${NC}"
129
+ echo ""
130
+ echo "Run this to authenticate:"
131
+ echo " agent-webex auth login --token <token>"
132
+ echo ""
133
+ echo "Get a token at: https://developer.webex.com/docs/getting-started"
134
+ exit 1
135
+ fi
136
+
137
+ USER_NAME=$(echo "$AUTH_STATUS" | jq -r '.displayName // "Unknown"')
138
+ echo -e "${GREEN}Authenticated as: $USER_NAME${NC}"
139
+
140
+ # If space title provided, look up space ID
141
+ if [ -n "$SPACE_TITLE" ]; then
142
+ echo "Looking up space '$SPACE_TITLE'..."
143
+ SPACES=$(agent-webex space list 2>&1)
144
+
145
+ if echo "$SPACES" | jq -e '.error' > /dev/null 2>&1; then
146
+ echo -e "${RED}Failed to list spaces${NC}"
147
+ exit 1
148
+ fi
149
+
150
+ SPACE_ID=$(echo "$SPACES" | jq -r --arg title "$SPACE_TITLE" '.[] | select(.title==$title) | .id')
151
+
152
+ if [ -z "$SPACE_ID" ]; then
153
+ echo -e "${RED}Space '$SPACE_TITLE' not found${NC}"
154
+ echo ""
155
+ echo "Available spaces:"
156
+ echo "$SPACES" | jq -r '.[] | " \(.title) (\(.id))"'
157
+ exit 1
158
+ fi
159
+
160
+ echo -e "${GREEN}Found space: $SPACE_ID${NC}"
161
+ fi
162
+
163
+ echo ""
164
+
165
+ # Send the message
166
+ echo "Sending message to space $SPACE_ID..."
167
+ echo "Message: $MESSAGE"
168
+ echo ""
169
+
170
+ send_message "$SPACE_ID" "$MESSAGE"
@@ -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.0.0
4
+ version: 2.2.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.0.0
4
+ version: 2.2.0
5
5
  allowed-tools: Bash(agent-whatsappbot:*)
6
6
  metadata:
7
7
  openclaw:
package/src/cli.ts CHANGED
@@ -68,6 +68,10 @@ program.command('channeltalkbot', 'Interact with Channel Talk using API credenti
68
68
  executableFile: join(__dirname, 'platforms', 'channeltalkbot', `cli${ext}`),
69
69
  })
70
70
 
71
+ program.command('webex', 'Interact with Cisco Webex', {
72
+ executableFile: join(__dirname, 'platforms', 'webex', `cli${ext}`),
73
+ })
74
+
71
75
  program.command('tui', 'Launch unified messenger TUI', {
72
76
  executableFile: join(__dirname, 'tui', `cli${ext}`),
73
77
  })
@@ -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