Skip to content

Commit 2f0c140

Browse files
authored
Merge pull request #39 from atxp-dev/naveen/agent-account-cli-changes
feat: Add agent create/list CLI commands
2 parents a20941e + b4c0eb3 commit 2f0c140

3 files changed

Lines changed: 179 additions & 1 deletion

File tree

Lines changed: 167 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,167 @@
1+
import chalk from 'chalk';
2+
import { getConnection } from '../config.js';
3+
4+
function getAccountsAuth(): { baseUrl: string; token: string } {
5+
const connection = getConnection();
6+
if (!connection) {
7+
console.error(chalk.red('Not logged in.'));
8+
console.error(`Run: ${chalk.cyan('npx atxp login')}`);
9+
process.exit(1);
10+
}
11+
const url = new URL(connection);
12+
const token = url.searchParams.get('connection_token');
13+
if (!token) {
14+
console.error(chalk.red('Invalid connection string: missing connection_token'));
15+
process.exit(1);
16+
}
17+
return { baseUrl: `${url.protocol}//${url.host}`, token };
18+
}
19+
20+
function showAgentHelp(): void {
21+
console.log(chalk.bold('Agent Commands:'));
22+
console.log();
23+
console.log(' ' + chalk.cyan('npx atxp agent create') + ' ' + 'Create a new agent account');
24+
console.log(' ' + chalk.cyan('npx atxp agent list') + ' ' + 'List your agents');
25+
console.log();
26+
console.log(chalk.bold('Details:'));
27+
console.log(' Each agent gets:');
28+
console.log(' - A unique email address ({agentId}@atxp.email)');
29+
console.log(' - An Ethereum wallet');
30+
console.log(' - 10 IOU tokens to start');
31+
console.log(' - A connection token for SDK/CLI access');
32+
console.log();
33+
console.log(chalk.bold('Examples:'));
34+
console.log(' npx atxp agent create');
35+
console.log(' npx atxp agent list');
36+
console.log(' CONNECTION_TOKEN=<agent_token> npx atxp email inbox');
37+
}
38+
39+
export async function agentCommand(subCommand: string): Promise<void> {
40+
if (!subCommand || subCommand === 'help' || subCommand === '--help' || subCommand === '-h') {
41+
showAgentHelp();
42+
return;
43+
}
44+
45+
switch (subCommand) {
46+
case 'create':
47+
await createAgent();
48+
break;
49+
50+
case 'list':
51+
await listAgents();
52+
break;
53+
54+
default:
55+
console.error(chalk.red(`Unknown agent command: ${subCommand}`));
56+
console.log();
57+
showAgentHelp();
58+
process.exit(1);
59+
}
60+
}
61+
62+
async function createAgent(): Promise<void> {
63+
const { baseUrl, token } = getAccountsAuth();
64+
65+
console.log(chalk.gray('Creating agent...'));
66+
67+
const res = await fetch(`${baseUrl}/agents`, {
68+
method: 'POST',
69+
headers: {
70+
'Authorization': `Bearer ${token}`,
71+
'Content-Type': 'application/json',
72+
},
73+
});
74+
75+
if (!res.ok) {
76+
const body = await res.json().catch(() => ({}));
77+
console.error(chalk.red(`Error: ${(body as Record<string, string>).error || res.statusText}`));
78+
process.exit(1);
79+
}
80+
81+
const data = await res.json() as {
82+
agentId: string;
83+
email: string;
84+
atxpAccountId: string;
85+
connectionToken: string;
86+
connectionString: string;
87+
walletAddress: string;
88+
fundedAmount: string;
89+
};
90+
91+
console.log();
92+
console.log(chalk.green.bold('Agent created successfully!'));
93+
console.log();
94+
console.log(' ' + chalk.bold('Agent ID:') + ' ' + data.agentId);
95+
console.log(' ' + chalk.bold('Email:') + ' ' + chalk.cyan(data.email));
96+
console.log(' ' + chalk.bold('Account ID:') + ' ' + data.atxpAccountId);
97+
console.log(' ' + chalk.bold('Connection Token:') + ' ' + data.connectionToken);
98+
console.log(' ' + chalk.bold('Wallet:') + ' ' + data.walletAddress);
99+
console.log(' ' + chalk.bold('Funded:') + ' ' + data.fundedAmount + ' IOU');
100+
console.log();
101+
console.log(chalk.bold('Connection String:'));
102+
console.log(' ' + chalk.cyan(data.connectionString));
103+
console.log();
104+
console.log(chalk.bold('Use this to authenticate as the agent:'));
105+
console.log(' ' + chalk.yellow(`CONNECTION_TOKEN=${data.connectionToken} npx atxp email inbox`));
106+
}
107+
108+
async function listAgents(): Promise<void> {
109+
const { baseUrl, token } = getAccountsAuth();
110+
111+
const res = await fetch(`${baseUrl}/agents`, {
112+
headers: {
113+
'Authorization': `Bearer ${token}`,
114+
},
115+
});
116+
117+
if (!res.ok) {
118+
const body = await res.json().catch(() => ({}));
119+
console.error(chalk.red(`Error: ${(body as Record<string, string>).error || res.statusText}`));
120+
process.exit(1);
121+
}
122+
123+
const data = await res.json() as {
124+
agents: Array<{
125+
connectionToken: string;
126+
atxpAccountId: string;
127+
email: string | null;
128+
walletAddress: string | null;
129+
balance: { totalUsdc: string; totalIou: string } | null;
130+
createdAt: string | null;
131+
}>;
132+
};
133+
134+
if (data.agents.length === 0) {
135+
console.log(chalk.gray('No agents created yet.'));
136+
console.log();
137+
console.log('Create one with: ' + chalk.cyan('npx atxp agent create'));
138+
return;
139+
}
140+
141+
console.log(chalk.bold(`Your Agents (${data.agents.length})`));
142+
console.log();
143+
144+
for (const agent of data.agents) {
145+
console.log(chalk.gray('─'.repeat(50)));
146+
console.log(' ' + chalk.bold('Email:') + ' ' + chalk.cyan(agent.email || 'Unknown'));
147+
console.log(' ' + chalk.bold('Account ID:') + ' ' + agent.atxpAccountId);
148+
console.log(' ' + chalk.bold('Connection Token:') + ' ' + agent.connectionToken);
149+
if (agent.walletAddress) {
150+
console.log(' ' + chalk.bold('Wallet:') + ' ' + agent.walletAddress);
151+
}
152+
if (agent.balance) {
153+
console.log(' ' + chalk.bold('Balance:') + ' ' + `$${agent.balance.totalUsdc} USDC / $${agent.balance.totalIou} IOU`);
154+
}
155+
if (agent.createdAt) {
156+
const date = new Date(agent.createdAt).toLocaleDateString('en-US', {
157+
month: 'short',
158+
day: 'numeric',
159+
year: 'numeric',
160+
hour: '2-digit',
161+
minute: '2-digit',
162+
});
163+
console.log(' ' + chalk.bold('Created:') + ' ' + chalk.gray(date));
164+
}
165+
}
166+
console.log(chalk.gray('─'.repeat(50)));
167+
}

