agent-messenger 2.18.0 → 2.19.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 (75) hide show
  1. package/.claude-plugin/plugin.json +1 -1
  2. package/bunfig.toml +1 -0
  3. package/dist/package.json +1 -1
  4. package/dist/src/platforms/discordbot/client.d.ts +1 -0
  5. package/dist/src/platforms/discordbot/client.d.ts.map +1 -1
  6. package/dist/src/platforms/discordbot/client.js +3 -0
  7. package/dist/src/platforms/discordbot/client.js.map +1 -1
  8. package/dist/src/platforms/discordbot/commands/message.d.ts +1 -0
  9. package/dist/src/platforms/discordbot/commands/message.d.ts.map +1 -1
  10. package/dist/src/platforms/discordbot/commands/message.js +2 -0
  11. package/dist/src/platforms/discordbot/commands/message.js.map +1 -1
  12. package/dist/src/platforms/kakaotalk/client.d.ts +4 -2
  13. package/dist/src/platforms/kakaotalk/client.d.ts.map +1 -1
  14. package/dist/src/platforms/kakaotalk/client.js +16 -2
  15. package/dist/src/platforms/kakaotalk/client.js.map +1 -1
  16. package/dist/src/platforms/kakaotalk/commands/message.d.ts.map +1 -1
  17. package/dist/src/platforms/kakaotalk/commands/message.js +23 -1
  18. package/dist/src/platforms/kakaotalk/commands/message.js.map +1 -1
  19. package/dist/src/platforms/kakaotalk/index.d.ts +1 -1
  20. package/dist/src/platforms/kakaotalk/index.d.ts.map +1 -1
  21. package/dist/src/platforms/kakaotalk/index.js.map +1 -1
  22. package/dist/src/platforms/kakaotalk/protocol/session.d.ts +2 -1
  23. package/dist/src/platforms/kakaotalk/protocol/session.d.ts.map +1 -1
  24. package/dist/src/platforms/kakaotalk/protocol/session.js +15 -0
  25. package/dist/src/platforms/kakaotalk/protocol/session.js.map +1 -1
  26. package/dist/src/platforms/kakaotalk/types.d.ts +18 -0
  27. package/dist/src/platforms/kakaotalk/types.d.ts.map +1 -1
  28. package/dist/src/platforms/kakaotalk/types.js +1 -0
  29. package/dist/src/platforms/kakaotalk/types.js.map +1 -1
  30. package/dist/src/shared/chromium/browsers.js +1 -1
  31. package/dist/src/shared/chromium/browsers.js.map +1 -1
  32. package/docs/content/docs/cli/discordbot.mdx +6 -0
  33. package/docs/content/docs/sdk/discordbot.mdx +4 -0
  34. package/package.json +1 -1
  35. package/skills/agent-channeltalk/SKILL.md +1 -1
  36. package/skills/agent-channeltalkbot/SKILL.md +1 -1
  37. package/skills/agent-discord/SKILL.md +1 -1
  38. package/skills/agent-discordbot/SKILL.md +9 -1
  39. package/skills/agent-instagram/SKILL.md +1 -1
  40. package/skills/agent-kakaotalk/SKILL.md +24 -1
  41. package/skills/agent-line/SKILL.md +1 -1
  42. package/skills/agent-slack/SKILL.md +1 -1
  43. package/skills/agent-slackbot/SKILL.md +1 -1
  44. package/skills/agent-teams/SKILL.md +1 -1
  45. package/skills/agent-telegram/SKILL.md +1 -1
  46. package/skills/agent-telegrambot/SKILL.md +1 -1
  47. package/skills/agent-webex/SKILL.md +1 -1
  48. package/skills/agent-wechatbot/SKILL.md +1 -1
  49. package/skills/agent-whatsapp/SKILL.md +1 -1
  50. package/skills/agent-whatsappbot/SKILL.md +1 -1
  51. package/src/platforms/discord/commands/dm.test.ts +28 -20
  52. package/src/platforms/discord/commands/reaction.test.ts +12 -7
  53. package/src/platforms/discordbot/client.test.ts +17 -0
  54. package/src/platforms/discordbot/client.ts +9 -2
  55. package/src/platforms/discordbot/commands/message.test.ts +28 -11
  56. package/src/platforms/discordbot/commands/message.ts +4 -2
  57. package/src/platforms/instagram/commands/auth.test.ts +11 -9
  58. package/src/platforms/instagram/commands/chat.test.ts +8 -6
  59. package/src/platforms/instagram/commands/message.test.ts +8 -6
  60. package/src/platforms/kakaotalk/client.test.ts +57 -0
  61. package/src/platforms/kakaotalk/client.ts +23 -2
  62. package/src/platforms/kakaotalk/commands/message.test.ts +42 -0
  63. package/src/platforms/kakaotalk/commands/message.ts +33 -2
  64. package/src/platforms/kakaotalk/index.ts +2 -0
  65. package/src/platforms/kakaotalk/protocol/session.ts +15 -1
  66. package/src/platforms/kakaotalk/types.ts +24 -0
  67. package/src/platforms/webex/commands/auth.test.ts +24 -14
  68. package/src/platforms/webex/commands/member.test.ts +14 -20
  69. package/src/platforms/webex/commands/message.test.ts +11 -20
  70. package/src/platforms/webex/commands/snapshot.test.ts +11 -20
  71. package/src/platforms/webex/commands/space.test.ts +15 -23
  72. package/src/platforms/webex/commands/whoami.test.ts +8 -22
  73. package/src/shared/chromium/browsers.ts +1 -1
  74. package/src/test-setup.ts +5 -0
  75. package/tsconfig.json +1 -1
