agent-messenger 1.3.6 → 1.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.
Files changed (127) hide show
  1. package/.claude-plugin/README.md +38 -14
  2. package/.claude-plugin/plugin.json +1 -1
  3. package/.github/workflows/ci.yml +3 -0
  4. package/CONTRIBUTING.md +24 -1
  5. package/README.md +12 -8
  6. package/dist/package.json +1 -1
  7. package/dist/src/cli.d.ts.map +1 -1
  8. package/dist/src/cli.js +3 -0
  9. package/dist/src/cli.js.map +1 -1
  10. package/dist/src/platforms/discord/cli.d.ts +2 -2
  11. package/dist/src/platforms/discord/cli.d.ts.map +1 -1
  12. package/dist/src/platforms/discord/cli.js +23 -1
  13. package/dist/src/platforms/discord/cli.js.map +1 -1
  14. package/dist/src/platforms/discord/commands/file.d.ts.map +1 -1
  15. package/dist/src/platforms/discord/commands/file.js +13 -7
  16. package/dist/src/platforms/discord/commands/file.js.map +1 -1
  17. package/dist/src/platforms/discord/commands/friend.d.ts.map +1 -1
  18. package/dist/src/platforms/discord/commands/friend.js +30 -30
  19. package/dist/src/platforms/discord/commands/friend.js.map +1 -1
  20. package/dist/src/platforms/discord/commands/index.d.ts +7 -0
  21. package/dist/src/platforms/discord/commands/index.d.ts.map +1 -1
  22. package/dist/src/platforms/discord/commands/index.js +7 -0
  23. package/dist/src/platforms/discord/commands/index.js.map +1 -1
  24. package/dist/src/platforms/discord/commands/snapshot.d.ts.map +1 -1
  25. package/dist/src/platforms/discord/commands/snapshot.js +1 -2
  26. package/dist/src/platforms/discord/commands/snapshot.js.map +1 -1
  27. package/dist/src/platforms/discord/ensure-auth.d.ts +2 -0
  28. package/dist/src/platforms/discord/ensure-auth.d.ts.map +1 -0
  29. package/dist/src/platforms/discord/ensure-auth.js +31 -0
  30. package/dist/src/platforms/discord/ensure-auth.js.map +1 -0
  31. package/dist/src/platforms/slack/cli.d.ts +2 -2
  32. package/dist/src/platforms/slack/cli.d.ts.map +1 -1
  33. package/dist/src/platforms/slack/cli.js +15 -0
  34. package/dist/src/platforms/slack/cli.js.map +1 -1
  35. package/dist/src/platforms/slack/client.d.ts +1 -0
  36. package/dist/src/platforms/slack/client.d.ts.map +1 -1
  37. package/dist/src/platforms/slack/client.js +13 -0
  38. package/dist/src/platforms/slack/client.js.map +1 -1
  39. package/dist/src/platforms/slack/commands/channel.d.ts.map +1 -1
  40. package/dist/src/platforms/slack/commands/channel.js +2 -0
  41. package/dist/src/platforms/slack/commands/channel.js.map +1 -1
  42. package/dist/src/platforms/slack/commands/file.d.ts.map +1 -1
  43. package/dist/src/platforms/slack/commands/file.js +13 -5
  44. package/dist/src/platforms/slack/commands/file.js.map +1 -1
  45. package/dist/src/platforms/slack/commands/message.d.ts.map +1 -1
  46. package/dist/src/platforms/slack/commands/message.js +12 -6
  47. package/dist/src/platforms/slack/commands/message.js.map +1 -1
  48. package/dist/src/platforms/slack/commands/reaction.d.ts.map +1 -1
  49. package/dist/src/platforms/slack/commands/reaction.js +3 -0
  50. package/dist/src/platforms/slack/commands/reaction.js.map +1 -1
  51. package/dist/src/platforms/slack/commands/sections.d.ts.map +1 -1
  52. package/dist/src/platforms/slack/commands/sections.js +5 -6
  53. package/dist/src/platforms/slack/commands/sections.js.map +1 -1
  54. package/dist/src/platforms/slack/commands/snapshot.d.ts.map +1 -1
  55. package/dist/src/platforms/slack/commands/snapshot.js +1 -2
  56. package/dist/src/platforms/slack/commands/snapshot.js.map +1 -1
  57. package/dist/src/platforms/slack/commands/unread.d.ts.map +1 -1
  58. package/dist/src/platforms/slack/commands/unread.js +2 -0
  59. package/dist/src/platforms/slack/commands/unread.js.map +1 -1
  60. package/dist/src/platforms/slack/commands/user.js +8 -8
  61. package/dist/src/platforms/slack/ensure-auth.d.ts +2 -0
  62. package/dist/src/platforms/slack/ensure-auth.d.ts.map +1 -0
  63. package/dist/src/platforms/slack/ensure-auth.js +30 -0
  64. package/dist/src/platforms/slack/ensure-auth.js.map +1 -0
  65. package/dist/src/platforms/slackbot/client.d.ts +1 -0
  66. package/dist/src/platforms/slackbot/client.d.ts.map +1 -1
  67. package/dist/src/platforms/slackbot/client.js +13 -0
  68. package/dist/src/platforms/slackbot/client.js.map +1 -1
  69. package/dist/src/platforms/slackbot/commands/channel.d.ts.map +1 -1
  70. package/dist/src/platforms/slackbot/commands/channel.js +3 -2
  71. package/dist/src/platforms/slackbot/commands/channel.js.map +1 -1
  72. package/dist/src/platforms/slackbot/commands/message.d.ts.map +1 -1
  73. package/dist/src/platforms/slackbot/commands/message.js +18 -12
  74. package/dist/src/platforms/slackbot/commands/message.js.map +1 -1
  75. package/dist/src/platforms/slackbot/commands/reaction.d.ts.map +1 -1
  76. package/dist/src/platforms/slackbot/commands/reaction.js +8 -6
  77. package/dist/src/platforms/slackbot/commands/reaction.js.map +1 -1
  78. package/dist/src/platforms/teams/cli.d.ts +2 -2
  79. package/dist/src/platforms/teams/cli.d.ts.map +1 -1
  80. package/dist/src/platforms/teams/cli.js +15 -0
  81. package/dist/src/platforms/teams/cli.js.map +1 -1
  82. package/dist/src/platforms/teams/commands/file.js +12 -12
  83. package/dist/src/platforms/teams/commands/file.js.map +1 -1
  84. package/dist/src/platforms/teams/commands/snapshot.d.ts.map +1 -1
  85. package/dist/src/platforms/teams/commands/snapshot.js +1 -2
  86. package/dist/src/platforms/teams/commands/snapshot.js.map +1 -1
  87. package/dist/src/platforms/teams/ensure-auth.d.ts +2 -0
  88. package/dist/src/platforms/teams/ensure-auth.d.ts.map +1 -0
  89. package/dist/src/platforms/teams/ensure-auth.js +32 -0
  90. package/dist/src/platforms/teams/ensure-auth.js.map +1 -0
  91. package/e2e/README.md +1 -1
  92. package/package.json +1 -1
  93. package/skills/agent-discord/SKILL.md +22 -22
  94. package/skills/agent-slack/SKILL.md +28 -40
  95. package/skills/agent-teams/SKILL.md +41 -65
  96. package/skills/agent-teams/references/common-patterns.md +63 -49
  97. package/src/cli.ts +4 -0
  98. package/src/platforms/discord/cli.ts +30 -0
  99. package/src/platforms/discord/commands/file.ts +13 -7
  100. package/src/platforms/discord/commands/friend.ts +34 -34
  101. package/src/platforms/discord/commands/index.ts +7 -0
  102. package/src/platforms/discord/commands/snapshot.ts +1 -2
  103. package/src/platforms/discord/ensure-auth.test.ts +123 -0
  104. package/src/platforms/discord/ensure-auth.ts +31 -0
  105. package/src/platforms/slack/cli.ts +16 -0
  106. package/src/platforms/slack/client.test.ts +101 -0
  107. package/src/platforms/slack/client.ts +22 -0
  108. package/src/platforms/slack/commands/channel.ts +2 -0
  109. package/src/platforms/slack/commands/file.ts +15 -5
  110. package/src/platforms/slack/commands/message.ts +17 -6
  111. package/src/platforms/slack/commands/reaction.ts +3 -0
  112. package/src/platforms/slack/commands/sections.ts +8 -9
  113. package/src/platforms/slack/commands/snapshot.ts +1 -2
  114. package/src/platforms/slack/commands/unread.ts +2 -0
  115. package/src/platforms/slack/commands/user.ts +8 -8
  116. package/src/platforms/slack/ensure-auth.test.ts +186 -0
  117. package/src/platforms/slack/ensure-auth.ts +30 -0
  118. package/src/platforms/slackbot/client.test.ts +87 -0
  119. package/src/platforms/slackbot/client.ts +21 -0
  120. package/src/platforms/slackbot/commands/channel.ts +3 -2
  121. package/src/platforms/slackbot/commands/message.ts +18 -12
  122. package/src/platforms/slackbot/commands/reaction.ts +8 -6
  123. package/src/platforms/teams/cli.ts +16 -0
  124. package/src/platforms/teams/commands/file.ts +12 -12
  125. package/src/platforms/teams/commands/snapshot.ts +1 -2
  126. package/src/platforms/teams/ensure-auth.test.ts +167 -0
  127. package/src/platforms/teams/ensure-auth.ts +34 -0