packages/atxp/src/help.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ export function showHelp(): void {
2525
console.log(' ' + chalk.cyan('x') + ' ' + chalk.yellow('<query>') + ' ' + 'Search X/Twitter');
2626
console.log(' ' + chalk.cyan('email') + ' ' + chalk.yellow('<command>') + ' ' + 'Send and receive emails');
2727
console.log(' ' + chalk.cyan('balance') + ' ' + 'Check your ATXP account balance');
28+
console.log(' ' + chalk.cyan('agent') + ' ' + chalk.yellow('<command>') + ' ' + 'Create and manage agent accounts');
2829
console.log();
2930

3031
console.log(chalk.bold('PAAS (Platform as a Service):'));
@@ -84,6 +85,11 @@ export function showHelp(): void {
8485
console.log(' npx atxp dev create my-app # Create a new project');
8586
console.log();
8687

88+
console.log(chalk.bold('Agent Examples:'));
89+
console.log(' npx atxp agent create # Create a new agent');
90+
console.log(' npx atxp agent list # List your agents');
91+
console.log();
92+
8793
console.log(chalk.bold('PAAS Examples:'));
8894
console.log(' npx atxp paas worker deploy my-api --code ./worker.js');
8995
console.log(' npx atxp paas db create my-database');

packages/atxp/src/index.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import { xCommand } from './commands/x.js';
1515
import { emailCommand } from './commands/email.js';
1616
import { balanceCommand } from './commands/balance.js';
1717
import { paasCommand } from './commands/paas/index.js';
18+
import { agentCommand } from './commands/agent.js';
1819

1920
interface DemoOptions {
2021
port: number;
@@ -88,7 +89,7 @@ function parseArgs(): {
8889

8990
// Check for help flags early - but NOT for paas or email commands (they handle --help internally)
9091
const helpFlag = process.argv.includes('--help') || process.argv.includes('-h');
91-
if (helpFlag && command !== 'paas' && command !== 'email') {
92+
if (helpFlag && command !== 'paas' && command !== 'email' && command !== 'agent') {
9293
return {
9394
command: 'help',
9495
demoOptions: { port: 8017, dir: '', verbose: false, refresh: false },
@@ -315,6 +316,10 @@ async function main() {
315316
await paasCommand(paasArgs, paasOptions);
316317
break;
317318

319+
case 'agent':
320+
await agentCommand(subCommand || '');
321+
break;
322+
318323
case 'dev':
319324
// Dev subcommands (demo, create)
320325
if (subCommand === 'demo') {

0 commit comments

Comments
 (0)