agent-messenger 2.8.0 → 2.10.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 (169) hide show
  1. package/.claude-plugin/plugin.json +1 -1
  2. package/README.md +0 -11
  3. package/dist/package.json +1 -1
  4. package/dist/src/platforms/channeltalk/commands/snapshot.d.ts +4 -2
  5. package/dist/src/platforms/channeltalk/commands/snapshot.d.ts.map +1 -1
  6. package/dist/src/platforms/channeltalk/commands/snapshot.js +86 -31
  7. package/dist/src/platforms/channeltalk/commands/snapshot.js.map +1 -1
  8. package/dist/src/platforms/channeltalkbot/commands/snapshot.d.ts +3 -1
  9. package/dist/src/platforms/channeltalkbot/commands/snapshot.d.ts.map +1 -1
  10. package/dist/src/platforms/channeltalkbot/commands/snapshot.js +110 -60
  11. package/dist/src/platforms/channeltalkbot/commands/snapshot.js.map +1 -1
  12. package/dist/src/platforms/discord/commands/snapshot.d.ts +1 -0
  13. package/dist/src/platforms/discord/commands/snapshot.d.ts.map +1 -1
  14. package/dist/src/platforms/discord/commands/snapshot.js +48 -34
  15. package/dist/src/platforms/discord/commands/snapshot.js.map +1 -1
  16. package/dist/src/platforms/discordbot/commands/snapshot.d.ts +2 -0
  17. package/dist/src/platforms/discordbot/commands/snapshot.d.ts.map +1 -1
  18. package/dist/src/platforms/discordbot/commands/snapshot.js +46 -34
  19. package/dist/src/platforms/discordbot/commands/snapshot.js.map +1 -1
  20. package/dist/src/platforms/slack/commands/snapshot.d.ts.map +1 -1
  21. package/dist/src/platforms/slack/commands/snapshot.js +75 -55
  22. package/dist/src/platforms/slack/commands/snapshot.js.map +1 -1
  23. package/dist/src/platforms/teams/client.d.ts +9 -1
  24. package/dist/src/platforms/teams/client.d.ts.map +1 -1
  25. package/dist/src/platforms/teams/client.js +69 -18
  26. package/dist/src/platforms/teams/client.js.map +1 -1
  27. package/dist/src/platforms/teams/commands/auth.d.ts.map +1 -1
  28. package/dist/src/platforms/teams/commands/auth.js +7 -2
  29. package/dist/src/platforms/teams/commands/auth.js.map +1 -1
  30. package/dist/src/platforms/teams/commands/channel.d.ts.map +1 -1
  31. package/dist/src/platforms/teams/commands/channel.js +18 -3
  32. package/dist/src/platforms/teams/commands/channel.js.map +1 -1
  33. package/dist/src/platforms/teams/commands/file.d.ts.map +1 -1
  34. package/dist/src/platforms/teams/commands/file.js +18 -3
  35. package/dist/src/platforms/teams/commands/file.js.map +1 -1
  36. package/dist/src/platforms/teams/commands/message.d.ts.map +1 -1
  37. package/dist/src/platforms/teams/commands/message.js +24 -4
  38. package/dist/src/platforms/teams/commands/message.js.map +1 -1
  39. package/dist/src/platforms/teams/commands/reaction.d.ts.map +1 -1
  40. package/dist/src/platforms/teams/commands/reaction.js +12 -2
  41. package/dist/src/platforms/teams/commands/reaction.js.map +1 -1
  42. package/dist/src/platforms/teams/commands/snapshot.d.ts +1 -0
  43. package/dist/src/platforms/teams/commands/snapshot.d.ts.map +1 -1
  44. package/dist/src/platforms/teams/commands/snapshot.js +50 -32
  45. package/dist/src/platforms/teams/commands/snapshot.js.map +1 -1
  46. package/dist/src/platforms/teams/commands/team.d.ts.map +1 -1
  47. package/dist/src/platforms/teams/commands/team.js +6 -1
  48. package/dist/src/platforms/teams/commands/team.js.map +1 -1
  49. package/dist/src/platforms/teams/commands/user.d.ts.map +1 -1
  50. package/dist/src/platforms/teams/commands/user.js +18 -3
  51. package/dist/src/platforms/teams/commands/user.js.map +1 -1
  52. package/dist/src/platforms/teams/commands/whoami.d.ts.map +1 -1
  53. package/dist/src/platforms/teams/commands/whoami.js +6 -1
  54. package/dist/src/platforms/teams/commands/whoami.js.map +1 -1
  55. package/dist/src/platforms/teams/credential-manager.d.ts +3 -1
  56. package/dist/src/platforms/teams/credential-manager.d.ts.map +1 -1
  57. package/dist/src/platforms/teams/credential-manager.js +6 -1
  58. package/dist/src/platforms/teams/credential-manager.js.map +1 -1
  59. package/dist/src/platforms/teams/ensure-auth.d.ts.map +1 -1
  60. package/dist/src/platforms/teams/ensure-auth.js +7 -2
  61. package/dist/src/platforms/teams/ensure-auth.js.map +1 -1
  62. package/dist/src/platforms/teams/token-extractor.d.ts +3 -1
  63. package/dist/src/platforms/teams/token-extractor.d.ts.map +1 -1
  64. package/dist/src/platforms/teams/token-extractor.js +67 -10
  65. package/dist/src/platforms/teams/token-extractor.js.map +1 -1
  66. package/dist/src/platforms/teams/types.d.ts +17 -0
  67. package/dist/src/platforms/teams/types.d.ts.map +1 -1
  68. package/dist/src/platforms/teams/types.js +2 -0
  69. package/dist/src/platforms/teams/types.js.map +1 -1
  70. package/dist/src/platforms/webex/client.d.ts +3 -0
  71. package/dist/src/platforms/webex/client.d.ts.map +1 -1
  72. package/dist/src/platforms/webex/client.js +58 -13
  73. package/dist/src/platforms/webex/client.js.map +1 -1
  74. package/dist/src/platforms/webex/commands/auth.d.ts.map +1 -1
  75. package/dist/src/platforms/webex/commands/auth.js +61 -10
  76. package/dist/src/platforms/webex/commands/auth.js.map +1 -1
  77. package/dist/src/platforms/webex/commands/snapshot.d.ts +1 -0
  78. package/dist/src/platforms/webex/commands/snapshot.d.ts.map +1 -1
  79. package/dist/src/platforms/webex/commands/snapshot.js +14 -7
  80. package/dist/src/platforms/webex/commands/snapshot.js.map +1 -1
  81. package/dist/src/platforms/webex/credential-manager.d.ts.map +1 -1
  82. package/dist/src/platforms/webex/credential-manager.js +18 -6
  83. package/dist/src/platforms/webex/credential-manager.js.map +1 -1
  84. package/dist/src/platforms/webex/encryption.d.ts.map +1 -1
  85. package/dist/src/platforms/webex/encryption.js +3 -1
  86. package/dist/src/platforms/webex/encryption.js.map +1 -1
  87. package/dist/src/platforms/webex/ensure-auth.d.ts.map +1 -1
  88. package/dist/src/platforms/webex/ensure-auth.js +10 -2
  89. package/dist/src/platforms/webex/ensure-auth.js.map +1 -1
  90. package/dist/src/platforms/webex/token-extractor.d.ts +1 -0
  91. package/dist/src/platforms/webex/token-extractor.d.ts.map +1 -1
  92. package/dist/src/platforms/webex/token-extractor.js +21 -4
  93. package/dist/src/platforms/webex/token-extractor.js.map +1 -1
  94. package/docs/content/docs/agent-skills.mdx +0 -10
  95. package/docs/content/docs/cli/channeltalk.mdx +18 -8
  96. package/docs/content/docs/cli/channeltalkbot.mdx +16 -6
  97. package/docs/content/docs/cli/discord.mdx +23 -7
  98. package/docs/content/docs/cli/discordbot.mdx +23 -7
  99. package/docs/content/docs/cli/slack.mdx +24 -7
  100. package/docs/content/docs/cli/teams.mdx +24 -8
  101. package/docs/content/docs/cli/webex.mdx +15 -2
  102. package/e2e/webex.e2e.test.ts +57 -0
  103. package/package.json +1 -1
  104. package/skills/agent-channeltalk/SKILL.md +19 -9
  105. package/skills/agent-channeltalk/references/common-patterns.md +10 -9
  106. package/skills/agent-channeltalkbot/SKILL.md +19 -9
  107. package/skills/agent-channeltalkbot/references/common-patterns.md +10 -9
  108. package/skills/agent-discord/SKILL.md +18 -9
  109. package/skills/agent-discord/references/common-patterns.md +8 -7
  110. package/skills/agent-discordbot/SKILL.md +18 -9
  111. package/skills/agent-instagram/SKILL.md +1 -1
  112. package/skills/agent-kakaotalk/SKILL.md +1 -1
  113. package/skills/agent-line/SKILL.md +1 -1
  114. package/skills/agent-slack/SKILL.md +19 -10
  115. package/skills/agent-slack/references/common-patterns.md +4 -7
  116. package/skills/agent-slackbot/SKILL.md +1 -1
  117. package/skills/agent-teams/SKILL.md +18 -9
  118. package/skills/agent-teams/references/common-patterns.md +9 -7
  119. package/skills/agent-telegram/SKILL.md +1 -1
  120. package/skills/agent-webex/SKILL.md +13 -4
  121. package/skills/agent-webex/references/common-patterns.md +8 -2
  122. package/skills/agent-wechatbot/SKILL.md +1 -1
  123. package/skills/agent-whatsapp/SKILL.md +1 -1
  124. package/skills/agent-whatsappbot/SKILL.md +1 -1
  125. package/src/platforms/channeltalk/commands/snapshot.test.ts +58 -26
  126. package/src/platforms/channeltalk/commands/snapshot.ts +107 -33
  127. package/src/platforms/channeltalkbot/commands/snapshot.test.ts +26 -8
  128. package/src/platforms/channeltalkbot/commands/snapshot.ts +131 -64
  129. package/src/platforms/discord/commands/snapshot.test.ts +1 -1
  130. package/src/platforms/discord/commands/snapshot.ts +58 -42
  131. package/src/platforms/discordbot/commands/snapshot.test.ts +40 -18
  132. package/src/platforms/discordbot/commands/snapshot.ts +54 -37
  133. package/src/platforms/slack/commands/snapshot.test.ts +63 -8
  134. package/src/platforms/slack/commands/snapshot.ts +98 -66
  135. package/src/platforms/teams/client.test.ts +34 -30
  136. package/src/platforms/teams/client.ts +92 -20
  137. package/src/platforms/teams/commands/auth.test.ts +6 -2
  138. package/src/platforms/teams/commands/auth.ts +7 -2
  139. package/src/platforms/teams/commands/channel.test.ts +6 -6
  140. package/src/platforms/teams/commands/channel.ts +18 -3
  141. package/src/platforms/teams/commands/file.ts +18 -3
  142. package/src/platforms/teams/commands/message.ts +24 -4
  143. package/src/platforms/teams/commands/reaction.ts +12 -2
  144. package/src/platforms/teams/commands/snapshot.test.ts +1 -1
  145. package/src/platforms/teams/commands/snapshot.ts +59 -39
  146. package/src/platforms/teams/commands/team.test.ts +2 -2
  147. package/src/platforms/teams/commands/team.ts +6 -1
  148. package/src/platforms/teams/commands/user.ts +18 -3
  149. package/src/platforms/teams/commands/whoami.ts +6 -1
  150. package/src/platforms/teams/credential-manager.test.ts +25 -0
  151. package/src/platforms/teams/credential-manager.ts +13 -3
  152. package/src/platforms/teams/ensure-auth.test.ts +6 -1
  153. package/src/platforms/teams/ensure-auth.ts +7 -2
  154. package/src/platforms/teams/token-extractor.ts +77 -12
  155. package/src/platforms/teams/types.test.ts +17 -0
  156. package/src/platforms/teams/types.ts +6 -0
  157. package/src/platforms/webex/client.test.ts +157 -13
  158. package/src/platforms/webex/client.ts +64 -15
  159. package/src/platforms/webex/commands/auth.test.ts +122 -1
  160. package/src/platforms/webex/commands/auth.ts +72 -17
  161. package/src/platforms/webex/commands/snapshot.test.ts +14 -1
  162. package/src/platforms/webex/commands/snapshot.ts +17 -9
  163. package/src/platforms/webex/credential-manager.test.ts +63 -0
  164. package/src/platforms/webex/credential-manager.ts +22 -8
  165. package/src/platforms/webex/encryption.test.ts +54 -0
  166. package/src/platforms/webex/encryption.ts +3 -1
  167. package/src/platforms/webex/ensure-auth.ts +10 -2
  168. package/src/platforms/webex/token-extractor.test.ts +32 -3
  169. package/src/platforms/webex/token-extractor.ts +26 -5
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  name: agent-wechatbot
3
3
  description: Interact with WeChat Official Account using API credentials - send messages, manage templates, list followers