@@ -1,14 +1,9 @@
1
1
  import { afterEach, beforeEach, describe, expect, mock, spyOn, it } from 'bun:test'
2
2
 
3
- import { WebexError } from '../types'
4
-
5
- const mockHandleError = mock((err: Error) => {
6
- throw err
7
- })
3
+ import * as errorHandler from '@/shared/utils/error-handler'
8
4
 
9
- mock.module('@/shared/utils/error-handler', () => ({
10
- handleError: mockHandleError,
11
- }))
5
+ import { WebexClient } from '../client'
6
+ import { WebexError } from '../types'
12
7
 
13
8
  const mockMembers = [
14
9
  {
@@ -32,30 +27,29 @@ const mockMembers = [
32
27
  ]
33
28
 
34
29
  const mockListMemberships = mock(() => Promise.resolve(mockMembers))
35
- const mockLogin = mock(() => Promise.resolve({ listMemberships: mockListMemberships }))
36
-
37
- mock.module('../client', () => ({
38
- WebexClient: class {
39
- login = mockLogin
40
- },
41
- }))
42
30
 
43
31
  import { listAction } from './member'
44
32
 
45
33
  describe('member commands', () => {
46
34
  let consoleSpy: ReturnType<typeof spyOn>
35
+ let loginSpy: ReturnType<typeof spyOn>
36
+ let handleErrorSpy: ReturnType<typeof spyOn>
47
37
 
48
38
  beforeEach(() => {
49
39
  mockListMemberships.mockReset().mockImplementation(() => Promise.resolve(mockMembers))
50
- mockLogin.mockReset().mockImplementation(() => Promise.resolve({ listMemberships: mockListMemberships }))
51
- mockHandleError.mockReset().mockImplementation((err: Error) => {
40
+ handleErrorSpy = spyOn(errorHandler, 'handleError').mockImplementation((err: Error) => {
52
41
  throw err
53
42
  })
54
43
 
44
+ loginSpy = spyOn(WebexClient.prototype, 'login').mockResolvedValue(
45
+ Object.assign(new WebexClient(), { listMemberships: mockListMemberships }),
46
+ )
55
47
  consoleSpy = spyOn(console, 'log').mockImplementation(() => {})
56
48
  })
57
49
 
58
50
  afterEach(() => {
51
+ loginSpy.mockRestore()
52
+ handleErrorSpy.mockRestore()
59
53
  consoleSpy.mockRestore()
60
54
  })
61
55
 
@@ -92,13 +86,13 @@ describe('member commands', () => {
92
86
  })
93
87
 
94
88
  it('throws when not authenticated', async () => {
95
- mockLogin.mockImplementation(async () => {
89
+ loginSpy.mockImplementation(async () => {
96
90
  throw new WebexError('No Webex credentials found.', 'no_credentials')
97
91
  })
98
92
 
99
93
  await expect(listAction('room-1', {})).rejects.toThrow('No Webex credentials found.')
100
94
 
101
- expect(mockHandleError).toHaveBeenCalledWith(expect.any(WebexError))
95
+ expect(handleErrorSpy).toHaveBeenCalledWith(expect.any(WebexError))
102
96
  })
103
97
 
104
98
  it('throws on API error', async () => {
@@ -108,6 +102,6 @@ describe('member commands', () => {
108
102
 
109
103
  await expect(listAction('room-1', {})).rejects.toThrow('API failure')
110
104
 
111
- expect(mockHandleError).toHaveBeenCalledWith(expect.any(Error))
105
+ expect(handleErrorSpy).toHaveBeenCalledWith(expect.any(Error))
112
106
  })
113
107
  })
@@ -1,14 +1,9 @@
1
1
  import { afterEach, beforeEach, expect, mock, spyOn, it } from 'bun:test'
2
2
 
3
- import { WebexError } from '../types'
4
-
5
- const mockHandleError = mock((err: Error) => {
6
- throw err
7
- })
3
+ import * as errorHandler from '@/shared/utils/error-handler'
8
4
 
9
- mock.module('@/shared/utils/error-handler', () => ({
10
- handleError: mockHandleError,
11
- }))
5
+ import { WebexClient } from '../client'
6
+ import { WebexError } from '../types'
12
7
 
13
8
  const mockMessage = {
14
9
  id: 'msg_123',
@@ -46,17 +41,11 @@ const mockClient = {
46
41
  editMessage: mockEditMessage,
47
42
  }
48
43
 
49
- const mockLogin = mock(() => Promise.resolve(mockClient))
50
-
51
- mock.module('../client', () => ({
52
- WebexClient: class {
53
- login = mockLogin
54
- },
55
- }))
56
-
57
44
  import { deleteAction, dmAction, editAction, getAction, listAction, sendAction } from './message'
58
45
 
59
46
  let consoleLogSpy: ReturnType<typeof spyOn>
47
+ let loginSpy: ReturnType<typeof spyOn>
48
+ let handleErrorSpy: ReturnType<typeof spyOn>
60
49
 
61
50
  beforeEach(() => {
62
51
  mockSendMessage.mockReset().mockImplementation(() => Promise.resolve(mockMessage))
@@ -65,15 +54,17 @@ beforeEach(() => {
65
54
  mockGetMessage.mockReset().mockImplementation(() => Promise.resolve(mockMessage))
66
55
  mockDeleteMessage.mockReset().mockImplementation(() => Promise.resolve(undefined))
67
56
  mockEditMessage.mockReset().mockImplementation(() => Promise.resolve({ ...mockMessage, text: 'Updated message' }))
68
- mockLogin.mockReset().mockImplementation(() => Promise.resolve(mockClient))
69
- mockHandleError.mockReset().mockImplementation((err: Error) => {
57
+ handleErrorSpy = spyOn(errorHandler, 'handleError').mockImplementation((err: Error) => {
70
58
  throw err
71
59
  })
72
60
 
61
+ loginSpy = spyOn(WebexClient.prototype, 'login').mockResolvedValue(Object.assign(new WebexClient(), mockClient))
73
62
  consoleLogSpy = spyOn(console, 'log').mockImplementation(() => {})
74
63
  })
75
64
 
76
65
  afterEach(() => {
66
+ loginSpy.mockRestore()
67
+ handleErrorSpy.mockRestore()
77
68
  consoleLogSpy.mockRestore()
78
69
  })
79
70
 
@@ -97,13 +88,13 @@ it('passes markdown option when --markdown flag is set on send', async () => {
97
88
  })
98
89
 
99
90
  it('throws when not authenticated on send', async () => {
100
- mockLogin.mockImplementation(async () => {
91
+ loginSpy.mockImplementation(async () => {
101
92
  throw new WebexError('No Webex credentials found.', 'no_credentials')
102
93
  })
103
94
 
104
95
  await expect(sendAction('space_456', 'Hello', { pretty: false })).rejects.toThrow('No Webex credentials found.')
105
96
 
106
- expect(mockHandleError).toHaveBeenCalledWith(expect.any(WebexError))
97
+ expect(handleErrorSpy).toHaveBeenCalledWith(expect.any(WebexError))
107
98
  })
108
99
 
109
100
  it('calls sendDirectMessage with email and text', async () => {
@@ -1,14 +1,9 @@
1
1
  import { afterEach, beforeEach, describe, expect, mock, spyOn, it } from 'bun:test'
2
2
 
3
- import { WebexError } from '../types'
4
-
5
- const mockHandleError = mock((err: Error) => {
6
- throw err
7
- })
3
+ import * as errorHandler from '@/shared/utils/error-handler'
8
4
 
9
- mock.module('@/shared/utils/error-handler', () => ({
10
- handleError: mockHandleError,
11
- }))
5
+ import { WebexClient } from '../client'
6
+ import { WebexError } from '../types'
12
7
 
13
8
  const mockSpaces = [
14
9
  {
@@ -51,31 +46,27 @@ const mockClient = {
51
46
  listMyMemberships: mockListMyMemberships,
52
47
  }
53
48
 
54
- const mockLogin = mock(() => Promise.resolve(mockClient))
55
-
56
- mock.module('../client', () => ({
57
- WebexClient: class {
58
- login = mockLogin
59
- },
60
- }))
61
-
62
49
  import { snapshotAction } from './snapshot'
63
50
 
64
51
  describe('snapshot command', () => {
65
52
  let consoleSpy: ReturnType<typeof spyOn>
53
+ let loginSpy: ReturnType<typeof spyOn>
54
+ let handleErrorSpy: ReturnType<typeof spyOn>
66
55
 
67
56
  beforeEach(() => {
68
57
  mockListSpaces.mockReset().mockImplementation(() => Promise.resolve(mockSpaces as any))
69
58
  mockListMyMemberships.mockReset().mockImplementation(() => Promise.resolve(mockMyMemberships as any))
70
- mockLogin.mockReset().mockImplementation(() => Promise.resolve(mockClient))
71
- mockHandleError.mockReset().mockImplementation((err: Error) => {
59
+ handleErrorSpy = spyOn(errorHandler, 'handleError').mockImplementation((err: Error) => {
72
60
  throw err
73
61
  })
74
62
 
63
+ loginSpy = spyOn(WebexClient.prototype, 'login').mockResolvedValue(Object.assign(new WebexClient(), mockClient))
75
64
  consoleSpy = spyOn(console, 'log').mockImplementation(() => {})
76
65
  })
77
66
 
78
67
  afterEach(() => {
68
+ loginSpy.mockRestore()
69
+ handleErrorSpy.mockRestore()
79
70
  consoleSpy.mockRestore()
80
71
  })
81
72
 
@@ -113,12 +104,12 @@ describe('snapshot command', () => {
113
104
  })
114
105
 
115
106
  it('throws when not authenticated', async () => {
116
- mockLogin.mockImplementation(async () => {
107
+ loginSpy.mockImplementation(async () => {
117
108
  throw new WebexError('No Webex credentials found.', 'no_credentials')
118
109
  })
119
110
 
120
111
  await expect(snapshotAction({})).rejects.toThrow('No Webex credentials found.')
121
112
 
122
- expect(mockHandleError).toHaveBeenCalledWith(expect.any(WebexError))
113
+ expect(handleErrorSpy).toHaveBeenCalledWith(expect.any(WebexError))
123
114
  })
124
115
  })
@@ -1,14 +1,9 @@
1
1
  import { afterEach, beforeEach, describe, expect, mock, spyOn, it } from 'bun:test'
2
2
 
3
- import { WebexError } from '../types'
4
-
5
- const mockHandleError = mock((err: Error) => {
6
- throw err
7
- })
3
+ import * as errorHandler from '@/shared/utils/error-handler'
8
4
 
9
- mock.module('@/shared/utils/error-handler', () => ({
10
- handleError: mockHandleError,
11
- }))
5
+ import { WebexClient } from '../client'
6
+ import { WebexError } from '../types'
12
7
 
13
8
  const mockSpaces = [
14
9
  {
@@ -44,32 +39,29 @@ const mockSpace = {
44
39
 
45
40
  const mockListSpaces = mock(() => Promise.resolve(mockSpaces))
46
41
  const mockGetSpace = mock(() => Promise.resolve(mockSpace))
47
- const mockLogin = mock(() => Promise.resolve({ listSpaces: mockListSpaces, getSpace: mockGetSpace }))
48
-
49
- mock.module('../client', () => ({
50
- WebexClient: class {
51
- login = mockLogin
52
- },
53
- }))
54
42
 
55
43
  import { infoAction, listAction } from './space'
56
44
 
57
45
  let consoleLogSpy: ReturnType<typeof spyOn>
46
+ let loginSpy: ReturnType<typeof spyOn>
47
+ let handleErrorSpy: ReturnType<typeof spyOn>
58
48
 
59
49
  beforeEach(() => {
60
50
  mockListSpaces.mockReset().mockImplementation(() => Promise.resolve(mockSpaces))
61
51
  mockGetSpace.mockReset().mockImplementation(() => Promise.resolve(mockSpace))
62
- mockLogin
63
- .mockReset()
64
- .mockImplementation(() => Promise.resolve({ listSpaces: mockListSpaces, getSpace: mockGetSpace }))
65
- mockHandleError.mockReset().mockImplementation((err: Error) => {
52
+ handleErrorSpy = spyOn(errorHandler, 'handleError').mockImplementation((err: Error) => {
66
53
  throw err
67
54
  })
68
55
 
56
+ loginSpy = spyOn(WebexClient.prototype, 'login').mockResolvedValue(
57
+ Object.assign(new WebexClient(), { listSpaces: mockListSpaces, getSpace: mockGetSpace }),
58
+ )
69
59
  consoleLogSpy = spyOn(console, 'log').mockImplementation(() => {})
70
60
  })
71
61
 
72
62
  afterEach(() => {
63
+ loginSpy.mockRestore()
64
+ handleErrorSpy.mockRestore()
73
65
  consoleLogSpy.mockRestore()
74
66
  })
75
67
 
@@ -138,14 +130,14 @@ describe('listAction', () => {
138
130
  })
139
131
 
140
132
  it('throws when not authenticated', async () => {
141
- mockLogin.mockImplementation(async () => {
133
+ loginSpy.mockImplementation(async () => {
142
134
  throw new WebexError('No Webex credentials found.', 'no_credentials')
143
135
  })
144
136
 
145
137
  await expect(listAction({})).rejects.toThrow('No Webex credentials found.')
146
138
 
147
139
  expect(mockListSpaces).not.toHaveBeenCalled()
148
- expect(mockHandleError).toHaveBeenCalledWith(expect.any(WebexError))
140
+ expect(handleErrorSpy).toHaveBeenCalledWith(expect.any(WebexError))
149
141
  })
150
142
  })
151
143
 
@@ -201,13 +193,13 @@ describe('infoAction', () => {
201
193
  })
202
194
 
203
195
  it('throws when not authenticated', async () => {
204
- mockLogin.mockImplementation(async () => {
196
+ loginSpy.mockImplementation(async () => {
205
197
  throw new WebexError('No Webex credentials found.', 'no_credentials')
206
198
  })
207
199
 
208
200
  await expect(infoAction('space-1', {})).rejects.toThrow('No Webex credentials found.')
209
201
 
210
202
  expect(mockGetSpace).not.toHaveBeenCalled()
211
- expect(mockHandleError).toHaveBeenCalledWith(expect.any(WebexError))
203
+ expect(handleErrorSpy).toHaveBeenCalledWith(expect.any(WebexError))
212
204
  })
213
205
  })
@@ -1,6 +1,6 @@
1
1
  import { afterEach, beforeEach, expect, spyOn, it } from 'bun:test'
2
2
 
3
- import * as clientModule from '../client'
3
+ import { WebexClient } from '../client'
4
4
  import { WebexError } from '../types'
5
5
  import { whoamiCommand } from './whoami'
6
6
 
@@ -17,27 +17,21 @@ const mockUser = {
17
17
  created: '2024-01-01T00:00:00.000Z',
18
18
  }
19
19
 
20
- const makeFakeClient = () => ({
21
- login: async function (this: unknown) {
22
- return this
23
- },
24
- testAuth: async () => mockUser,
25
- })
26
-
27
- let webexClientSpy: ReturnType<typeof spyOn>
20
+ let loginSpy: ReturnType<typeof spyOn>
21
+ let testAuthSpy: ReturnType<typeof spyOn>
28
22
  let consoleLogSpy: ReturnType<typeof spyOn>
29
23
  let processExitSpy: ReturnType<typeof spyOn>
30
24
 
31
25
  beforeEach(() => {
32
- webexClientSpy = spyOn(clientModule, 'WebexClient').mockImplementation(
33
- makeFakeClient as unknown as typeof clientModule.WebexClient,
34
- )
26
+ loginSpy = spyOn(WebexClient.prototype, 'login').mockResolvedValue(new WebexClient())
27
+ testAuthSpy = spyOn(WebexClient.prototype, 'testAuth').mockResolvedValue(mockUser)
35
28
  consoleLogSpy = spyOn(console, 'log').mockImplementation(() => {})
36
29
  processExitSpy = spyOn(process, 'exit').mockImplementation((_code?: number) => undefined as never)
37
30
  })
38
31
 
39
32
  afterEach(() => {
40
- webexClientSpy?.mockRestore()
33
+ loginSpy?.mockRestore()
34
+ testAuthSpy?.mockRestore()
41
35
  consoleLogSpy?.mockRestore()
42
36
  processExitSpy?.mockRestore()
43
37
  })
@@ -102,15 +96,7 @@ it('whoami outputs pretty-printed JSON when --pretty flag is passed', async () =
102
96
 
103
97
  it('whoami exits with code 1 when not authenticated', async () => {
104
98
  // given: no credentials
105
- webexClientSpy.mockImplementation(
106
- () =>
107
- ({
108
- login: async () => {
109
- throw new WebexError('No Webex credentials found.', 'no_credentials')
110
- },
111
- testAuth: async () => mockUser,
112
- }) as unknown as clientModule.WebexClient,
113
- )
99
+ loginSpy.mockRejectedValue(new WebexError('No Webex credentials found.', 'no_credentials'))
114
100
 
115
101
  // when: running whoami
116
102
  await whoamiCommand.parseAsync([], { from: 'user' })
@@ -75,7 +75,7 @@ export function discoverBrowserProfileDirs(browserBase: string): string[] {
75
75
  dirs.push(join(browserBase, 'Default'))
76
76
  if (!existsSync(browserBase)) return dirs
77
77
  try {
78
- const entries = readdirSync(browserBase, { withFileTypes: true })
78
+ const entries = readdirSync(browserBase, { withFileTypes: true }).sort((a, b) => a.name.localeCompare(b.name))
79
79
  for (const entry of entries) {
80
80
  if (!entry.isDirectory()) continue
81
81
  if (!/^Profile \d+$/i.test(entry.name)) continue
@@ -0,0 +1,5 @@
1
+ import { afterEach, mock } from 'bun:test'
2
+
3
+ afterEach(() => {
4
+ mock.restore()
5
+ })
package/tsconfig.json CHANGED
@@ -38,5 +38,5 @@
38
38
  "noFallthroughCasesInSwitch": true
39
39
  },
40
40
  "include": ["src/**/*", "tests/**/*"],
41
- "exclude": ["node_modules", "dist", "**/*.test.ts", "**/*-test.ts"]
41
+ "exclude": ["node_modules", "dist", "**/*.test.ts", "**/*-test.ts", "src/test-setup.ts"]
42
42
  }