agent-messenger 2.10.2 → 2.11.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude-plugin/plugin.json +1 -1
- package/.env.template +4 -1
- package/README.md +77 -27
- package/bun.lock +26 -0
- package/dist/package.json +21 -1
- package/dist/src/platforms/channeltalk/commands/auth.d.ts +2 -1
- package/dist/src/platforms/channeltalk/commands/auth.d.ts.map +1 -1
- package/dist/src/platforms/channeltalk/commands/auth.js +5 -3
- package/dist/src/platforms/channeltalk/commands/auth.js.map +1 -1
- package/dist/src/platforms/channeltalk/token-extractor.d.ts +2 -1
- package/dist/src/platforms/channeltalk/token-extractor.d.ts.map +1 -1
- package/dist/src/platforms/channeltalk/token-extractor.js +22 -6
- package/dist/src/platforms/channeltalk/token-extractor.js.map +1 -1
- package/dist/src/platforms/channeltalkbot/cli.d.ts.map +1 -1
- package/dist/src/platforms/channeltalkbot/cli.js +11 -1
- package/dist/src/platforms/channeltalkbot/cli.js.map +1 -1
- package/dist/src/platforms/channeltalkbot/commands/auth.d.ts.map +1 -1
- package/dist/src/platforms/channeltalkbot/commands/auth.js +1 -5
- package/dist/src/platforms/channeltalkbot/commands/auth.js.map +1 -1
- package/dist/src/platforms/channeltalkbot/commands/bot.d.ts.map +1 -1
- package/dist/src/platforms/channeltalkbot/commands/bot.js +1 -6
- package/dist/src/platforms/channeltalkbot/commands/bot.js.map +1 -1
- package/dist/src/platforms/channeltalkbot/commands/chat.d.ts.map +1 -1
- package/dist/src/platforms/channeltalkbot/commands/chat.js +1 -6
- package/dist/src/platforms/channeltalkbot/commands/chat.js.map +1 -1
- package/dist/src/platforms/channeltalkbot/commands/group.d.ts.map +1 -1
- package/dist/src/platforms/channeltalkbot/commands/group.js +1 -6
- package/dist/src/platforms/channeltalkbot/commands/group.js.map +1 -1
- package/dist/src/platforms/channeltalkbot/commands/manager.d.ts.map +1 -1
- package/dist/src/platforms/channeltalkbot/commands/manager.js +1 -6
- package/dist/src/platforms/channeltalkbot/commands/manager.js.map +1 -1
- package/dist/src/platforms/channeltalkbot/commands/message.d.ts.map +1 -1
- package/dist/src/platforms/channeltalkbot/commands/message.js +1 -6
- package/dist/src/platforms/channeltalkbot/commands/message.js.map +1 -1
- package/dist/src/platforms/channeltalkbot/commands/whoami.d.ts.map +1 -1
- package/dist/src/platforms/channeltalkbot/commands/whoami.js +1 -6
- package/dist/src/platforms/channeltalkbot/commands/whoami.js.map +1 -1
- package/dist/src/platforms/channeltalkbot/credential-manager.d.ts +5 -0
- package/dist/src/platforms/channeltalkbot/credential-manager.d.ts.map +1 -1
- package/dist/src/platforms/channeltalkbot/credential-manager.js +34 -4
- package/dist/src/platforms/channeltalkbot/credential-manager.js.map +1 -1
- package/dist/src/platforms/discord/commands/auth.d.ts +1 -0
- package/dist/src/platforms/discord/commands/auth.d.ts.map +1 -1
- package/dist/src/platforms/discord/commands/auth.js +3 -1
- package/dist/src/platforms/discord/commands/auth.js.map +1 -1
- package/dist/src/platforms/discord/listener.d.ts +2 -0
- package/dist/src/platforms/discord/listener.d.ts.map +1 -1
- package/dist/src/platforms/discord/listener.js +51 -21
- package/dist/src/platforms/discord/listener.js.map +1 -1
- package/dist/src/platforms/discord/token-extractor.d.ts +2 -1
- package/dist/src/platforms/discord/token-extractor.d.ts.map +1 -1
- package/dist/src/platforms/discord/token-extractor.js +21 -6
- package/dist/src/platforms/discord/token-extractor.js.map +1 -1
- package/dist/src/platforms/discordbot/cli.d.ts.map +1 -1
- package/dist/src/platforms/discordbot/cli.js +12 -1
- package/dist/src/platforms/discordbot/cli.js.map +1 -1
- package/dist/src/platforms/discordbot/client.d.ts +3 -0
- package/dist/src/platforms/discordbot/client.d.ts.map +1 -1
- package/dist/src/platforms/discordbot/client.js +3 -0
- package/dist/src/platforms/discordbot/client.js.map +1 -1
- package/dist/src/platforms/discordbot/commands/auth.d.ts.map +1 -1
- package/dist/src/platforms/discordbot/commands/auth.js +1 -5
- package/dist/src/platforms/discordbot/commands/auth.js.map +1 -1
- package/dist/src/platforms/discordbot/commands/message.d.ts.map +1 -1
- package/dist/src/platforms/discordbot/commands/message.js +1 -6
- package/dist/src/platforms/discordbot/commands/message.js.map +1 -1
- package/dist/src/platforms/discordbot/commands/server.d.ts.map +1 -1
- package/dist/src/platforms/discordbot/commands/server.js +1 -4
- package/dist/src/platforms/discordbot/commands/server.js.map +1 -1
- package/dist/src/platforms/discordbot/commands/whoami.d.ts.map +1 -1
- package/dist/src/platforms/discordbot/commands/whoami.js +1 -6
- package/dist/src/platforms/discordbot/commands/whoami.js.map +1 -1
- package/dist/src/platforms/discordbot/index.d.ts +3 -1
- package/dist/src/platforms/discordbot/index.d.ts.map +1 -1
- package/dist/src/platforms/discordbot/index.js +2 -1
- package/dist/src/platforms/discordbot/index.js.map +1 -1
- package/dist/src/platforms/discordbot/listener.d.ts +43 -0
- package/dist/src/platforms/discordbot/listener.d.ts.map +1 -0
- package/dist/src/platforms/discordbot/listener.js +292 -0
- package/dist/src/platforms/discordbot/listener.js.map +1 -0
- package/dist/src/platforms/discordbot/types.d.ts +161 -0
- package/dist/src/platforms/discordbot/types.d.ts.map +1 -1
- package/dist/src/platforms/discordbot/types.js +34 -0
- package/dist/src/platforms/discordbot/types.js.map +1 -1
- package/dist/src/platforms/instagram/commands/auth.d.ts.map +1 -1
- package/dist/src/platforms/instagram/commands/auth.js +3 -1
- package/dist/src/platforms/instagram/commands/auth.js.map +1 -1
- package/dist/src/platforms/instagram/token-extractor.d.ts +2 -1
- package/dist/src/platforms/instagram/token-extractor.d.ts.map +1 -1
- package/dist/src/platforms/instagram/token-extractor.js +11 -2
- package/dist/src/platforms/instagram/token-extractor.js.map +1 -1
- package/dist/src/platforms/slack/commands/auth.d.ts.map +1 -1
- package/dist/src/platforms/slack/commands/auth.js +4 -2
- package/dist/src/platforms/slack/commands/auth.js.map +1 -1
- package/dist/src/platforms/slack/token-extractor.d.ts +4 -1
- package/dist/src/platforms/slack/token-extractor.d.ts.map +1 -1
- package/dist/src/platforms/slack/token-extractor.js +64 -15
- package/dist/src/platforms/slack/token-extractor.js.map +1 -1
- package/dist/src/platforms/slackbot/cli.d.ts.map +1 -1
- package/dist/src/platforms/slackbot/cli.js +15 -3
- package/dist/src/platforms/slackbot/cli.js.map +1 -1
- package/dist/src/platforms/slackbot/client.d.ts +22 -1
- package/dist/src/platforms/slackbot/client.d.ts.map +1 -1
- package/dist/src/platforms/slackbot/client.js +104 -1
- package/dist/src/platforms/slackbot/client.js.map +1 -1
- package/dist/src/platforms/slackbot/commands/auth.d.ts.map +1 -1
- package/dist/src/platforms/slackbot/commands/auth.js +1 -5
- package/dist/src/platforms/slackbot/commands/auth.js.map +1 -1
- package/dist/src/platforms/slackbot/commands/file.d.ts +3 -0
- package/dist/src/platforms/slackbot/commands/file.d.ts.map +1 -0
- package/dist/src/platforms/slackbot/commands/file.js +164 -0
- package/dist/src/platforms/slackbot/commands/file.js.map +1 -0
- package/dist/src/platforms/slackbot/commands/index.d.ts +1 -0
- package/dist/src/platforms/slackbot/commands/index.d.ts.map +1 -1
- package/dist/src/platforms/slackbot/commands/index.js +1 -0
- package/dist/src/platforms/slackbot/commands/index.js.map +1 -1
- package/dist/src/platforms/slackbot/commands/message.d.ts.map +1 -1
- package/dist/src/platforms/slackbot/commands/message.js +19 -0
- package/dist/src/platforms/slackbot/commands/message.js.map +1 -1
- package/dist/src/platforms/slackbot/commands/whoami.d.ts.map +1 -1
- package/dist/src/platforms/slackbot/commands/whoami.js +1 -6
- package/dist/src/platforms/slackbot/commands/whoami.js.map +1 -1
- package/dist/src/platforms/slackbot/credential-manager.d.ts +1 -0
- package/dist/src/platforms/slackbot/credential-manager.d.ts.map +1 -1
- package/dist/src/platforms/slackbot/credential-manager.js +30 -2
- package/dist/src/platforms/slackbot/credential-manager.js.map +1 -1
- package/dist/src/platforms/slackbot/index.d.ts +4 -1
- package/dist/src/platforms/slackbot/index.d.ts.map +1 -1
- package/dist/src/platforms/slackbot/index.js +1 -0
- package/dist/src/platforms/slackbot/index.js.map +1 -1
- package/dist/src/platforms/slackbot/listener.d.ts +44 -0
- package/dist/src/platforms/slackbot/listener.d.ts.map +1 -0
- package/dist/src/platforms/slackbot/listener.js +313 -0
- package/dist/src/platforms/slackbot/listener.js.map +1 -0
- package/dist/src/platforms/slackbot/types.d.ts +196 -1
- package/dist/src/platforms/slackbot/types.d.ts.map +1 -1
- package/dist/src/platforms/slackbot/types.js +4 -1
- package/dist/src/platforms/slackbot/types.js.map +1 -1
- package/dist/src/platforms/teams/commands/auth.d.ts +1 -0
- package/dist/src/platforms/teams/commands/auth.d.ts.map +1 -1
- package/dist/src/platforms/teams/commands/auth.js +37 -6
- package/dist/src/platforms/teams/commands/auth.js.map +1 -1
- package/dist/src/platforms/teams/ensure-auth.js +31 -9
- package/dist/src/platforms/teams/ensure-auth.js.map +1 -1
- package/dist/src/platforms/teams/token-extractor.d.ts +4 -1
- package/dist/src/platforms/teams/token-extractor.d.ts.map +1 -1
- package/dist/src/platforms/teams/token-extractor.js +71 -29
- package/dist/src/platforms/teams/token-extractor.js.map +1 -1
- package/dist/src/platforms/webex/commands/auth.d.ts +1 -0
- package/dist/src/platforms/webex/commands/auth.d.ts.map +1 -1
- package/dist/src/platforms/webex/commands/auth.js +3 -1
- package/dist/src/platforms/webex/commands/auth.js.map +1 -1
- package/dist/src/platforms/webex/token-extractor.d.ts +3 -1
- package/dist/src/platforms/webex/token-extractor.d.ts.map +1 -1
- package/dist/src/platforms/webex/token-extractor.js +16 -2
- package/dist/src/platforms/webex/token-extractor.js.map +1 -1
- package/dist/src/platforms/wechatbot/cli.d.ts.map +1 -1
- package/dist/src/platforms/wechatbot/cli.js +11 -1
- package/dist/src/platforms/wechatbot/cli.js.map +1 -1
- package/dist/src/platforms/wechatbot/commands/auth.d.ts.map +1 -1
- package/dist/src/platforms/wechatbot/commands/auth.js +1 -5
- package/dist/src/platforms/wechatbot/commands/auth.js.map +1 -1
- package/dist/src/platforms/wechatbot/commands/message.d.ts.map +1 -1
- package/dist/src/platforms/wechatbot/commands/message.js +1 -6
- package/dist/src/platforms/wechatbot/commands/message.js.map +1 -1
- package/dist/src/platforms/wechatbot/commands/template.d.ts.map +1 -1
- package/dist/src/platforms/wechatbot/commands/template.js +1 -6
- package/dist/src/platforms/wechatbot/commands/template.js.map +1 -1
- package/dist/src/platforms/wechatbot/commands/user.d.ts.map +1 -1
- package/dist/src/platforms/wechatbot/commands/user.js +1 -6
- package/dist/src/platforms/wechatbot/commands/user.js.map +1 -1
- package/dist/src/platforms/wechatbot/commands/whoami.d.ts.map +1 -1
- package/dist/src/platforms/wechatbot/commands/whoami.js +1 -6
- package/dist/src/platforms/wechatbot/commands/whoami.js.map +1 -1
- package/dist/src/platforms/whatsappbot/cli.d.ts.map +1 -1
- package/dist/src/platforms/whatsappbot/cli.js +11 -1
- package/dist/src/platforms/whatsappbot/cli.js.map +1 -1
- package/dist/src/platforms/whatsappbot/commands/auth.d.ts.map +1 -1
- package/dist/src/platforms/whatsappbot/commands/auth.js +1 -5
- package/dist/src/platforms/whatsappbot/commands/auth.js.map +1 -1
- package/dist/src/platforms/whatsappbot/commands/message.d.ts.map +1 -1
- package/dist/src/platforms/whatsappbot/commands/message.js +1 -6
- package/dist/src/platforms/whatsappbot/commands/message.js.map +1 -1
- package/dist/src/platforms/whatsappbot/commands/template.d.ts.map +1 -1
- package/dist/src/platforms/whatsappbot/commands/template.js +1 -6
- package/dist/src/platforms/whatsappbot/commands/template.js.map +1 -1
- package/dist/src/platforms/whatsappbot/commands/whoami.d.ts.map +1 -1
- package/dist/src/platforms/whatsappbot/commands/whoami.js +1 -6
- package/dist/src/platforms/whatsappbot/commands/whoami.js.map +1 -1
- package/dist/src/shared/chromium/browsers.d.ts +8 -0
- package/dist/src/shared/chromium/browsers.d.ts.map +1 -1
- package/dist/src/shared/chromium/browsers.js +58 -3
- package/dist/src/shared/chromium/browsers.js.map +1 -1
- package/dist/src/shared/chromium/cli-options.d.ts +5 -0
- package/dist/src/shared/chromium/cli-options.d.ts.map +1 -0
- package/dist/src/shared/chromium/cli-options.js +8 -0
- package/dist/src/shared/chromium/cli-options.js.map +1 -0
- package/dist/src/shared/chromium/index.d.ts +3 -1
- package/dist/src/shared/chromium/index.d.ts.map +1 -1
- package/dist/src/shared/chromium/index.js +2 -1
- package/dist/src/shared/chromium/index.js.map +1 -1
- package/dist/src/shared/utils/cli-output.d.ts +7 -0
- package/dist/src/shared/utils/cli-output.d.ts.map +1 -0
- package/dist/src/shared/utils/cli-output.js +7 -0
- package/dist/src/shared/utils/cli-output.js.map +1 -0
- package/dist/src/tui/app.d.ts.map +1 -1
- package/dist/src/tui/app.js +73 -20
- package/dist/src/tui/app.js.map +1 -1
- package/docs/content/docs/cli/channeltalk.mdx +4 -0
- package/docs/content/docs/cli/discord.mdx +5 -0
- package/docs/content/docs/cli/instagram.mdx +3 -0
- package/docs/content/docs/cli/slack.mdx +5 -0
- package/docs/content/docs/cli/slackbot.mdx +60 -22
- package/docs/content/docs/cli/teams.mdx +5 -0
- package/docs/content/docs/cli/webex.mdx +3 -0
- package/docs/content/docs/sdk/channeltalkbot.mdx +38 -1
- package/docs/content/docs/sdk/discordbot.mdx +501 -0
- package/docs/content/docs/sdk/meta.json +2 -0
- package/docs/content/docs/sdk/slackbot.mdx +576 -0
- package/e2e/README.md +1 -1
- package/e2e/config.ts +9 -4
- package/examples/discordbot-listen.ts +65 -0
- package/examples/slackbot-listen.ts +65 -0
- package/package.json +21 -1
- package/skills/agent-channeltalk/SKILL.md +5 -1
- package/skills/agent-channeltalk/references/authentication.md +5 -1
- package/skills/agent-channeltalkbot/SKILL.md +17 -3
- package/skills/agent-channeltalkbot/references/authentication.md +7 -5
- package/skills/agent-discord/SKILL.md +5 -1
- package/skills/agent-discord/references/authentication.md +7 -1
- package/skills/agent-discordbot/SKILL.md +13 -2
- package/skills/agent-discordbot/references/common-patterns.md +1 -1
- package/skills/agent-instagram/SKILL.md +7 -1
- package/skills/agent-instagram/references/authentication.md +6 -0
- package/skills/agent-kakaotalk/SKILL.md +1 -1
- package/skills/agent-line/SKILL.md +1 -1
- package/skills/agent-slack/SKILL.md +5 -1
- package/skills/agent-slack/references/authentication.md +7 -1
- package/skills/agent-slackbot/SKILL.md +56 -4
- package/skills/agent-slackbot/references/authentication.md +4 -0
- package/skills/agent-teams/SKILL.md +5 -1
- package/skills/agent-teams/references/authentication.md +7 -1
- package/skills/agent-telegram/SKILL.md +1 -1
- package/skills/agent-webex/SKILL.md +7 -1
- package/skills/agent-webex/references/authentication.md +6 -0
- package/skills/agent-wechatbot/SKILL.md +16 -1
- package/skills/agent-wechatbot/references/authentication.md +219 -0
- package/skills/agent-wechatbot/references/common-patterns.md +358 -0
- package/skills/agent-wechatbot/templates/account-summary.sh +122 -0
- package/skills/agent-wechatbot/templates/post-message.sh +122 -0
- package/skills/agent-wechatbot/templates/send-template.sh +152 -0
- package/skills/agent-whatsapp/SKILL.md +1 -1
- package/skills/agent-whatsappbot/SKILL.md +30 -1
- package/src/platforms/channeltalk/commands/auth.test.ts +15 -3
- package/src/platforms/channeltalk/commands/auth.ts +15 -5
- package/src/platforms/channeltalk/token-extractor.ts +24 -5
- package/src/platforms/channeltalkbot/cli.ts +9 -0
- package/src/platforms/channeltalkbot/commands/auth.ts +1 -5
- package/src/platforms/channeltalkbot/commands/bot.ts +1 -6
- package/src/platforms/channeltalkbot/commands/chat.ts +1 -6
- package/src/platforms/channeltalkbot/commands/group.ts +1 -6
- package/src/platforms/channeltalkbot/commands/manager.ts +1 -6
- package/src/platforms/channeltalkbot/commands/message.ts +1 -6
- package/src/platforms/channeltalkbot/commands/whoami.test.ts +2 -0
- package/src/platforms/channeltalkbot/commands/whoami.ts +1 -6
- package/src/platforms/channeltalkbot/credential-manager.test.ts +96 -2
- package/src/platforms/channeltalkbot/credential-manager.ts +37 -4
- package/src/platforms/discord/commands/auth.ts +13 -2
- package/src/platforms/discord/listener.test.ts +59 -1
- package/src/platforms/discord/listener.ts +43 -19
- package/src/platforms/discord/token-extractor.ts +30 -6
- package/src/platforms/discordbot/cli.ts +10 -0
- package/src/platforms/discordbot/client.ts +4 -0
- package/src/platforms/discordbot/commands/auth.ts +1 -5
- package/src/platforms/discordbot/commands/message.ts +1 -6
- package/src/platforms/discordbot/commands/server.ts +1 -5
- package/src/platforms/discordbot/commands/whoami.ts +1 -6
- package/src/platforms/discordbot/index.test.ts +82 -0
- package/src/platforms/discordbot/index.ts +27 -9
- package/src/platforms/discordbot/listener.test.ts +1002 -0
- package/src/platforms/discordbot/listener.ts +321 -0
- package/src/platforms/discordbot/types.ts +163 -0
- package/src/platforms/instagram/commands/auth.ts +9 -1
- package/src/platforms/instagram/token-extractor.ts +13 -1
- package/src/platforms/slack/commands/auth.ts +11 -2
- package/src/platforms/slack/token-extractor.test.ts +96 -0
- package/src/platforms/slack/token-extractor.ts +76 -13
- package/src/platforms/slackbot/cli.ts +13 -1
- package/src/platforms/slackbot/client.test.ts +274 -0
- package/src/platforms/slackbot/client.ts +130 -2
- package/src/platforms/slackbot/commands/auth.ts +1 -5
- package/src/platforms/slackbot/commands/file.test.ts +201 -0
- package/src/platforms/slackbot/commands/file.ts +212 -0
- package/src/platforms/slackbot/commands/index.ts +1 -0
- package/src/platforms/slackbot/commands/message.ts +22 -0
- package/src/platforms/slackbot/commands/whoami.ts +1 -6
- package/src/platforms/slackbot/credential-manager.test.ts +62 -2
- package/src/platforms/slackbot/credential-manager.ts +32 -2
- package/src/platforms/slackbot/index.test.ts +59 -0
- package/src/platforms/slackbot/index.ts +31 -7
- package/src/platforms/slackbot/listener.test.ts +1012 -0
- package/src/platforms/slackbot/listener.ts +362 -0
- package/src/platforms/slackbot/types.ts +224 -1
- package/src/platforms/teams/commands/auth.test.ts +1 -1
- package/src/platforms/teams/commands/auth.ts +66 -7
- package/src/platforms/teams/ensure-auth.test.ts +56 -5
- package/src/platforms/teams/ensure-auth.ts +39 -11
- package/src/platforms/teams/token-extractor.test.ts +146 -24
- package/src/platforms/teams/token-extractor.ts +87 -29
- package/src/platforms/webex/commands/auth.ts +13 -2
- package/src/platforms/webex/token-extractor.ts +25 -3
- package/src/platforms/wechatbot/cli.ts +9 -0
- package/src/platforms/wechatbot/commands/auth.ts +1 -5
- package/src/platforms/wechatbot/commands/message.ts +1 -6
- package/src/platforms/wechatbot/commands/template.ts +1 -6
- package/src/platforms/wechatbot/commands/user.ts +1 -6
- package/src/platforms/wechatbot/commands/whoami.ts +1 -6
- package/src/platforms/whatsappbot/cli.ts +9 -0
- package/src/platforms/whatsappbot/commands/auth.ts +1 -5
- package/src/platforms/whatsappbot/commands/message.ts +1 -6
- package/src/platforms/whatsappbot/commands/template.ts +1 -6
- package/src/platforms/whatsappbot/commands/whoami.ts +1 -6
- package/src/shared/chromium/browsers.test.ts +80 -0
- package/src/shared/chromium/browsers.ts +72 -3
- package/src/shared/chromium/cli-options.test.ts +22 -0
- package/src/shared/chromium/cli-options.ts +12 -0
- package/src/shared/chromium/index.ts +3 -0
- package/src/shared/utils/cli-output.test.ts +57 -0
- package/src/shared/utils/cli-output.ts +8 -0
- package/src/tui/app.ts +129 -20
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
#
|
|
3
|
+
# account-summary.sh - Generate a summary of the WeChat Official Account, templates, and followers
|
|
4
|
+
#
|
|
5
|
+
# Usage:
|
|
6
|
+
# ./account-summary.sh [--json]
|
|
7
|
+
#
|
|
8
|
+
# Options:
|
|
9
|
+
# --json Output raw JSON instead of formatted text
|
|
10
|
+
#
|
|
11
|
+
# Example:
|
|
12
|
+
# ./account-summary.sh
|
|
13
|
+
# ./account-summary.sh --json > summary.json
|
|
14
|
+
|
|
15
|
+
set -euo pipefail
|
|
16
|
+
|
|
17
|
+
OUTPUT_JSON=false
|
|
18
|
+
if [ $# -gt 0 ] && [ "$1" = "--json" ]; then
|
|
19
|
+
OUTPUT_JSON=true
|
|
20
|
+
fi
|
|
21
|
+
|
|
22
|
+
RED='\033[0;31m'
|
|
23
|
+
GREEN='\033[0;32m'
|
|
24
|
+
YELLOW='\033[1;33m'
|
|
25
|
+
BLUE='\033[0;34m'
|
|
26
|
+
CYAN='\033[0;36m'
|
|
27
|
+
BOLD='\033[1m'
|
|
28
|
+
NC='\033[0m'
|
|
29
|
+
|
|
30
|
+
if ! command -v agent-wechatbot &> /dev/null; then
|
|
31
|
+
echo -e "${RED}Error: agent-wechatbot not found${NC}" >&2
|
|
32
|
+
echo "" >&2
|
|
33
|
+
echo "Install it with:" >&2
|
|
34
|
+
echo " npm install -g agent-messenger" >&2
|
|
35
|
+
exit 1
|
|
36
|
+
fi
|
|
37
|
+
|
|
38
|
+
AUTH_STATUS=$(agent-wechatbot auth status 2>&1) || true
|
|
39
|
+
|
|
40
|
+
if echo "$AUTH_STATUS" | jq -e '.error' > /dev/null 2>&1; then
|
|
41
|
+
echo -e "${RED}Not authenticated!${NC}" >&2
|
|
42
|
+
echo "" >&2
|
|
43
|
+
echo "Run this to authenticate:" >&2
|
|
44
|
+
echo " agent-wechatbot auth set <app-id> <app-secret>" >&2
|
|
45
|
+
exit 1
|
|
46
|
+
fi
|
|
47
|
+
|
|
48
|
+
echo -e "${YELLOW}Fetching templates and followers...${NC}" >&2
|
|
49
|
+
TEMPLATES_RESULT=$(agent-wechatbot template list 2>&1) || true
|
|
50
|
+
USERS_RESULT=$(agent-wechatbot user list 2>&1) || true
|
|
51
|
+
|
|
52
|
+
if [ "$OUTPUT_JSON" = true ]; then
|
|
53
|
+
jq -n \
|
|
54
|
+
--argjson auth "$AUTH_STATUS" \
|
|
55
|
+
--argjson templates "$TEMPLATES_RESULT" \
|
|
56
|
+
--argjson users "$USERS_RESULT" \
|
|
57
|
+
'{"auth": $auth, "templates": $templates, "users": $users}'
|
|
58
|
+
exit 0
|
|
59
|
+
fi
|
|
60
|
+
|
|
61
|
+
APP_ID=$(echo "$AUTH_STATUS" | jq -r '.app_id // "Unknown"')
|
|
62
|
+
ACCOUNT_NAME=$(echo "$AUTH_STATUS" | jq -r '.account_name // "Unknown"')
|
|
63
|
+
|
|
64
|
+
TEMPLATES=$(echo "$TEMPLATES_RESULT" | jq '.template_list // []' 2>/dev/null || echo '[]')
|
|
65
|
+
TEMPLATE_COUNT=$(echo "$TEMPLATES" | jq 'length')
|
|
66
|
+
|
|
67
|
+
FOLLOWER_TOTAL=$(echo "$USERS_RESULT" | jq -r '.total // 0' 2>/dev/null || echo '0')
|
|
68
|
+
FOLLOWER_COUNT=$(echo "$USERS_RESULT" | jq -r '.count // 0' 2>/dev/null || echo '0')
|
|
69
|
+
|
|
70
|
+
echo ""
|
|
71
|
+
echo -e "${BOLD}${BLUE}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}"
|
|
72
|
+
echo -e "${BOLD}${BLUE} WeChat Official Account Summary${NC}"
|
|
73
|
+
echo -e "${BOLD}${BLUE}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}"
|
|
74
|
+
echo ""
|
|
75
|
+
echo -e "${BOLD}Account:${NC} $ACCOUNT_NAME"
|
|
76
|
+
echo -e "${BOLD}App ID:${NC} $APP_ID"
|
|
77
|
+
echo ""
|
|
78
|
+
|
|
79
|
+
echo -e "${BOLD}${CYAN}Followers${NC}"
|
|
80
|
+
echo " Total: $FOLLOWER_TOTAL"
|
|
81
|
+
echo " This page: $FOLLOWER_COUNT"
|
|
82
|
+
echo ""
|
|
83
|
+
|
|
84
|
+
echo -e "${BOLD}${CYAN}Templates (${TEMPLATE_COUNT} total)${NC}"
|
|
85
|
+
if [ "$TEMPLATE_COUNT" -gt 0 ]; then
|
|
86
|
+
echo "$TEMPLATES" | jq -r '
|
|
87
|
+
.[0:10] |
|
|
88
|
+
.[] |
|
|
89
|
+
" \(.template_id) — \(.title)"
|
|
90
|
+
'
|
|
91
|
+
if [ "$TEMPLATE_COUNT" -gt 10 ]; then
|
|
92
|
+
echo " ... and $((TEMPLATE_COUNT - 10)) more"
|
|
93
|
+
fi
|
|
94
|
+
else
|
|
95
|
+
echo " (no templates approved yet)"
|
|
96
|
+
fi
|
|
97
|
+
echo ""
|
|
98
|
+
|
|
99
|
+
echo -e "${BOLD}${CYAN}Quick Actions:${NC}"
|
|
100
|
+
echo ""
|
|
101
|
+
echo -e " ${GREEN}# Send a customer service message (within 48h window)${NC}"
|
|
102
|
+
echo -e " agent-wechatbot message send oABCD1234 \"Hello!\""
|
|
103
|
+
echo ""
|
|
104
|
+
echo -e " ${GREEN}# Send a template notification (anytime)${NC}"
|
|
105
|
+
FIRST_TEMPLATE=$(echo "$TEMPLATES" | jq -r '.[0].template_id // "TM00001"')
|
|
106
|
+
echo -e " agent-wechatbot template send oABCD1234 $FIRST_TEMPLATE --data '{...}'"
|
|
107
|
+
echo ""
|
|
108
|
+
echo -e " ${GREEN}# List all templates${NC}"
|
|
109
|
+
echo -e " agent-wechatbot template list"
|
|
110
|
+
echo ""
|
|
111
|
+
|
|
112
|
+
echo -e "${BOLD}${BLUE}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}"
|
|
113
|
+
echo ""
|
|
114
|
+
|
|
115
|
+
SUMMARY_FILE="account-summary-$(date +%Y%m%d-%H%M%S).json"
|
|
116
|
+
jq -n \
|
|
117
|
+
--argjson auth "$AUTH_STATUS" \
|
|
118
|
+
--argjson templates "$TEMPLATES_RESULT" \
|
|
119
|
+
--argjson users "$USERS_RESULT" \
|
|
120
|
+
'{"auth": $auth, "templates": $templates, "users": $users}' > "$SUMMARY_FILE"
|
|
121
|
+
echo -e "${GREEN}✓ Full data saved to: $SUMMARY_FILE${NC}"
|
|
122
|
+
echo ""
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
#
|
|
3
|
+
# post-message.sh - Send a customer service message via WeChat Official Account API
|
|
4
|
+
#
|
|
5
|
+
# Usage:
|
|
6
|
+
# ./post-message.sh <openid> <message>
|
|
7
|
+
#
|
|
8
|
+
# Arguments:
|
|
9
|
+
# openid - Recipient OpenID (e.g. oABCD1234)
|
|
10
|
+
# message - Message text to send
|
|
11
|
+
#
|
|
12
|
+
# Example:
|
|
13
|
+
# ./post-message.sh oABCD1234 "Hello from script!"
|
|
14
|
+
# ./post-message.sh oABCD1234 "Thanks for your purchase ✅"
|
|
15
|
+
#
|
|
16
|
+
# Note: Customer service messages only work within the 48-hour interaction window.
|
|
17
|
+
# Outside that window, use template messages via send-template.sh.
|
|
18
|
+
|
|
19
|
+
set -euo pipefail
|
|
20
|
+
|
|
21
|
+
# Check arguments
|
|
22
|
+
if [ $# -lt 2 ]; then
|
|
23
|
+
echo "Usage: $0 <openid> <message>"
|
|
24
|
+
echo ""
|
|
25
|
+
echo "Examples:"
|
|
26
|
+
echo " $0 oABCD1234 'Hello world!'"
|
|
27
|
+
echo " $0 oABCD1234 'Build completed'"
|
|
28
|
+
exit 1
|
|
29
|
+
fi
|
|
30
|
+
|
|
31
|
+
OPENID="$1"
|
|
32
|
+
MESSAGE="$2"
|
|
33
|
+
|
|
34
|
+
# Colors for output
|
|
35
|
+
RED='\033[0;31m'
|
|
36
|
+
GREEN='\033[0;32m'
|
|
37
|
+
YELLOW='\033[1;33m'
|
|
38
|
+
NC='\033[0m' # No Color
|
|
39
|
+
|
|
40
|
+
# Function to send message with retry logic
|
|
41
|
+
send_message() {
|
|
42
|
+
local openid=$1
|
|
43
|
+
local message=$2
|
|
44
|
+
local max_attempts=3
|
|
45
|
+
local attempt=1
|
|
46
|
+
|
|
47
|
+
while [ $attempt -le $max_attempts ]; do
|
|
48
|
+
echo -e "${YELLOW}Attempt $attempt/$max_attempts...${NC}"
|
|
49
|
+
|
|
50
|
+
# Send message and capture result
|
|
51
|
+
RESULT=$(agent-wechatbot message send "$openid" "$message" 2>&1) || true
|
|
52
|
+
|
|
53
|
+
# Check if successful (no error field)
|
|
54
|
+
if ! echo "$RESULT" | jq -e '.error' > /dev/null 2>&1; then
|
|
55
|
+
echo -e "${GREEN}✓ Message sent successfully!${NC}"
|
|
56
|
+
echo ""
|
|
57
|
+
echo "Message details:"
|
|
58
|
+
echo " To OpenID: $openid"
|
|
59
|
+
return 0
|
|
60
|
+
fi
|
|
61
|
+
|
|
62
|
+
# Extract error information
|
|
63
|
+
ERROR_MSG=$(echo "$RESULT" | jq -r '.error // "Unknown error"')
|
|
64
|
+
echo -e "${RED}✗ Failed: $ERROR_MSG${NC}"
|
|
65
|
+
|
|
66
|
+
# Don't retry on certain errors
|
|
67
|
+
if echo "$ERROR_MSG" | grep -qE "40164|IP whitelist"; then
|
|
68
|
+
echo -e "${RED}IP not in WeChat whitelist. Add your server IP in the admin panel.${NC}"
|
|
69
|
+
return 1
|
|
70
|
+
fi
|
|
71
|
+
|
|
72
|
+
if echo "$ERROR_MSG" | grep -qE "48h|48-hour"; then
|
|
73
|
+
echo -e "${YELLOW}Outside 48h window. Use a template message instead:${NC}"
|
|
74
|
+
echo " ./send-template.sh $openid <template-id> --data '...'"
|
|
75
|
+
return 1
|
|
76
|
+
fi
|
|
77
|
+
|
|
78
|
+
# Exponential backoff before retry
|
|
79
|
+
if [ $attempt -lt $max_attempts ]; then
|
|
80
|
+
SLEEP_TIME=$((attempt * 2))
|
|
81
|
+
echo "Retrying in ${SLEEP_TIME}s..."
|
|
82
|
+
sleep $SLEEP_TIME
|
|
83
|
+
fi
|
|
84
|
+
|
|
85
|
+
attempt=$((attempt + 1))
|
|
86
|
+
done
|
|
87
|
+
|
|
88
|
+
echo -e "${RED}Failed after $max_attempts attempts${NC}"
|
|
89
|
+
return 1
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
# Check if agent-wechatbot is installed
|
|
93
|
+
if ! command -v agent-wechatbot &> /dev/null; then
|
|
94
|
+
echo -e "${RED}Error: agent-wechatbot not found${NC}"
|
|
95
|
+
echo ""
|
|
96
|
+
echo "Install it with:"
|
|
97
|
+
echo " npm install -g agent-messenger"
|
|
98
|
+
exit 1
|
|
99
|
+
fi
|
|
100
|
+
|
|
101
|
+
# Check authentication
|
|
102
|
+
echo "Checking authentication..."
|
|
103
|
+
AUTH_STATUS=$(agent-wechatbot auth status 2>&1) || true
|
|
104
|
+
|
|
105
|
+
if echo "$AUTH_STATUS" | jq -e '.error' > /dev/null 2>&1; then
|
|
106
|
+
echo -e "${RED}Not authenticated!${NC}"
|
|
107
|
+
echo ""
|
|
108
|
+
echo "Run this to authenticate:"
|
|
109
|
+
echo " agent-wechatbot auth set <app-id> <app-secret>"
|
|
110
|
+
exit 1
|
|
111
|
+
fi
|
|
112
|
+
|
|
113
|
+
APP_ID=$(echo "$AUTH_STATUS" | jq -r '.app_id // "Unknown"')
|
|
114
|
+
echo -e "${GREEN}✓ Authenticated (App ID: $APP_ID)${NC}"
|
|
115
|
+
echo ""
|
|
116
|
+
|
|
117
|
+
# Send the message
|
|
118
|
+
echo "Sending message to $OPENID..."
|
|
119
|
+
echo "Message: $MESSAGE"
|
|
120
|
+
echo ""
|
|
121
|
+
|
|
122
|
+
send_message "$OPENID" "$MESSAGE"
|
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
#
|
|
3
|
+
# send-template.sh - Send a WeChat template message via Official Account API
|
|
4
|
+
#
|
|
5
|
+
# Usage:
|
|
6
|
+
# ./send-template.sh <openid> <template-id> --data <json> [--url <url>]
|
|
7
|
+
#
|
|
8
|
+
# Arguments:
|
|
9
|
+
# openid - Recipient follower OpenID (e.g. oABCD1234)
|
|
10
|
+
# template-id - Pre-approved template ID (e.g. TM00001)
|
|
11
|
+
#
|
|
12
|
+
# Options:
|
|
13
|
+
# --data <json> - Required. JSON object with template parameters.
|
|
14
|
+
# Format: {"<param>":{"value":"<text>","color":"<#hex>"}}
|
|
15
|
+
# --url <url> - Optional. URL the message links to when tapped.
|
|
16
|
+
#
|
|
17
|
+
# Example:
|
|
18
|
+
# ./send-template.sh oABCD1234 TM00001 \
|
|
19
|
+
# --data '{"order_id":{"value":"ORD-9876"},"customer_name":{"value":"Alice"}}'
|
|
20
|
+
#
|
|
21
|
+
# ./send-template.sh oABCD1234 TM00001 \
|
|
22
|
+
# --data '{"status":{"value":"shipped","color":"#00AA00"}}' \
|
|
23
|
+
# --url "https://example.com/orders/9876"
|
|
24
|
+
|
|
25
|
+
set -euo pipefail
|
|
26
|
+
|
|
27
|
+
if [ $# -lt 2 ]; then
|
|
28
|
+
echo "Usage: $0 <openid> <template-id> --data <json> [--url <url>]"
|
|
29
|
+
echo ""
|
|
30
|
+
echo "Examples:"
|
|
31
|
+
echo " $0 oABCD1234 TM00001 --data '{\"order_id\":{\"value\":\"ORD-001\"}}'"
|
|
32
|
+
echo " $0 oABCD1234 TM00001 --data '{...}' --url https://example.com/path"
|
|
33
|
+
exit 1
|
|
34
|
+
fi
|
|
35
|
+
|
|
36
|
+
OPENID="$1"
|
|
37
|
+
TEMPLATE_ID="$2"
|
|
38
|
+
shift 2
|
|
39
|
+
|
|
40
|
+
DATA=""
|
|
41
|
+
URL=""
|
|
42
|
+
|
|
43
|
+
while [ $# -gt 0 ]; do
|
|
44
|
+
case "$1" in
|
|
45
|
+
--data)
|
|
46
|
+
if [ $# -lt 2 ]; then
|
|
47
|
+
echo "Error: --data requires a JSON value"
|
|
48
|
+
exit 1
|
|
49
|
+
fi
|
|
50
|
+
DATA="$2"
|
|
51
|
+
shift 2
|
|
52
|
+
;;
|
|
53
|
+
--url)
|
|
54
|
+
if [ $# -lt 2 ]; then
|
|
55
|
+
echo "Error: --url requires a value"
|
|
56
|
+
exit 1
|
|
57
|
+
fi
|
|
58
|
+
URL="$2"
|
|
59
|
+
shift 2
|
|
60
|
+
;;
|
|
61
|
+
*)
|
|
62
|
+
echo "Unknown option: $1"
|
|
63
|
+
exit 1
|
|
64
|
+
;;
|
|
65
|
+
esac
|
|
66
|
+
done
|
|
67
|
+
|
|
68
|
+
if [ -z "$DATA" ]; then
|
|
69
|
+
echo "Error: --data is required"
|
|
70
|
+
exit 1
|
|
71
|
+
fi
|
|
72
|
+
|
|
73
|
+
RED='\033[0;31m'
|
|
74
|
+
GREEN='\033[0;32m'
|
|
75
|
+
YELLOW='\033[1;33m'
|
|
76
|
+
NC='\033[0m'
|
|
77
|
+
|
|
78
|
+
# Check if agent-wechatbot is installed
|
|
79
|
+
if ! command -v agent-wechatbot &> /dev/null; then
|
|
80
|
+
echo -e "${RED}Error: agent-wechatbot not found${NC}"
|
|
81
|
+
echo ""
|
|
82
|
+
echo "Install it with:"
|
|
83
|
+
echo " npm install -g agent-messenger"
|
|
84
|
+
exit 1
|
|
85
|
+
fi
|
|
86
|
+
|
|
87
|
+
# Check authentication
|
|
88
|
+
echo "Checking authentication..."
|
|
89
|
+
AUTH_STATUS=$(agent-wechatbot auth status 2>&1) || true
|
|
90
|
+
|
|
91
|
+
if echo "$AUTH_STATUS" | jq -e '.error' > /dev/null 2>&1; then
|
|
92
|
+
echo -e "${RED}Not authenticated!${NC}"
|
|
93
|
+
echo ""
|
|
94
|
+
echo "Run this to authenticate:"
|
|
95
|
+
echo " agent-wechatbot auth set <app-id> <app-secret>"
|
|
96
|
+
exit 1
|
|
97
|
+
fi
|
|
98
|
+
|
|
99
|
+
APP_ID=$(echo "$AUTH_STATUS" | jq -r '.app_id // "Unknown"')
|
|
100
|
+
echo -e "${GREEN}✓ Authenticated (App ID: $APP_ID)${NC}"
|
|
101
|
+
echo ""
|
|
102
|
+
|
|
103
|
+
# Send template message with retry
|
|
104
|
+
max_attempts=3
|
|
105
|
+
attempt=1
|
|
106
|
+
|
|
107
|
+
echo "Sending template '$TEMPLATE_ID' to $OPENID..."
|
|
108
|
+
if [ -n "$URL" ]; then
|
|
109
|
+
echo "URL: $URL"
|
|
110
|
+
fi
|
|
111
|
+
echo ""
|
|
112
|
+
|
|
113
|
+
while [ $attempt -le $max_attempts ]; do
|
|
114
|
+
echo -e "${YELLOW}Attempt $attempt/$max_attempts...${NC}"
|
|
115
|
+
|
|
116
|
+
if [ -n "$URL" ]; then
|
|
117
|
+
RESULT=$(agent-wechatbot template send "$OPENID" "$TEMPLATE_ID" --data "$DATA" --url "$URL" 2>&1) || true
|
|
118
|
+
else
|
|
119
|
+
RESULT=$(agent-wechatbot template send "$OPENID" "$TEMPLATE_ID" --data "$DATA" 2>&1) || true
|
|
120
|
+
fi
|
|
121
|
+
|
|
122
|
+
if ! echo "$RESULT" | jq -e '.error' > /dev/null 2>&1; then
|
|
123
|
+
echo -e "${GREEN}✓ Template message sent successfully!${NC}"
|
|
124
|
+
echo ""
|
|
125
|
+
echo "Message details:"
|
|
126
|
+
echo " To OpenID: $OPENID"
|
|
127
|
+
echo " Template: $TEMPLATE_ID"
|
|
128
|
+
if [ -n "$URL" ]; then
|
|
129
|
+
echo " URL: $URL"
|
|
130
|
+
fi
|
|
131
|
+
exit 0
|
|
132
|
+
fi
|
|
133
|
+
|
|
134
|
+
ERROR_MSG=$(echo "$RESULT" | jq -r '.error // "Unknown error"')
|
|
135
|
+
echo -e "${RED}✗ Failed: $ERROR_MSG${NC}"
|
|
136
|
+
|
|
137
|
+
# Don't retry on permanent errors
|
|
138
|
+
if echo "$ERROR_MSG" | grep -qE "40164|IP whitelist|40125|Invalid App"; then
|
|
139
|
+
exit 1
|
|
140
|
+
fi
|
|
141
|
+
|
|
142
|
+
if [ $attempt -lt $max_attempts ]; then
|
|
143
|
+
SLEEP_TIME=$((attempt * 2))
|
|
144
|
+
echo "Retrying in ${SLEEP_TIME}s..."
|
|
145
|
+
sleep $SLEEP_TIME
|
|
146
|
+
fi
|
|
147
|
+
|
|
148
|
+
attempt=$((attempt + 1))
|
|
149
|
+
done
|
|
150
|
+
|
|
151
|
+
echo -e "${RED}Failed after $max_attempts attempts${NC}"
|
|
152
|
+
exit 1
|
|
@@ -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.
|
|
4
|
+
version: 2.11.1
|
|
5
5
|
allowed-tools: Bash(agent-whatsappbot:*)
|
|
6
6
|
metadata:
|
|
7
7
|
openclaw:
|
|
@@ -245,6 +245,8 @@ agent-whatsappbot template list --pretty
|
|
|
245
245
|
|
|
246
246
|
## Common Patterns
|
|
247
247
|
|
|
248
|
+
See `references/common-patterns.md` for additional workflows.
|
|
249
|
+
|
|
248
250
|
### Send a notification outside the 24h window
|
|
249
251
|
|
|
250
252
|
Template messages are required when the customer hasn't messaged you in the last 24 hours. Always check your available templates first:
|
|
@@ -286,6 +288,14 @@ agent-whatsappbot message send-template 15559876543 deployment_alert \
|
|
|
286
288
|
--components '[{"type":"body","parameters":[{"type":"text","text":"v2.1.0"},{"type":"text","text":"production"},{"type":"text","text":"success"}]}]'
|
|
287
289
|
```
|
|
288
290
|
|
|
291
|
+
## Templates
|
|
292
|
+
|
|
293
|
+
See `templates/` directory for runnable examples:
|
|
294
|
+
|
|
295
|
+
- `post-message.sh` - Send messages with error handling and retries
|
|
296
|
+
- `account-summary.sh` - Generate account and template summary
|
|
297
|
+
- `send-template.sh` - Send a template message with parameters
|
|
298
|
+
|
|
289
299
|
## Error Handling
|
|
290
300
|
|
|
291
301
|
All commands return consistent error format:
|
|
@@ -318,6 +328,20 @@ Config format:
|
|
|
318
328
|
}
|
|
319
329
|
```
|
|
320
330
|
|
|
331
|
+
## Key Differences from agent-whatsapp
|
|
332
|
+
|
|
333
|
+
| Feature | agent-whatsapp | agent-whatsappbot |
|
|
334
|
+
| ----------------- | ------------------------------------ | ---------------------------------- |
|
|
335
|
+
| Auth type | User account (Baileys, QR/pairing) | Cloud API (Phone Number ID + Token) |
|
|
336
|
+
| Token source | Pairing flow with phone number | Meta Business Manager |
|
|
337
|
+
| Read messages | Yes | No (webhook-only inbound) |
|
|
338
|
+
| Group chats | Yes | No |
|
|
339
|
+
| Template messages | No | Yes (required outside 24h window) |
|
|
340
|
+
| Free-form text | Anytime | Only within 24h customer window |
|
|
341
|
+
| Media uploads | Direct (local files) | URL only |
|
|
342
|
+
| Multi-account | Multi-phone, single CLI session | Multi-account by Phone Number ID |
|
|
343
|
+
| CI/CD friendly | Requires phone, pairing flow | Yes (just set token) |
|
|
344
|
+
|
|
321
345
|
## Limitations
|
|
322
346
|
|
|
323
347
|
- **Cannot list or read received messages** — WhatsApp Cloud API delivers inbound messages via webhooks only. This CLI is send-only.
|
|
@@ -378,3 +402,8 @@ WhatsApp enforces rate limits based on your business tier. The CLI automatically
|
|
|
378
402
|
- Use full international format without `+` prefix (e.g., `15551234567` not `+1-555-123-4567`)
|
|
379
403
|
- If outside the 24h window, use `message send-template` instead of `message send`
|
|
380
404
|
- Check that your WhatsApp Business account is active and not restricted
|
|
405
|
+
|
|
406
|
+
## References
|
|
407
|
+
|
|
408
|
+
- [Authentication Guide](references/authentication.md)
|
|
409
|
+
- [Common Patterns](references/common-patterns.md)
|
|
@@ -20,6 +20,9 @@ const mockListChannels = mock(() =>
|
|
|
20
20
|
]),
|
|
21
21
|
)
|
|
22
22
|
const mockExtract = mock(() => Promise.resolve([{ accountCookie: 'fresh-account', sessionCookie: 'fresh-session' }]))
|
|
23
|
+
const mockCreateTokenExtractor = mock((_browserProfile?: string[]) => ({
|
|
24
|
+
extract: mockExtract,
|
|
25
|
+
}))
|
|
23
26
|
|
|
24
27
|
import {
|
|
25
28
|
clearAction,
|
|
@@ -89,9 +92,7 @@ setChannelAuthCommandDependenciesForTesting({
|
|
|
89
92
|
return true
|
|
90
93
|
},
|
|
91
94
|
}),
|
|
92
|
-
createTokenExtractor:
|
|
93
|
-
extract: mockExtract,
|
|
94
|
-
}),
|
|
95
|
+
createTokenExtractor: mockCreateTokenExtractor,
|
|
95
96
|
})
|
|
96
97
|
|
|
97
98
|
describe('channel auth commands', () => {
|
|
@@ -105,6 +106,7 @@ describe('channel auth commands', () => {
|
|
|
105
106
|
mockGetAccount.mockReset()
|
|
106
107
|
mockListChannels.mockReset()
|
|
107
108
|
mockExtract.mockReset()
|
|
109
|
+
mockCreateTokenExtractor.mockReset()
|
|
108
110
|
|
|
109
111
|
mockGetAccount.mockImplementation(() => Promise.resolve({ id: 'acct-1', name: 'Alice' }))
|
|
110
112
|
mockListChannels.mockImplementation(() =>
|
|
@@ -116,6 +118,9 @@ describe('channel auth commands', () => {
|
|
|
116
118
|
mockExtract.mockImplementation(() =>
|
|
117
119
|
Promise.resolve([{ accountCookie: 'fresh-account', sessionCookie: 'fresh-session' }]),
|
|
118
120
|
)
|
|
121
|
+
mockCreateTokenExtractor.mockImplementation((_browserProfile?: string[]) => ({
|
|
122
|
+
extract: mockExtract,
|
|
123
|
+
}))
|
|
119
124
|
})
|
|
120
125
|
|
|
121
126
|
describe('extractAction', () => {
|
|
@@ -136,6 +141,13 @@ describe('channel auth commands', () => {
|
|
|
136
141
|
expect(workspaceStore.get('ws-2')?.account_cookie).toBe('fresh-account')
|
|
137
142
|
})
|
|
138
143
|
|
|
144
|
+
it('passes custom browser profile paths to the token extractor', async () => {
|
|
145
|
+
await extractAction({ browserProfile: ['/tmp/profile-a', '/tmp/profile-b'] })
|
|
146
|
+
|
|
147
|
+
expect(mockCreateTokenExtractor).toHaveBeenCalledWith(['/tmp/profile-a', '/tmp/profile-b'])
|
|
148
|
+
expect(mockExtract).toHaveBeenCalledTimes(1)
|
|
149
|
+
})
|
|
150
|
+
|
|
139
151
|
it('preserves current workspace if it still exists after re-extraction', async () => {
|
|
140
152
|
workspaceStore.set('ws-2', {
|
|
141
153
|
workspace_id: 'ws-2',
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { Command } from 'commander'
|
|
2
2
|
|
|
3
|
+
import { collectBrowserProfileOption } from '@/shared/chromium'
|
|
3
4
|
import { formatOutput } from '@/shared/utils/output'
|
|
4
5
|
|
|
5
6
|
import { ChannelClient } from '../client'
|
|
@@ -9,6 +10,7 @@ import { ChannelTokenExtractor } from '../token-extractor'
|
|
|
9
10
|
interface ActionOptions {
|
|
10
11
|
workspace?: string
|
|
11
12
|
pretty?: boolean
|
|
13
|
+
browserProfile?: string[]
|
|
12
14
|
_credManager?: ChannelCredentialManager
|
|
13
15
|
}
|
|
14
16
|
|
|
@@ -60,7 +62,8 @@ let createChannelClient: (
|
|
|
60
62
|
|
|
61
63
|
let createCredentialManager = (): ChannelCredentialManagerLike => new ChannelCredentialManager()
|
|
62
64
|
|
|
63
|
-
let createTokenExtractor = (): ChannelTokenExtractorLike =>
|
|
65
|
+
let createTokenExtractor = (browserProfile?: string[]): ChannelTokenExtractorLike =>
|
|
66
|
+
new ChannelTokenExtractor(undefined, browserProfile)
|
|
64
67
|
|
|
65
68
|
export function setChannelAuthCommandDependenciesForTesting(dependencies: {
|
|
66
69
|
createChannelClient?: (
|
|
@@ -68,7 +71,7 @@ export function setChannelAuthCommandDependenciesForTesting(dependencies: {
|
|
|
68
71
|
sessionCookie?: string,
|
|
69
72
|
) => ChannelClientLike | Promise<ChannelClientLike>
|
|
70
73
|
createCredentialManager?: () => ChannelCredentialManagerLike
|
|
71
|
-
createTokenExtractor?: () => ChannelTokenExtractorLike
|
|
74
|
+
createTokenExtractor?: (browserProfile?: string[]) => ChannelTokenExtractorLike
|
|
72
75
|
}): void {
|
|
73
76
|
if (dependencies.createChannelClient) createChannelClient = dependencies.createChannelClient
|
|
74
77
|
if (dependencies.createCredentialManager) createCredentialManager = dependencies.createCredentialManager
|
|
@@ -79,13 +82,14 @@ export function resetChannelAuthCommandDependenciesForTesting(): void {
|
|
|
79
82
|
createChannelClient = async (accountCookie: string, sessionCookie?: string): Promise<ChannelClientLike> =>
|
|
80
83
|
new ChannelClient().login({ accountCookie, sessionCookie })
|
|
81
84
|
createCredentialManager = (): ChannelCredentialManagerLike => new ChannelCredentialManager()
|
|
82
|
-
createTokenExtractor = (): ChannelTokenExtractorLike =>
|
|
85
|
+
createTokenExtractor = (browserProfile?: string[]): ChannelTokenExtractorLike =>
|
|
86
|
+
new ChannelTokenExtractor(undefined, browserProfile)
|
|
83
87
|
}
|
|
84
88
|
|
|
85
89
|
export async function extractAction(options: ActionOptions = {}): Promise<ExtractResult | ErrorResult> {
|
|
86
90
|
try {
|
|
87
91
|
const credManager = options._credManager ?? createCredentialManager()
|
|
88
|
-
const extractor = createTokenExtractor()
|
|
92
|
+
const extractor = createTokenExtractor(options.browserProfile)
|
|
89
93
|
const extracted = await extractor.extract()
|
|
90
94
|
|
|
91
95
|
if (extracted.length === 0) {
|
|
@@ -270,7 +274,13 @@ export function createAuthCommand(): Command {
|
|
|
270
274
|
new Command('extract')
|
|
271
275
|
.description('Extract cookies from Channel Talk desktop app or a supported Chromium browser')
|
|
272
276
|
.option('--pretty', 'Pretty print JSON output')
|
|
273
|
-
.
|
|
277
|
+
.option(
|
|
278
|
+
'--browser-profile <path>',
|
|
279
|
+
'Additional Chromium profile/user-data directory to scan (repeatable, comma-separated supported)',
|
|
280
|
+
collectBrowserProfileOption,
|
|
281
|
+
[],
|
|
282
|
+
)
|
|
283
|
+
.action(async (opts: { pretty?: boolean; browserProfile?: string[] }) => {
|
|
274
284
|
cliOutput(await extractAction(opts), opts.pretty)
|
|
275
285
|
}),
|
|
276
286
|
)
|
|
@@ -12,6 +12,7 @@ import {
|
|
|
12
12
|
discoverBrowserProfileDirs,
|
|
13
13
|
findLocalStatePath,
|
|
14
14
|
getBrowserBasePath,
|
|
15
|
+
getAgentBrowserProfileDirs,
|
|
15
16
|
} from '@/shared/chromium'
|
|
16
17
|
import type { KeychainVariant } from '@/shared/chromium'
|
|
17
18
|
|
|
@@ -29,9 +30,11 @@ export class ChannelTokenExtractor {
|
|
|
29
30
|
private platform: NodeJS.Platform
|
|
30
31
|
private decryptor: ChromiumCookieDecryptor
|
|
31
32
|
private cookieReader: ChromiumCookieReader
|
|
33
|
+
private customBrowserProfileDirs: string[]
|
|
32
34
|
|
|
33
|
-
constructor(platform?: NodeJS.Platform) {
|
|
35
|
+
constructor(platform?: NodeJS.Platform, customBrowserProfileDirs?: string[]) {
|
|
34
36
|
this.platform = platform ?? process.platform
|
|
37
|
+
this.customBrowserProfileDirs = customBrowserProfileDirs ?? []
|
|
35
38
|
this.cookieReader = new ChromiumCookieReader()
|
|
36
39
|
this.decryptor = new ChromiumCookieDecryptor({ platform: this.platform })
|
|
37
40
|
}
|
|
@@ -94,6 +97,11 @@ export class ChannelTokenExtractor {
|
|
|
94
97
|
}
|
|
95
98
|
}
|
|
96
99
|
|
|
100
|
+
for (const profileDir of getAgentBrowserProfileDirs({ customProfileDirs: this.customBrowserProfileDirs })) {
|
|
101
|
+
paths.push(join(profileDir, 'Cookies'))
|
|
102
|
+
paths.push(join(profileDir, 'Network', 'Cookies'))
|
|
103
|
+
}
|
|
104
|
+
|
|
97
105
|
return paths
|
|
98
106
|
}
|
|
99
107
|
|
|
@@ -105,16 +113,27 @@ export class ChannelTokenExtractor {
|
|
|
105
113
|
const results: ExtractedChannelToken[] = []
|
|
106
114
|
const seenAccounts = new Set<string>()
|
|
107
115
|
|
|
116
|
+
if (this.customBrowserProfileDirs.length > 0) {
|
|
117
|
+
for (const browserResult of await this.extractAllFromBrowserPaths()) {
|
|
118
|
+
if (!seenAccounts.has(browserResult.accountCookie)) {
|
|
119
|
+
seenAccounts.add(browserResult.accountCookie)
|
|
120
|
+
results.push(browserResult)
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
|
|
108
125
|
const desktopResult = await this.extractFromDesktopApp()
|
|
109
126
|
if (desktopResult && !seenAccounts.has(desktopResult.accountCookie)) {
|
|
110
127
|
seenAccounts.add(desktopResult.accountCookie)
|
|
111
128
|
results.push(desktopResult)
|
|
112
129
|
}
|
|
113
130
|
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
seenAccounts.
|
|
117
|
-
|
|
131
|
+
if (this.customBrowserProfileDirs.length === 0) {
|
|
132
|
+
for (const browserResult of await this.extractAllFromBrowserPaths()) {
|
|
133
|
+
if (!seenAccounts.has(browserResult.accountCookie)) {
|
|
134
|
+
seenAccounts.add(browserResult.accountCookie)
|
|
135
|
+
results.push(browserResult)
|
|
136
|
+
}
|
|
118
137
|
}
|
|
119
138
|
}
|
|
120
139
|
|
|
@@ -23,6 +23,15 @@ program
|
|
|
23
23
|
.option('--pretty', 'Pretty-print JSON output')
|
|
24
24
|
.option('--workspace <id>', 'Workspace ID to use')
|
|
25
25
|
.option('--bot <name>', 'Bot name to use for sending messages')
|
|
26
|
+
.hook('preAction', (thisCmd, actionCmd) => {
|
|
27
|
+
for (const [key, value] of Object.entries(thisCmd.opts())) {
|
|
28
|
+
if (value === undefined) continue
|
|
29
|
+
const source = actionCmd.getOptionValueSource(key)
|
|
30
|
+
if (source === undefined || source === 'default') {
|
|
31
|
+
actionCmd.setOptionValue(key, value)
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
})
|
|
26
35
|
|
|
27
36
|
program.addCommand(authCommand)
|
|
28
37
|
program.addCommand(whoamiCommand)
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { Command } from 'commander'
|
|
2
2
|
|
|
3
|
+
import { cliOutput } from '@/shared/utils/cli-output'
|
|
3
4
|
import { formatOutput } from '@/shared/utils/output'
|
|
4
5
|
|
|
5
6
|
import { ChannelBotClient } from '../client'
|
|
@@ -158,11 +159,6 @@ export async function botAction(name: string, options: ActionOptions): Promise<A
|
|
|
158
159
|
}
|
|
159
160
|
}
|
|
160
161
|
|
|
161
|
-
function cliOutput(result: ActionResult, pretty?: boolean, exitOnError = true): void {
|
|
162
|
-
console.log(formatOutput(result, pretty))
|
|
163
|
-
if (result.error && exitOnError) process.exit(1)
|
|
164
|
-
}
|
|
165
|
-
|
|
166
162
|
export const authCommand = new Command('auth')
|
|
167
163
|
.description('Authentication commands')
|
|
168
164
|
.addCommand(
|