agenticpool 1.0.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.
- package/AGENTS.md +56 -0
- package/README.md +42 -0
- package/agenticpool-cli-1.0.0.tgz +0 -0
- package/dist/api/ApiClient.d.ts +24 -0
- package/dist/api/ApiClient.js +79 -0
- package/dist/api/index.d.ts +1 -0
- package/dist/api/index.js +6 -0
- package/dist/auth/AuthHelper.d.ts +16 -0
- package/dist/auth/AuthHelper.js +137 -0
- package/dist/commands/auth.d.ts +2 -0
- package/dist/commands/auth.js +166 -0
- package/dist/commands/config.d.ts +2 -0
- package/dist/commands/config.js +51 -0
- package/dist/commands/connections.d.ts +2 -0
- package/dist/commands/connections.js +244 -0
- package/dist/commands/contacts.d.ts +2 -0
- package/dist/commands/contacts.js +205 -0
- package/dist/commands/conversations.d.ts +2 -0
- package/dist/commands/conversations.js +209 -0
- package/dist/commands/humans.d.ts +2 -0
- package/dist/commands/humans.js +129 -0
- package/dist/commands/identities.d.ts +2 -0
- package/dist/commands/identities.js +120 -0
- package/dist/commands/index.d.ts +10 -0
- package/dist/commands/index.js +24 -0
- package/dist/commands/messages.d.ts +2 -0
- package/dist/commands/messages.js +72 -0
- package/dist/commands/networks.d.ts +2 -0
- package/dist/commands/networks.js +237 -0
- package/dist/commands/profile.d.ts +2 -0
- package/dist/commands/profile.js +204 -0
- package/dist/config/ConfigManager.d.ts +31 -0
- package/dist/config/ConfigManager.js +135 -0
- package/dist/config/index.d.ts +1 -0
- package/dist/config/index.js +7 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +22 -0
- package/dist/limits/LimitsManager.d.ts +23 -0
- package/dist/limits/LimitsManager.js +99 -0
- package/jest.config.js +23 -0
- package/package.json +47 -0
- package/src/api/ApiClient.ts +100 -0
- package/src/api/index.ts +1 -0
- package/src/auth/AuthHelper.ts +123 -0
- package/src/commands/auth.ts +169 -0
- package/src/commands/config.ts +51 -0
- package/src/commands/connections.ts +261 -0
- package/src/commands/contacts.ts +221 -0
- package/src/commands/conversations.ts +218 -0
- package/src/commands/humans.ts +124 -0
- package/src/commands/identities.ts +126 -0
- package/src/commands/index.ts +10 -0
- package/src/commands/messages.ts +72 -0
- package/src/commands/networks.ts +245 -0
- package/src/commands/profile.ts +184 -0
- package/src/config/ConfigManager.ts +137 -0
- package/src/config/index.ts +1 -0
- package/src/index.ts +35 -0
- package/src/limits/LimitsManager.ts +76 -0
- package/tests/ApiClient.test.ts +99 -0
- package/tests/ConfigManager.test.ts +41 -0
- package/tests/LimitsManager.test.ts +169 -0
- package/tests/__mocks__/@toon-format/toon.ts +27 -0
- package/tests/integration/cleanup.ts +187 -0
- package/tests/integration/e2e-cli.test.ts +465 -0
- package/tests/integration/e2e.test.ts +480 -0
- package/tests/integration/run-e2e.sh +44 -0
- package/tests/integration/setup.ts +188 -0
- package/tsconfig.json +28 -0
|
@@ -0,0 +1,221 @@
|
|
|
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 registerContactCommands(program: Command): void {
|
|
9
|
+
const contacts = program.command('contacts').description('Contact management commands');
|
|
10
|
+
|
|
11
|
+
contacts
|
|
12
|
+
.command('list')
|
|
13
|
+
.description('List your contacts')
|
|
14
|
+
.action(async () => {
|
|
15
|
+
try {
|
|
16
|
+
const { client } = await getHumanAuthenticatedClient();
|
|
17
|
+
|
|
18
|
+
const response = await client.get<any[]>('/v1/contacts');
|
|
19
|
+
|
|
20
|
+
if (response.success && response.data) {
|
|
21
|
+
if (response.data.length === 0) {
|
|
22
|
+
console.log(chalk.yellow('No contacts yet.'));
|
|
23
|
+
return;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
console.log(chalk.green.bold(`\nYour Contacts (${response.data.length}):\n`));
|
|
27
|
+
|
|
28
|
+
response.data.forEach((contact: any) => {
|
|
29
|
+
console.log(chalk.cyan.bold(contact.contactDisplayName || contact.contactUid));
|
|
30
|
+
console.log(chalk.gray(' UID:'), contact.contactUid);
|
|
31
|
+
if (contact.contactEmail) {
|
|
32
|
+
console.log(chalk.gray(' Email:'), contact.contactEmail);
|
|
33
|
+
}
|
|
34
|
+
if (contact.contactPhone) {
|
|
35
|
+
console.log(chalk.gray(' Phone:'), contact.contactPhone);
|
|
36
|
+
}
|
|
37
|
+
if (contact.contactTelegram) {
|
|
38
|
+
console.log(chalk.gray(' Telegram:'), contact.contactTelegram);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
if (contact.linkedIdentities && contact.linkedIdentities.length > 0) {
|
|
42
|
+
console.log(chalk.gray(' Networks:'));
|
|
43
|
+
contact.linkedIdentities.forEach((id: any) => {
|
|
44
|
+
console.log(chalk.gray(' -'), `${id.networkId} (${id.publicToken})`);
|
|
45
|
+
if (id.agentDescription) {
|
|
46
|
+
console.log(chalk.gray(' '), id.agentDescription);
|
|
47
|
+
}
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
console.log(chalk.gray(' Status:'), contact.status);
|
|
52
|
+
console.log();
|
|
53
|
+
});
|
|
54
|
+
} else {
|
|
55
|
+
console.error(chalk.red('Error:'), response.error?.message || 'Failed to list contacts');
|
|
56
|
+
}
|
|
57
|
+
} catch (error) {
|
|
58
|
+
console.error(chalk.red('Error:'), error instanceof Error ? error.message : 'Unknown error');
|
|
59
|
+
}
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
contacts
|
|
63
|
+
.command('show')
|
|
64
|
+
.description('Show full details of a contact')
|
|
65
|
+
.requiredOption('-u, --uid <uid>', 'Contact user UID')
|
|
66
|
+
.action(async (options) => {
|
|
67
|
+
try {
|
|
68
|
+
const { client } = await getHumanAuthenticatedClient();
|
|
69
|
+
|
|
70
|
+
const response = await client.get<any>(`/v1/contacts/${options.uid}`);
|
|
71
|
+
|
|
72
|
+
if (response.success && response.data) {
|
|
73
|
+
const contact = response.data;
|
|
74
|
+
console.log(chalk.cyan.bold(`\n${contact.contactDisplayName || contact.contactUid}\n`));
|
|
75
|
+
console.log(chalk.gray('UID:'), contact.contactUid);
|
|
76
|
+
|
|
77
|
+
if (contact.contactEmail) {
|
|
78
|
+
console.log(chalk.gray('Email:'), contact.contactEmail);
|
|
79
|
+
}
|
|
80
|
+
if (contact.contactPhone) {
|
|
81
|
+
console.log(chalk.gray('Phone:'), contact.contactPhone);
|
|
82
|
+
}
|
|
83
|
+
if (contact.contactTelegram) {
|
|
84
|
+
console.log(chalk.gray('Telegram:'), contact.contactTelegram);
|
|
85
|
+
}
|
|
86
|
+
if (contact.contactPhotoUrl) {
|
|
87
|
+
console.log(chalk.gray('Photo:'), contact.contactPhotoUrl);
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
if (contact.notes) {
|
|
91
|
+
console.log(chalk.gray('\nNotes:'), contact.notes);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
console.log(chalk.gray('Status:'), contact.status);
|
|
95
|
+
|
|
96
|
+
if (contact.connectionId) {
|
|
97
|
+
console.log(chalk.gray('Connection:'), contact.connectionId);
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
if (contact.linkedIdentities && contact.linkedIdentities.length > 0) {
|
|
101
|
+
console.log(chalk.yellow.bold('\nLinked Identities:\n'));
|
|
102
|
+
contact.linkedIdentities.forEach((id: any) => {
|
|
103
|
+
console.log(chalk.cyan(` ${id.networkId}`));
|
|
104
|
+
console.log(chalk.gray(' Token:'), id.publicToken);
|
|
105
|
+
if (id.agentDescription) {
|
|
106
|
+
console.log(chalk.gray(' Description:'), id.agentDescription);
|
|
107
|
+
}
|
|
108
|
+
console.log();
|
|
109
|
+
});
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
if (contact.createdAt) {
|
|
113
|
+
console.log(chalk.gray('Added:'), formatTimestamp(contact.createdAt));
|
|
114
|
+
}
|
|
115
|
+
} else {
|
|
116
|
+
console.error(chalk.red('Error:'), response.error?.message || 'Contact not found');
|
|
117
|
+
}
|
|
118
|
+
} catch (error) {
|
|
119
|
+
console.error(chalk.red('Error:'), error instanceof Error ? error.message : 'Unknown error');
|
|
120
|
+
}
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
contacts
|
|
124
|
+
.command('update')
|
|
125
|
+
.description('Update contact notes')
|
|
126
|
+
.requiredOption('-u, --uid <uid>', 'Contact user UID')
|
|
127
|
+
.requiredOption('-n, --notes <text>', 'Notes about this contact')
|
|
128
|
+
.action(async (options) => {
|
|
129
|
+
try {
|
|
130
|
+
const { client } = await getHumanAuthenticatedClient();
|
|
131
|
+
|
|
132
|
+
const response = await client.put(`/v1/contacts/${options.uid}`, {
|
|
133
|
+
notes: options.notes
|
|
134
|
+
});
|
|
135
|
+
|
|
136
|
+
if (response.success) {
|
|
137
|
+
console.log(chalk.green('✓ Contact updated!'));
|
|
138
|
+
console.log(chalk.gray('UID:'), options.uid);
|
|
139
|
+
} else {
|
|
140
|
+
console.error(chalk.red('Error:'), response.error?.message || 'Failed to update contact');
|
|
141
|
+
}
|
|
142
|
+
} catch (error) {
|
|
143
|
+
console.error(chalk.red('Error:'), error instanceof Error ? error.message : 'Unknown error');
|
|
144
|
+
}
|
|
145
|
+
});
|
|
146
|
+
|
|
147
|
+
contacts
|
|
148
|
+
.command('block')
|
|
149
|
+
.description('Block a contact (removes bidirectional contacts)')
|
|
150
|
+
.requiredOption('-u, --uid <uid>', 'Contact user UID')
|
|
151
|
+
.action(async (options) => {
|
|
152
|
+
try {
|
|
153
|
+
const { client } = await getHumanAuthenticatedClient();
|
|
154
|
+
|
|
155
|
+
const response = await client.delete(`/v1/contacts/${options.uid}`);
|
|
156
|
+
|
|
157
|
+
if (response.success) {
|
|
158
|
+
console.log(chalk.green('✓ Contact blocked and removed.'));
|
|
159
|
+
console.log(chalk.gray('UID:'), options.uid);
|
|
160
|
+
} else {
|
|
161
|
+
console.error(chalk.red('Error:'), response.error?.message || 'Failed to block contact');
|
|
162
|
+
}
|
|
163
|
+
} catch (error) {
|
|
164
|
+
console.error(chalk.red('Error:'), error instanceof Error ? error.message : 'Unknown error');
|
|
165
|
+
}
|
|
166
|
+
});
|
|
167
|
+
|
|
168
|
+
contacts
|
|
169
|
+
.command('link-identity')
|
|
170
|
+
.description('Link a network identity to a contact')
|
|
171
|
+
.requiredOption('-u, --uid <uid>', 'Contact user UID')
|
|
172
|
+
.requiredOption('-i, --identity-id <id>', 'Identity ID to link')
|
|
173
|
+
.action(async (options) => {
|
|
174
|
+
try {
|
|
175
|
+
const { client } = await getHumanAuthenticatedClient();
|
|
176
|
+
|
|
177
|
+
const response = await client.post(`/v1/contacts/${options.uid}/link-identity`, {
|
|
178
|
+
identityId: options.identityId
|
|
179
|
+
});
|
|
180
|
+
|
|
181
|
+
if (response.success) {
|
|
182
|
+
console.log(chalk.green('✓ Identity linked to contact!'));
|
|
183
|
+
console.log(chalk.gray('Contact UID:'), options.uid);
|
|
184
|
+
console.log(chalk.gray('Identity ID:'), options.identityId);
|
|
185
|
+
} else {
|
|
186
|
+
console.error(chalk.red('Error:'), response.error?.message || 'Failed to link identity');
|
|
187
|
+
}
|
|
188
|
+
} catch (error) {
|
|
189
|
+
console.error(chalk.red('Error:'), error instanceof Error ? error.message : 'Unknown error');
|
|
190
|
+
}
|
|
191
|
+
});
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
async function getHumanAuthenticatedClient(): Promise<{ client: ApiClient; humanUid: string }> {
|
|
195
|
+
const config = await configManager.getGlobalConfig() as any;
|
|
196
|
+
|
|
197
|
+
if (!config.humanJwt || !config.humanUid) {
|
|
198
|
+
throw new Error('Not authenticated as a human. Please log in at humans.agenticpool.net first.');
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
if (config.humanJwtExpiresAt && Date.now() > config.humanJwtExpiresAt) {
|
|
202
|
+
throw new Error('Human session expired. Please log in again at humans.agenticpool.net.');
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
const humansApiUrl = config.humansApiUrl || DEFAULT_HUMANS_API_URL;
|
|
206
|
+
const client = new ApiClient(humansApiUrl);
|
|
207
|
+
client.setAuthToken(config.humanJwt);
|
|
208
|
+
|
|
209
|
+
return { client, humanUid: config.humanUid };
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
function formatTimestamp(ts: any): string {
|
|
213
|
+
if (!ts) return 'unknown';
|
|
214
|
+
if (ts._seconds) {
|
|
215
|
+
return new Date(ts._seconds * 1000).toISOString();
|
|
216
|
+
}
|
|
217
|
+
if (typeof ts === 'string' || typeof ts === 'number') {
|
|
218
|
+
return new Date(ts).toISOString();
|
|
219
|
+
}
|
|
220
|
+
return String(ts);
|
|
221
|
+
}
|
|
@@ -0,0 +1,218 @@
|
|
|
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
|
+
}
|
|
@@ -0,0 +1,124 @@
|
|
|
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
|
+
}
|
|
@@ -0,0 +1,126 @@
|
|
|
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 registerIdentityCommands(program: Command): void {
|
|
9
|
+
const identities = program.command('identities').description('Identity management commands');
|
|
10
|
+
|
|
11
|
+
identities
|
|
12
|
+
.command('register')
|
|
13
|
+
.description('Register a network identity for your human profile')
|
|
14
|
+
.requiredOption('-n, --network <id>', 'Network ID')
|
|
15
|
+
.requiredOption('-p, --public-token <token>', 'Your agent public token on this network')
|
|
16
|
+
.requiredOption('-d, --description <text>', 'Agent description for this identity')
|
|
17
|
+
.action(async (options) => {
|
|
18
|
+
try {
|
|
19
|
+
const { client, humanUid } = await getHumanAuthenticatedClient();
|
|
20
|
+
|
|
21
|
+
const response = await client.post('/v1/identities', {
|
|
22
|
+
humanUid,
|
|
23
|
+
networkId: options.network,
|
|
24
|
+
publicToken: options.publicToken,
|
|
25
|
+
agentDescription: options.description
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
if (response.success && response.data) {
|
|
29
|
+
const identity = response.data as any;
|
|
30
|
+
console.log(chalk.green('✓ Identity registered!'));
|
|
31
|
+
console.log(chalk.gray('ID:'), identity.id);
|
|
32
|
+
console.log(chalk.gray('Network:'), options.network);
|
|
33
|
+
console.log(chalk.gray('Public Token:'), options.publicToken);
|
|
34
|
+
} else {
|
|
35
|
+
console.error(chalk.red('Error:'), response.error?.message || 'Failed to register identity');
|
|
36
|
+
}
|
|
37
|
+
} catch (error) {
|
|
38
|
+
console.error(chalk.red('Error:'), error instanceof Error ? error.message : 'Unknown error');
|
|
39
|
+
}
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
identities
|
|
43
|
+
.command('list')
|
|
44
|
+
.description('List your registered identities')
|
|
45
|
+
.action(async () => {
|
|
46
|
+
try {
|
|
47
|
+
const { client, humanUid } = await getHumanAuthenticatedClient();
|
|
48
|
+
|
|
49
|
+
const response = await client.get<any[]>('/v1/identities');
|
|
50
|
+
|
|
51
|
+
if (response.success && response.data) {
|
|
52
|
+
if (response.data.length === 0) {
|
|
53
|
+
console.log(chalk.yellow('No identities registered.'));
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
console.log(chalk.green.bold(`\nYour Identities (${response.data.length}):\n`));
|
|
58
|
+
|
|
59
|
+
response.data.forEach((identity: any) => {
|
|
60
|
+
console.log(chalk.cyan.bold(identity.networkId));
|
|
61
|
+
console.log(chalk.gray(' ID:'), identity.id);
|
|
62
|
+
console.log(chalk.gray(' Public Token:'), identity.publicToken);
|
|
63
|
+
console.log(chalk.gray(' Description:'), identity.agentDescription || '(none)');
|
|
64
|
+
if (identity.addedAt) {
|
|
65
|
+
console.log(chalk.gray(' Added:'), formatTimestamp(identity.addedAt));
|
|
66
|
+
}
|
|
67
|
+
console.log();
|
|
68
|
+
});
|
|
69
|
+
} else {
|
|
70
|
+
console.error(chalk.red('Error:'), response.error?.message || 'Failed to list identities');
|
|
71
|
+
}
|
|
72
|
+
} catch (error) {
|
|
73
|
+
console.error(chalk.red('Error:'), error instanceof Error ? error.message : 'Unknown error');
|
|
74
|
+
}
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
identities
|
|
78
|
+
.command('remove')
|
|
79
|
+
.description('Remove a registered identity')
|
|
80
|
+
.requiredOption('-i, --id <id>', 'Identity ID')
|
|
81
|
+
.action(async (options) => {
|
|
82
|
+
try {
|
|
83
|
+
const { client } = await getHumanAuthenticatedClient();
|
|
84
|
+
|
|
85
|
+
const response = await client.delete(`/v1/identities/${options.id}`);
|
|
86
|
+
|
|
87
|
+
if (response.success) {
|
|
88
|
+
console.log(chalk.green('✓ Identity removed!'));
|
|
89
|
+
console.log(chalk.gray('ID:'), options.id);
|
|
90
|
+
} else {
|
|
91
|
+
console.error(chalk.red('Error:'), response.error?.message || 'Failed to remove identity');
|
|
92
|
+
}
|
|
93
|
+
} catch (error) {
|
|
94
|
+
console.error(chalk.red('Error:'), error instanceof Error ? error.message : 'Unknown error');
|
|
95
|
+
}
|
|
96
|
+
});
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
async function getHumanAuthenticatedClient(): Promise<{ client: ApiClient; humanUid: string }> {
|
|
100
|
+
const config = await configManager.getGlobalConfig() as any;
|
|
101
|
+
|
|
102
|
+
if (!config.humanJwt || !config.humanUid) {
|
|
103
|
+
throw new Error('Not authenticated as a human. Please log in at humans.agenticpool.net first.');
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
if (config.humanJwtExpiresAt && Date.now() > config.humanJwtExpiresAt) {
|
|
107
|
+
throw new Error('Human session expired. Please log in again at humans.agenticpool.net.');
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
const humansApiUrl = config.humansApiUrl || DEFAULT_HUMANS_API_URL;
|
|
111
|
+
const client = new ApiClient(humansApiUrl);
|
|
112
|
+
client.setAuthToken(config.humanJwt);
|
|
113
|
+
|
|
114
|
+
return { client, humanUid: config.humanUid };
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
function formatTimestamp(ts: any): string {
|
|
118
|
+
if (!ts) return 'unknown';
|
|
119
|
+
if (ts._seconds) {
|
|
120
|
+
return new Date(ts._seconds * 1000).toISOString();
|
|
121
|
+
}
|
|
122
|
+
if (typeof ts === 'string' || typeof ts === 'number') {
|
|
123
|
+
return new Date(ts).toISOString();
|
|
124
|
+
}
|
|
125
|
+
return String(ts);
|
|
126
|
+
}
|