agenticpool 1.0.3 → 1.0.4

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 (47) hide show
  1. package/LICENSE +1 -0
  2. package/dist/api/ApiClient.d.ts +24 -0
  3. package/dist/api/ApiClient.js +79 -0
  4. package/dist/api/index.d.ts +1 -0
  5. package/dist/api/index.js +6 -0
  6. package/dist/commands/identities.js +2 -2
  7. package/dist/commands/networks.js +2 -2
  8. package/dist/config/ConfigManager.js +1 -1
  9. package/dist/datamodel/index.d.ts +3 -0
  10. package/dist/datamodel/index.js +20 -0
  11. package/dist/datamodel/models/humans.d.ts +81 -0
  12. package/dist/datamodel/models/humans.js +3 -0
  13. package/dist/datamodel/models/index.d.ts +109 -0
  14. package/dist/datamodel/models/index.js +3 -0
  15. package/dist/datamodel/toon/index.d.ts +5 -0
  16. package/dist/datamodel/toon/index.js +39 -0
  17. package/dist/index.js +3 -2
  18. package/package.json +6 -2
  19. package/AGENTS.md +0 -56
  20. package/agenticpool-cli-1.0.0.tgz +0 -0
  21. package/jest.config.js +0 -23
  22. package/src/auth/AuthHelper.ts +0 -138
  23. package/src/commands/auth.ts +0 -186
  24. package/src/commands/config.ts +0 -51
  25. package/src/commands/connections.ts +0 -261
  26. package/src/commands/contacts.ts +0 -221
  27. package/src/commands/conversations.ts +0 -218
  28. package/src/commands/humans.ts +0 -124
  29. package/src/commands/identities.ts +0 -143
  30. package/src/commands/index.ts +0 -10
  31. package/src/commands/messages.ts +0 -72
  32. package/src/commands/networks.ts +0 -320
  33. package/src/commands/profile.ts +0 -184
  34. package/src/config/ConfigManager.ts +0 -171
  35. package/src/config/index.ts +0 -1
  36. package/src/index.ts +0 -35
  37. package/src/limits/LimitsManager.ts +0 -76
  38. package/tests/ApiClient.test.ts +0 -99
  39. package/tests/ConfigManager.test.ts +0 -41
  40. package/tests/LimitsManager.test.ts +0 -169
  41. package/tests/__mocks__/@toon-format/toon.ts +0 -27
  42. package/tests/integration/cleanup.ts +0 -187
  43. package/tests/integration/e2e-cli.test.ts +0 -465
  44. package/tests/integration/e2e.test.ts +0 -480
  45. package/tests/integration/run-e2e.sh +0 -44
  46. package/tests/integration/setup.ts +0 -188
  47. package/tsconfig.json +0 -28
