agent-messenger 2.5.0 → 2.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (64) hide show
  1. package/.claude-plugin/plugin.json +1 -1
  2. package/.github/workflows/ci.yml +35 -0
  3. package/bun.lock +10 -2
  4. package/dist/package.json +3 -1
  5. package/dist/src/platforms/kakaotalk/client.d.ts +4 -1
  6. package/dist/src/platforms/kakaotalk/client.d.ts.map +1 -1
  7. package/dist/src/platforms/kakaotalk/client.js +21 -7
  8. package/dist/src/platforms/kakaotalk/client.js.map +1 -1
  9. package/dist/src/platforms/kakaotalk/commands/auth.d.ts.map +1 -1
  10. package/dist/src/platforms/kakaotalk/commands/auth.js +24 -55
  11. package/dist/src/platforms/kakaotalk/commands/auth.js.map +1 -1
  12. package/dist/src/platforms/kakaotalk/credential-manager.d.ts.map +1 -1
  13. package/dist/src/platforms/kakaotalk/credential-manager.js +1 -0
  14. package/dist/src/platforms/kakaotalk/credential-manager.js.map +1 -1
  15. package/dist/src/platforms/kakaotalk/index.d.ts +1 -1
  16. package/dist/src/platforms/kakaotalk/index.d.ts.map +1 -1
  17. package/dist/src/platforms/kakaotalk/index.js.map +1 -1
  18. package/dist/src/platforms/kakaotalk/listener.js +2 -2
  19. package/dist/src/platforms/kakaotalk/listener.js.map +1 -1
  20. package/dist/src/platforms/kakaotalk/protocol/config.d.ts +8 -2
  21. package/dist/src/platforms/kakaotalk/protocol/config.d.ts.map +1 -1
  22. package/dist/src/platforms/kakaotalk/protocol/config.js +15 -2
  23. package/dist/src/platforms/kakaotalk/protocol/config.js.map +1 -1
  24. package/dist/src/platforms/kakaotalk/protocol/session.d.ts +3 -1
  25. package/dist/src/platforms/kakaotalk/protocol/session.d.ts.map +1 -1
  26. package/dist/src/platforms/kakaotalk/protocol/session.js +13 -10
  27. package/dist/src/platforms/kakaotalk/protocol/session.js.map +1 -1
  28. package/dist/src/platforms/kakaotalk/types.d.ts +10 -0
  29. package/dist/src/platforms/kakaotalk/types.d.ts.map +1 -1
  30. package/dist/src/platforms/kakaotalk/types.js +1 -0
  31. package/dist/src/platforms/kakaotalk/types.js.map +1 -1
  32. package/dist/src/tui/adapters/kakaotalk-adapter.d.ts.map +1 -1
  33. package/dist/src/tui/adapters/kakaotalk-adapter.js +5 -2
  34. package/dist/src/tui/adapters/kakaotalk-adapter.js.map +1 -1
  35. package/docs/content/docs/cli/kakaotalk.mdx +3 -39
  36. package/e2e/config.ts +1 -1
  37. package/package.json +3 -1
  38. package/skills/agent-channeltalk/SKILL.md +1 -1
  39. package/skills/agent-channeltalkbot/SKILL.md +1 -1
  40. package/skills/agent-discord/SKILL.md +1 -1
  41. package/skills/agent-discordbot/SKILL.md +1 -1
  42. package/skills/agent-instagram/SKILL.md +1 -1
  43. package/skills/agent-kakaotalk/SKILL.md +11 -63
  44. package/skills/agent-kakaotalk/references/authentication.md +4 -69
  45. package/skills/agent-kakaotalk/references/common-patterns.md +13 -0
  46. package/skills/agent-line/SKILL.md +1 -1
  47. package/skills/agent-slack/SKILL.md +1 -1
  48. package/skills/agent-slackbot/SKILL.md +1 -1
  49. package/skills/agent-teams/SKILL.md +1 -1
  50. package/skills/agent-telegram/SKILL.md +1 -1
  51. package/skills/agent-webex/SKILL.md +1 -1
  52. package/skills/agent-wechatbot/SKILL.md +1 -1
  53. package/skills/agent-whatsapp/SKILL.md +1 -1
  54. package/skills/agent-whatsappbot/SKILL.md +1 -1
  55. package/src/platforms/kakaotalk/client.ts +25 -10
  56. package/src/platforms/kakaotalk/commands/auth.ts +22 -73
  57. package/src/platforms/kakaotalk/credential-manager.ts +1 -0
  58. package/src/platforms/kakaotalk/index.ts +1 -0
  59. package/src/platforms/kakaotalk/listener.test.ts +2 -2
  60. package/src/platforms/kakaotalk/listener.ts +2 -2
  61. package/src/platforms/kakaotalk/protocol/config.ts +26 -2
  62. package/src/platforms/kakaotalk/protocol/session.ts +16 -10
  63. package/src/platforms/kakaotalk/types.ts +4 -0
  64. package/src/tui/adapters/kakaotalk-adapter.ts +5 -2
