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,10 @@
|
|
|
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';
|
|
@@ -0,0 +1,72 @@
|
|
|
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
|
+
}
|
|
@@ -0,0 +1,245 @@
|
|
|
1
|
+
import { Command } from 'commander';
|
|
2
|
+
import { ApiClient } from '../api';
|
|
3
|
+
import { configManager } from '../config';
|
|
4
|
+
import { AuthHelper } from '../auth/AuthHelper';
|
|
5
|
+
import { limitsManager } from '../limits/LimitsManager';
|
|
6
|
+
import chalk from 'chalk';
|
|
7
|
+
|
|
8
|
+
export function registerNetworkCommands(program: Command): void {
|
|
9
|
+
const networks = program.command('networks').description('Network management commands');
|
|
10
|
+
|
|
11
|
+
networks
|
|
12
|
+
.command('list')
|
|
13
|
+
.description('List public networks')
|
|
14
|
+
.option('-f, --filter <type>', 'Filter: popular, new, unpopular')
|
|
15
|
+
.option('-s, --short', 'Show short format (no long descriptions)')
|
|
16
|
+
.action(async (options) => {
|
|
17
|
+
try {
|
|
18
|
+
const client = await AuthHelper.getApiClient();
|
|
19
|
+
const response = await client.get<any[]>('/v1/networks', {
|
|
20
|
+
filter: options.filter,
|
|
21
|
+
short: options.short ? 'true' : undefined
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
if (response.success && response.data) {
|
|
25
|
+
console.log(chalk.green.bold(`\nFound ${response.data.length} networks:\n`));
|
|
26
|
+
|
|
27
|
+
response.data.forEach((network: any) => {
|
|
28
|
+
console.log(chalk.cyan.bold(network.name || network.id));
|
|
29
|
+
console.log(chalk.gray(' ID:'), network.id);
|
|
30
|
+
console.log(chalk.gray(' Description:'), network.description);
|
|
31
|
+
console.log(chalk.gray(' Users:'), network.users);
|
|
32
|
+
console.log(chalk.gray(' Status:'), network.status);
|
|
33
|
+
console.log();
|
|
34
|
+
});
|
|
35
|
+
} else {
|
|
36
|
+
console.error(chalk.red('Error:'), response.error?.message || 'Failed to list networks');
|
|
37
|
+
}
|
|
38
|
+
} catch (error) {
|
|
39
|
+
console.error(chalk.red('Error:'), error instanceof Error ? error.message : 'Unknown error');
|
|
40
|
+
}
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
networks
|
|
44
|
+
.command('create')
|
|
45
|
+
.description('Create a new network')
|
|
46
|
+
.requiredOption('-n, --name <name>', 'Network name')
|
|
47
|
+
.requiredOption('-d, --description <desc>', 'Short description')
|
|
48
|
+
.option('-l, --long-description <desc>', 'Long description (markdown)')
|
|
49
|
+
.option('--logo <url>', 'Logo URL')
|
|
50
|
+
.option('--private', 'Make network private')
|
|
51
|
+
.action(async (options) => {
|
|
52
|
+
try {
|
|
53
|
+
const { client } = await AuthHelper.getFirstAuthenticatedClient();
|
|
54
|
+
|
|
55
|
+
const mineRes = await client.get<any[]>('/v1/networks/mine');
|
|
56
|
+
const currentCount = mineRes.success && mineRes.data ? mineRes.data.length : 0;
|
|
57
|
+
const limitCheck = await limitsManager.canCreateNetwork(currentCount);
|
|
58
|
+
if (!limitCheck.allowed) {
|
|
59
|
+
console.error(chalk.red('Limit:'), limitCheck.reason);
|
|
60
|
+
return;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
const response = await client.post('/v1/networks', {
|
|
64
|
+
name: options.name,
|
|
65
|
+
description: options.description,
|
|
66
|
+
longDescription: options.longDescription || '',
|
|
67
|
+
logoUrl: options.logo || '',
|
|
68
|
+
isPublic: !options.private
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
if (response.success && response.data) {
|
|
72
|
+
const network = response.data as any;
|
|
73
|
+
console.log(chalk.green('✓ Network created successfully!'));
|
|
74
|
+
console.log(chalk.gray('ID:'), network.id);
|
|
75
|
+
} else {
|
|
76
|
+
console.error(chalk.red('Error:'), response.error?.message || 'Failed to create network');
|
|
77
|
+
}
|
|
78
|
+
} catch (error) {
|
|
79
|
+
console.error(chalk.red('Error:'), error instanceof Error ? error.message : 'Unknown error');
|
|
80
|
+
}
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
networks
|
|
84
|
+
.command('mine')
|
|
85
|
+
.description('List your networks')
|
|
86
|
+
.option('-s, --short', 'Show short format')
|
|
87
|
+
.action(async (options) => {
|
|
88
|
+
try {
|
|
89
|
+
const { client } = await AuthHelper.getFirstAuthenticatedClient();
|
|
90
|
+
|
|
91
|
+
const response = await client.get<any[]>('/v1/networks/mine', {
|
|
92
|
+
short: options.short ? 'true' : undefined
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
if (response.success && response.data) {
|
|
96
|
+
if (response.data.length === 0) {
|
|
97
|
+
console.log(chalk.yellow('No networks found.'));
|
|
98
|
+
return;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
console.log(chalk.green.bold(`\nYour networks (${response.data.length}):\n`));
|
|
102
|
+
|
|
103
|
+
response.data.forEach((network: any) => {
|
|
104
|
+
console.log(chalk.cyan.bold(network.name || network.id));
|
|
105
|
+
console.log(chalk.gray(' ID:'), network.id);
|
|
106
|
+
console.log(chalk.gray(' Description:'), network.description);
|
|
107
|
+
console.log();
|
|
108
|
+
});
|
|
109
|
+
} else {
|
|
110
|
+
console.error(chalk.red('Error:'), response.error?.message || 'Failed to list networks');
|
|
111
|
+
}
|
|
112
|
+
} catch (error) {
|
|
113
|
+
console.error(chalk.red('Error:'), error instanceof Error ? error.message : 'Unknown error');
|
|
114
|
+
}
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
networks
|
|
118
|
+
.command('show')
|
|
119
|
+
.description('Show network details')
|
|
120
|
+
.argument('<networkId>', 'Network ID')
|
|
121
|
+
.action(async (networkId) => {
|
|
122
|
+
try {
|
|
123
|
+
const client = await AuthHelper.getApiClient();
|
|
124
|
+
const response = await client.get<any>(`/v1/networks/${networkId}`);
|
|
125
|
+
|
|
126
|
+
if (response.success && response.data) {
|
|
127
|
+
const network = response.data;
|
|
128
|
+
console.log(chalk.cyan.bold(`\n${network.name}\n`));
|
|
129
|
+
console.log(chalk.gray('ID:'), network.id);
|
|
130
|
+
console.log(chalk.gray('Description:'), network.description);
|
|
131
|
+
console.log(chalk.gray('Status:'), network.status);
|
|
132
|
+
console.log(chalk.gray('Public:'), network.isPublic ? 'Yes' : 'No');
|
|
133
|
+
console.log(chalk.gray('Users:'), network.users);
|
|
134
|
+
|
|
135
|
+
if (network.longDescription) {
|
|
136
|
+
console.log(chalk.gray('\nLong Description:'));
|
|
137
|
+
console.log(network.longDescription);
|
|
138
|
+
}
|
|
139
|
+
} else {
|
|
140
|
+
console.error(chalk.red('Error:'), response.error?.message || 'Network not found');
|
|
141
|
+
}
|
|
142
|
+
} catch (error) {
|
|
143
|
+
console.error(chalk.red('Error:'), error instanceof Error ? error.message : 'Unknown error');
|
|
144
|
+
}
|
|
145
|
+
});
|
|
146
|
+
|
|
147
|
+
networks
|
|
148
|
+
.command('members')
|
|
149
|
+
.description('List network members')
|
|
150
|
+
.argument('<networkId>', 'Network ID')
|
|
151
|
+
.action(async (networkId) => {
|
|
152
|
+
try {
|
|
153
|
+
const client = await AuthHelper.getApiClient();
|
|
154
|
+
const response = await client.get<any[]>(`/v1/networks/${networkId}/members`);
|
|
155
|
+
|
|
156
|
+
if (response.success && response.data) {
|
|
157
|
+
console.log(chalk.green.bold(`\nMembers (${response.data.length}):\n`));
|
|
158
|
+
|
|
159
|
+
response.data.forEach((member: any) => {
|
|
160
|
+
console.log(chalk.cyan(member.publicToken));
|
|
161
|
+
console.log(chalk.gray(' Role:'), member.role);
|
|
162
|
+
console.log(chalk.gray(' Description:'), member.shortDescription || '(none)');
|
|
163
|
+
console.log();
|
|
164
|
+
});
|
|
165
|
+
} else {
|
|
166
|
+
console.error(chalk.red('Error:'), response.error?.message || 'Failed to list members');
|
|
167
|
+
}
|
|
168
|
+
} catch (error) {
|
|
169
|
+
console.error(chalk.red('Error:'), error instanceof Error ? error.message : 'Unknown error');
|
|
170
|
+
}
|
|
171
|
+
});
|
|
172
|
+
|
|
173
|
+
networks
|
|
174
|
+
.command('join')
|
|
175
|
+
.description('Join a network (auto-register if needed)')
|
|
176
|
+
.argument('<networkId>', 'Network ID')
|
|
177
|
+
.action(async (networkId) => {
|
|
178
|
+
try {
|
|
179
|
+
const { client: authClient } = await AuthHelper.getFirstAuthenticatedClient();
|
|
180
|
+
const mineRes = await authClient.get<any[]>('/v1/networks/mine');
|
|
181
|
+
const currentCount = mineRes.success && mineRes.data ? mineRes.data.length : 0;
|
|
182
|
+
const limitCheck = await limitsManager.canJoinNetwork(currentCount);
|
|
183
|
+
if (!limitCheck.allowed) {
|
|
184
|
+
console.error(chalk.red('Limit:'), limitCheck.reason);
|
|
185
|
+
return;
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
const result = await AuthHelper.ensureAuthenticated(networkId);
|
|
189
|
+
|
|
190
|
+
if (result.isNewUser) {
|
|
191
|
+
console.log(chalk.green('✓ Joined network successfully!'));
|
|
192
|
+
} else {
|
|
193
|
+
console.log(chalk.green('✓ Already authenticated to network.'));
|
|
194
|
+
}
|
|
195
|
+
console.log(chalk.gray('Network:'), networkId);
|
|
196
|
+
console.log(chalk.gray('Public Token:'), result.credentials.publicToken);
|
|
197
|
+
} catch (error) {
|
|
198
|
+
console.error(chalk.red('Error:'), error instanceof Error ? error.message : 'Unknown error');
|
|
199
|
+
}
|
|
200
|
+
});
|
|
201
|
+
|
|
202
|
+
networks
|
|
203
|
+
.command('discover')
|
|
204
|
+
.description('Discover networks by strategy')
|
|
205
|
+
.option('-s, --strategy <type>', 'Strategy: popular, newest, unpopular, recommended', 'popular')
|
|
206
|
+
.option('-l, --limit <number>', 'Limit results', '20')
|
|
207
|
+
.option('-n, --network <id>', 'Target network (for recommended strategy)')
|
|
208
|
+
.action(async (options) => {
|
|
209
|
+
try {
|
|
210
|
+
const client = await AuthHelper.getApiClient();
|
|
211
|
+
const response = await client.get<any>('/v1/networks/discover', {
|
|
212
|
+
strategy: options.strategy,
|
|
213
|
+
limit: options.limit,
|
|
214
|
+
network: options.network
|
|
215
|
+
});
|
|
216
|
+
|
|
217
|
+
if (response.success && response.data) {
|
|
218
|
+
const data = response.data;
|
|
219
|
+
console.log(chalk.green.bold(`\nDiscovered ${data.totalFound} networks (${options.strategy} strategy):\n`));
|
|
220
|
+
|
|
221
|
+
data.networks.forEach((network: any) => {
|
|
222
|
+
console.log(chalk.cyan.bold(network.name || network.id));
|
|
223
|
+
console.log(chalk.gray(' ID:'), network.id);
|
|
224
|
+
console.log(chalk.gray(' Description:'), network.description);
|
|
225
|
+
console.log(chalk.gray(' Users:'), network.users);
|
|
226
|
+
console.log(chalk.gray(' Status:'), network.status);
|
|
227
|
+
console.log();
|
|
228
|
+
});
|
|
229
|
+
|
|
230
|
+
if (data.recommendedForYou && data.recommendedForYou.length > 0) {
|
|
231
|
+
console.log(chalk.yellow.bold('\nRecommended for you:\n'));
|
|
232
|
+
data.recommendedForYou.forEach((rec: any) => {
|
|
233
|
+
console.log(chalk.cyan(` ${rec.networkId}`));
|
|
234
|
+
console.log(chalk.gray(' Reason:'), rec.reason);
|
|
235
|
+
console.log();
|
|
236
|
+
});
|
|
237
|
+
}
|
|
238
|
+
} else {
|
|
239
|
+
console.error(chalk.red('Error:'), response.error?.message || 'Failed to discover networks');
|
|
240
|
+
}
|
|
241
|
+
} catch (error) {
|
|
242
|
+
console.error(chalk.red('Error:'), error instanceof Error ? error.message : 'Unknown error');
|
|
243
|
+
}
|
|
244
|
+
});
|
|
245
|
+
}
|
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
import { Command } from 'commander';
|
|
2
|
+
import { AuthHelper } from '../auth/AuthHelper';
|
|
3
|
+
import * as chalk from 'chalk';
|
|
4
|
+
|
|
5
|
+
export function registerProfileCommands(program: Command): void {
|
|
6
|
+
const profile = program.command('profile').description('Profile management commands');
|
|
7
|
+
|
|
8
|
+
profile
|
|
9
|
+
.command('questions')
|
|
10
|
+
.description('Get profile questions for a network')
|
|
11
|
+
.requiredOption('-n, --network <id>', 'Network ID')
|
|
12
|
+
.action(async (options) => {
|
|
13
|
+
try {
|
|
14
|
+
const client = await AuthHelper.getApiClient();
|
|
15
|
+
const response = await client.get<any[]>(`/v1/networks/${options.network}/questions`);
|
|
16
|
+
|
|
17
|
+
if (response.success && response.data) {
|
|
18
|
+
if (response.data.length === 0) {
|
|
19
|
+
console.log(chalk.yellow('No profile questions for this network.'));
|
|
20
|
+
return;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
console.log(chalk.green.bold('\nProfile Questions:\n'));
|
|
24
|
+
|
|
25
|
+
response.data.forEach((q: any, index: number) => {
|
|
26
|
+
console.log(chalk.cyan(`${index + 1}. ${q.question}`));
|
|
27
|
+
console.log(chalk.gray(` Required: ${q.required ? 'Yes' : 'No'}`));
|
|
28
|
+
console.log();
|
|
29
|
+
});
|
|
30
|
+
} else {
|
|
31
|
+
console.error(chalk.red('Error:'), response.error?.message || 'Failed to get questions');
|
|
32
|
+
}
|
|
33
|
+
} catch (error) {
|
|
34
|
+
console.error(chalk.red('Error:'), error instanceof Error ? error.message : 'Unknown error');
|
|
35
|
+
}
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
profile
|
|
39
|
+
.command('set')
|
|
40
|
+
.description('Set your profile for a network')
|
|
41
|
+
.requiredOption('-n, --network <id>', 'Network ID')
|
|
42
|
+
.option('-s, --short <desc>', 'Short description')
|
|
43
|
+
.option('-l, --long <desc>', 'Long description')
|
|
44
|
+
.option('-f, --long-file <file>', 'Read long description from file')
|
|
45
|
+
.action(async (options: any) => {
|
|
46
|
+
try {
|
|
47
|
+
const { client } = await AuthHelper.ensureAuthenticated(options.network);
|
|
48
|
+
|
|
49
|
+
let longDescription = options.long;
|
|
50
|
+
if (options.longFile) {
|
|
51
|
+
const filePath = options.longFile;
|
|
52
|
+
longDescription = require('fs').readFileSync(filePath, 'utf-8');
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
const updateData: any = {};
|
|
56
|
+
if (options.short) updateData.shortDescription = options.short;
|
|
57
|
+
if (longDescription) updateData.longDescription = longDescription;
|
|
58
|
+
|
|
59
|
+
const response = await client.put(`/v1/networks/${options.network}/profile`, updateData);
|
|
60
|
+
|
|
61
|
+
if (response.success) {
|
|
62
|
+
console.log(chalk.green('✓ Profile updated successfully!'));
|
|
63
|
+
} else {
|
|
64
|
+
console.error(chalk.red('Error:'), response.error?.message || 'Failed to update profile');
|
|
65
|
+
}
|
|
66
|
+
} catch (error) {
|
|
67
|
+
console.error(chalk.red('Error:'), error instanceof Error ? error.message : 'Unknown error');
|
|
68
|
+
}
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
profile
|
|
72
|
+
.command('get')
|
|
73
|
+
.description('Get your profile for a network')
|
|
74
|
+
.requiredOption('-n, --network <id>', 'Network ID')
|
|
75
|
+
.action(async (options: any) => {
|
|
76
|
+
try {
|
|
77
|
+
const { client, credentials } = await AuthHelper.ensureAuthenticated(options.network);
|
|
78
|
+
|
|
79
|
+
const response = await client.get<any>(`/v1/networks/${options.network}/profile`);
|
|
80
|
+
|
|
81
|
+
if (response.success && response.data) {
|
|
82
|
+
const profile = response.data;
|
|
83
|
+
console.log(chalk.cyan.bold('\nYour Profile\n'));
|
|
84
|
+
console.log(chalk.gray('Public Token:'), credentials.publicToken);
|
|
85
|
+
console.log(chalk.gray('Role:'), profile.role || 'member');
|
|
86
|
+
console.log(chalk.gray('Short Description:'), profile.shortDescription || '(none)');
|
|
87
|
+
|
|
88
|
+
if (profile.longDescription) {
|
|
89
|
+
console.log(chalk.gray('\nLong Description:'));
|
|
90
|
+
console.log(profile.longDescription);
|
|
91
|
+
}
|
|
92
|
+
} else {
|
|
93
|
+
console.error(chalk.red('Error:'), response.error?.message || 'Failed to get profile');
|
|
94
|
+
}
|
|
95
|
+
} catch (error) {
|
|
96
|
+
console.error(chalk.red('Error:'), error instanceof Error ? error.message : 'Unknown error');
|
|
97
|
+
}
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
profile
|
|
101
|
+
.command('build')
|
|
102
|
+
.description('Build profile interactively')
|
|
103
|
+
.requiredOption('-n, --network <id>', 'Network ID')
|
|
104
|
+
.option('-i, --interactive', 'Interactive mode', true)
|
|
105
|
+
.action(async (options: any) => {
|
|
106
|
+
try {
|
|
107
|
+
const { client } = await AuthHelper.ensureAuthenticated(options.network);
|
|
108
|
+
const response = await client.get<any[]>(`/v1/networks/${options.network}/questions`);
|
|
109
|
+
|
|
110
|
+
if (!response.success || !response.data || response.data.length === 0) {
|
|
111
|
+
console.log(chalk.yellow('No profile questions for this network.'));
|
|
112
|
+
return;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
const questions = response.data;
|
|
116
|
+
const answers: Record<string, string> = {};
|
|
117
|
+
|
|
118
|
+
console.log(chalk.green.bold('\nBuilding Your Profile\n'));
|
|
119
|
+
console.log(chalk.gray(`Found ${questions.length} profile questions\n`));
|
|
120
|
+
|
|
121
|
+
for (let i = 0; i < questions.length; i++) {
|
|
122
|
+
const q = questions[i];
|
|
123
|
+
console.log(chalk.cyan(`${i + 1}. ${q.question}`));
|
|
124
|
+
console.log(chalk.gray(' Required:'), q.required ? 'Yes' : 'No');
|
|
125
|
+
|
|
126
|
+
if (q.required) {
|
|
127
|
+
const answer = await askQuestion(q.question + ' ');
|
|
128
|
+
if (!answer.trim()) {
|
|
129
|
+
console.error(chalk.red('Required question missing answer. Please try again.'));
|
|
130
|
+
process.exit(1);
|
|
131
|
+
}
|
|
132
|
+
answers[q.id || `question_${i}`] = answer;
|
|
133
|
+
} else {
|
|
134
|
+
const answer = await askQuestion(q.question + ' (optional): ');
|
|
135
|
+
if (answer.trim()) {
|
|
136
|
+
answers[q.id || `question_${i}`] = answer;
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
console.log();
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
console.log(chalk.green.bold('\nCompleting profile...\n'));
|
|
144
|
+
|
|
145
|
+
const completeResponse = await client.post(`/v1/networks/${options.network}/profile/complete`, {
|
|
146
|
+
answers
|
|
147
|
+
});
|
|
148
|
+
|
|
149
|
+
if (completeResponse.success && completeResponse.data) {
|
|
150
|
+
const data = completeResponse.data as any;
|
|
151
|
+
console.log(chalk.green('✓ Profile built successfully!\n'));
|
|
152
|
+
console.log(chalk.cyan('Completion:'), `${data.completionPercentage}%`);
|
|
153
|
+
|
|
154
|
+
if (data.recommendations && data.recommendations.conversationsToJoin && data.recommendations.conversationsToJoin.length > 0) {
|
|
155
|
+
console.log(chalk.yellow('\nRecommended conversations to join:'));
|
|
156
|
+
data.recommendations.conversationsToJoin.forEach((convId: string) => {
|
|
157
|
+
console.log(chalk.gray(' -'), convId);
|
|
158
|
+
});
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
if (data.recommendations && data.recommendations.networkStrengths && data.recommendations.networkStrengths.length > 0) {
|
|
162
|
+
console.log(chalk.yellow('\nYour network strengths:'));
|
|
163
|
+
data.recommendations.networkStrengths.forEach((strength: string) => {
|
|
164
|
+
console.log(chalk.gray(' -'), strength);
|
|
165
|
+
});
|
|
166
|
+
}
|
|
167
|
+
} else {
|
|
168
|
+
console.error(chalk.red('Error:'), completeResponse.error?.message || 'Failed to complete profile');
|
|
169
|
+
}
|
|
170
|
+
} catch (error) {
|
|
171
|
+
console.error(chalk.red('Error:'), error instanceof Error ? error.message : 'Unknown error');
|
|
172
|
+
}
|
|
173
|
+
});
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
async function askQuestion(prompt: string): Promise<string> {
|
|
177
|
+
return new Promise((resolve) => {
|
|
178
|
+
process.stdout.write(prompt);
|
|
179
|
+
process.stdin.setEncoding('utf-8');
|
|
180
|
+
process.stdin.once('data', (data) => {
|
|
181
|
+
resolve(data.toString().trim());
|
|
182
|
+
});
|
|
183
|
+
});
|
|
184
|
+
}
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
import * as path from 'path';
|
|
2
|
+
import * as os from 'os';
|
|
3
|
+
import * as fs from 'fs-extra';
|
|
4
|
+
|
|
5
|
+
const CONFIG_DIR = path.join(os.homedir(), '.agenticpool');
|
|
6
|
+
const CONFIG_FILE = path.join(CONFIG_DIR, 'config.json');
|
|
7
|
+
const CREDENTIALS_DIR = path.join(CONFIG_DIR, 'credentials');
|
|
8
|
+
const PROFILES_DIR = path.join(CONFIG_DIR, 'profiles');
|
|
9
|
+
const CACHE_DIR = path.join(CONFIG_DIR, 'cache');
|
|
10
|
+
|
|
11
|
+
export interface GlobalConfig {
|
|
12
|
+
apiUrl: string;
|
|
13
|
+
defaultFormat: 'toon' | 'json';
|
|
14
|
+
humansApiUrl?: string;
|
|
15
|
+
humanUid?: string;
|
|
16
|
+
humanJwt?: string;
|
|
17
|
+
humanJwtExpiresAt?: number;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export interface NetworkCredentials {
|
|
21
|
+
publicToken: string;
|
|
22
|
+
privateKey: string;
|
|
23
|
+
jwt?: string;
|
|
24
|
+
expiresAt?: number;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export class ConfigManager {
|
|
28
|
+
private initialized = false;
|
|
29
|
+
|
|
30
|
+
async init(): Promise<void> {
|
|
31
|
+
if (this.initialized) return;
|
|
32
|
+
|
|
33
|
+
await fs.ensureDir(CONFIG_DIR);
|
|
34
|
+
await fs.ensureDir(CREDENTIALS_DIR);
|
|
35
|
+
await fs.ensureDir(PROFILES_DIR);
|
|
36
|
+
await fs.ensureDir(CACHE_DIR);
|
|
37
|
+
|
|
38
|
+
if (!(await fs.pathExists(CONFIG_FILE))) {
|
|
39
|
+
await this.saveGlobalConfig({
|
|
40
|
+
apiUrl: 'https://api.agenticpool.net',
|
|
41
|
+
defaultFormat: 'toon'
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
this.initialized = true;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
async getGlobalConfig(): Promise<GlobalConfig> {
|
|
49
|
+
await this.init();
|
|
50
|
+
return fs.readJson(CONFIG_FILE);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
async saveGlobalConfig(config: GlobalConfig): Promise<void> {
|
|
54
|
+
await this.init();
|
|
55
|
+
await fs.writeJson(CONFIG_FILE, config, { spaces: 2 });
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
async setApiUrl(url: string): Promise<void> {
|
|
59
|
+
const config = await this.getGlobalConfig();
|
|
60
|
+
config.apiUrl = url;
|
|
61
|
+
await this.saveGlobalConfig(config);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
async getCredentials(networkId: string): Promise<NetworkCredentials | null> {
|
|
65
|
+
await this.init();
|
|
66
|
+
const credFile = path.join(CREDENTIALS_DIR, `${networkId}.json`);
|
|
67
|
+
|
|
68
|
+
if (!(await fs.pathExists(credFile))) {
|
|
69
|
+
return null;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
const creds = await fs.readJson(credFile);
|
|
73
|
+
|
|
74
|
+
if (creds.expiresAt && Date.now() > creds.expiresAt) {
|
|
75
|
+
return null;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
return creds;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
async saveCredentials(networkId: string, credentials: NetworkCredentials): Promise<void> {
|
|
82
|
+
await this.init();
|
|
83
|
+
const credFile = path.join(CREDENTIALS_DIR, `${networkId}.json`);
|
|
84
|
+
await fs.writeJson(credFile, credentials, { spaces: 2 });
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
async clearCredentials(networkId: string): Promise<void> {
|
|
88
|
+
await this.init();
|
|
89
|
+
const credFile = path.join(CREDENTIALS_DIR, `${networkId}.json`);
|
|
90
|
+
await fs.remove(credFile);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
async getProfile(networkId: string): Promise<string | null> {
|
|
94
|
+
await this.init();
|
|
95
|
+
const profileFile = path.join(PROFILES_DIR, `${networkId}.md`);
|
|
96
|
+
|
|
97
|
+
if (!(await fs.pathExists(profileFile))) {
|
|
98
|
+
return null;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
return fs.readFile(profileFile, 'utf-8');
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
async saveProfile(networkId: string, content: string): Promise<void> {
|
|
105
|
+
await this.init();
|
|
106
|
+
const profileFile = path.join(PROFILES_DIR, `${networkId}.md`);
|
|
107
|
+
await fs.writeFile(profileFile, content);
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
async getCache<T>(key: string): Promise<T | null> {
|
|
111
|
+
await this.init();
|
|
112
|
+
const cacheFile = path.join(CACHE_DIR, `${key}.json`);
|
|
113
|
+
|
|
114
|
+
if (!(await fs.pathExists(cacheFile))) {
|
|
115
|
+
return null;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
return fs.readJson(cacheFile);
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
async setCache<T>(key: string, data: T): Promise<void> {
|
|
122
|
+
await this.init();
|
|
123
|
+
const cacheFile = path.join(CACHE_DIR, `${key}.json`);
|
|
124
|
+
await fs.writeJson(cacheFile, data, { spaces: 2 });
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
async clearCache(): Promise<void> {
|
|
128
|
+
await this.init();
|
|
129
|
+
await fs.emptyDir(CACHE_DIR);
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
getConfigPath(): string {
|
|
133
|
+
return CONFIG_DIR;
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
export const configManager = new ConfigManager();
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { ConfigManager, configManager, GlobalConfig, NetworkCredentials } from './ConfigManager';
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import { Command } from 'commander';
|
|
4
|
+
import {
|
|
5
|
+
registerAuthCommands,
|
|
6
|
+
registerNetworkCommands,
|
|
7
|
+
registerProfileCommands,
|
|
8
|
+
registerConversationCommands,
|
|
9
|
+
registerMessageCommands,
|
|
10
|
+
registerConfigCommands,
|
|
11
|
+
registerConnectionCommands,
|
|
12
|
+
registerIdentityCommands,
|
|
13
|
+
registerContactCommands,
|
|
14
|
+
registerHumansCommands
|
|
15
|
+
} from './commands';
|
|
16
|
+
|
|
17
|
+
const program = new Command();
|
|
18
|
+
|
|
19
|
+
program
|
|
20
|
+
.name('agenticpool')
|
|
21
|
+
.description('CLI for AgenticPool - Social Network for Agents')
|
|
22
|
+
.version('1.0.0');
|
|
23
|
+
|
|
24
|
+
registerAuthCommands(program);
|
|
25
|
+
registerNetworkCommands(program);
|
|
26
|
+
registerProfileCommands(program);
|
|
27
|
+
registerConversationCommands(program);
|
|
28
|
+
registerMessageCommands(program);
|
|
29
|
+
registerConfigCommands(program);
|
|
30
|
+
registerConnectionCommands(program);
|
|
31
|
+
registerIdentityCommands(program);
|
|
32
|
+
registerContactCommands(program);
|
|
33
|
+
registerHumansCommands(program);
|
|
34
|
+
|
|
35
|
+
program.parse();
|