4
- version: 2.8.0
4
+ version: 2.10.0
5
5
  allowed-tools: Bash(agent-wechatbot:*)
6
6
  metadata:
7
7
  openclaw:
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  name: agent-whatsapp
3
3
  description: Interact with WhatsApp - send messages, read chats, manage conversations
4
- version: 2.8.0
4
+ version: 2.10.0
5
5
  allowed-tools: Bash(agent-whatsapp:*)
6
6
  metadata:
7
7
  openclaw:
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  name: agent-whatsappbot
3
3
  description: Interact with WhatsApp using Cloud API credentials - send messages, manage templates
4
- version: 2.8.0
4
+ version: 2.10.0
5
5
  allowed-tools: Bash(agent-whatsappbot:*)
6
6
  metadata:
7
7
  openclaw:
@@ -81,9 +81,54 @@ describe('snapshot command', () => {
81
81
  mockListUserChats.mockClear()
82
82
  })
83
83
 
84
- test('returns workspace, managers, bots, groups, and user chats', async () => {
84
+ test('brief snapshot returns workspace, groups (name only), chat counts, and hint', async () => {
85
85
  const result = await snapshotAction()
86
86
 
87
+ expect(result.error).toBeUndefined()
88
+ expect(result.workspace).toEqual({ id: 'ws-1', name: 'Workspace One' })
89
+ expect(result.groups).toEqual([
90
+ { id: 'grp-1', name: 'Support' },
91
+ { id: 'grp-2', name: 'Sales' },
92
+ ])
93
+ expect(result.user_chats).toEqual({
94
+ total: 4,
95
+ by_state: { opened: 2, snoozed: 1, closed: 1 },
96
+ })
97
+ expect(result.hint).toBeDefined()
98
+ expect(result.managers).toBeUndefined()
99
+ expect(result.bots).toBeUndefined()
100
+ expect(mockGetGroupMessages).not.toHaveBeenCalled()
101
+ })
102
+
103
+ test('brief groups-only returns group names without messages', async () => {
104
+ const result = await snapshotAction({ groupsOnly: true })
105
+
106
+ expect(result.workspace).toEqual({ id: 'ws-1', name: 'Workspace One' })
107
+ expect(result.groups).toHaveLength(2)
108
+ expect(result.groups?.[0]).toEqual({ id: 'grp-1', name: 'Support' })
109
+ expect(result.hint).toBeDefined()
110
+ expect(result.user_chats).toBeUndefined()
111
+ expect(mockGetGroupMessages).not.toHaveBeenCalled()
112
+ expect(mockListUserChats).not.toHaveBeenCalled()
113
+ })
114
+
115
+ test('brief chats-only returns counts without recent details', async () => {
116
+ const result = await snapshotAction({ chatsOnly: true })
117
+
118
+ expect(result.workspace).toEqual({ id: 'ws-1', name: 'Workspace One' })
119
+ expect(result.groups).toBeUndefined()
120
+ expect(result.user_chats).toEqual({
121
+ total: 4,
122
+ by_state: { opened: 2, snoozed: 1, closed: 1 },
123
+ })
124
+ expect(result.hint).toBeDefined()
125
+ expect(mockListGroups).not.toHaveBeenCalled()
126
+ expect(mockGetGroupMessages).not.toHaveBeenCalled()
127
+ })
128
+
129
+ test('full snapshot returns workspace, managers, bots, groups, and user chats', async () => {
130
+ const result = await snapshotAction({ full: true })
131
+
87
132
  expect(result.error).toBeUndefined()
88
133
  expect(result).toEqual({
89
134
  workspace: { id: 'ws-1', name: 'Workspace One' },
@@ -156,19 +201,21 @@ describe('snapshot command', () => {
156
201
  })
157
202
  })
158
203
 
159
- test('groups-only skips user chats', async () => {
160
- const result = await snapshotAction({ groupsOnly: true })
204
+ test('full groups-only includes messages', async () => {
205
+ const result = await snapshotAction({ full: true, groupsOnly: true, limit: 3 })
161
206
 
162
- expect(result.workspace).toEqual({ id: 'ws-1', name: 'Workspace One' })
163
- expect(result.groups).toHaveLength(2)
164
- expect(result.user_chats).toBeUndefined()
165
- expect(result.managers).toBeUndefined()
166
- expect(result.bots).toBeUndefined()
167
- expect(mockListUserChats).not.toHaveBeenCalled()
207
+ expect(mockGetGroupMessages).toHaveBeenCalledWith('ws-1', 'grp-1', { limit: 3, sortOrder: 'desc' })
208
+ expect(mockGetGroupMessages).toHaveBeenCalledWith('ws-1', 'grp-2', { limit: 3, sortOrder: 'desc' })
209
+ expect(result.groups?.[0].recent_messages?.[0]).toEqual({
210
+ id: 'grp-1-msg-1',
211
+ person_type: 'manager',
212
+ plain_text: 'Message for grp-1',
213
+ created_at: 1000,
214
+ })
168
215
  })
169
216
 
170
- test('chats-only skips groups', async () => {
171
- const result = await snapshotAction({ chatsOnly: true, limit: 1 })
217
+ test('full chats-only includes recent details', async () => {
218
+ const result = await snapshotAction({ full: true, chatsOnly: true, limit: 1 })
172
219
 
173
220
  expect(result.workspace).toEqual({ id: 'ws-1', name: 'Workspace One' })
174
221
  expect(result.groups).toBeUndefined()
@@ -189,20 +236,5 @@ describe('snapshot command', () => {
189
236
  },
190
237
  ],
191
238
  })
192
- expect(mockListGroups).not.toHaveBeenCalled()
193
- expect(mockGetGroupMessages).not.toHaveBeenCalled()
194
- })
195
-
196
- test('includes recent messages for each group with requested limit', async () => {
197
- const result = await snapshotAction({ groupsOnly: true, limit: 3 })
198
-
199
- expect(mockGetGroupMessages).toHaveBeenCalledWith('ws-1', 'grp-1', { limit: 3, sortOrder: 'desc' })
200
- expect(mockGetGroupMessages).toHaveBeenCalledWith('ws-1', 'grp-2', { limit: 3, sortOrder: 'desc' })
201
- expect(result.groups?.[0].recent_messages[0]).toEqual({
202
- id: 'grp-1-msg-1',
203
- person_type: 'manager',
204
- plain_text: 'Message for grp-1',
205
- created_at: 1000,
206
- })
207
239
  })
208
240
  })
@@ -10,6 +10,7 @@ interface SnapshotOptions {
10
10
  pretty?: boolean
11
11
  groupsOnly?: boolean
12
12
  chatsOnly?: boolean
13
+ full?: boolean
13
14
  limit?: number | string
14
15
  }
15
16
 
@@ -33,7 +34,7 @@ interface SnapshotResult {
33
34
  groups?: Array<{
34
35
  id: string
35
36
  name: string
36
- recent_messages: Array<{
37
+ recent_messages?: Array<{
37
38
  id: string
38
39
  person_type?: string
39
40
  plain_text?: string
@@ -43,7 +44,7 @@ interface SnapshotResult {
43
44
  user_chats?: {
44
45
  total: number
45
46
  by_state: Record<string, number>
46
- recent: Array<{
47
+ recent?: Array<{
47
48
  id: string
48
49
  state?: string
49
50
  assignee_id?: string
@@ -51,6 +52,7 @@ interface SnapshotResult {
51
52
  updated_at?: number
52
53
  }>
53
54
  }
55
+ hint?: string
54
56
  error?: string
55
57
  }
56
58
 
@@ -58,7 +60,6 @@ export async function snapshotAction(options: SnapshotOptions = {}): Promise<Sna
58
60
  try {
59
61
  const client = await getClient(options)
60
62
  const workspaceId = await getCurrentWorkspaceId(options)
61
- const limit = parseLimit(options.limit)
62
63
 
63
64
  const channel = await client.getChannel(workspaceId)
64
65
  const workspace = {
@@ -66,42 +67,114 @@ export async function snapshotAction(options: SnapshotOptions = {}): Promise<Sna
66
67
  name: channel.name,
67
68
  }
68
69
 
69
- if (options.groupsOnly) {
70
- const groups = await buildGroupsSnapshot(client, workspaceId, limit)
71
- return { workspace, groups }
70
+ if (options.full) {
71
+ return buildFullSnapshot(client, workspaceId, workspace, options)
72
72
  }
73
73
 
74
- if (options.chatsOnly) {
75
- const userChats = await buildUserChatsSnapshot(client, workspaceId, limit)
76
- return { workspace, user_chats: userChats }
74
+ return buildBriefSnapshot(client, workspaceId, workspace, options)
75
+ } catch (error) {
76
+ return { error: (error as Error).message }
77
+ }
78
+ }
79
+
80
+ async function buildBriefSnapshot(
81
+ client: Awaited<ReturnType<typeof getClient>>,
82
+ workspaceId: string,
83
+ workspace: { id: string; name: string },
84
+ options: SnapshotOptions,
85
+ ): Promise<SnapshotResult> {
86
+ if (options.groupsOnly) {
87
+ const groups = await client.listGroups(workspaceId, { limit: 20 })
88
+ return {
89
+ workspace,
90
+ groups: groups.map((g) => ({ id: g.id, name: g.name })),
91
+ hint: "Use 'group messages <group>' for messages.",
77
92
  }
93
+ }
78
94
 
79
- const [managers, bots, groups, userChats] = await Promise.all([
80
- client.listManagers(workspaceId, { limit: 50 }),
81
- client.listBots(workspaceId, { limit: 50 }),
82
- buildGroupsSnapshot(client, workspaceId, limit),
83
- buildUserChatsSnapshot(client, workspaceId, limit),
95
+ if (options.chatsOnly) {
96
+ const [openedChats, snoozedChats, closedChats] = await Promise.all([
97
+ client.listUserChats(workspaceId, { state: 'opened', limit: 100 }),
98
+ client.listUserChats(workspaceId, { state: 'snoozed', limit: 100 }),
99
+ client.listUserChats(workspaceId, { state: 'closed', limit: 100 }),
84
100
  ])
85
-
86
101
  return {
87
102
  workspace,
88
- managers: managers.map((manager) => ({
89
- id: manager.id,
90
- name: manager.name,
91
- email: manager.email,
92
- account_id: manager.accountId,
93
- role_id: manager.roleId,
94
- })),
95
- bots: bots.map((bot) => ({
96
- id: bot.id,
97
- name: bot.name,
98
- avatar_url: bot.avatarUrl,
99
- })),
100
- groups,
101
- user_chats: userChats,
103
+ user_chats: {
104
+ total: openedChats.length + snoozedChats.length + closedChats.length,
105
+ by_state: {
106
+ opened: openedChats.length,
107
+ snoozed: snoozedChats.length,
108
+ closed: closedChats.length,
109
+ },
110
+ },
111
+ hint: "Use 'chat list --state opened' for chat details, 'chat messages <chat>' for messages.",
102
112
  }
103
- } catch (error) {
104
- return { error: (error as Error).message }
113
+ }
114
+
115
+ const [groups, openedChats, snoozedChats, closedChats] = await Promise.all([
116
+ client.listGroups(workspaceId, { limit: 20 }),
117
+ client.listUserChats(workspaceId, { state: 'opened', limit: 100 }),
118
+ client.listUserChats(workspaceId, { state: 'snoozed', limit: 100 }),
119
+ client.listUserChats(workspaceId, { state: 'closed', limit: 100 }),
120
+ ])
121
+
122
+ return {
123
+ workspace,
124
+ groups: groups.map((g) => ({ id: g.id, name: g.name })),
125
+ user_chats: {
126
+ total: openedChats.length + snoozedChats.length + closedChats.length,
127
+ by_state: {
128
+ opened: openedChats.length,
129
+ snoozed: snoozedChats.length,
130
+ closed: closedChats.length,
131
+ },
132
+ },
133
+ hint: "Use 'group messages <group>' for group messages, 'chat list --state opened' for chats, 'manager list' for managers.",
134
+ }
135
+ }
136
+
137
+ async function buildFullSnapshot(
138
+ client: Awaited<ReturnType<typeof getClient>>,
139
+ workspaceId: string,
140
+ workspace: { id: string; name: string },
141
+ options: SnapshotOptions,
142
+ ): Promise<SnapshotResult> {
143
+ const limit = parseLimit(options.limit)
144
+
145
+ if (options.groupsOnly) {
146
+ const groups = await buildGroupsSnapshot(client, workspaceId, limit)
147
+ return { workspace, groups }
148
+ }
149
+
150
+ if (options.chatsOnly) {
151
+ const userChats = await buildUserChatsSnapshot(client, workspaceId, limit)
152
+ return { workspace, user_chats: userChats }
153
+ }
154
+
155
+ const [managers, bots, groups, userChats] = await Promise.all([
156
+ client.listManagers(workspaceId, { limit: 50 }),
157
+ client.listBots(workspaceId, { limit: 50 }),
158
+ buildGroupsSnapshot(client, workspaceId, limit),
159
+ buildUserChatsSnapshot(client, workspaceId, limit),
160
+ ])
161
+
162
+ return {
163
+ workspace,
164
+ managers: managers.map((manager) => ({
165
+ id: manager.id,
166
+ name: manager.name,
167
+ email: manager.email,
168
+ account_id: manager.accountId,
169
+ role_id: manager.roleId,
170
+ })),
171
+ bots: bots.map((bot) => ({
172
+ id: bot.id,
173
+ name: bot.name,
174
+ avatar_url: bot.avatarUrl,
175
+ })),
176
+ groups,
177
+ user_chats: userChats,
105
178
  }
106
179
  }
107
180
 
@@ -178,10 +251,11 @@ function cliOutput(result: SnapshotResult, pretty?: boolean): void {
178
251
 
179
252
  export function createSnapshotCommand(): Command {
180
253
  return new Command('snapshot')
181
- .description('Workspace overview for AI agent context')
254
+ .description('Workspace overview for AI agents (brief by default, use --full for comprehensive data)')
255
+ .option('--full', 'Include messages, managers, and bots (verbose)')
182
256
  .option('--groups-only', 'List groups only, skip user chats')
183
257
  .option('--chats-only', 'List user chats only, skip groups')
184
- .option('--limit <n>', 'Messages per group and recent opened chats', '5')
258
+ .option('--limit <n>', 'Messages per group and recent opened chats with --full', '5')
185
259
  .option('--workspace <id>', 'Workspace ID')
186
260
  .option('--pretty', 'Pretty print JSON output')
187
261
  .action(async (options: SnapshotOptions) => {
@@ -67,10 +67,28 @@ describe('snapshot command', () => {
67
67
  })
68
68
 
69
69
  describe('snapshotAction', () => {
70
- test('returns workspace, groups, user_chats, managers, bots', async () => {
70
+ test('brief snapshot returns workspace, groups (names), chat counts, and hint', async () => {
71
71
  const manager = new ChannelBotCredentialManager(tempDir)
72
72
  const result = await snapshotAction({ _credManager: manager })
73
73
 
74
+ expect(result.error).toBeUndefined()
75
+ expect(result.workspace).toBeDefined()
76
+ expect(result.workspace?.id).toBe('ch1')
77
+ expect(result.workspace?.name).toBe('Test Workspace')
78
+ expect(result.groups).toBeDefined()
79
+ expect(result.groups?.[0]).toEqual({ id: 'grp1', name: 'Team Alpha' })
80
+ expect(result.user_chats).toBeDefined()
81
+ expect(result.user_chats?.opened_count).toBe(1)
82
+ expect(result.hint).toBeDefined()
83
+ expect(result.managers).toBeUndefined()
84
+ expect(result.bots).toBeUndefined()
85
+ expect(mockGetGroupMessages).not.toHaveBeenCalled()
86
+ })
87
+
88
+ test('full snapshot returns workspace, groups, user_chats, managers, bots', async () => {
89
+ const manager = new ChannelBotCredentialManager(tempDir)
90
+ const result = await snapshotAction({ full: true, _credManager: manager })
91
+
74
92
  expect(result.error).toBeUndefined()
75
93
  expect(result.workspace).toBeDefined()
76
94
  expect(result.workspace?.id).toBe('ch1')
@@ -83,7 +101,7 @@ describe('snapshot command', () => {
83
101
 
84
102
  test('groups-only flag skips user_chats, managers, bots', async () => {
85
103
  const manager = new ChannelBotCredentialManager(tempDir)
86
- const result = await snapshotAction({ groupsOnly: true, _credManager: manager })
104
+ const result = await snapshotAction({ full: true, groupsOnly: true, _credManager: manager })
87
105
 
88
106
  expect(result.error).toBeUndefined()
89
107
  expect(result.workspace).toBeDefined()
@@ -95,7 +113,7 @@ describe('snapshot command', () => {
95
113
 
96
114
  test('chats-only flag skips groups, managers, bots', async () => {
97
115
  const manager = new ChannelBotCredentialManager(tempDir)
98
- const result = await snapshotAction({ chatsOnly: true, _credManager: manager })
116
+ const result = await snapshotAction({ full: true, chatsOnly: true, _credManager: manager })
99
117
 
100
118
  expect(result.error).toBeUndefined()
101
119
  expect(result.workspace).toBeDefined()
@@ -105,21 +123,21 @@ describe('snapshot command', () => {
105
123
  expect(result.bots).toBeUndefined()
106
124
  })
107
125
 
108
- test('groups include recent messages', async () => {
126
+ test('full groups include recent messages', async () => {
109
127
  const manager = new ChannelBotCredentialManager(tempDir)
110
- const result = await snapshotAction({ groupsOnly: true, limit: 3, _credManager: manager })
128
+ const result = await snapshotAction({ full: true, groupsOnly: true, limit: 3, _credManager: manager })
111
129
 
112
130
  expect(result.groups?.[0].messages).toBeDefined()
113
131
  expect(result.groups?.[0].messages?.[0].id).toBe('msg1')
114
132
  })
115
133
 
116
- test('user_chats includes counts and recent opened', async () => {
134
+ test('full user_chats includes counts and recent opened', async () => {
117
135
  const manager = new ChannelBotCredentialManager(tempDir)
118
- const result = await snapshotAction({ chatsOnly: true, _credManager: manager })
136
+ const result = await snapshotAction({ full: true, chatsOnly: true, _credManager: manager })
119
137
 
120
138
  expect(result.user_chats?.opened_count).toBe(1)
121
139
  expect(result.user_chats?.recent_opened).toHaveLength(1)
122
- expect(result.user_chats?.recent_opened[0].id).toBe('chat1')
140
+ expect(result.user_chats?.recent_opened?.[0].id).toBe('chat1')
123
141
  })
124
142
  })
125
143
  })
@@ -9,6 +9,7 @@ import { getClient } from './shared'
9
9
  interface SnapshotOption extends WorkspaceOption {
10
10
  groupsOnly?: boolean
11
11
  chatsOnly?: boolean
12
+ full?: boolean
12
13
  limit?: number
13
14
  }
14
15
 
@@ -33,7 +34,7 @@ interface SnapshotResult {
33
34
  opened_count: number
34
35
  snoozed_count: number
35
36
  closed_count: number
36
- recent_opened: Array<{
37
+ recent_opened?: Array<{
37
38
  id: string
38
39
  name?: string
39
40
  user_id?: string
@@ -46,13 +47,13 @@ interface SnapshotResult {
46
47
  }
47
48
  managers?: Array<{ id: string; name: string; description?: string }>
48
49
  bots?: Array<{ id: string; name: string }>
50
+ hint?: string
49
51
  error?: string
50
52
  }
51
53
 
52
54
  export async function snapshotAction(options: SnapshotOption): Promise<SnapshotResult> {
53
55
  try {
54
56
  const client = await getClient(options)
55
- const limit = options.limit ?? 5
56
57
 
57
58
  const channel = await client.getChannel()
58
59
  const workspace = {
@@ -62,71 +63,75 @@ export async function snapshotAction(options: SnapshotOption): Promise<SnapshotR
62
63
  description: channel.description,
63
64
  }
64
65
 
65
- if (options.groupsOnly) {
66
- const groups = await client.listGroups({ limit: 20 })
67
- const groupsWithMessages = await Promise.all(
68
- groups.map(async (g) => {
69
- const messages = await client.getGroupMessages(g.id, { limit, sortOrder: 'desc' })
70
- return {
71
- id: g.id,
72
- name: g.name,
73
- messages: messages.map((m) => ({
74
- id: m.id,
75
- person_type: m.personType,
76
- plain_text: m.plainText,
77
- created_at: m.createdAt,
78
- })),
79
- }
80
- }),
81
- )
82
- return { workspace, groups: groupsWithMessages }
66
+ if (options.full) {
67
+ return buildFullSnapshot(client, workspace, options)
83
68
  }
84
69
 
85
- if (options.chatsOnly) {
86
- const [openedChats, snoozedChats, closedChats] = await Promise.all([
87
- client.listUserChats({ state: 'opened', limit: 10, sortOrder: 'desc' }),
88
- client.listUserChats({ state: 'snoozed', limit: 1 }),
89
- client.listUserChats({ state: 'closed', limit: 1 }),
90
- ])
91
-
92
- const recentOpened = await Promise.all(
93
- openedChats.slice(0, 5).map(async (chat) => {
94
- const messages = await client.getUserChatMessages(chat.id, { limit: 1, sortOrder: 'desc' })
95
- return {
96
- id: chat.id,
97
- name: chat.name,
98
- user_id: chat.userId,
99
- last_message: messages[0]
100
- ? {
101
- id: messages[0].id,
102
- plain_text: messages[0].plainText,
103
- created_at: messages[0].createdAt,
104
- }
105
- : undefined,
106
- }
107
- }),
108
- )
70
+ return buildBriefSnapshot(client, workspace, options)
71
+ } catch (error) {
72
+ return { error: (error as Error).message }
73
+ }
74
+ }
109
75
 
110
- return {
111
- workspace,
112
- user_chats: {
113
- opened_count: openedChats.length,
114
- snoozed_count: snoozedChats.length,
115
- closed_count: closedChats.length,
116
- recent_opened: recentOpened,
117
- },
118
- }
76
+ async function buildBriefSnapshot(
77
+ client: Awaited<ReturnType<typeof getClient>>,
78
+ workspace: SnapshotResult['workspace'],
79
+ options: SnapshotOption,
80
+ ): Promise<SnapshotResult> {
81
+ if (options.groupsOnly) {
82
+ const groups = await client.listGroups({ limit: 20 })
83
+ return {
84
+ workspace,
85
+ groups: groups.map((g) => ({ id: g.id, name: g.name })),
86
+ hint: "Use 'group messages <group>' for messages.",
119
87
  }
88
+ }
120
89
 
121
- const [groups, openedChats, snoozedChats, closedChats, managers, bots] = await Promise.all([
122
- client.listGroups({ limit: 20 }),
90
+ if (options.chatsOnly) {
91
+ const [openedChats, snoozedChats, closedChats] = await Promise.all([
123
92
  client.listUserChats({ state: 'opened', limit: 10, sortOrder: 'desc' }),
124
93
  client.listUserChats({ state: 'snoozed', limit: 1 }),
125
94
  client.listUserChats({ state: 'closed', limit: 1 }),
126
- client.listManagers({ limit: 50 }),
127
- client.listBots({ limit: 50 }),
128
95
  ])
96
+ return {
97
+ workspace,
98
+ user_chats: {
99
+ opened_count: openedChats.length,
100
+ snoozed_count: snoozedChats.length,
101
+ closed_count: closedChats.length,
102
+ },
103
+ hint: "Use 'chat list --state opened' for chat details, 'chat messages <chat>' for messages.",
104
+ }
105
+ }
106
+
107
+ const [groups, openedChats, snoozedChats, closedChats] = await Promise.all([
108
+ client.listGroups({ limit: 20 }),
109
+ client.listUserChats({ state: 'opened', limit: 10, sortOrder: 'desc' }),
110
+ client.listUserChats({ state: 'snoozed', limit: 1 }),
111
+ client.listUserChats({ state: 'closed', limit: 1 }),
112
+ ])
113
+
114
+ return {
115
+ workspace,
116
+ groups: groups.map((g) => ({ id: g.id, name: g.name })),
117
+ user_chats: {
118
+ opened_count: openedChats.length,
119
+ snoozed_count: snoozedChats.length,
120
+ closed_count: closedChats.length,
121
+ },
122
+ hint: "Use 'group messages <group>' for group messages, 'chat list --state opened' for chats, 'manager list' for managers.",
123
+ }
124
+ }
125
+
126
+ async function buildFullSnapshot(
127
+ client: Awaited<ReturnType<typeof getClient>>,
128
+ workspace: SnapshotResult['workspace'],
129
+ options: SnapshotOption,
130
+ ): Promise<SnapshotResult> {
131
+ const limit = options.limit ?? 5
129
132
 
133
+ if (options.groupsOnly) {
134
+ const groups = await client.listGroups({ limit: 20 })
130
135
  const groupsWithMessages = await Promise.all(
131
136
  groups.map(async (g) => {
132
137
  const messages = await client.getGroupMessages(g.id, { limit, sortOrder: 'desc' })
@@ -142,6 +147,15 @@ export async function snapshotAction(options: SnapshotOption): Promise<SnapshotR
142
147
  }
143
148
  }),
144
149
  )
150
+ return { workspace, groups: groupsWithMessages }
151
+ }
152
+
153
+ if (options.chatsOnly) {
154
+ const [openedChats, snoozedChats, closedChats] = await Promise.all([
155
+ client.listUserChats({ state: 'opened', limit: 10, sortOrder: 'desc' }),
156
+ client.listUserChats({ state: 'snoozed', limit: 1 }),
157
+ client.listUserChats({ state: 'closed', limit: 1 }),
158
+ ])
145
159
 
146
160
  const recentOpened = await Promise.all(
147
161
  openedChats.slice(0, 5).map(async (chat) => {
@@ -163,26 +177,78 @@ export async function snapshotAction(options: SnapshotOption): Promise<SnapshotR
163
177
 
164
178
  return {
165
179
  workspace,
166
- groups: groupsWithMessages,
167
180
  user_chats: {
168
181
  opened_count: openedChats.length,
169
182
  snoozed_count: snoozedChats.length,
170
183
  closed_count: closedChats.length,
171
184
  recent_opened: recentOpened,
172
185
  },
173
- managers: managers.map((m) => ({ id: m.id, name: m.name, description: m.description })),
174
- bots: bots.map((b) => ({ id: b.id, name: b.name })),
175
186
  }
176
- } catch (error) {
177
- return { error: (error as Error).message }
187
+ }
188
+
189
+ const [groups, openedChats, snoozedChats, closedChats, managers, bots] = await Promise.all([
190
+ client.listGroups({ limit: 20 }),
191
+ client.listUserChats({ state: 'opened', limit: 10, sortOrder: 'desc' }),
192
+ client.listUserChats({ state: 'snoozed', limit: 1 }),
193
+ client.listUserChats({ state: 'closed', limit: 1 }),
194
+ client.listManagers({ limit: 50 }),
195
+ client.listBots({ limit: 50 }),
196
+ ])
197
+
198
+ const groupsWithMessages = await Promise.all(
199
+ groups.map(async (g) => {
200
+ const messages = await client.getGroupMessages(g.id, { limit, sortOrder: 'desc' })
201
+ return {
202
+ id: g.id,
203
+ name: g.name,
204
+ messages: messages.map((m) => ({
205
+ id: m.id,
206
+ person_type: m.personType,
207
+ plain_text: m.plainText,
208
+ created_at: m.createdAt,
209
+ })),
210
+ }
211
+ }),
212
+ )
213
+
214
+ const recentOpened = await Promise.all(
215
+ openedChats.slice(0, 5).map(async (chat) => {
216
+ const messages = await client.getUserChatMessages(chat.id, { limit: 1, sortOrder: 'desc' })
217
+ return {
218
+ id: chat.id,
219
+ name: chat.name,
220
+ user_id: chat.userId,
221
+ last_message: messages[0]
222
+ ? {
223
+ id: messages[0].id,
224
+ plain_text: messages[0].plainText,
225
+ created_at: messages[0].createdAt,
226
+ }
227
+ : undefined,
228
+ }
229
+ }),
230
+ )
231
+
232
+ return {
233
+ workspace,
234
+ groups: groupsWithMessages,
235
+ user_chats: {
236
+ opened_count: openedChats.length,
237
+ snoozed_count: snoozedChats.length,
238
+ closed_count: closedChats.length,
239
+ recent_opened: recentOpened,
240
+ },
241
+ managers: managers.map((m) => ({ id: m.id, name: m.name, description: m.description })),
242
+ bots: bots.map((b) => ({ id: b.id, name: b.name })),
178
243
  }
179
244
  }
180
245
 
181
246
  export const snapshotCommand = new Command('snapshot')
182
- .description('Workspace overview for AI agent context')
247
+ .description('Workspace overview for AI agents (brief by default, use --full for comprehensive data)')
248
+ .option('--full', 'Include messages, managers, and bots (verbose)')
183
249
  .option('--groups-only', 'List groups only, skip user chats')
184
250
  .option('--chats-only', 'List user chats only, skip groups')
185
- .option('--limit <n>', 'Messages per group/chat (default: 5)', '5')
251
+ .option('--limit <n>', 'Messages per group/chat with --full (default: 5)', '5')
186
252
  .option('--workspace <id>', 'Workspace ID')
187
253
  .option('--bot <name>', 'Bot name')
188
254
  .option('--pretty', 'Pretty print JSON output')
@@ -190,6 +256,7 @@ export const snapshotCommand = new Command('snapshot')
190
256
  try {
191
257
  const result = await snapshotAction({
192
258
  ...options,
259
+ full: options.full,
193
260
  limit: parseInt(options.limit, 10),
194
261
  })
195
262
  console.log(formatOutput(result, options.pretty))