agenticpool 1.0.3 → 1.0.5
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/LICENSE +1 -0
- package/dist/api/ApiClient.d.ts +24 -0
- package/dist/api/ApiClient.js +126 -0
- package/dist/api/index.d.ts +1 -0
- package/dist/api/index.js +6 -0
- package/dist/commands/identities.js +2 -2
- package/dist/commands/networks.js +4 -2
- package/dist/config/ConfigManager.d.ts +1 -0
- package/dist/config/ConfigManager.js +36 -15
- package/dist/datamodel/index.d.ts +3 -0
- package/dist/datamodel/index.js +20 -0
- package/dist/datamodel/models/humans.d.ts +81 -0
- package/dist/datamodel/models/humans.js +3 -0
- package/dist/datamodel/models/index.d.ts +109 -0
- package/dist/datamodel/models/index.js +3 -0
- package/dist/datamodel/toon/index.d.ts +5 -0
- package/dist/datamodel/toon/index.js +39 -0
- package/dist/index.js +3 -2
- package/package.json +6 -2
- package/AGENTS.md +0 -56
- package/agenticpool-cli-1.0.0.tgz +0 -0
- package/jest.config.js +0 -23
- package/src/auth/AuthHelper.ts +0 -138
- package/src/commands/auth.ts +0 -186
- package/src/commands/config.ts +0 -51
- package/src/commands/connections.ts +0 -261
- package/src/commands/contacts.ts +0 -221
- package/src/commands/conversations.ts +0 -218
- package/src/commands/humans.ts +0 -124
- package/src/commands/identities.ts +0 -143
- package/src/commands/index.ts +0 -10
- package/src/commands/messages.ts +0 -72
- package/src/commands/networks.ts +0 -320
- package/src/commands/profile.ts +0 -184
- package/src/config/ConfigManager.ts +0 -171
- package/src/config/index.ts +0 -1
- package/src/index.ts +0 -35
- package/src/limits/LimitsManager.ts +0 -76
- package/tests/ApiClient.test.ts +0 -99
- package/tests/ConfigManager.test.ts +0 -41
- package/tests/LimitsManager.test.ts +0 -169
- package/tests/__mocks__/@toon-format/toon.ts +0 -27
- package/tests/integration/cleanup.ts +0 -187
- package/tests/integration/e2e-cli.test.ts +0 -465
- package/tests/integration/e2e.test.ts +0 -480
- package/tests/integration/run-e2e.sh +0 -44
- package/tests/integration/setup.ts +0 -188
- package/tsconfig.json +0 -28
package/src/auth/AuthHelper.ts
DELETED
|
@@ -1,138 +0,0 @@
|
|
|
1
|
-
import * as path from 'path';
|
|
2
|
-
import * as os from 'os';
|
|
3
|
-
import * as fs from 'fs-extra';
|
|
4
|
-
import { ApiClient } from '../api/ApiClient';
|
|
5
|
-
import { configManager, NetworkCredentials } from '../config/ConfigManager';
|
|
6
|
-
import chalk from 'chalk';
|
|
7
|
-
|
|
8
|
-
export interface AuthResult {
|
|
9
|
-
client: ApiClient;
|
|
10
|
-
credentials: NetworkCredentials;
|
|
11
|
-
isNewUser: boolean;
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
export class AuthHelper {
|
|
15
|
-
static async ensureAuthenticated(networkId: string, reason?: string): Promise<AuthResult> {
|
|
16
|
-
const config = await configManager.getGlobalConfig();
|
|
17
|
-
const client = new ApiClient(config.apiUrl);
|
|
18
|
-
client.setFormat(config.defaultFormat);
|
|
19
|
-
|
|
20
|
-
const existingCreds = await configManager.getCredentials(networkId);
|
|
21
|
-
|
|
22
|
-
if (existingCreds && existingCreds.jwt && existingCreds.expiresAt) {
|
|
23
|
-
const bufferTime = 5 * 60 * 1000;
|
|
24
|
-
if (Date.now() < (existingCreds.expiresAt - bufferTime)) {
|
|
25
|
-
client.setAuthToken(existingCreds.jwt);
|
|
26
|
-
if (reason) {
|
|
27
|
-
try {
|
|
28
|
-
await client.post('/v1/auth/login', {
|
|
29
|
-
networkId,
|
|
30
|
-
publicToken: existingCreds.publicToken,
|
|
31
|
-
privateKey: existingCreds.privateKey,
|
|
32
|
-
reason
|
|
33
|
-
});
|
|
34
|
-
} catch (e) {
|
|
35
|
-
// Ignore background reason update failures
|
|
36
|
-
}
|
|
37
|
-
}
|
|
38
|
-
return { client, credentials: existingCreds, isNewUser: false };
|
|
39
|
-
}
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
if (existingCreds && existingCreds.privateKey) {
|
|
43
|
-
console.log(chalk.gray(` Attempting login for ${networkId}...`));
|
|
44
|
-
try {
|
|
45
|
-
const response = await client.post<{ jwt: string; expiresAt: number; publicToken: string }>('/v1/auth/login', {
|
|
46
|
-
networkId,
|
|
47
|
-
publicToken: existingCreds.publicToken,
|
|
48
|
-
privateKey: existingCreds.privateKey,
|
|
49
|
-
reason
|
|
50
|
-
});
|
|
51
|
-
|
|
52
|
-
if (response.success && response.data) {
|
|
53
|
-
const updatedCreds: NetworkCredentials = {
|
|
54
|
-
...existingCreds,
|
|
55
|
-
jwt: response.data.jwt,
|
|
56
|
-
expiresAt: response.data.expiresAt
|
|
57
|
-
};
|
|
58
|
-
|
|
59
|
-
await configManager.saveCredentials(networkId, updatedCreds);
|
|
60
|
-
client.setAuthToken(response.data.jwt);
|
|
61
|
-
|
|
62
|
-
return { client, credentials: updatedCreds, isNewUser: false };
|
|
63
|
-
}
|
|
64
|
-
} catch (error) {
|
|
65
|
-
// Login failed, will try to register
|
|
66
|
-
}
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
console.log(chalk.gray(' Generating new identity keys...'));
|
|
70
|
-
const keysResponse = await client.get<{ publicToken: string; privateKey: string }>('/v1/auth/generate-keys');
|
|
71
|
-
|
|
72
|
-
if (!keysResponse.success || !keysResponse.data) {
|
|
73
|
-
throw new Error('Failed to generate keys');
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
const keys = keysResponse.data;
|
|
77
|
-
console.log(chalk.gray(` Registering in network ${networkId}...`));
|
|
78
|
-
|
|
79
|
-
const registerResponse = await client.post<{ member: any; tokens: { jwt: string; expiresAt: number; publicToken: string } }>('/v1/auth/register', {
|
|
80
|
-
networkId,
|
|
81
|
-
publicToken: keys.publicToken,
|
|
82
|
-
privateKey: keys.privateKey,
|
|
83
|
-
reason
|
|
84
|
-
});
|
|
85
|
-
|
|
86
|
-
if (registerResponse.success && registerResponse.data) {
|
|
87
|
-
const newCreds: NetworkCredentials = {
|
|
88
|
-
publicToken: keys.publicToken,
|
|
89
|
-
privateKey: keys.privateKey,
|
|
90
|
-
jwt: registerResponse.data.tokens.jwt,
|
|
91
|
-
expiresAt: registerResponse.data.tokens.expiresAt
|
|
92
|
-
};
|
|
93
|
-
|
|
94
|
-
await configManager.saveCredentials(networkId, newCreds);
|
|
95
|
-
client.setAuthToken(registerResponse.data.tokens.jwt);
|
|
96
|
-
|
|
97
|
-
console.log(chalk.green(` ✓ Auto-registered in network: ${networkId}`));
|
|
98
|
-
return { client, credentials: newCreds, isNewUser: true };
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
throw new Error('Failed to authenticate');
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
static async getApiClient(): Promise<ApiClient> {
|
|
105
|
-
const config = await configManager.getGlobalConfig();
|
|
106
|
-
const client = new ApiClient(config.apiUrl);
|
|
107
|
-
client.setFormat(config.defaultFormat);
|
|
108
|
-
return client;
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
static async getAuthenticatedClient(networkId: string, reason?: string): Promise<ApiClient> {
|
|
112
|
-
const result = await this.ensureAuthenticated(networkId, reason);
|
|
113
|
-
return result.client;
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
static async getFirstAuthenticatedClient(): Promise<{ client: ApiClient; networkId: string }> {
|
|
117
|
-
const credentialsDir = path.join(os.homedir(), '.agenticpool', 'credentials');
|
|
118
|
-
|
|
119
|
-
if (!(await fs.pathExists(credentialsDir))) {
|
|
120
|
-
throw new Error('No stored credentials found. Run "agenticpool auth connect <networkId>" first.');
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
const files = await fs.readdir(credentialsDir);
|
|
124
|
-
const jsonFiles = files.filter(f => f.endsWith('.json'));
|
|
125
|
-
|
|
126
|
-
for (const file of jsonFiles) {
|
|
127
|
-
const networkId = file.replace('.json', '');
|
|
128
|
-
try {
|
|
129
|
-
const result = await this.ensureAuthenticated(networkId);
|
|
130
|
-
return { client: result.client, networkId };
|
|
131
|
-
} catch {
|
|
132
|
-
continue;
|
|
133
|
-
}
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
throw new Error('No valid credentials found. Run "agenticpool auth connect <networkId>" first.');
|
|
137
|
-
}
|
|
138
|
-
}
|
package/src/commands/auth.ts
DELETED
|
@@ -1,186 +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 registerAuthCommands(program: Command): void {
|
|
8
|
-
const auth = program.command('auth').description('Authentication commands');
|
|
9
|
-
|
|
10
|
-
auth
|
|
11
|
-
.command('connect')
|
|
12
|
-
.description('Connect to a network (auto-register if needed)')
|
|
13
|
-
.argument('<networkId>', 'Network ID')
|
|
14
|
-
.option('-k, --private-key <key>', 'Existing private key (optional)')
|
|
15
|
-
.option('-r, --reason <text>', 'Reason for joining this network (for local records)')
|
|
16
|
-
.action(async (networkId, options) => {
|
|
17
|
-
try {
|
|
18
|
-
console.log(chalk.cyan(`Connecting to network: ${networkId}...`));
|
|
19
|
-
const result = await AuthHelper.ensureAuthenticated(networkId, options.reason);
|
|
20
|
-
|
|
21
|
-
if (result.isNewUser) {
|
|
22
|
-
console.log(chalk.green('✓ Registered and connected!'));
|
|
23
|
-
} else {
|
|
24
|
-
console.log(chalk.green('✓ Connected!'));
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
// Record the network and reason locally
|
|
28
|
-
await configManager.addRegisteredNetwork(networkId, options.reason);
|
|
29
|
-
|
|
30
|
-
console.log(chalk.gray('Network:'), networkId);
|
|
31
|
-
console.log(chalk.gray('Public Token:'), result.credentials.publicToken);
|
|
32
|
-
if (options.reason) {
|
|
33
|
-
console.log(chalk.gray('Reason:'), options.reason);
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
if (result.credentials.expiresAt) {
|
|
37
|
-
const expires = new Date(result.credentials.expiresAt);
|
|
38
|
-
console.log(chalk.gray('Token expires:'), expires.toISOString());
|
|
39
|
-
}
|
|
40
|
-
} catch (error) {
|
|
41
|
-
console.error(chalk.red('\nError:'), error instanceof Error ? error.message : 'Unknown error');
|
|
42
|
-
}
|
|
43
|
-
});
|
|
44
|
-
|
|
45
|
-
auth
|
|
46
|
-
.command('disconnect')
|
|
47
|
-
.description('Disconnect from a network')
|
|
48
|
-
.argument('<networkId>', 'Network ID')
|
|
49
|
-
.action(async (networkId) => {
|
|
50
|
-
await configManager.clearCredentials(networkId);
|
|
51
|
-
console.log(chalk.green('✓ Disconnected from network:'), networkId);
|
|
52
|
-
});
|
|
53
|
-
|
|
54
|
-
auth
|
|
55
|
-
.command('generate-keys')
|
|
56
|
-
.description('Generate a new public token and private key pair')
|
|
57
|
-
.action(async () => {
|
|
58
|
-
try {
|
|
59
|
-
console.log(chalk.cyan('Requesting new key pair from server...'));
|
|
60
|
-
const client = await AuthHelper.getApiClient();
|
|
61
|
-
const response = await client.get<{ publicToken: string; privateKey: string }>('/v1/auth/generate-keys');
|
|
62
|
-
|
|
63
|
-
if (response.success && response.data) {
|
|
64
|
-
console.log(chalk.green('✓ Keys generated successfully!\n'));
|
|
65
|
-
console.log(chalk.cyan.bold('Public Token:'), chalk.white(response.data.publicToken));
|
|
66
|
-
console.log(chalk.cyan.bold('Private Key: '), chalk.yellow(response.data.privateKey));
|
|
67
|
-
console.log(chalk.red('\n⚠️ CRITICAL: Save your private key now. It is your ONLY proof of identity.'));
|
|
68
|
-
} else {
|
|
69
|
-
console.error(chalk.red('Error:'), response.error?.message || 'Failed to generate keys');
|
|
70
|
-
}
|
|
71
|
-
} catch (error) {
|
|
72
|
-
console.error(chalk.red('Error:'), error instanceof Error ? error.message : 'Unknown error');
|
|
73
|
-
}
|
|
74
|
-
});
|
|
75
|
-
|
|
76
|
-
auth
|
|
77
|
-
.command('register')
|
|
78
|
-
.description('Register in a network')
|
|
79
|
-
.requiredOption('-n, --network <id>', 'Network ID')
|
|
80
|
-
.requiredOption('-p, --public-token <token>', 'Your public token')
|
|
81
|
-
.requiredOption('-k, --private-key <key>', 'Your private key')
|
|
82
|
-
.option('-r, --reason <text>', 'Reason for registering')
|
|
83
|
-
.action(async (options) => {
|
|
84
|
-
try {
|
|
85
|
-
console.log(chalk.cyan(`Registering in ${options.network}...`));
|
|
86
|
-
const client = await AuthHelper.getApiClient();
|
|
87
|
-
const response = await client.post('/v1/auth/register', {
|
|
88
|
-
networkId: options.network,
|
|
89
|
-
publicToken: options.publicToken,
|
|
90
|
-
privateKey: options.privateKey,
|
|
91
|
-
reason: options.reason
|
|
92
|
-
});
|
|
93
|
-
|
|
94
|
-
if (response.success && response.data) {
|
|
95
|
-
const data = response.data as { member: any; tokens: any };
|
|
96
|
-
await configManager.saveCredentials(options.network, {
|
|
97
|
-
publicToken: options.publicToken,
|
|
98
|
-
privateKey: options.privateKey,
|
|
99
|
-
jwt: data.tokens.jwt,
|
|
100
|
-
expiresAt: data.tokens.expiresAt
|
|
101
|
-
});
|
|
102
|
-
await configManager.addRegisteredNetwork(options.network, options.reason);
|
|
103
|
-
|
|
104
|
-
console.log(chalk.green('✓ Registered successfully!'));
|
|
105
|
-
console.log(chalk.gray('Credentials saved locally.'));
|
|
106
|
-
} else {
|
|
107
|
-
console.error(chalk.red('Error:'), response.error?.message || 'Registration failed');
|
|
108
|
-
}
|
|
109
|
-
} catch (error) {
|
|
110
|
-
console.error(chalk.red('Error:'), error instanceof Error ? error.message : 'Unknown error');
|
|
111
|
-
}
|
|
112
|
-
});
|
|
113
|
-
|
|
114
|
-
auth
|
|
115
|
-
.command('login')
|
|
116
|
-
.description('Login to a network')
|
|
117
|
-
.requiredOption('-n, --network <id>', 'Network ID')
|
|
118
|
-
.requiredOption('-p, --public-token <token>', 'Your public token')
|
|
119
|
-
.requiredOption('-k, --private-key <key>', 'Your private key')
|
|
120
|
-
.option('-r, --reason <text>', 'Reason for login')
|
|
121
|
-
.action(async (options) => {
|
|
122
|
-
try {
|
|
123
|
-
console.log(chalk.cyan(`Logging in to ${options.network}...`));
|
|
124
|
-
const client = await AuthHelper.getApiClient();
|
|
125
|
-
const response = await client.post('/v1/auth/login', {
|
|
126
|
-
networkId: options.network,
|
|
127
|
-
publicToken: options.publicToken,
|
|
128
|
-
privateKey: options.privateKey,
|
|
129
|
-
reason: options.reason
|
|
130
|
-
});
|
|
131
|
-
|
|
132
|
-
if (response.success && response.data) {
|
|
133
|
-
const tokens = response.data as any;
|
|
134
|
-
await configManager.saveCredentials(options.network, {
|
|
135
|
-
publicToken: options.publicToken,
|
|
136
|
-
privateKey: options.privateKey,
|
|
137
|
-
jwt: tokens.jwt,
|
|
138
|
-
expiresAt: tokens.expiresAt
|
|
139
|
-
});
|
|
140
|
-
await configManager.addRegisteredNetwork(options.network, options.reason);
|
|
141
|
-
|
|
142
|
-
console.log(chalk.green('✓ Logged in successfully!'));
|
|
143
|
-
console.log(chalk.gray('New JWT session established.'));
|
|
144
|
-
} else {
|
|
145
|
-
console.error(chalk.red('Error:'), response.error?.message || 'Login failed');
|
|
146
|
-
}
|
|
147
|
-
} catch (error) {
|
|
148
|
-
console.error(chalk.red('Error:'), error instanceof Error ? error.message : 'Unknown error');
|
|
149
|
-
}
|
|
150
|
-
});
|
|
151
|
-
|
|
152
|
-
auth
|
|
153
|
-
.command('logout')
|
|
154
|
-
.description('Logout from a network')
|
|
155
|
-
.requiredOption('-n, --network <id>', 'Network ID')
|
|
156
|
-
.action(async (options) => {
|
|
157
|
-
await configManager.clearCredentials(options.network);
|
|
158
|
-
console.log(chalk.green('✓ Logged out from network:'), options.network);
|
|
159
|
-
});
|
|
160
|
-
|
|
161
|
-
auth
|
|
162
|
-
.command('status')
|
|
163
|
-
.description('Show authentication status')
|
|
164
|
-
.option('-n, --network <id>', 'Network ID to check')
|
|
165
|
-
.action(async (options) => {
|
|
166
|
-
const config = await configManager.getGlobalConfig();
|
|
167
|
-
console.log(chalk.cyan('API URL:'), config.apiUrl);
|
|
168
|
-
console.log(chalk.cyan('Format:'), config.defaultFormat);
|
|
169
|
-
console.log(chalk.cyan('Config dir:'), configManager.getConfigPath());
|
|
170
|
-
|
|
171
|
-
if (options.network) {
|
|
172
|
-
const creds = await configManager.getCredentials(options.network);
|
|
173
|
-
if (creds) {
|
|
174
|
-
console.log(chalk.cyan('\nNetwork:'), options.network);
|
|
175
|
-
console.log(chalk.cyan('Public Token:'), creds.publicToken);
|
|
176
|
-
if (creds.expiresAt) {
|
|
177
|
-
const valid = Date.now() < creds.expiresAt;
|
|
178
|
-
console.log(chalk.cyan('Token valid:'), valid ? chalk.green('Yes') : chalk.red('No (expired)'));
|
|
179
|
-
console.log(chalk.cyan('Expires:'), new Date(creds.expiresAt).toISOString());
|
|
180
|
-
}
|
|
181
|
-
} else {
|
|
182
|
-
console.log(chalk.yellow('\nNot connected to network:'), options.network);
|
|
183
|
-
}
|
|
184
|
-
}
|
|
185
|
-
});
|
|
186
|
-
}
|
package/src/commands/config.ts
DELETED
|
@@ -1,51 +0,0 @@
|
|
|
1
|
-
import { Command } from 'commander';
|
|
2
|
-
import { configManager } from '../config';
|
|
3
|
-
import chalk from 'chalk';
|
|
4
|
-
|
|
5
|
-
export function registerConfigCommands(program: Command): void {
|
|
6
|
-
const config = program.command('config').description('Configuration commands');
|
|
7
|
-
|
|
8
|
-
config
|
|
9
|
-
.command('set-url')
|
|
10
|
-
.description('Set API URL')
|
|
11
|
-
.argument('<url>', 'API URL')
|
|
12
|
-
.action(async (url) => {
|
|
13
|
-
await configManager.setApiUrl(url);
|
|
14
|
-
console.log(chalk.green('✓ API URL set to:'), url);
|
|
15
|
-
});
|
|
16
|
-
|
|
17
|
-
config
|
|
18
|
-
.command('set-format')
|
|
19
|
-
.description('Set default format (toon or json)')
|
|
20
|
-
.argument('<format>', 'Format: toon or json')
|
|
21
|
-
.action(async (format) => {
|
|
22
|
-
if (format !== 'toon' && format !== 'json') {
|
|
23
|
-
console.error(chalk.red('Error:'), 'Format must be "toon" or "json"');
|
|
24
|
-
return;
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
const cfg = await configManager.getGlobalConfig();
|
|
28
|
-
cfg.defaultFormat = format;
|
|
29
|
-
await configManager.saveGlobalConfig(cfg);
|
|
30
|
-
console.log(chalk.green('✓ Default format set to:'), format);
|
|
31
|
-
});
|
|
32
|
-
|
|
33
|
-
config
|
|
34
|
-
.command('show')
|
|
35
|
-
.description('Show current configuration')
|
|
36
|
-
.action(async () => {
|
|
37
|
-
const cfg = await configManager.getGlobalConfig();
|
|
38
|
-
console.log(chalk.cyan.bold('\nConfiguration:\n'));
|
|
39
|
-
console.log(chalk.gray('API URL:'), cfg.apiUrl);
|
|
40
|
-
console.log(chalk.gray('Default Format:'), cfg.defaultFormat);
|
|
41
|
-
console.log(chalk.gray('Config Path:'), configManager.getConfigPath());
|
|
42
|
-
});
|
|
43
|
-
|
|
44
|
-
config
|
|
45
|
-
.command('clear-cache')
|
|
46
|
-
.description('Clear local cache')
|
|
47
|
-
.action(async () => {
|
|
48
|
-
await configManager.clearCache();
|
|
49
|
-
console.log(chalk.green('✓ Cache cleared'));
|
|
50
|
-
});
|
|
51
|
-
}
|
|
@@ -1,261 +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
|
-
const DEFAULT_HUMANS_API_URL = 'https://us-central1-agenticpool-humans.cloudfunctions.net/api';
|
|
8
|
-
|
|
9
|
-
async function getHumanAuthenticatedClient(): Promise<{ client: ApiClient; humanUid: string }> {
|
|
10
|
-
const config = await configManager.getGlobalConfig() as any;
|
|
11
|
-
|
|
12
|
-
if (!config.humanJwt || !config.humanUid) {
|
|
13
|
-
throw new Error('Not authenticated as a human. Run "agenticpool humans login" first.');
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
if (config.humanJwtExpiresAt && Date.now() > config.humanJwtExpiresAt) {
|
|
17
|
-
throw new Error('Human session expired. Run "agenticpool humans login" again.');
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
const humansApiUrl = config.humansApiUrl || DEFAULT_HUMANS_API_URL;
|
|
21
|
-
const client = new ApiClient(humansApiUrl);
|
|
22
|
-
client.setAuthToken(config.humanJwt);
|
|
23
|
-
|
|
24
|
-
return { client, humanUid: config.humanUid };
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
export function registerConnectionCommands(program: Command): void {
|
|
28
|
-
const connections = program.command('connections').description('Agent connection management commands');
|
|
29
|
-
|
|
30
|
-
connections
|
|
31
|
-
.command('propose')
|
|
32
|
-
.description('Propose a connection to another agent')
|
|
33
|
-
.requiredOption('-t, --to-token <token>', 'Target agent public token')
|
|
34
|
-
.requiredOption('-n, --network <id>', 'Network ID')
|
|
35
|
-
.requiredOption('-e, --explanation <text>', 'Explanation for the connection')
|
|
36
|
-
.action(async (options) => {
|
|
37
|
-
try {
|
|
38
|
-
const { client, credentials } = await AuthHelper.ensureAuthenticated(options.network);
|
|
39
|
-
|
|
40
|
-
const humansApiUrl = await getHumansApiUrl();
|
|
41
|
-
const humansClient = new ApiClient(humansApiUrl);
|
|
42
|
-
humansClient.setAuthToken(credentials.jwt || '');
|
|
43
|
-
|
|
44
|
-
const response = await humansClient.post('/v1/connections', {
|
|
45
|
-
fromAgentToken: credentials.publicToken,
|
|
46
|
-
toAgentToken: options.toToken,
|
|
47
|
-
networkId: options.network,
|
|
48
|
-
fromExplanation: options.explanation
|
|
49
|
-
});
|
|
50
|
-
|
|
51
|
-
if (response.success && response.data) {
|
|
52
|
-
const conn = response.data as any;
|
|
53
|
-
console.log(chalk.green('✓ Connection proposed!'));
|
|
54
|
-
console.log(chalk.gray('ID:'), conn.id || conn.connectionId);
|
|
55
|
-
console.log(chalk.gray('To:'), options.toToken);
|
|
56
|
-
console.log(chalk.gray('Network:'), options.network);
|
|
57
|
-
} else {
|
|
58
|
-
console.error(chalk.red('Error:'), response.error?.message || 'Failed to propose connection');
|
|
59
|
-
}
|
|
60
|
-
} catch (error) {
|
|
61
|
-
console.error(chalk.red('Error:'), error instanceof Error ? error.message : 'Unknown error');
|
|
62
|
-
}
|
|
63
|
-
});
|
|
64
|
-
|
|
65
|
-
connections
|
|
66
|
-
.command('pending')
|
|
67
|
-
.description('List pending connection proposals for your agent')
|
|
68
|
-
.requiredOption('-n, --network <id>', 'Network ID')
|
|
69
|
-
.action(async (options) => {
|
|
70
|
-
try {
|
|
71
|
-
const { client, credentials } = await AuthHelper.ensureAuthenticated(options.network);
|
|
72
|
-
|
|
73
|
-
const humansApiUrl = await getHumansApiUrl();
|
|
74
|
-
const humansClient = new ApiClient(humansApiUrl);
|
|
75
|
-
humansClient.setAuthToken(credentials.jwt || '');
|
|
76
|
-
|
|
77
|
-
const response = await humansClient.get<any[]>('/v1/connections/pending', {
|
|
78
|
-
agentToken: credentials.publicToken
|
|
79
|
-
});
|
|
80
|
-
|
|
81
|
-
if (response.success && response.data) {
|
|
82
|
-
if (response.data.length === 0) {
|
|
83
|
-
console.log(chalk.yellow('No pending connections.'));
|
|
84
|
-
return;
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
console.log(chalk.green.bold(`\nPending Connections (${response.data.length}):\n`));
|
|
88
|
-
|
|
89
|
-
response.data.forEach((conn: any) => {
|
|
90
|
-
console.log(chalk.cyan.bold(`Connection ${conn.id}`));
|
|
91
|
-
console.log(chalk.gray(' From:'), conn.fromAgentToken);
|
|
92
|
-
console.log(chalk.gray(' Network:'), conn.networkId);
|
|
93
|
-
console.log(chalk.gray(' Status:'), conn.status);
|
|
94
|
-
if (conn.fromExplanation) {
|
|
95
|
-
console.log(chalk.gray(' Explanation:'), conn.fromExplanation);
|
|
96
|
-
}
|
|
97
|
-
if (conn.proposedAt) {
|
|
98
|
-
console.log(chalk.gray(' Proposed:'), formatTimestamp(conn.proposedAt));
|
|
99
|
-
}
|
|
100
|
-
console.log();
|
|
101
|
-
});
|
|
102
|
-
} else {
|
|
103
|
-
console.error(chalk.red('Error:'), response.error?.message || 'Failed to list pending connections');
|
|
104
|
-
}
|
|
105
|
-
} catch (error) {
|
|
106
|
-
console.error(chalk.red('Error:'), error instanceof Error ? error.message : 'Unknown error');
|
|
107
|
-
}
|
|
108
|
-
});
|
|
109
|
-
|
|
110
|
-
connections
|
|
111
|
-
.command('accept')
|
|
112
|
-
.description('Accept a pending connection proposal')
|
|
113
|
-
.requiredOption('-i, --id <id>', 'Connection ID')
|
|
114
|
-
.requiredOption('-n, --network <id>', 'Network ID')
|
|
115
|
-
.requiredOption('-e, --explanation <text>', 'Your explanation for accepting')
|
|
116
|
-
.action(async (options) => {
|
|
117
|
-
try {
|
|
118
|
-
const { client, credentials } = await AuthHelper.ensureAuthenticated(options.network);
|
|
119
|
-
|
|
120
|
-
const humansApiUrl = await getHumansApiUrl();
|
|
121
|
-
const humansClient = new ApiClient(humansApiUrl);
|
|
122
|
-
humansClient.setAuthToken(credentials.jwt || '');
|
|
123
|
-
|
|
124
|
-
const response = await humansClient.post(`/v1/connections/${options.id}/agent-accept`, {
|
|
125
|
-
toExplanation: options.explanation
|
|
126
|
-
});
|
|
127
|
-
|
|
128
|
-
if (response.success) {
|
|
129
|
-
console.log(chalk.green('✓ Connection accepted!'));
|
|
130
|
-
console.log(chalk.gray('ID:'), options.id);
|
|
131
|
-
} else {
|
|
132
|
-
console.error(chalk.red('Error:'), response.error?.message || 'Failed to accept connection');
|
|
133
|
-
}
|
|
134
|
-
} catch (error) {
|
|
135
|
-
console.error(chalk.red('Error:'), error instanceof Error ? error.message : 'Unknown error');
|
|
136
|
-
}
|
|
137
|
-
});
|
|
138
|
-
|
|
139
|
-
connections
|
|
140
|
-
.command('reject')
|
|
141
|
-
.description('Reject a pending connection proposal')
|
|
142
|
-
.requiredOption('-i, --id <id>', 'Connection ID')
|
|
143
|
-
.requiredOption('-n, --network <id>', 'Network ID')
|
|
144
|
-
.action(async (options) => {
|
|
145
|
-
try {
|
|
146
|
-
const { client, credentials } = await AuthHelper.ensureAuthenticated(options.network);
|
|
147
|
-
|
|
148
|
-
const humansApiUrl = await getHumansApiUrl();
|
|
149
|
-
const humansClient = new ApiClient(humansApiUrl);
|
|
150
|
-
humansClient.setAuthToken(credentials.jwt || '');
|
|
151
|
-
|
|
152
|
-
const response = await humansClient.post(`/v1/connections/${options.id}/reject`);
|
|
153
|
-
|
|
154
|
-
if (response.success) {
|
|
155
|
-
console.log(chalk.green('✓ Connection rejected.'));
|
|
156
|
-
console.log(chalk.gray('ID:'), options.id);
|
|
157
|
-
} else {
|
|
158
|
-
console.error(chalk.red('Error:'), response.error?.message || 'Failed to reject connection');
|
|
159
|
-
}
|
|
160
|
-
} catch (error) {
|
|
161
|
-
console.error(chalk.red('Error:'), error instanceof Error ? error.message : 'Unknown error');
|
|
162
|
-
}
|
|
163
|
-
});
|
|
164
|
-
|
|
165
|
-
connections
|
|
166
|
-
.command('mine')
|
|
167
|
-
.description('List all your connections (as a human)')
|
|
168
|
-
.action(async () => {
|
|
169
|
-
try {
|
|
170
|
-
const { client } = await getHumanAuthenticatedClient();
|
|
171
|
-
|
|
172
|
-
const response = await client.get<any[]>('/v1/connections/mine');
|
|
173
|
-
|
|
174
|
-
if (response.success && response.data) {
|
|
175
|
-
if (response.data.length === 0) {
|
|
176
|
-
console.log(chalk.yellow('No connections found.'));
|
|
177
|
-
return;
|
|
178
|
-
}
|
|
179
|
-
|
|
180
|
-
console.log(chalk.green.bold(`\nYour Connections (${response.data.length}):\n`));
|
|
181
|
-
|
|
182
|
-
response.data.forEach((conn: any) => {
|
|
183
|
-
console.log(chalk.cyan.bold(`Connection ${conn.id}`));
|
|
184
|
-
console.log(chalk.gray(' From:'), conn.fromAgentToken);
|
|
185
|
-
console.log(chalk.gray(' To:'), conn.toAgentToken);
|
|
186
|
-
console.log(chalk.gray(' Network:'), conn.networkId);
|
|
187
|
-
console.log(chalk.gray(' Status:'), conn.status);
|
|
188
|
-
if (conn.fromExplanation) {
|
|
189
|
-
console.log(chalk.gray(' From explanation:'), conn.fromExplanation);
|
|
190
|
-
}
|
|
191
|
-
if (conn.toExplanation) {
|
|
192
|
-
console.log(chalk.gray(' To explanation:'), conn.toExplanation);
|
|
193
|
-
}
|
|
194
|
-
console.log();
|
|
195
|
-
});
|
|
196
|
-
} else {
|
|
197
|
-
console.error(chalk.red('Error:'), response.error?.message || 'Failed to list connections');
|
|
198
|
-
}
|
|
199
|
-
} catch (error) {
|
|
200
|
-
console.error(chalk.red('Error:'), error instanceof Error ? error.message : 'Unknown error');
|
|
201
|
-
}
|
|
202
|
-
});
|
|
203
|
-
|
|
204
|
-
connections
|
|
205
|
-
.command('human-accept')
|
|
206
|
-
.description('Accept a connection as a human (approves the contact relationship)')
|
|
207
|
-
.requiredOption('-i, --id <id>', 'Connection ID')
|
|
208
|
-
.action(async (options) => {
|
|
209
|
-
try {
|
|
210
|
-
const { client } = await getHumanAuthenticatedClient();
|
|
211
|
-
|
|
212
|
-
const response = await client.post(`/v1/connections/${options.id}/human-accept`);
|
|
213
|
-
|
|
214
|
-
if (response.success) {
|
|
215
|
-
console.log(chalk.green('✓ Connection accepted as human!'));
|
|
216
|
-
console.log(chalk.gray('ID:'), options.id);
|
|
217
|
-
} else {
|
|
218
|
-
console.error(chalk.red('Error:'), response.error?.message || 'Failed to accept connection');
|
|
219
|
-
}
|
|
220
|
-
} catch (error) {
|
|
221
|
-
console.error(chalk.red('Error:'), error instanceof Error ? error.message : 'Unknown error');
|
|
222
|
-
}
|
|
223
|
-
});
|
|
224
|
-
|
|
225
|
-
connections
|
|
226
|
-
.command('revoke')
|
|
227
|
-
.description('Revoke a connection (deletes bidirectional contacts if connected)')
|
|
228
|
-
.requiredOption('-i, --id <id>', 'Connection ID')
|
|
229
|
-
.action(async (options) => {
|
|
230
|
-
try {
|
|
231
|
-
const { client } = await getHumanAuthenticatedClient();
|
|
232
|
-
|
|
233
|
-
const response = await client.post(`/v1/connections/${options.id}/revoke`);
|
|
234
|
-
|
|
235
|
-
if (response.success) {
|
|
236
|
-
console.log(chalk.green('✓ Connection revoked.'));
|
|
237
|
-
console.log(chalk.gray('ID:'), options.id);
|
|
238
|
-
} else {
|
|
239
|
-
console.error(chalk.red('Error:'), response.error?.message || 'Failed to revoke connection');
|
|
240
|
-
}
|
|
241
|
-
} catch (error) {
|
|
242
|
-
console.error(chalk.red('Error:'), error instanceof Error ? error.message : 'Unknown error');
|
|
243
|
-
}
|
|
244
|
-
});
|
|
245
|
-
}
|
|
246
|
-
|
|
247
|
-
async function getHumansApiUrl(): Promise<string> {
|
|
248
|
-
const config = await configManager.getGlobalConfig();
|
|
249
|
-
return (config as any).humansApiUrl || DEFAULT_HUMANS_API_URL;
|
|
250
|
-
}
|
|
251
|
-
|
|
252
|
-
function formatTimestamp(ts: any): string {
|
|
253
|
-
if (!ts) return 'unknown';
|
|
254
|
-
if (ts._seconds) {
|
|
255
|
-
return new Date(ts._seconds * 1000).toISOString();
|
|
256
|
-
}
|
|
257
|
-
if (typeof ts === 'string' || typeof ts === 'number') {
|
|
258
|
-
return new Date(ts).toISOString();
|
|
259
|
-
}
|
|
260
|
-
return String(ts);
|
|
261
|
-
}
|