@@ -72,7 +72,7 @@ export class KakaoTalkListener {
72
72
  if (!this.running) return
73
73
 
74
74
  try {
75
- const { oauthToken, userId, deviceUuid } = this.client.getCredentials()
75
+ const { oauthToken, userId, deviceUuid, deviceType } = this.client.getCredentials()
76
76
  if (!this.running) return
77
77
 
78
78
  this.userId = userId
@@ -88,7 +88,7 @@ export class KakaoTalkListener {
88
88
  }
89
89
  })
90
90
 
91
- await session.login(oauthToken, userId, deviceUuid)
91
+ await session.login(oauthToken, userId, deviceUuid, undefined, deviceType)
92
92
 
93
93
  if (!this.running) {
94
94
  session.close()
@@ -1,6 +1,8 @@
1
1
  // Protocol constants for KakaoTalk LOCO.
2
2
  // See protocol/NOTICE.md for attribution of protocol knowledge.
3
3
 
4
+ import type { KakaoDeviceType } from '../types'
5
+
4
6
  // LOCO RSA public key (PKCS#1 DER, base64). RSA-2048, e=3.
5
7
  // Source: openkakao (MIT) — extracted from KakaoTalk macOS binary.
6
8
  export const LOCO_RSA_PUBLIC_KEY_DER_B64 =
@@ -17,8 +19,17 @@ export const BOOKING_PORT = 443
17
19
  export const CHECKIN_HOST = 'ticket-loco.kakao.com'
18
20
  export const CHECKIN_PORT = 995
19
21
 
20
- export const APP_VERSION = '26.2.0'
21
- export const OS = 'mac'
22
+ // PC slot identity — platform-aware: 'win' on Windows, 'mac' on macOS
23
+ const PC_APP_VERSION = '26.2.0'
24
+ const PC_OS: string = process.platform === 'win32' ? 'win' : 'mac'
25
+ export const PC_OS_NAME: string = process.platform === 'win32' ? 'Windows' : 'macOS'
26
+
27
+ // Android (tablet slot) identity — must match the Android sub-device agent
28
+ // used in auth/kakao-login.ts so the server sees a consistent tablet session.
29
+ const ANDROID_APP_VERSION = '25.9.2'
30
+ const ANDROID_OS = 'android'
31
+
32
+ // dtype: 2 = sub-device, 1 = main device (ref: node-kakao config.ts)
22
33
  export const DTYPE = 2
23
34
  export const MCCMNC = '99999'
24
35
  export const LANG = 'ko'
@@ -26,3 +37,16 @@ export const COUNTRY_ISO = 'KR'
26
37
  export const PROTOCOL_VERSION = '1'
27
38
 
28
39
  export const PING_INTERVAL_MS = 300_000
40
+
41
+ export interface LocoDeviceConfig {
42
+ os: string
43
+ appVersion: string
44
+ useSub: boolean
45
+ }
46
+
47
+ export function getLocoDeviceConfig(deviceType: KakaoDeviceType): LocoDeviceConfig {
48
+ if (deviceType === 'tablet') {
49
+ return { os: ANDROID_OS, appVersion: ANDROID_APP_VERSION, useSub: true }
50
+ }
51
+ return { os: PC_OS, appVersion: PC_APP_VERSION, useSub: false }
52
+ }
@@ -1,7 +1,8 @@
1
1
  import { Binary, Long } from 'bson'
2
2
 
3
+ import type { KakaoDeviceType } from '../types'
4
+
3
5
  import {
4
- APP_VERSION,
5
6
  BOOKING_HOST,
6
7
  BOOKING_PORT,
7
8
  CHECKIN_HOST,
@@ -12,6 +13,7 @@ import {
12
13
  MCCMNC,
13
14
  PING_INTERVAL_MS,
14
15
  PROTOCOL_VERSION,
16
+ getLocoDeviceConfig,
15
17
  } from './config'
16
18
  import { LocoConnection } from './connection'
17
19
  import type { BookingResponse, CheckinResponse, LoginListResponse, LocoPacket, SyncState } from './types'
@@ -21,9 +23,13 @@ export class LocoSession {
21
23
  private pingTimer: ReturnType<typeof setInterval> | null = null
22
24
  private pushHandler: ((packet: LocoPacket) => void) | null = null
23
25
  private closeHandler: (() => void) | null = null
26
+ private deviceType: KakaoDeviceType = 'tablet'
27
+
28
+ async login(oauthToken: string, userId: string, deviceUuid: string, syncState?: SyncState, deviceType?: KakaoDeviceType): Promise<LoginListResponse> {
29
+ this.deviceType = deviceType ?? 'tablet'
30
+ const deviceConfig = getLocoDeviceConfig(this.deviceType)
24
31
 
25
- async login(oauthToken: string, userId: string, deviceUuid: string, syncState?: SyncState): Promise<LoginListResponse> {
26
- const { host, port } = await this.bookAndCheckin(userId)
32
+ const { host, port } = await this.bookAndCheckin(userId, deviceConfig)
27
33
 
28
34
  this.connection = new LocoConnection()
29
35
  await this.connection.connectSecure(host, port)
@@ -43,9 +49,9 @@ export class LocoSession {
43
49
  const lbk = syncState?.lbk ?? 0
44
50
 
45
51
  const response = await this.connection.sendPacket('LOGINLIST', {
46
- appVer: APP_VERSION,
52
+ appVer: deviceConfig.appVersion,
47
53
  prtVer: PROTOCOL_VERSION,
48
- os: 'mac',
54
+ os: deviceConfig.os,
49
55
  lang: LANG,
50
56
  dtype: DTYPE,
51
57
  duuid: deviceUuid,
@@ -65,12 +71,12 @@ export class LocoSession {
65
71
  return response.body as unknown as LoginListResponse
66
72
  }
67
73
 
68
- private async bookAndCheckin(userId: string): Promise<{ host: string; port: number }> {
74
+ private async bookAndCheckin(userId: string, deviceConfig: { os: string; appVersion: string; useSub: boolean }): Promise<{ host: string; port: number }> {
69
75
  const bookingConn = new LocoConnection()
70
76
  await bookingConn.connectTls(BOOKING_HOST, BOOKING_PORT)
71
77
 
72
78
  const bookingResponse = await bookingConn.sendPacket('GETCONF', {
73
- os: 'mac',
79
+ os: deviceConfig.os,
74
80
  model: '',
75
81
  })
76
82
  bookingConn.close()
@@ -86,13 +92,13 @@ export class LocoSession {
86
92
 
87
93
  const checkinResponse = await checkinConn.sendPacket('CHECKIN', {
88
94
  userId: Number(userId),
89
- os: 'mac',
95
+ os: deviceConfig.os,
90
96
  ntype: 0,
91
- appVer: APP_VERSION,
97
+ appVer: deviceConfig.appVersion,
92
98
  MCCMNC: MCCMNC,
93
99
  lang: LANG,
94
100
  countryISO: COUNTRY_ISO,
95
- useSub: true,
101
+ useSub: deviceConfig.useSub,
96
102
  })
97
103
  checkinConn.close()
98
104
 
@@ -11,6 +11,8 @@ export interface ExtractedKakaoToken {
11
11
  login_form_body?: string
12
12
  }
13
13
 
14
+ export type KakaoAuthMethod = 'login' | 'extract'
15
+
14
16
  export interface KakaoAccountCredentials {
15
17
  account_id: string
16
18
  oauth_token: string
@@ -18,6 +20,7 @@ export interface KakaoAccountCredentials {
18
20
  refresh_token?: string
19
21
  device_uuid: string
20
22
  device_type: KakaoDeviceType
23
+ auth_method?: KakaoAuthMethod
21
24
  created_at: string
22
25
  updated_at: string
23
26
  }
@@ -162,6 +165,7 @@ export const KakaoAccountCredentialsSchema = z.object({
162
165
  refresh_token: z.string().optional(),
163
166
  device_uuid: z.string(),
164
167
  device_type: z.enum(['pc', 'tablet']),
168
+ auth_method: z.enum(['login', 'extract']).optional(),
165
169
  created_at: z.string(),
166
170
  updated_at: z.string(),
167
171
  })
@@ -64,7 +64,7 @@ export class KakaoTalkAdapter implements PlatformAdapter {
64
64
  if (!creds) throw new Error(`Account ${accountId} not found`)
65
65
 
66
66
  const client = new KakaoTalkClient()
67
- await client.login({ oauthToken: creds.oauth_token, userId: creds.user_id, deviceUuid: creds.device_uuid })
67
+ await client.login({ oauthToken: creds.oauth_token, userId: creds.user_id, deviceUuid: creds.device_uuid, deviceType: creds.device_type })
68
68
  this.client = client
69
69
  this.currentAccount = { id: creds.account_id, name: creds.account_id }
70
70
  }
@@ -86,7 +86,8 @@ export class KakaoTalkAdapter implements PlatformAdapter {
86
86
 
87
87
  const existing = await this.credManager.getAccount()
88
88
  const pendingState = await this.credManager.loadPendingLogin()
89
- const savedDeviceUuid = pendingState?.device_uuid ?? existing?.device_uuid ?? generateDeviceUuid()
89
+ const existingUuid = existing?.auth_method === 'login' ? existing?.device_uuid : undefined
90
+ const savedDeviceUuid = pendingState?.device_uuid ?? existingUuid ?? generateDeviceUuid()
90
91
 
91
92
  let email: string | undefined
92
93
  let password: string | undefined
@@ -139,6 +140,7 @@ export class KakaoTalkAdapter implements PlatformAdapter {
139
140
  refresh_token: result.credentials.refresh_token,
140
141
  device_uuid: result.credentials.device_uuid,
141
142
  device_type: result.credentials.device_type,
143
+ auth_method: 'login',
142
144
  created_at: now,
143
145
  updated_at: now,
144
146
  })
@@ -149,6 +151,7 @@ export class KakaoTalkAdapter implements PlatformAdapter {
149
151
  oauthToken: result.credentials.access_token,
150
152
  userId: result.credentials.user_id,
151
153
  deviceUuid: result.credentials.device_uuid,
154
+ deviceType: result.credentials.device_type,
152
155
  })
153
156
  this.client = client
154
157
  this.currentAccount = { id: result.credentials.user_id, name: email }