agent-messenger 2.4.0 → 2.5.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.
- package/.claude-plugin/plugin.json +1 -1
- package/.github/workflows/release.yml +0 -12
- package/README.md +3 -3
- package/dist/package.json +1 -1
- package/dist/src/platforms/channeltalk/cli.d.ts.map +1 -1
- package/dist/src/platforms/channeltalk/cli.js +2 -1
- package/dist/src/platforms/channeltalk/cli.js.map +1 -1
- package/dist/src/platforms/channeltalk/commands/index.d.ts +1 -0
- package/dist/src/platforms/channeltalk/commands/index.d.ts.map +1 -1
- package/dist/src/platforms/channeltalk/commands/index.js +1 -0
- package/dist/src/platforms/channeltalk/commands/index.js.map +1 -1
- package/dist/src/platforms/channeltalk/commands/whoami.d.ts +22 -0
- package/dist/src/platforms/channeltalk/commands/whoami.d.ts.map +1 -0
- package/dist/src/platforms/channeltalk/commands/whoami.js +40 -0
- package/dist/src/platforms/channeltalk/commands/whoami.js.map +1 -0
- package/dist/src/platforms/channeltalkbot/cli.d.ts.map +1 -1
- package/dist/src/platforms/channeltalkbot/cli.js +2 -1
- package/dist/src/platforms/channeltalkbot/cli.js.map +1 -1
- package/dist/src/platforms/channeltalkbot/commands/index.d.ts +1 -0
- package/dist/src/platforms/channeltalkbot/commands/index.d.ts.map +1 -1
- package/dist/src/platforms/channeltalkbot/commands/index.js +1 -0
- package/dist/src/platforms/channeltalkbot/commands/index.js.map +1 -1
- package/dist/src/platforms/channeltalkbot/commands/whoami.d.ts +13 -0
- package/dist/src/platforms/channeltalkbot/commands/whoami.d.ts.map +1 -0
- package/dist/src/platforms/channeltalkbot/commands/whoami.js +31 -0
- package/dist/src/platforms/channeltalkbot/commands/whoami.js.map +1 -0
- package/dist/src/platforms/discord/cli.d.ts.map +1 -1
- package/dist/src/platforms/discord/cli.js +2 -1
- package/dist/src/platforms/discord/cli.js.map +1 -1
- package/dist/src/platforms/discord/commands/index.d.ts +1 -0
- package/dist/src/platforms/discord/commands/index.d.ts.map +1 -1
- package/dist/src/platforms/discord/commands/index.js +1 -0
- package/dist/src/platforms/discord/commands/index.js.map +1 -1
- package/dist/src/platforms/discord/commands/whoami.d.ts +6 -0
- package/dist/src/platforms/discord/commands/whoami.d.ts.map +1 -0
- package/dist/src/platforms/discord/commands/whoami.js +33 -0
- package/dist/src/platforms/discord/commands/whoami.js.map +1 -0
- package/dist/src/platforms/discordbot/cli.d.ts.map +1 -1
- package/dist/src/platforms/discordbot/cli.js +2 -1
- package/dist/src/platforms/discordbot/cli.js.map +1 -1
- package/dist/src/platforms/discordbot/commands/index.d.ts +1 -0
- package/dist/src/platforms/discordbot/commands/index.d.ts.map +1 -1
- package/dist/src/platforms/discordbot/commands/index.js +1 -0
- package/dist/src/platforms/discordbot/commands/index.js.map +1 -1
- package/dist/src/platforms/discordbot/commands/whoami.d.ts +14 -0
- package/dist/src/platforms/discordbot/commands/whoami.d.ts.map +1 -0
- package/dist/src/platforms/discordbot/commands/whoami.js +32 -0
- package/dist/src/platforms/discordbot/commands/whoami.js.map +1 -0
- package/dist/src/platforms/instagram/cli.d.ts.map +1 -1
- package/dist/src/platforms/instagram/cli.js +2 -1
- package/dist/src/platforms/instagram/cli.js.map +1 -1
- package/dist/src/platforms/instagram/client.d.ts +6 -0
- package/dist/src/platforms/instagram/client.d.ts.map +1 -1
- package/dist/src/platforms/instagram/client.js +12 -0
- package/dist/src/platforms/instagram/client.js.map +1 -1
- package/dist/src/platforms/instagram/commands/index.d.ts +1 -0
- package/dist/src/platforms/instagram/commands/index.d.ts.map +1 -1
- package/dist/src/platforms/instagram/commands/index.js +1 -0
- package/dist/src/platforms/instagram/commands/index.js.map +1 -1
- package/dist/src/platforms/instagram/commands/whoami.d.ts +7 -0
- package/dist/src/platforms/instagram/commands/whoami.d.ts.map +1 -0
- package/dist/src/platforms/instagram/commands/whoami.js +19 -0
- package/dist/src/platforms/instagram/commands/whoami.js.map +1 -0
- package/dist/src/platforms/kakaotalk/cli.js +2 -2
- package/dist/src/platforms/kakaotalk/cli.js.map +1 -1
- package/dist/src/platforms/kakaotalk/client.d.ts.map +1 -1
- package/dist/src/platforms/kakaotalk/client.js +173 -21
- package/dist/src/platforms/kakaotalk/client.js.map +1 -1
- package/dist/src/platforms/kakaotalk/commands/index.d.ts +1 -1
- package/dist/src/platforms/kakaotalk/commands/index.d.ts.map +1 -1
- package/dist/src/platforms/kakaotalk/commands/index.js +1 -1
- package/dist/src/platforms/kakaotalk/commands/index.js.map +1 -1
- package/dist/src/platforms/kakaotalk/commands/whoami.d.ts +3 -0
- package/dist/src/platforms/kakaotalk/commands/whoami.d.ts.map +1 -0
- package/dist/src/platforms/kakaotalk/commands/{profile.js → whoami.js} +5 -5
- package/dist/src/platforms/kakaotalk/commands/whoami.js.map +1 -0
- package/dist/src/platforms/kakaotalk/protocol/session.d.ts +4 -2
- package/dist/src/platforms/kakaotalk/protocol/session.d.ts.map +1 -1
- package/dist/src/platforms/kakaotalk/protocol/session.js +25 -6
- package/dist/src/platforms/kakaotalk/protocol/session.js.map +1 -1
- package/dist/src/platforms/kakaotalk/protocol/types.d.ts +17 -0
- package/dist/src/platforms/kakaotalk/protocol/types.d.ts.map +1 -1
- package/dist/src/platforms/kakaotalk/protocol/types.js.map +1 -1
- package/dist/src/platforms/kakaotalk/types.d.ts +12 -0
- package/dist/src/platforms/kakaotalk/types.d.ts.map +1 -1
- package/dist/src/platforms/kakaotalk/types.js +6 -0
- package/dist/src/platforms/kakaotalk/types.js.map +1 -1
- package/dist/src/platforms/line/cli.js +2 -2
- package/dist/src/platforms/line/cli.js.map +1 -1
- package/dist/src/platforms/line/commands/auth.d.ts.map +1 -1
- package/dist/src/platforms/line/commands/auth.js +9 -59
- package/dist/src/platforms/line/commands/auth.js.map +1 -1
- package/dist/src/platforms/line/commands/index.d.ts +1 -1
- package/dist/src/platforms/line/commands/index.d.ts.map +1 -1
- package/dist/src/platforms/line/commands/index.js +1 -1
- package/dist/src/platforms/line/commands/index.js.map +1 -1
- package/dist/src/platforms/line/commands/whoami.d.ts +3 -0
- package/dist/src/platforms/line/commands/whoami.d.ts.map +1 -0
- package/dist/src/platforms/line/commands/{profile.js → whoami.js} +5 -5
- package/dist/src/platforms/line/commands/whoami.js.map +1 -0
- package/dist/src/platforms/slack/cli.d.ts.map +1 -1
- package/dist/src/platforms/slack/cli.js +2 -1
- package/dist/src/platforms/slack/cli.js.map +1 -1
- package/dist/src/platforms/slack/commands/index.d.ts +1 -0
- package/dist/src/platforms/slack/commands/index.d.ts.map +1 -1
- package/dist/src/platforms/slack/commands/index.js +1 -0
- package/dist/src/platforms/slack/commands/index.js.map +1 -1
- package/dist/src/platforms/slack/commands/whoami.d.ts +6 -0
- package/dist/src/platforms/slack/commands/whoami.d.ts.map +1 -0
- package/dist/src/platforms/slack/commands/whoami.js +39 -0
- package/dist/src/platforms/slack/commands/whoami.js.map +1 -0
- package/dist/src/platforms/slackbot/cli.d.ts.map +1 -1
- package/dist/src/platforms/slackbot/cli.js +2 -1
- package/dist/src/platforms/slackbot/cli.js.map +1 -1
- 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/whoami.d.ts +14 -0
- package/dist/src/platforms/slackbot/commands/whoami.d.ts.map +1 -0
- package/dist/src/platforms/slackbot/commands/whoami.js +32 -0
- package/dist/src/platforms/slackbot/commands/whoami.js.map +1 -0
- package/dist/src/platforms/teams/cli.d.ts.map +1 -1
- package/dist/src/platforms/teams/cli.js +2 -1
- package/dist/src/platforms/teams/cli.js.map +1 -1
- package/dist/src/platforms/teams/commands/index.d.ts +1 -0
- package/dist/src/platforms/teams/commands/index.d.ts.map +1 -1
- package/dist/src/platforms/teams/commands/index.js +1 -0
- package/dist/src/platforms/teams/commands/index.js.map +1 -1
- package/dist/src/platforms/teams/commands/whoami.d.ts +6 -0
- package/dist/src/platforms/teams/commands/whoami.d.ts.map +1 -0
- package/dist/src/platforms/teams/commands/whoami.js +30 -0
- package/dist/src/platforms/teams/commands/whoami.js.map +1 -0
- package/dist/src/platforms/telegram/cli.d.ts.map +1 -1
- package/dist/src/platforms/telegram/cli.js +2 -1
- package/dist/src/platforms/telegram/cli.js.map +1 -1
- package/dist/src/platforms/telegram/commands/index.d.ts +1 -0
- package/dist/src/platforms/telegram/commands/index.d.ts.map +1 -1
- package/dist/src/platforms/telegram/commands/index.js +1 -0
- package/dist/src/platforms/telegram/commands/index.js.map +1 -1
- package/dist/src/platforms/telegram/commands/whoami.d.ts +7 -0
- package/dist/src/platforms/telegram/commands/whoami.d.ts.map +1 -0
- package/dist/src/platforms/telegram/commands/whoami.js +27 -0
- package/dist/src/platforms/telegram/commands/whoami.js.map +1 -0
- package/dist/src/platforms/webex/cli.d.ts.map +1 -1
- package/dist/src/platforms/webex/cli.js +2 -1
- package/dist/src/platforms/webex/cli.js.map +1 -1
- package/dist/src/platforms/webex/commands/index.d.ts +1 -0
- package/dist/src/platforms/webex/commands/index.d.ts.map +1 -1
- package/dist/src/platforms/webex/commands/index.js +1 -0
- package/dist/src/platforms/webex/commands/index.js.map +1 -1
- package/dist/src/platforms/webex/commands/message.js +1 -1
- package/dist/src/platforms/webex/commands/message.js.map +1 -1
- package/dist/src/platforms/webex/commands/whoami.d.ts +6 -0
- package/dist/src/platforms/webex/commands/whoami.d.ts.map +1 -0
- package/dist/src/platforms/webex/commands/whoami.js +30 -0
- package/dist/src/platforms/webex/commands/whoami.js.map +1 -0
- package/dist/src/platforms/wechatbot/cli.d.ts.map +1 -1
- package/dist/src/platforms/wechatbot/cli.js +2 -1
- package/dist/src/platforms/wechatbot/cli.js.map +1 -1
- package/dist/src/platforms/wechatbot/commands/index.d.ts +1 -0
- package/dist/src/platforms/wechatbot/commands/index.d.ts.map +1 -1
- package/dist/src/platforms/wechatbot/commands/index.js +1 -0
- package/dist/src/platforms/wechatbot/commands/index.js.map +1 -1
- package/dist/src/platforms/wechatbot/commands/whoami.d.ts +12 -0
- package/dist/src/platforms/wechatbot/commands/whoami.d.ts.map +1 -0
- package/dist/src/platforms/wechatbot/commands/whoami.js +33 -0
- package/dist/src/platforms/wechatbot/commands/whoami.js.map +1 -0
- package/dist/src/platforms/whatsapp/cli.d.ts.map +1 -1
- package/dist/src/platforms/whatsapp/cli.js +2 -1
- package/dist/src/platforms/whatsapp/cli.js.map +1 -1
- package/dist/src/platforms/whatsapp/client.d.ts +8 -0
- package/dist/src/platforms/whatsapp/client.d.ts.map +1 -1
- package/dist/src/platforms/whatsapp/client.js +116 -8
- package/dist/src/platforms/whatsapp/client.js.map +1 -1
- package/dist/src/platforms/whatsapp/commands/auth.d.ts.map +1 -1
- package/dist/src/platforms/whatsapp/commands/auth.js +115 -45
- package/dist/src/platforms/whatsapp/commands/auth.js.map +1 -1
- package/dist/src/platforms/whatsapp/commands/index.d.ts +1 -0
- package/dist/src/platforms/whatsapp/commands/index.d.ts.map +1 -1
- package/dist/src/platforms/whatsapp/commands/index.js +1 -0
- package/dist/src/platforms/whatsapp/commands/index.js.map +1 -1
- package/dist/src/platforms/whatsapp/commands/shared.js +2 -2
- package/dist/src/platforms/whatsapp/commands/shared.js.map +1 -1
- package/dist/src/platforms/whatsapp/commands/whoami.d.ts +7 -0
- package/dist/src/platforms/whatsapp/commands/whoami.d.ts.map +1 -0
- package/dist/src/platforms/whatsapp/commands/whoami.js +19 -0
- package/dist/src/platforms/whatsapp/commands/whoami.js.map +1 -0
- package/dist/src/platforms/whatsapp/ensure-auth.js +2 -2
- package/dist/src/platforms/whatsapp/ensure-auth.js.map +1 -1
- package/dist/src/platforms/whatsappbot/cli.d.ts.map +1 -1
- package/dist/src/platforms/whatsappbot/cli.js +2 -1
- package/dist/src/platforms/whatsappbot/cli.js.map +1 -1
- package/dist/src/platforms/whatsappbot/commands/index.d.ts +1 -0
- package/dist/src/platforms/whatsappbot/commands/index.d.ts.map +1 -1
- package/dist/src/platforms/whatsappbot/commands/index.js +1 -0
- package/dist/src/platforms/whatsappbot/commands/index.js.map +1 -1
- package/dist/src/platforms/whatsappbot/commands/whoami.d.ts +17 -0
- package/dist/src/platforms/whatsappbot/commands/whoami.d.ts.map +1 -0
- package/dist/src/platforms/whatsappbot/commands/whoami.js +39 -0
- package/dist/src/platforms/whatsappbot/commands/whoami.js.map +1 -0
- package/dist/src/shared/utils/qr.d.ts +15 -0
- package/dist/src/shared/utils/qr.d.ts.map +1 -0
- package/dist/src/shared/utils/qr.js +74 -0
- package/dist/src/shared/utils/qr.js.map +1 -0
- package/dist/src/tui/adapters/whatsapp-adapter.d.ts.map +1 -1
- package/dist/src/tui/adapters/whatsapp-adapter.js +20 -15
- package/dist/src/tui/adapters/whatsapp-adapter.js.map +1 -1
- package/docs/content/docs/cli/channeltalk.mdx +11 -0
- package/docs/content/docs/cli/channeltalkbot.mdx +9 -0
- package/docs/content/docs/cli/discord.mdx +10 -0
- package/docs/content/docs/cli/discordbot.mdx +9 -0
- package/docs/content/docs/cli/instagram.mdx +11 -0
- package/docs/content/docs/cli/kakaotalk.mdx +24 -0
- package/docs/content/docs/cli/line.mdx +4 -4
- package/docs/content/docs/cli/slack.mdx +10 -0
- package/docs/content/docs/cli/slackbot.mdx +9 -0
- package/docs/content/docs/cli/teams.mdx +10 -0
- package/docs/content/docs/cli/telegram.mdx +11 -0
- package/docs/content/docs/cli/webex.mdx +10 -0
- package/docs/content/docs/cli/wechatbot.mdx +9 -0
- package/docs/content/docs/cli/whatsapp.mdx +36 -7
- package/docs/content/docs/cli/whatsappbot.mdx +9 -0
- package/package.json +1 -1
- package/skills/agent-channeltalk/SKILL.md +12 -1
- package/skills/agent-channeltalkbot/SKILL.md +10 -1
- package/skills/agent-discord/SKILL.md +11 -1
- package/skills/agent-discordbot/SKILL.md +10 -1
- package/skills/agent-instagram/SKILL.md +12 -1
- package/skills/agent-kakaotalk/SKILL.md +14 -8
- package/skills/agent-kakaotalk/references/common-patterns.md +1 -1
- package/skills/agent-line/SKILL.md +5 -5
- package/skills/agent-slack/SKILL.md +11 -1
- package/skills/agent-slackbot/SKILL.md +10 -1
- package/skills/agent-teams/SKILL.md +11 -1
- package/skills/agent-telegram/SKILL.md +6 -1
- package/skills/agent-webex/SKILL.md +11 -1
- package/skills/agent-wechatbot/SKILL.md +10 -1
- package/skills/agent-whatsapp/SKILL.md +52 -15
- package/skills/agent-whatsapp/references/authentication.md +36 -6
- package/skills/agent-whatsappbot/SKILL.md +10 -1
- package/src/platforms/channeltalk/cli.ts +2 -0
- package/src/platforms/channeltalk/commands/index.ts +1 -0
- package/src/platforms/channeltalk/commands/whoami.test.ts +64 -0
- package/src/platforms/channeltalk/commands/whoami.ts +62 -0
- package/src/platforms/channeltalkbot/cli.ts +2 -0
- package/src/platforms/channeltalkbot/commands/index.ts +1 -0
- package/src/platforms/channeltalkbot/commands/whoami.test.ts +104 -0
- package/src/platforms/channeltalkbot/commands/whoami.ts +42 -0
- package/src/platforms/discord/cli.ts +2 -0
- package/src/platforms/discord/commands/index.ts +1 -0
- package/src/platforms/discord/commands/whoami.test.ts +91 -0
- package/src/platforms/discord/commands/whoami.ts +36 -0
- package/src/platforms/discordbot/cli.ts +2 -0
- package/src/platforms/discordbot/commands/index.ts +1 -0
- package/src/platforms/discordbot/commands/whoami.test.ts +96 -0
- package/src/platforms/discordbot/commands/whoami.ts +44 -0
- package/src/platforms/instagram/cli.ts +2 -1
- package/src/platforms/instagram/client.ts +13 -0
- package/src/platforms/instagram/commands/chat.test.ts +1 -5
- package/src/platforms/instagram/commands/index.ts +1 -0
- package/src/platforms/instagram/commands/message.test.ts +1 -5
- package/src/platforms/instagram/commands/whoami.test.ts +60 -0
- package/src/platforms/instagram/commands/whoami.ts +21 -0
- package/src/platforms/kakaotalk/cli.ts +2 -2
- package/src/platforms/kakaotalk/client.test.ts +25 -14
- package/src/platforms/kakaotalk/client.ts +204 -24
- package/src/platforms/kakaotalk/commands/index.ts +1 -1
- package/src/platforms/kakaotalk/commands/{profile.test.ts → whoami.test.ts} +37 -5
- package/src/platforms/kakaotalk/commands/{profile.ts → whoami.ts} +4 -4
- package/src/platforms/kakaotalk/protocol/session.ts +27 -7
- package/src/platforms/kakaotalk/protocol/types.ts +9 -0
- package/src/platforms/kakaotalk/types.ts +12 -0
- package/src/platforms/line/cli.ts +2 -2
- package/src/platforms/line/commands/auth.ts +37 -70
- package/src/platforms/line/commands/index.ts +1 -1
- package/src/platforms/line/commands/{profile.test.ts → whoami.test.ts} +11 -11
- package/src/platforms/line/commands/{profile.ts → whoami.ts} +4 -4
- package/src/platforms/slack/cli.ts +2 -0
- package/src/platforms/slack/commands/index.ts +1 -0
- package/src/platforms/slack/commands/whoami.test.ts +126 -0
- package/src/platforms/slack/commands/whoami.ts +40 -0
- package/src/platforms/slackbot/cli.ts +2 -1
- package/src/platforms/slackbot/commands/index.ts +1 -0
- package/src/platforms/slackbot/commands/whoami.test.ts +102 -0
- package/src/platforms/slackbot/commands/whoami.ts +44 -0
- package/src/platforms/teams/cli.ts +2 -0
- package/src/platforms/teams/commands/index.ts +1 -0
- package/src/platforms/teams/commands/whoami.test.ts +83 -0
- package/src/platforms/teams/commands/whoami.ts +33 -0
- package/src/platforms/telegram/cli.ts +2 -1
- package/src/platforms/telegram/commands/index.ts +1 -0
- package/src/platforms/telegram/commands/whoami.test.ts +75 -0
- package/src/platforms/telegram/commands/whoami.ts +29 -0
- package/src/platforms/webex/cli.ts +2 -1
- package/src/platforms/webex/commands/auth.test.ts +58 -46
- package/src/platforms/webex/commands/index.ts +1 -0
- package/src/platforms/webex/commands/member.test.ts +1 -5
- package/src/platforms/webex/commands/message.test.ts +1 -5
- package/src/platforms/webex/commands/message.ts +1 -1
- package/src/platforms/webex/commands/snapshot.test.ts +1 -5
- package/src/platforms/webex/commands/space.test.ts +1 -5
- package/src/platforms/webex/commands/whoami.test.ts +113 -0
- package/src/platforms/webex/commands/whoami.ts +31 -0
- package/src/platforms/webex/credential-manager.test.ts +0 -1
- package/src/platforms/wechatbot/cli.ts +2 -1
- package/src/platforms/wechatbot/commands/index.ts +1 -0
- package/src/platforms/wechatbot/commands/whoami.test.ts +109 -0
- package/src/platforms/wechatbot/commands/whoami.ts +43 -0
- package/src/platforms/whatsapp/cli.ts +2 -1
- package/src/platforms/whatsapp/client.ts +156 -24
- package/src/platforms/whatsapp/commands/auth.ts +176 -70
- package/src/platforms/whatsapp/commands/index.ts +1 -0
- package/src/platforms/whatsapp/commands/shared.ts +2 -2
- package/src/platforms/whatsapp/commands/whoami.test.ts +59 -0
- package/src/platforms/whatsapp/commands/whoami.ts +21 -0
- package/src/platforms/whatsapp/ensure-auth.ts +2 -2
- package/src/platforms/whatsappbot/cli.ts +2 -1
- package/src/platforms/whatsappbot/commands/index.ts +1 -0
- package/src/platforms/whatsappbot/commands/whoami.test.ts +100 -0
- package/src/platforms/whatsappbot/commands/whoami.ts +57 -0
- package/src/shared/utils/qr.ts +92 -0
- package/src/tui/adapters/whatsapp-adapter.ts +19 -16
- package/dist/src/platforms/kakaotalk/commands/profile.d.ts +0 -3
- package/dist/src/platforms/kakaotalk/commands/profile.d.ts.map +0 -1
- package/dist/src/platforms/kakaotalk/commands/profile.js.map +0 -1
- package/dist/src/platforms/line/commands/profile.d.ts +0 -3
- package/dist/src/platforms/line/commands/profile.d.ts.map +0 -1
- package/dist/src/platforms/line/commands/profile.js.map +0 -1
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { Command } from 'commander'
|
|
2
|
+
|
|
3
|
+
import { formatOutput } from '@/shared/utils/output'
|
|
4
|
+
|
|
5
|
+
import type { BotOption } from './shared'
|
|
6
|
+
import { getClient } from './shared'
|
|
7
|
+
|
|
8
|
+
interface WhoamiResult {
|
|
9
|
+
id?: string
|
|
10
|
+
username?: string
|
|
11
|
+
global_name?: string
|
|
12
|
+
avatar?: string
|
|
13
|
+
bot?: boolean
|
|
14
|
+
error?: string
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export async function whoamiAction(options: BotOption): Promise<WhoamiResult> {
|
|
18
|
+
try {
|
|
19
|
+
const client = await getClient(options)
|
|
20
|
+
const info = await client.testAuth()
|
|
21
|
+
return {
|
|
22
|
+
id: info.id,
|
|
23
|
+
username: info.username,
|
|
24
|
+
global_name: info.global_name,
|
|
25
|
+
avatar: info.avatar,
|
|
26
|
+
bot: info.bot,
|
|
27
|
+
}
|
|
28
|
+
} catch (error) {
|
|
29
|
+
return { error: (error as Error).message }
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
function cliOutput(result: WhoamiResult, pretty?: boolean): void {
|
|
34
|
+
console.log(formatOutput(result, pretty))
|
|
35
|
+
if (result.error) process.exit(1)
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export const whoamiCommand = new Command('whoami')
|
|
39
|
+
.description('Show current authenticated bot')
|
|
40
|
+
.option('--bot <id>', 'Bot ID to use')
|
|
41
|
+
.option('--pretty', 'Pretty print JSON output')
|
|
42
|
+
.action(async (opts: BotOption) => {
|
|
43
|
+
cliOutput(await whoamiAction(opts), opts.pretty)
|
|
44
|
+
})
|
|
@@ -4,7 +4,7 @@ import type { Command as CommandType } from 'commander'
|
|
|
4
4
|
import { Command } from 'commander'
|
|
5
5
|
|
|
6
6
|
import pkg from '../../../package.json' with { type: 'json' }
|
|
7
|
-
import { authCommand, chatCommand, messageCommand } from './commands/index'
|
|
7
|
+
import { authCommand, chatCommand, messageCommand, whoamiCommand } from './commands/index'
|
|
8
8
|
import { ensureInstagramAuth } from './ensure-auth'
|
|
9
9
|
|
|
10
10
|
function isAuthCommand(command: CommandType): boolean {
|
|
@@ -31,6 +31,7 @@ program.hook('preAction', async (_thisCommand, actionCommand) => {
|
|
|
31
31
|
program.addCommand(authCommand)
|
|
32
32
|
program.addCommand(chatCommand)
|
|
33
33
|
program.addCommand(messageCommand)
|
|
34
|
+
program.addCommand(whoamiCommand)
|
|
34
35
|
|
|
35
36
|
program.parse(process.argv)
|
|
36
37
|
|
|
@@ -410,6 +410,19 @@ export class InstagramClient {
|
|
|
410
410
|
return this.userId
|
|
411
411
|
}
|
|
412
412
|
|
|
413
|
+
async getProfile(): Promise<{ user_id: string; username: string; full_name: string | null; profile_pic_url: string | null }> {
|
|
414
|
+
if (!this.userId) {
|
|
415
|
+
throw new InstagramError('Not authenticated. Call login() first.', 'not_authenticated')
|
|
416
|
+
}
|
|
417
|
+
const account = await this.credentialManager.getAccount()
|
|
418
|
+
return {
|
|
419
|
+
user_id: this.userId,
|
|
420
|
+
username: account?.username ?? '',
|
|
421
|
+
full_name: account?.full_name ?? null,
|
|
422
|
+
profile_pic_url: account?.profile_pic_url ?? null,
|
|
423
|
+
}
|
|
424
|
+
}
|
|
425
|
+
|
|
413
426
|
private async preLoginFlow(): Promise<{ keyId: string; publicKey: string } | null> {
|
|
414
427
|
const url = `${IG_BASE_URL}/qe/sync/`
|
|
415
428
|
const headers = this.buildHeaders()
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { afterEach, beforeEach, describe, expect, mock, spyOn, test } from 'bun:test'
|
|
2
2
|
|
|
3
3
|
const originalConsoleLog = console.log
|
|
4
4
|
import type { Command } from 'commander'
|
|
@@ -34,10 +34,6 @@ function resetCommandState(cmd: Command): void {
|
|
|
34
34
|
}
|
|
35
35
|
}
|
|
36
36
|
|
|
37
|
-
afterAll(() => {
|
|
38
|
-
mock.restore()
|
|
39
|
-
})
|
|
40
|
-
|
|
41
37
|
describe('chat commands', () => {
|
|
42
38
|
let consoleLogSpy: ReturnType<typeof mock>
|
|
43
39
|
let processExitSpy: ReturnType<typeof spyOn>
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { afterEach, beforeEach, describe, expect, mock, spyOn, test } from 'bun:test'
|
|
2
2
|
|
|
3
3
|
const originalConsoleLog = console.log
|
|
4
4
|
import type { Command } from 'commander'
|
|
@@ -32,10 +32,6 @@ function resetCommandState(cmd: Command): void {
|
|
|
32
32
|
}
|
|
33
33
|
}
|
|
34
34
|
|
|
35
|
-
afterAll(() => {
|
|
36
|
-
mock.restore()
|
|
37
|
-
})
|
|
38
|
-
|
|
39
35
|
describe('message commands', () => {
|
|
40
36
|
let consoleLogSpy: ReturnType<typeof mock>
|
|
41
37
|
let processExitSpy: ReturnType<typeof spyOn>
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { afterEach, beforeEach, describe, expect, spyOn, test } from 'bun:test'
|
|
2
|
+
|
|
3
|
+
import { InstagramClient } from '../client'
|
|
4
|
+
import * as sharedModule from './shared'
|
|
5
|
+
import { whoamiAction } from './whoami'
|
|
6
|
+
|
|
7
|
+
let withInstagramClientSpy: ReturnType<typeof spyOn>
|
|
8
|
+
let getProfileSpy: ReturnType<typeof spyOn>
|
|
9
|
+
let consoleLogSpy: ReturnType<typeof spyOn>
|
|
10
|
+
|
|
11
|
+
describe('whoami command', () => {
|
|
12
|
+
beforeEach(() => {
|
|
13
|
+
getProfileSpy = spyOn(InstagramClient.prototype, 'getProfile').mockResolvedValue({
|
|
14
|
+
user_id: '987654321',
|
|
15
|
+
username: 'testuser',
|
|
16
|
+
full_name: 'Test User',
|
|
17
|
+
profile_pic_url: 'https://example.com/pic.jpg',
|
|
18
|
+
})
|
|
19
|
+
withInstagramClientSpy = spyOn(sharedModule, 'withInstagramClient').mockImplementation(
|
|
20
|
+
async (_opts, fn) => {
|
|
21
|
+
const fakeClient = Object.create(InstagramClient.prototype) as InstagramClient
|
|
22
|
+
return fn(fakeClient)
|
|
23
|
+
},
|
|
24
|
+
)
|
|
25
|
+
consoleLogSpy = spyOn(console, 'log').mockImplementation(() => {})
|
|
26
|
+
})
|
|
27
|
+
|
|
28
|
+
afterEach(() => {
|
|
29
|
+
getProfileSpy?.mockRestore()
|
|
30
|
+
withInstagramClientSpy?.mockRestore()
|
|
31
|
+
consoleLogSpy?.mockRestore()
|
|
32
|
+
})
|
|
33
|
+
|
|
34
|
+
test('outputs profile information', async () => {
|
|
35
|
+
await whoamiAction({})
|
|
36
|
+
|
|
37
|
+
expect(consoleLogSpy).toHaveBeenCalledTimes(1)
|
|
38
|
+
const output = JSON.parse(consoleLogSpy.mock.calls[0][0] as string)
|
|
39
|
+
expect(output.user_id).toBe('987654321')
|
|
40
|
+
expect(output.username).toBe('testuser')
|
|
41
|
+
expect(output.full_name).toBe('Test User')
|
|
42
|
+
expect(output.profile_pic_url).toBe('https://example.com/pic.jpg')
|
|
43
|
+
})
|
|
44
|
+
|
|
45
|
+
test('outputs profile with null optional fields', async () => {
|
|
46
|
+
getProfileSpy.mockResolvedValue({
|
|
47
|
+
user_id: '987654321',
|
|
48
|
+
username: 'testuser',
|
|
49
|
+
full_name: null,
|
|
50
|
+
profile_pic_url: null,
|
|
51
|
+
})
|
|
52
|
+
|
|
53
|
+
await whoamiAction({})
|
|
54
|
+
|
|
55
|
+
expect(consoleLogSpy).toHaveBeenCalledTimes(1)
|
|
56
|
+
const output = JSON.parse(consoleLogSpy.mock.calls[0][0] as string)
|
|
57
|
+
expect(output.full_name).toBeNull()
|
|
58
|
+
expect(output.profile_pic_url).toBeNull()
|
|
59
|
+
})
|
|
60
|
+
})
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { Command } from 'commander'
|
|
2
|
+
|
|
3
|
+
import { handleError } from '@/shared/utils/error-handler'
|
|
4
|
+
import { formatOutput } from '@/shared/utils/output'
|
|
5
|
+
|
|
6
|
+
import { withInstagramClient } from './shared'
|
|
7
|
+
|
|
8
|
+
export async function whoamiAction(options: { account?: string; pretty?: boolean }): Promise<void> {
|
|
9
|
+
try {
|
|
10
|
+
const profile = await withInstagramClient(options, (client) => client.getProfile())
|
|
11
|
+
console.log(formatOutput(profile, options.pretty))
|
|
12
|
+
} catch (error) {
|
|
13
|
+
handleError(error as Error)
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export const whoamiCommand = new Command('whoami')
|
|
18
|
+
.description('Show current authenticated user')
|
|
19
|
+
.option('--account <id>', 'Use a specific Instagram account')
|
|
20
|
+
.option('--pretty', 'Pretty print JSON output')
|
|
21
|
+
.action(whoamiAction)
|
|
@@ -4,7 +4,7 @@ import type { Command as CommandType } from 'commander'
|
|
|
4
4
|
import { Command } from 'commander'
|
|
5
5
|
|
|
6
6
|
import pkg from '../../../package.json' with { type: 'json' }
|
|
7
|
-
import { authCommand, chatCommand, messageCommand,
|
|
7
|
+
import { authCommand, chatCommand, messageCommand, whoamiCommand } from './commands/index'
|
|
8
8
|
import { ensureKakaoAuth } from './ensure-auth'
|
|
9
9
|
|
|
10
10
|
function isAuthCommand(command: CommandType): boolean {
|
|
@@ -31,7 +31,7 @@ program.hook('preAction', async (_thisCommand, actionCommand) => {
|
|
|
31
31
|
program.addCommand(authCommand)
|
|
32
32
|
program.addCommand(chatCommand)
|
|
33
33
|
program.addCommand(messageCommand)
|
|
34
|
-
program.addCommand(
|
|
34
|
+
program.addCommand(whoamiCommand)
|
|
35
35
|
|
|
36
36
|
program.parse(process.argv)
|
|
37
37
|
|
|
@@ -5,6 +5,8 @@ import { KakaoTalkClient, KakaoTalkError } from './client'
|
|
|
5
5
|
// Mock LocoSession at module level
|
|
6
6
|
const mockLogin = mock(() => Promise.resolve({}))
|
|
7
7
|
const mockGetChatList = mock(() => Promise.resolve({}))
|
|
8
|
+
const mockGetChatLogs = mock(() => Promise.resolve({}))
|
|
9
|
+
const mockGetChatInfo = mock(() => Promise.resolve({}))
|
|
8
10
|
const mockSyncMessages = mock(() => Promise.resolve({}))
|
|
9
11
|
const mockSendMessage = mock(() => Promise.resolve({}))
|
|
10
12
|
const mockClose = mock(() => {})
|
|
@@ -14,6 +16,8 @@ mock.module('./protocol/session', () => ({
|
|
|
14
16
|
LocoSession: class MockLocoSession {
|
|
15
17
|
login = mockLogin
|
|
16
18
|
getChatList = mockGetChatList
|
|
19
|
+
getChatLogs = mockGetChatLogs
|
|
20
|
+
getChatInfo = mockGetChatInfo
|
|
17
21
|
syncMessages = mockSyncMessages
|
|
18
22
|
sendMessage = mockSendMessage
|
|
19
23
|
close = mockClose
|
|
@@ -28,6 +32,8 @@ function makeLong(n: number): { low: number; high: number } {
|
|
|
28
32
|
function resetAllMocks() {
|
|
29
33
|
mockLogin.mockReset()
|
|
30
34
|
mockGetChatList.mockReset()
|
|
35
|
+
mockGetChatLogs.mockReset()
|
|
36
|
+
mockGetChatInfo.mockReset()
|
|
31
37
|
mockSyncMessages.mockReset()
|
|
32
38
|
mockSendMessage.mockReset()
|
|
33
39
|
mockClose.mockReset()
|
|
@@ -67,6 +73,8 @@ describe('KakaoTalkClient', () => {
|
|
|
67
73
|
beforeEach(() => {
|
|
68
74
|
resetAllMocks()
|
|
69
75
|
mockLogin.mockResolvedValue(DEFAULT_LOGIN_RESULT)
|
|
76
|
+
mockGetChatLogs.mockResolvedValue({ body: { status: 0, chatLogs: [], eof: true } })
|
|
77
|
+
mockGetChatInfo.mockResolvedValue({ body: { l: makeLong(99999) } })
|
|
70
78
|
})
|
|
71
79
|
|
|
72
80
|
afterEach(() => {
|
|
@@ -316,13 +324,14 @@ describe('KakaoTalkClient', () => {
|
|
|
316
324
|
|
|
317
325
|
describe('getMessages', () => {
|
|
318
326
|
test('returns formatted messages', async () => {
|
|
319
|
-
|
|
327
|
+
mockGetChatLogs.mockResolvedValueOnce({
|
|
320
328
|
body: {
|
|
329
|
+
status: 0,
|
|
321
330
|
chatLogs: [
|
|
322
|
-
{ logId: makeLong(10), type: 1, authorId: 42, message: 'hello', sendAt: 1700000001 },
|
|
323
|
-
{ logId: makeLong(11), type: 1, authorId: 43, message: 'world', sendAt: 1700000002 },
|
|
331
|
+
{ logId: makeLong(10), chatId: 100, type: 1, authorId: 42, message: 'hello', sendAt: 1700000001 },
|
|
332
|
+
{ logId: makeLong(11), chatId: 100, type: 1, authorId: 43, message: 'world', sendAt: 1700000002 },
|
|
324
333
|
],
|
|
325
|
-
|
|
334
|
+
eof: true,
|
|
326
335
|
},
|
|
327
336
|
})
|
|
328
337
|
|
|
@@ -351,14 +360,15 @@ describe('KakaoTalkClient', () => {
|
|
|
351
360
|
test('respects count option', async () => {
|
|
352
361
|
const logs = Array.from({ length: 50 }, (_, i) => ({
|
|
353
362
|
logId: makeLong(i + 1),
|
|
363
|
+
chatId: 100,
|
|
354
364
|
type: 1,
|
|
355
365
|
authorId: 1,
|
|
356
366
|
message: `msg-${i}`,
|
|
357
367
|
sendAt: 1700000000 + i,
|
|
358
368
|
}))
|
|
359
369
|
|
|
360
|
-
|
|
361
|
-
body: { chatLogs: logs,
|
|
370
|
+
mockGetChatLogs.mockResolvedValueOnce({
|
|
371
|
+
body: { status: 0, chatLogs: logs, eof: true },
|
|
362
372
|
})
|
|
363
373
|
|
|
364
374
|
const client = await new KakaoTalkClient().login({ oauthToken: 'token', userId: 'user1', deviceUuid: 'device1' })
|
|
@@ -373,13 +383,14 @@ describe('KakaoTalkClient', () => {
|
|
|
373
383
|
})
|
|
374
384
|
|
|
375
385
|
test('sorts messages by sent_at ascending', async () => {
|
|
376
|
-
|
|
386
|
+
mockGetChatLogs.mockResolvedValueOnce({
|
|
377
387
|
body: {
|
|
388
|
+
status: 0,
|
|
378
389
|
chatLogs: [
|
|
379
|
-
{ logId: makeLong(2), type: 1, authorId: 1, message: 'second', sendAt: 200 },
|
|
380
|
-
{ logId: makeLong(1), type: 1, authorId: 1, message: 'first', sendAt: 100 },
|
|
390
|
+
{ logId: makeLong(2), chatId: 100, type: 1, authorId: 1, message: 'second', sendAt: 200 },
|
|
391
|
+
{ logId: makeLong(1), chatId: 100, type: 1, authorId: 1, message: 'first', sendAt: 100 },
|
|
381
392
|
],
|
|
382
|
-
|
|
393
|
+
eof: true,
|
|
383
394
|
},
|
|
384
395
|
})
|
|
385
396
|
|
|
@@ -556,8 +567,8 @@ describe('KakaoTalkClient', () => {
|
|
|
556
567
|
})
|
|
557
568
|
|
|
558
569
|
test('reuses session across multiple calls', async () => {
|
|
559
|
-
|
|
560
|
-
body: { chatLogs: [],
|
|
570
|
+
mockGetChatLogs.mockResolvedValue({
|
|
571
|
+
body: { status: 0, chatLogs: [], eof: true },
|
|
561
572
|
})
|
|
562
573
|
|
|
563
574
|
const client = await new KakaoTalkClient().login({ oauthToken: 'token', userId: 'user1', deviceUuid: 'device1' })
|
|
@@ -574,8 +585,8 @@ describe('KakaoTalkClient', () => {
|
|
|
574
585
|
mockLogin.mockImplementation(
|
|
575
586
|
() => new Promise((resolve) => setTimeout(() => resolve(DEFAULT_LOGIN_RESULT), 50)),
|
|
576
587
|
)
|
|
577
|
-
|
|
578
|
-
body: { chatLogs: [],
|
|
588
|
+
mockGetChatLogs.mockResolvedValue({
|
|
589
|
+
body: { status: 0, chatLogs: [], eof: true },
|
|
579
590
|
})
|
|
580
591
|
|
|
581
592
|
const client = await new KakaoTalkClient().login({ oauthToken: 'token', userId: 'user1', deviceUuid: 'device1' })
|
|
@@ -1,10 +1,14 @@
|
|
|
1
1
|
import { Long } from 'bson'
|
|
2
|
+
import { existsSync } from 'node:fs'
|
|
3
|
+
import { chmod, mkdir, readFile, writeFile } from 'node:fs/promises'
|
|
4
|
+
import { homedir } from 'node:os'
|
|
5
|
+
import { join } from 'node:path'
|
|
2
6
|
|
|
3
7
|
import { warn } from '@/shared/utils/stderr'
|
|
4
8
|
|
|
5
9
|
import { APP_VERSION, LANG, OS } from './protocol/config'
|
|
6
10
|
import { LocoSession } from './protocol/session'
|
|
7
|
-
import type { ChatListResponse, LoginListResponse } from './protocol/types'
|
|
11
|
+
import type { ChatListResponse, LoginListResponse, SyncState } from './protocol/types'
|
|
8
12
|
import type { KakaoChat, KakaoMessage, KakaoProfile, KakaoSendResult } from './types'
|
|
9
13
|
|
|
10
14
|
export class KakaoTalkError extends Error {
|
|
@@ -74,6 +78,14 @@ function matchesSearch(chat: ChatData, term: string): boolean {
|
|
|
74
78
|
return names.some((n) => n.toLowerCase().includes(lower))
|
|
75
79
|
}
|
|
76
80
|
|
|
81
|
+
function findMaxLogId(logs: Array<Record<string, unknown>>, field: string): Long | null {
|
|
82
|
+
return logs.reduce<Long | null>((max, log) => {
|
|
83
|
+
const current = bsonToLong(log[field])
|
|
84
|
+
if (!current) return max
|
|
85
|
+
return !max || current.greaterThan(max) ? current : max
|
|
86
|
+
}, null)
|
|
87
|
+
}
|
|
88
|
+
|
|
77
89
|
function collectChats(chatDatas: ChatData[], into: ChatData[], seen: Set<string>): void {
|
|
78
90
|
for (const chat of chatDatas) {
|
|
79
91
|
const id = String(chat.c)
|
|
@@ -92,6 +104,129 @@ function wrapError(error: unknown, code: string): KakaoTalkError {
|
|
|
92
104
|
|
|
93
105
|
const MAX_PAGES = 50
|
|
94
106
|
|
|
107
|
+
const CONFIG_DIR = join(homedir(), '.config', 'agent-messenger')
|
|
108
|
+
|
|
109
|
+
function syncStatePath(deviceUuid: string): string {
|
|
110
|
+
return join(CONFIG_DIR, `kakaotalk-sync-state-${deviceUuid}.json`)
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
async function loadSyncState(deviceUuid: string): Promise<SyncState | undefined> {
|
|
114
|
+
const path = syncStatePath(deviceUuid)
|
|
115
|
+
if (!existsSync(path)) return undefined
|
|
116
|
+
const content = await readFile(path, 'utf-8')
|
|
117
|
+
const parsed = JSON.parse(content) as Partial<SyncState>
|
|
118
|
+
|
|
119
|
+
if (
|
|
120
|
+
parsed.version !== 2 ||
|
|
121
|
+
typeof parsed.revision !== 'number' ||
|
|
122
|
+
!Array.isArray(parsed.chatIds) ||
|
|
123
|
+
!Array.isArray(parsed.maxIds) ||
|
|
124
|
+
parsed.chatIds.length !== parsed.maxIds.length ||
|
|
125
|
+
!parsed.lastTokenId ||
|
|
126
|
+
typeof parsed.lbk !== 'number'
|
|
127
|
+
) {
|
|
128
|
+
return undefined
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
return parsed as SyncState
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
async function saveSyncState(deviceUuid: string, state: SyncState): Promise<void> {
|
|
135
|
+
await mkdir(CONFIG_DIR, { recursive: true })
|
|
136
|
+
const path = syncStatePath(deviceUuid)
|
|
137
|
+
await writeFile(path, JSON.stringify(state, null, 2))
|
|
138
|
+
await chmod(path, 0o600)
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
function toLongLike(v: unknown): { low: number; high: number } {
|
|
142
|
+
if (v && typeof v === 'object' && 'low' in v && 'high' in v) {
|
|
143
|
+
const { low, high } = v as { low: number; high: number }
|
|
144
|
+
return { low, high }
|
|
145
|
+
}
|
|
146
|
+
if (typeof v === 'number') {
|
|
147
|
+
const big = BigInt(v)
|
|
148
|
+
return { low: Number(big & 0xffffffffn), high: Number((big >> 32n) & 0xffffffffn) }
|
|
149
|
+
}
|
|
150
|
+
return { low: 0, high: 0 }
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
function buildSyncState(loginResult: LoginListResponse, previousRevision: number): SyncState {
|
|
154
|
+
const chatDatas = (loginResult.chatDatas ?? []) as Array<Record<string, unknown>>
|
|
155
|
+
return {
|
|
156
|
+
version: 2,
|
|
157
|
+
revision: typeof loginResult.revision === 'number' ? loginResult.revision : previousRevision,
|
|
158
|
+
chatIds: chatDatas.map((chat) => toLongLike(chat.c)),
|
|
159
|
+
maxIds: chatDatas.map((chat) => toLongLike(chat.ll)),
|
|
160
|
+
lastTokenId: toLongLike(loginResult.lastTokenId),
|
|
161
|
+
lbk: typeof loginResult.lbk === 'number' ? loginResult.lbk : 0,
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
function deleteFromSyncState(state: SyncState, chatId: string): void {
|
|
166
|
+
const index = state.chatIds.findIndex((entry) => longToString(entry) === chatId)
|
|
167
|
+
if (index === -1) return
|
|
168
|
+
|
|
169
|
+
state.chatIds.splice(index, 1)
|
|
170
|
+
state.maxIds.splice(index, 1)
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
function upsertSyncState(state: SyncState, chatId: unknown, maxId: unknown): void {
|
|
174
|
+
const chatIdString = longToString(chatId)
|
|
175
|
+
const nextChatId = toLongLike(chatId)
|
|
176
|
+
const nextMaxId = toLongLike(maxId)
|
|
177
|
+
const index = state.chatIds.findIndex((entry) => longToString(entry) === chatIdString)
|
|
178
|
+
|
|
179
|
+
if (index === -1) {
|
|
180
|
+
state.chatIds.push(nextChatId)
|
|
181
|
+
state.maxIds.push(nextMaxId)
|
|
182
|
+
return
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
state.chatIds[index] = nextChatId
|
|
186
|
+
state.maxIds[index] = nextMaxId
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
function mergeSyncState(previous: SyncState | undefined, loginResult: LoginListResponse): SyncState {
|
|
190
|
+
const next = previous
|
|
191
|
+
? {
|
|
192
|
+
version: 2 as const,
|
|
193
|
+
revision: previous.revision,
|
|
194
|
+
chatIds: [...previous.chatIds],
|
|
195
|
+
maxIds: [...previous.maxIds],
|
|
196
|
+
lastTokenId: previous.lastTokenId,
|
|
197
|
+
lbk: previous.lbk,
|
|
198
|
+
}
|
|
199
|
+
: buildSyncState(loginResult, 0)
|
|
200
|
+
|
|
201
|
+
next.revision = typeof loginResult.revision === 'number' ? loginResult.revision : next.revision
|
|
202
|
+
next.lastTokenId = toLongLike(loginResult.lastTokenId)
|
|
203
|
+
next.lbk = typeof loginResult.lbk === 'number' ? loginResult.lbk : next.lbk
|
|
204
|
+
|
|
205
|
+
const delChatIds = Array.isArray(loginResult.delChatIds) ? loginResult.delChatIds : []
|
|
206
|
+
for (const chatId of delChatIds) {
|
|
207
|
+
deleteFromSyncState(next, longToString(chatId))
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
const chatDatas = Array.isArray(loginResult.chatDatas) ? loginResult.chatDatas : []
|
|
211
|
+
for (const chat of chatDatas) {
|
|
212
|
+
upsertSyncState(next, chat.c, chat.ll)
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
return next
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
function formatMessages(logs: Array<Record<string, unknown>>, count: number): KakaoMessage[] {
|
|
219
|
+
logs.sort((a, b) => (a.sendAt as number) - (b.sendAt as number))
|
|
220
|
+
|
|
221
|
+
return logs.slice(-count).map((log) => ({
|
|
222
|
+
log_id: longToString(log.logId),
|
|
223
|
+
type: log.type as number,
|
|
224
|
+
author_id: log.authorId as number,
|
|
225
|
+
message: log.message as string,
|
|
226
|
+
sent_at: log.sendAt as number,
|
|
227
|
+
}))
|
|
228
|
+
}
|
|
229
|
+
|
|
95
230
|
export class KakaoTalkClient {
|
|
96
231
|
private oauthToken: string | null = null
|
|
97
232
|
private userId: string | null = null
|
|
@@ -179,7 +314,11 @@ export class KakaoTalkClient {
|
|
|
179
314
|
private async connect(): Promise<SessionState> {
|
|
180
315
|
const session = new LocoSession()
|
|
181
316
|
try {
|
|
182
|
-
const
|
|
317
|
+
const syncState = await loadSyncState(this.deviceUuid!)
|
|
318
|
+
const loginResult = await session.login(this.oauthToken!, this.userId!, this.deviceUuid!, syncState)
|
|
319
|
+
|
|
320
|
+
const newSyncState = mergeSyncState(syncState, loginResult)
|
|
321
|
+
await saveSyncState(this.deviceUuid!, newSyncState)
|
|
183
322
|
|
|
184
323
|
session.onClose(() => {
|
|
185
324
|
if (this.state?.session === session) {
|
|
@@ -253,21 +392,62 @@ export class KakaoTalkClient {
|
|
|
253
392
|
}
|
|
254
393
|
|
|
255
394
|
async getMessages(chatId: string, options?: { count?: number; from?: string }): Promise<KakaoMessage[]> {
|
|
256
|
-
return this.executeWithReconnect(async ({ session
|
|
395
|
+
return this.executeWithReconnect(async ({ session }) => {
|
|
257
396
|
try {
|
|
258
|
-
const rawChats = (loginResult.chatDatas ?? []) as ChatData[]
|
|
259
|
-
const chat = rawChats.find((c) => String(c.c) === chatId)
|
|
260
|
-
const lastLogId = chat?.ll as { high: number; low: number } | undefined
|
|
261
|
-
const maxLogId = lastLogId ? new Long(lastLogId.low, lastLogId.high) : undefined
|
|
262
|
-
|
|
263
397
|
const count = options?.count ?? 20
|
|
264
398
|
const cursor = options?.from ? parseLong(options.from) : undefined
|
|
265
399
|
|
|
266
400
|
const cid = parseLong(chatId)
|
|
267
|
-
|
|
401
|
+
|
|
268
402
|
const allMessages: Array<Record<string, unknown>> = []
|
|
269
403
|
const seenLogIds = new Set<string>()
|
|
270
|
-
let cur =
|
|
404
|
+
let cur = cursor ?? Long.fromNumber(0)
|
|
405
|
+
|
|
406
|
+
try {
|
|
407
|
+
for (let page = 0; page < MAX_PAGES; page++) {
|
|
408
|
+
const response = await session.getChatLogs([cid], [cur])
|
|
409
|
+
const responseStatus = response.body.status
|
|
410
|
+
if (typeof responseStatus === 'number' && responseStatus !== 0) {
|
|
411
|
+
throw new Error(`MCHATLOGS failed: ${responseStatus}`)
|
|
412
|
+
}
|
|
413
|
+
|
|
414
|
+
const batch = ((response.body.chatLogs ?? []) as Array<Record<string, unknown>>).filter(
|
|
415
|
+
(log) => longToString(log.chatId) === chatId,
|
|
416
|
+
)
|
|
417
|
+
if (batch.length === 0) {
|
|
418
|
+
return formatMessages(allMessages, count)
|
|
419
|
+
}
|
|
420
|
+
|
|
421
|
+
for (const log of batch) {
|
|
422
|
+
const lid = longToString(log.logId)
|
|
423
|
+
if (!seenLogIds.has(lid)) {
|
|
424
|
+
seenLogIds.add(lid)
|
|
425
|
+
allMessages.push(log)
|
|
426
|
+
}
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
const maxLog = findMaxLogId(batch, 'logId')
|
|
430
|
+
if (!maxLog || maxLog.equals(cur) || response.body.eof) {
|
|
431
|
+
return formatMessages(allMessages, count)
|
|
432
|
+
}
|
|
433
|
+
|
|
434
|
+
cur = maxLog
|
|
435
|
+
}
|
|
436
|
+
} catch {
|
|
437
|
+
allMessages.length = 0
|
|
438
|
+
seenLogIds.clear()
|
|
439
|
+
cur = cursor ?? Long.fromNumber(0)
|
|
440
|
+
}
|
|
441
|
+
|
|
442
|
+
if (allMessages.length > 0) {
|
|
443
|
+
warn(`[agent-kakaotalk] Warning: message fetch capped at ${MAX_PAGES} pages. Results may be incomplete.`)
|
|
444
|
+
return formatMessages(allMessages, count)
|
|
445
|
+
}
|
|
446
|
+
|
|
447
|
+
// Fetch fresh lastLogId via CHATONROOM (not the stale login-time snapshot)
|
|
448
|
+
const chatInfo = await session.getChatInfo(cid)
|
|
449
|
+
const chatBody = chatInfo.body as Record<string, unknown>
|
|
450
|
+
const maxLogId = bsonToLong(chatBody.l)
|
|
271
451
|
|
|
272
452
|
let reachedEnd = false
|
|
273
453
|
for (let page = 0; page < MAX_PAGES; page++) {
|
|
@@ -283,11 +463,7 @@ export class KakaoTalkClient {
|
|
|
283
463
|
}
|
|
284
464
|
}
|
|
285
465
|
|
|
286
|
-
const maxLog = batch
|
|
287
|
-
const lid = l.logId as { high: number; low: number }
|
|
288
|
-
const long = new Long(lid.low, lid.high)
|
|
289
|
-
return !max || long.greaterThan(max) ? long : max
|
|
290
|
-
}, null)
|
|
466
|
+
const maxLog = findMaxLogId(batch, 'logId')
|
|
291
467
|
|
|
292
468
|
if (!maxLog || maxLog.equals(cur) || response.body.isOK) { reachedEnd = true; break }
|
|
293
469
|
cur = maxLog
|
|
@@ -296,15 +472,7 @@ export class KakaoTalkClient {
|
|
|
296
472
|
warn(`[agent-kakaotalk] Warning: message fetch capped at ${MAX_PAGES} pages. Results may be incomplete.`)
|
|
297
473
|
}
|
|
298
474
|
|
|
299
|
-
allMessages
|
|
300
|
-
|
|
301
|
-
return allMessages.slice(-count).map((log) => ({
|
|
302
|
-
log_id: longToString(log.logId),
|
|
303
|
-
type: log.type as number,
|
|
304
|
-
author_id: log.authorId as number,
|
|
305
|
-
message: log.message as string,
|
|
306
|
-
sent_at: log.sendAt as number,
|
|
307
|
-
}))
|
|
475
|
+
return formatMessages(allMessages, count)
|
|
308
476
|
} catch (error) {
|
|
309
477
|
throw wrapError(error, 'get_messages_failed')
|
|
310
478
|
}
|
|
@@ -353,9 +521,15 @@ export class KakaoTalkClient {
|
|
|
353
521
|
const profile = profileData.profile as Record<string, unknown> | undefined
|
|
354
522
|
|
|
355
523
|
let accountDisplayId: string | null = null
|
|
524
|
+
let accountEmail: string | null = null
|
|
525
|
+
let pstnNumber: string | null = null
|
|
526
|
+
let emailVerified: boolean | null = null
|
|
356
527
|
if (settingsRes.ok) {
|
|
357
528
|
const settingsData = await settingsRes.json() as Record<string, unknown>
|
|
358
529
|
accountDisplayId = (settingsData.accountDisplayId as string) || null
|
|
530
|
+
accountEmail = (settingsData.accountEmail as string) || null
|
|
531
|
+
pstnNumber = (settingsData.pstnNumber as string) || null
|
|
532
|
+
emailVerified = typeof settingsData.emailVerified === 'boolean' ? settingsData.emailVerified : null
|
|
359
533
|
}
|
|
360
534
|
|
|
361
535
|
return {
|
|
@@ -363,8 +537,14 @@ export class KakaoTalkClient {
|
|
|
363
537
|
nickname: (profile?.nickName as string) || '',
|
|
364
538
|
profile_image_url: (profile?.profileImageUrl as string) || null,
|
|
365
539
|
original_profile_image_url: (profile?.originalProfileImageUrl as string) || null,
|
|
540
|
+
background_image_url: (profile?.backgroundImageUrl as string) || null,
|
|
541
|
+
original_background_image_url: (profile?.originalBackgroundImageUrl as string) || null,
|
|
542
|
+
fullname: (profile?.fullname as string) || null,
|
|
366
543
|
status_message: (profile?.statusMessage as string) || null,
|
|
367
544
|
account_display_id: accountDisplayId,
|
|
545
|
+
account_email: accountEmail,
|
|
546
|
+
pstn_number: pstnNumber,
|
|
547
|
+
email_verified: emailVerified,
|
|
368
548
|
}
|
|
369
549
|
} catch (error) {
|
|
370
550
|
throw wrapError(error, 'get_profile_failed')
|