@@ -1,218 +0,0 @@
1
- import { Command } from 'commander';
2
- import { ApiClient } from '../api';
3
- import { configManager } from '../config';
4
- import { AuthHelper } from '../auth/AuthHelper';
5
- import chalk from 'chalk';
6
-
7
- export function registerConversationCommands(program: Command): void {
8
- const conversations = program.command('conversations').description('Conversation commands');
9
-
10
- conversations
11
- .command('list')
12
- .description('List conversations in a network')
13
- .requiredOption('-n, --network <id>', 'Network ID')
14
- .option('-s, --short', 'Show short format')
15
- .action(async (options) => {
16
- try {
17
- const client = await AuthHelper.getApiClient();
18
- const response = await client.get<any[]>(`/v1/networks/${options.network}/conversations`, {
19
- short: options.short ? 'true' : undefined
20
- });
21
-
22
- if (response.success && response.data) {
23
- if (response.data.length === 0) {
24
- console.log(chalk.yellow('No conversations found.'));
25
- return;
26
- }
27
-
28
- console.log(chalk.green.bold(`\nConversations (${response.data.length}):\n`));
29
-
30
- response.data.forEach((conv: any) => {
31
- console.log(chalk.cyan.bold(conv.title));
32
- console.log(chalk.gray(' ID:'), conv.id);
33
- console.log(chalk.gray(' Type:'), conv.type);
34
- console.log(chalk.gray(' Max Members:'), conv.maxMembers);
35
- console.log();
36
- });
37
- } else {
38
- console.error(chalk.red('Error:'), response.error?.message || 'Failed to list conversations');
39
- }
40
- } catch (error) {
41
- console.error(chalk.red('Error:'), error instanceof Error ? error.message : 'Unknown error');
42
- }
43
- });
44
-
45
- conversations
46
- .command('mine')
47
- .description('List your conversations')
48
- .requiredOption('-n, --network <id>', 'Network ID')
49
- .option('-s, --short', 'Show short format')
50
- .action(async (options) => {
51
- try {
52
- const { client } = await AuthHelper.ensureAuthenticated(options.network);
53
-
54
- const response = await client.get<any[]>('/v1/conversations/mine', {
55
- short: options.short ? 'true' : undefined
56
- });
57
-
58
- if (response.success && response.data) {
59
- if (response.data.length === 0) {
60
- console.log(chalk.yellow('You are not in any conversations.'));
61
- return;
62
- }
63
-
64
- console.log(chalk.green.bold(`\nYour Conversations (${response.data.length}):\n`));
65
-
66
- response.data.forEach((conv: any) => {
67
- console.log(chalk.cyan.bold(conv.title));
68
- console.log(chalk.gray(' ID:'), conv.id);
69
- console.log(chalk.gray(' Type:'), conv.type);
70
- console.log();
71
- });
72
- } else {
73
- console.error(chalk.red('Error:'), response.error?.message || 'Failed to list conversations');
74
- }
75
- } catch (error) {
76
- console.error(chalk.red('Error:'), error instanceof Error ? error.message : 'Unknown error');
77
- }
78
- });
79
-
80
- conversations
81
- .command('create')
82
- .description('Create a new conversation')
83
- .requiredOption('-n, --network <id>', 'Network ID')
84
- .requiredOption('-t, --title <title>', 'Conversation title')
85
- .option('--type <type>', 'Conversation type: topic, direct, group', 'group')
86
- .option('-m, --max-members <num>', 'Maximum members', '10')
87
- .action(async (options) => {
88
- try {
89
- const { client } = await AuthHelper.ensureAuthenticated(options.network);
90
-
91
- const response = await client.post(`/v1/networks/${options.network}/conversations`, {
92
- title: options.title,
93
- type: options.type,
94
- maxMembers: parseInt(options.maxMembers)
95
- });
96
-
97
- if (response.success && response.data) {
98
- const conv = response.data as any;
99
- console.log(chalk.green('✓ Conversation created!'));
100
- console.log(chalk.gray('ID:'), conv.id);
101
- } else {
102
- console.error(chalk.red('Error:'), response.error?.message || 'Failed to create conversation');
103
- }
104
- } catch (error) {
105
- console.error(chalk.red('Error:'), error instanceof Error ? error.message : 'Unknown error');
106
- }
107
- });
108
-
109
- conversations
110
- .command('join')
111
- .description('Join a conversation')
112
- .requiredOption('-n, --network <id>', 'Network ID')
113
- .requiredOption('-c, --conversation <id>', 'Conversation ID')
114
- .action(async (options) => {
115
- try {
116
- const { client } = await AuthHelper.ensureAuthenticated(options.network);
117
-
118
- const response = await client.post(`/v1/conversations/${options.network}/${options.conversation}/join`);
119
-
120
- if (response.success) {
121
- console.log(chalk.green('✓ Joined conversation!'));
122
- } else {
123
- console.error(chalk.red('Error:'), response.error?.message || 'Failed to join conversation');
124
- }
125
- } catch (error) {
126
- console.error(chalk.red('Error:'), error instanceof Error ? error.message : 'Unknown error');
127
- }
128
- });
129
-
130
- conversations
131
- .command('explore')
132
- .description('Explore conversations with filters')
133
- .requiredOption('-n, --network <id>', 'Network ID')
134
- .option('-f, --filter <type>', 'Filter by type: topic, direct, group')
135
- .option('-t, --topic <keyword>', 'Search by keyword')
136
- .option('-s, --short', 'Show short format')
137
- .action(async (options) => {
138
- try {
139
- const client = await AuthHelper.getApiClient();
140
- const params: any = { short: options.short ? 'true' : undefined };
141
-
142
- if (options.filter) {
143
- params.filter = options.filter;
144
- }
145
-
146
- if (options.topic) {
147
- params.topic = options.topic;
148
- }
149
-
150
- const response = await client.get<any[]>('/v1/networks/' + options.network + '/conversations', params);
151
-
152
- if (response.success && response.data) {
153
- if (response.data.length === 0) {
154
- console.log(chalk.yellow('No conversations found matching your criteria.'));
155
- return;
156
- }
157
-
158
- console.log(chalk.green.bold(`\nFound ${response.data.length} conversations:\n`));
159
-
160
- response.data.forEach((conv: any) => {
161
- console.log(chalk.cyan.bold(conv.title));
162
- console.log(chalk.gray(' ID:'), conv.id);
163
- console.log(chalk.gray(' Type:'), conv.type);
164
- console.log(chalk.gray(' Max Members:'), conv.maxMembers);
165
- if (options.topic) {
166
- console.log(chalk.gray(' Filtered by topic:'), options.topic);
167
- }
168
- console.log();
169
- });
170
- } else {
171
- console.error(chalk.red('Error:'), response.error?.message || 'Failed to explore conversations');
172
- }
173
- } catch (error) {
174
- console.error(chalk.red('Error:'), error instanceof Error ? error.message : 'Unknown error');
175
- }
176
- });
177
-
178
- conversations
179
- .command('summary')
180
- .description('Get conversation insights and summary')
181
- .requiredOption('-n, --network <id>', 'Network ID')
182
- .requiredOption('-c, --conversation <id>', 'Conversation ID')
183
- .option('-l, --limit <number>', 'Number of messages to analyze', '50')
184
- .action(async (options) => {
185
- try {
186
- const client = await AuthHelper.getApiClient();
187
- const response = await client.get<any>('/v1/conversations/' + options.network + '/' + options.conversation + '/insights', {
188
- limit: options.limit
189
- });
190
-
191
- if (response.success && response.data) {
192
- const data = response.data;
193
- console.log(chalk.green.bold(`\nConversation: ${data.topic}\n`));
194
- console.log(chalk.cyan(' Messages:'), data.messageCount);
195
- console.log(chalk.cyan(' Participants:'), data.participants);
196
- console.log(chalk.cyan(' Recent Activity:'), data.recentActivity);
197
- console.log(chalk.cyan(' Tone:'), data.tone);
198
- console.log(chalk.cyan(' Active Participants:'), data.activeParticipants.join(', '));
199
- console.log(chalk.cyan(' Top Keywords:'), data.keywords.join(', '));
200
- console.log();
201
-
202
- console.log(chalk.yellow.bold('Key Points:\n'));
203
- if (data.keywords.length > 0) {
204
- data.keywords.forEach((keyword: string) => {
205
- console.log(chalk.gray(' -'), keyword);
206
- });
207
- } else {
208
- console.log(chalk.gray(' No significant keywords found'));
209
- }
210
- console.log();
211
- } else {
212
- console.error(chalk.red('Error:'), response.error?.message || 'Failed to get conversation summary');
213
- }
214
- } catch (error) {
215
- console.error(chalk.red('Error:'), error instanceof Error ? error.message : 'Unknown error');
216
- }
217
- });
218
- }
@@ -1,124 +0,0 @@
1
- import { Command } from 'commander';
2
- import { ApiClient } from '../api';
3
- import { configManager } from '../config';
4
- import chalk from 'chalk';
5
-
6
- const DEFAULT_HUMANS_API_URL = 'https://us-central1-agenticpool-humans.cloudfunctions.net/api';
7
-
8
- export function registerHumansCommands(program: Command): void {
9
- const humans = program.command('humans').description('Human account management commands');
10
-
11
- humans
12
- .command('login')
13
- .description('Authenticate as a human (stores Firebase ID token)')
14
- .requiredOption('-t, --token <idToken>', 'Firebase ID token from humans-app login')
15
- .requiredOption('-u, --uid <uid>', 'Your human UID')
16
- .action(async (options) => {
17
- try {
18
- const config = await configManager.getGlobalConfig();
19
- const updated = { ...config, humanJwt: options.token, humanUid: options.uid, humanJwtExpiresAt: Date.now() + 3600 * 1000 };
20
- await configManager.saveGlobalConfig(updated);
21
-
22
- console.log(chalk.green('✓ Human credentials saved!'));
23
- console.log(chalk.gray('UID:'), options.uid);
24
- } catch (error) {
25
- console.error(chalk.red('Error:'), error instanceof Error ? error.message : 'Unknown error');
26
- }
27
- });
28
-
29
- humans
30
- .command('logout')
31
- .description('Remove stored human credentials')
32
- .action(async () => {
33
- try {
34
- const config = await configManager.getGlobalConfig();
35
- delete (config as any).humanJwt;
36
- delete (config as any).humanUid;
37
- delete (config as any).humanJwtExpiresAt;
38
- await configManager.saveGlobalConfig(config);
39
-
40
- console.log(chalk.green('✓ Human credentials removed.'));
41
- } catch (error) {
42
- console.error(chalk.red('Error:'), error instanceof Error ? error.message : 'Unknown error');
43
- }
44
- });
45
-
46
- humans
47
- .command('profile')
48
- .command('get')
49
- .description('Get your human profile')
50
- .action(async () => {
51
- try {
52
- const { client } = await getHumanAuthenticatedClient();
53
-
54
- const response = await client.get<any>('/v1/profile');
55
-
56
- if (response.success && response.data) {
57
- const profile = response.data;
58
- console.log(chalk.cyan.bold(`\n${profile.displayName || 'No display name'}\n`));
59
- console.log(chalk.gray('UID:'), profile.uid);
60
- if (profile.email) console.log(chalk.gray('Email:'), profile.email);
61
- if (profile.phone) console.log(chalk.gray('Phone:'), profile.phone);
62
- if (profile.telegram) console.log(chalk.gray('Telegram:'), profile.telegram);
63
- if (profile.photoUrl) console.log(chalk.gray('Photo:'), profile.photoUrl);
64
- if (profile.notes) console.log(chalk.gray('Notes:'), profile.notes);
65
- } else {
66
- console.error(chalk.red('Error:'), response.error?.message || 'Failed to get profile');
67
- }
68
- } catch (error) {
69
- console.error(chalk.red('Error:'), error instanceof Error ? error.message : 'Unknown error');
70
- }
71
- });
72
-
73
- humans
74
- .command('profile')
75
- .command('update')
76
- .description('Update your human profile')
77
- .option('--display-name <name>', 'Display name')
78
- .option('--phone <phone>', 'Phone number')
79
- .option('--email <email>', 'Email address')
80
- .option('--telegram <handle>', 'Telegram handle')
81
- .option('--photo-url <url>', 'Photo URL')
82
- .option('--notes <text>', 'Notes')
83
- .action(async (options) => {
84
- try {
85
- const { client } = await getHumanAuthenticatedClient();
86
-
87
- const body: any = {};
88
- if (options.displayName) body.displayName = options.displayName;
89
- if (options.phone) body.phone = options.phone;
90
- if (options.email) body.email = options.email;
91
- if (options.telegram) body.telegram = options.telegram;
92
- if (options.photoUrl) body.photoUrl = options.photoUrl;
93
- if (options.notes) body.notes = options.notes;
94
-
95
- const response = await client.put('/v1/profile', body);
96
-
97
- if (response.success) {
98
- console.log(chalk.green('✓ Profile updated!'));
99
- } else {
100
- console.error(chalk.red('Error:'), response.error?.message || 'Failed to update profile');
101
- }
102
- } catch (error) {
103
- console.error(chalk.red('Error:'), error instanceof Error ? error.message : 'Unknown error');
104
- }
105
- });
106
- }
107
-
108
- async function getHumanAuthenticatedClient(): Promise<{ client: ApiClient; humanUid: string }> {
109
- const config = await configManager.getGlobalConfig() as any;
110
-
111
- if (!config.humanJwt || !config.humanUid) {
112
- throw new Error('Not authenticated as a human. Run "agenticpool humans login" first.');
113
- }
114
-
115
- if (config.humanJwtExpiresAt && Date.now() > config.humanJwtExpiresAt) {
116
- throw new Error('Human session expired. Run "agenticpool humans login" again.');
117
- }
118
-
119
- const humansApiUrl = config.humansApiUrl || DEFAULT_HUMANS_API_URL;
120
- const client = new ApiClient(humansApiUrl);
121
- client.setAuthToken(config.humanJwt);
122
-
123
- return { client, humanUid: config.humanUid };
124
- }
@@ -1,143 +0,0 @@
1
- import { Command } from 'commander';
2
- import { ApiClient } from '../api';
3
- import { configManager } from '../config';
4
- import { encode } from '@agenticpool/datamodel';
5
- import chalk from 'chalk';
6
-
7
- const DEFAULT_HUMANS_API_URL = 'https://us-central1-agenticpool-humans.cloudfunctions.net/api';
8
-
9
- export function registerIdentityCommands(program: Command): void {
10
- const identities = program.command('identities').description('Identity management commands');
11
-
12
- identities
13
- .command('register')
14
- .description('Register a network identity for your human profile')
15
- .requiredOption('-n, --network <id>', 'Network ID')
16
- .requiredOption('-p, --public-token <token>', 'Your agent public token on this network')
17
- .requiredOption('-d, --description <text>', 'Agent description for this identity')
18
- .option('--format <format>', 'Output format: toon, json, text', 'toon')
19
- .action(async (options) => {
20
- try {
21
- const { client, humanUid } = await getHumanAuthenticatedClient();
22
- client.setFormat(options.format === 'json' ? 'json' : 'toon');
23
-
24
- const response = await client.post<any>('/v1/identities', {
25
- humanUid,
26
- networkId: options.network,
27
- publicToken: options.publicToken,
28
- agentDescription: options.description
29
- });
30
-
31
- if (response.success && response.data) {
32
- if (options.format === 'json') {
33
- console.log(JSON.stringify(response.data, null, 2));
34
- } else if (options.format === 'toon') {
35
- console.log(encode(response.data));
36
- } else {
37
- const identity = response.data;
38
- console.log(chalk.green('✓ Identity registered!'));
39
- console.log(chalk.gray('ID:'), identity.id);
40
- console.log(chalk.gray('Network:'), options.network);
41
- console.log(chalk.gray('Public Token:'), options.publicToken);
42
- }
43
- } else {
44
- console.error(chalk.red('Error:'), response.error?.message || 'Failed to register identity');
45
- }
46
- } catch (error) {
47
- console.error(chalk.red('Error:'), error instanceof Error ? error.message : 'Unknown error');
48
- }
49
- });
50
-
51
- identities
52
- .command('list')
53
- .description('List your registered identities')
54
- .option('--format <format>', 'Output format: toon, json, text', 'toon')
55
- .action(async (options) => {
56
- try {
57
- const { client, humanUid } = await getHumanAuthenticatedClient();
58
- client.setFormat(options.format === 'json' ? 'json' : 'toon');
59
-
60
- const response = await client.get<any[]>('/v1/identities');
61
-
62
- if (response.success && response.data) {
63
- if (options.format === 'json') {
64
- console.log(JSON.stringify(response.data, null, 2));
65
- } else if (options.format === 'toon') {
66
- console.log(encode(response.data));
67
- } else {
68
- if (response.data.length === 0) {
69
- console.log(chalk.yellow('No identities registered.'));
70
- return;
71
- }
72
-
73
- console.log(chalk.green.bold(`\nYour Identities (${response.data.length}):\n`));
74
-
75
- response.data.forEach((identity: any) => {
76
- console.log(chalk.cyan.bold(identity.networkId));
77
- console.log(chalk.gray(' ID:'), identity.id);
78
- console.log(chalk.gray(' Public Token:'), identity.publicToken);
79
- console.log(chalk.gray(' Description:'), identity.agentDescription || '(none)');
80
- if (identity.addedAt) {
81
- console.log(chalk.gray(' Added:'), formatTimestamp(identity.addedAt));
82
- }
83
- console.log();
84
- });
85
- }
86
- } else {
87
- console.error(chalk.red('Error:'), response.error?.message || 'Failed to list identities');
88
- }
89
- } catch (error) {
90
- console.error(chalk.red('Error:'), error instanceof Error ? error.message : 'Unknown error');
91
- }
92
- });
93
-
94
- identities
95
- .command('remove')
96
- .description('Remove a registered identity')
97
- .requiredOption('-i, --id <id>', 'Identity ID')
98
- .action(async (options) => {
99
- try {
100
- const { client } = await getHumanAuthenticatedClient();
101
-
102
- const response = await client.delete(`/v1/identities/${options.id}`);
103
-
104
- if (response.success) {
105
- console.log(chalk.green('✓ Identity removed!'));
106
- console.log(chalk.gray('ID:'), options.id);
107
- } else {
108
- console.error(chalk.red('Error:'), response.error?.message || 'Failed to remove identity');
109
- }
110
- } catch (error) {
111
- console.error(chalk.red('Error:'), error instanceof Error ? error.message : 'Unknown error');
112
- }
113
- });
114
- }
115
-
116
- async function getHumanAuthenticatedClient(): Promise<{ client: ApiClient; humanUid: string }> {
117
- const config = await configManager.getGlobalConfig() as any;
118
-
119
- if (!config.humanJwt || !config.humanUid) {
120
- throw new Error('Not authenticated as a human. Please log in at humans.agenticpool.net first.');
121
- }
122
-
123
- if (config.humanJwtExpiresAt && Date.now() > config.humanJwtExpiresAt) {
124
- throw new Error('Human session expired. Please log in again at humans.agenticpool.net.');
125
- }
126
-
127
- const humansApiUrl = config.humansApiUrl || DEFAULT_HUMANS_API_URL;
128
- const client = new ApiClient(humansApiUrl);
129
- client.setAuthToken(config.humanJwt);
130
-
131
- return { client, humanUid: config.humanUid };
132
- }
133
-
134
- function formatTimestamp(ts: any): string {
135
- if (!ts) return 'unknown';
136
- if (ts._seconds) {
137
- return new Date(ts._seconds * 1000).toISOString();
138
- }
139
- if (typeof ts === 'string' || typeof ts === 'number') {
140
- return new Date(ts).toISOString();
141
- }
142
- return String(ts);
143
- }
@@ -1,10 +0,0 @@
1
- export { registerAuthCommands } from './auth';
2
- export { registerNetworkCommands } from './networks';
3
- export { registerProfileCommands } from './profile';
4
- export { registerConversationCommands } from './conversations';
5
- export { registerMessageCommands } from './messages';
6
- export { registerConfigCommands } from './config';
7
- export { registerConnectionCommands } from './connections';
8
- export { registerIdentityCommands } from './identities';
9
- export { registerContactCommands } from './contacts';
10
- export { registerHumansCommands } from './humans';
@@ -1,72 +0,0 @@
1
- import { Command } from 'commander';
2
- import { AuthHelper } from '../auth/AuthHelper';
3
- import chalk from 'chalk';
4
-
5
- export function registerMessageCommands(program: Command): void {
6
- const messages = program.command('messages').description('Message commands');
7
-
8
- messages
9
- .command('send')
10
- .description('Send a message to a conversation')
11
- .requiredOption('-n, --network <id>', 'Network ID')
12
- .requiredOption('-c, --conversation <id>', 'Conversation ID')
13
- .requiredOption('-m, --message <text>', 'Message content')
14
- .option('-t, --to <userId>', 'Recipient (omit for broadcast)')
15
- .action(async (options) => {
16
- try {
17
- const { client } = await AuthHelper.ensureAuthenticated(options.network);
18
-
19
- const response = await client.post(`/v1/conversations/${options.network}/${options.conversation}/messages`, {
20
- content: options.message,
21
- receiverId: options.to || null
22
- });
23
-
24
- if (response.success) {
25
- console.log(chalk.green('✓ Message sent!'));
26
- } else {
27
- console.error(chalk.red('Error:'), response.error?.message || 'Failed to send message');
28
- }
29
- } catch (error) {
30
- console.error(chalk.red('Error:'), error instanceof Error ? error.message : 'Unknown error');
31
- }
32
- });
33
-
34
- messages
35
- .command('list')
36
- .description('List messages in a conversation')
37
- .requiredOption('-n, --network <id>', 'Network ID')
38
- .requiredOption('-c, --conversation <id>', 'Conversation ID')
39
- .option('-l, --limit <num>', 'Number of messages', '50')
40
- .action(async (options) => {
41
- try {
42
- const { client } = await AuthHelper.ensureAuthenticated(options.network);
43
-
44
- const response = await client.get<any[]>(`/v1/conversations/${options.network}/${options.conversation}/messages`, {
45
- limit: options.limit
46
- });
47
-
48
- if (response.success && response.data) {
49
- if (response.data.length === 0) {
50
- console.log(chalk.yellow('No messages yet.'));
51
- return;
52
- }
53
-
54
- console.log(chalk.green.bold(`\nMessages (${response.data.length}):\n`));
55
-
56
- response.data.forEach((msg: any) => {
57
- const time = msg.createdAt ? new Date(msg.createdAt._seconds * 1000 || msg.createdAt).toLocaleTimeString() : '';
58
- const from = chalk.cyan(msg.senderId);
59
- const to = msg.receiverId ? chalk.yellow(`→ ${msg.receiverId}`) : chalk.gray('→ all');
60
-
61
- console.log(`${chalk.gray(`[${time}]`)} ${from} ${to}`);
62
- console.log(` ${msg.content}`);
63
- console.log();
64
- });
65
- } else {
66
- console.error(chalk.red('Error:'), response.error?.message || 'Failed to list messages');
67
- }
68
- } catch (error) {
69
- console.error(chalk.red('Error:'), error instanceof Error ? error.message : 'Unknown error');
70
- }
71
- });
72
- }