@@ -0,0 +1,167 @@
1
+ import { afterEach, beforeEach, describe, expect, spyOn, test } from 'bun:test'
2
+ import { TeamsClient } from './client'
3
+ import { TeamsCredentialManager } from './credential-manager'
4
+ import { ensureTeamsAuth } from './ensure-auth'
5
+ import { TeamsTokenExtractor } from './token-extractor'
6
+
7
+ let loadConfigSpy: ReturnType<typeof spyOn>
8
+ let isTokenExpiredSpy: ReturnType<typeof spyOn>
9
+ let extractSpy: ReturnType<typeof spyOn>
10
+ let testAuthSpy: ReturnType<typeof spyOn>
11
+ let listTeamsSpy: ReturnType<typeof spyOn>
12
+ let saveConfigSpy: ReturnType<typeof spyOn>
13
+
14
+ beforeEach(() => {
15
+ loadConfigSpy = spyOn(TeamsCredentialManager.prototype, 'loadConfig').mockResolvedValue(null)
16
+
17
+ isTokenExpiredSpy = spyOn(TeamsCredentialManager.prototype, 'isTokenExpired').mockResolvedValue(true)
18
+
19
+ extractSpy = spyOn(TeamsTokenExtractor.prototype, 'extract').mockResolvedValue({
20
+ token: 'test-teams-token',
21
+ })
22
+
23
+ testAuthSpy = spyOn(TeamsClient.prototype, 'testAuth').mockResolvedValue({
24
+ id: 'user-123',
25
+ displayName: 'Test User',
26
+ })
27
+
28
+ listTeamsSpy = spyOn(TeamsClient.prototype, 'listTeams').mockResolvedValue([
29
+ { id: 'team-1', name: 'Team One' },
30
+ { id: 'team-2', name: 'Team Two' },
31
+ ])
32
+
33
+ saveConfigSpy = spyOn(TeamsCredentialManager.prototype, 'saveConfig').mockResolvedValue(undefined)
34
+ })
35
+
36
+ afterEach(() => {
37
+ loadConfigSpy?.mockRestore()
38
+ isTokenExpiredSpy?.mockRestore()
39
+ extractSpy?.mockRestore()
40
+ testAuthSpy?.mockRestore()
41
+ listTeamsSpy?.mockRestore()
42
+ saveConfigSpy?.mockRestore()
43
+ })
44
+
45
+ describe('ensureTeamsAuth', () => {
46
+ test('skips extraction when token exists and not expired', async () => {
47
+ // given
48
+ loadConfigSpy.mockResolvedValue({
49
+ token: 'existing-token',
50
+ current_team: 'team-1',
51
+ teams: { 'team-1': { team_id: 'team-1', team_name: 'Team One' } },
52
+ })
53
+ isTokenExpiredSpy.mockResolvedValue(false)
54
+
55
+ // when
56
+ await ensureTeamsAuth()
57
+
58
+ // then
59
+ expect(extractSpy).not.toHaveBeenCalled()
60
+ })
61
+
62
+ test('extracts when no config exists', async () => {
63
+ // given
64
+ loadConfigSpy.mockResolvedValue(null)
65
+
66
+ // when
67
+ await ensureTeamsAuth()
68
+
69
+ // then
70
+ expect(extractSpy).toHaveBeenCalled()
71
+ expect(testAuthSpy).toHaveBeenCalled()
72
+ expect(saveConfigSpy).toHaveBeenCalledWith(
73
+ expect.objectContaining({
74
+ token: 'test-teams-token',
75
+ current_team: 'team-1',
76
+ teams: {
77
+ 'team-1': { team_id: 'team-1', team_name: 'Team One' },
78
+ 'team-2': { team_id: 'team-2', team_name: 'Team Two' },
79
+ },
80
+ }),
81
+ )
82
+ })
83
+
84
+ test('re-extracts when token is expired', async () => {
85
+ // given
86
+ loadConfigSpy.mockResolvedValue({
87
+ token: 'expired-token',
88
+ current_team: 'team-1',
89
+ teams: { 'team-1': { team_id: 'team-1', team_name: 'Team One' } },
90
+ token_expires_at: new Date(Date.now() - 3600000).toISOString(),
91
+ })
92
+ isTokenExpiredSpy.mockResolvedValue(true)
93
+
94
+ // when
95
+ await ensureTeamsAuth()
96
+
97
+ // then
98
+ expect(extractSpy).toHaveBeenCalled()
99
+ expect(saveConfigSpy).toHaveBeenCalledWith(expect.objectContaining({ token: 'test-teams-token' }))
100
+ })
101
+
102
+ test('sets first team as current', async () => {
103
+ // when
104
+ await ensureTeamsAuth()
105
+
106
+ // then
107
+ expect(saveConfigSpy).toHaveBeenCalledWith(expect.objectContaining({ current_team: 'team-1' }))
108
+ })
109
+
110
+ test('saves token_expires_at', async () => {
111
+ // when
112
+ const before = Date.now()
113
+ await ensureTeamsAuth()
114
+ const after = Date.now()
115
+
116
+ // then
117
+ const savedConfig = saveConfigSpy.mock.calls[0][0]
118
+ const expiresAt = new Date(savedConfig.token_expires_at).getTime()
119
+ expect(expiresAt).toBeGreaterThanOrEqual(before + 60 * 60 * 1000 - 1)
120
+ expect(expiresAt).toBeLessThanOrEqual(after + 60 * 60 * 1000 + 1)
121
+ })
122
+
123
+ test('does not save when extraction returns null', async () => {
124
+ // given
125
+ extractSpy.mockResolvedValue(null)
126
+
127
+ // when
128
+ await ensureTeamsAuth()
129
+
130
+ // then
131
+ expect(testAuthSpy).not.toHaveBeenCalled()
132
+ expect(saveConfigSpy).not.toHaveBeenCalled()
133
+ })
134
+
135
+ test('does not save when no teams found', async () => {
136
+ // given
137
+ listTeamsSpy.mockResolvedValue([])
138
+
139
+ // when
140
+ await ensureTeamsAuth()
141
+
142
+ // then
143
+ expect(saveConfigSpy).not.toHaveBeenCalled()
144
+ })
145
+
146
+ test('silently handles extraction failure', async () => {
147
+ // given
148
+ extractSpy.mockRejectedValue(new Error('Teams not found'))
149
+
150
+ // when
151
+ await ensureTeamsAuth()
152
+
153
+ // then
154
+ expect(saveConfigSpy).not.toHaveBeenCalled()
155
+ })
156
+
157
+ test('silently handles auth validation failure', async () => {
158
+ // given
159
+ testAuthSpy.mockRejectedValue(new Error('401 Unauthorized'))
160
+
161
+ // when
162
+ await ensureTeamsAuth()
163
+
164
+ // then
165
+ expect(saveConfigSpy).not.toHaveBeenCalled()
166
+ })
167
+ })
@@ -0,0 +1,34 @@
1
+ import { TeamsClient } from './client'
2
+ import { TeamsCredentialManager } from './credential-manager'
3
+ import { TeamsTokenExtractor } from './token-extractor'
4
+
5
+ export async function ensureTeamsAuth(): Promise<void> {
6
+ try {
7
+ const credManager = new TeamsCredentialManager()
8
+ const config = await credManager.loadConfig()
9
+
10
+ if (config?.token && !(await credManager.isTokenExpired())) return
11
+
12
+ const extractor = new TeamsTokenExtractor()
13
+ const extracted = await extractor.extract()
14
+ if (!extracted) return
15
+
16
+ const client = new TeamsClient(extracted.token)
17
+ await client.testAuth()
18
+
19
+ const teams = await client.listTeams()
20
+ if (teams.length === 0) return
21
+
22
+ const teamMap: Record<string, { team_id: string; team_name: string }> = {}
23
+ for (const team of teams) {
24
+ teamMap[team.id] = { team_id: team.id, team_name: team.name }
25
+ }
26
+
27
+ await credManager.saveConfig({
28
+ token: extracted.token,
29
+ current_team: teams[0].id,
30
+ teams: teamMap,
31
+ token_expires_at: new Date(Date.now() + 60 * 60 * 1000).toISOString(),
32
+ })
33
+ } catch {}
34
+ }