Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
79 changes: 46 additions & 33 deletions packages/atxp/src/commands/agent.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,14 +48,16 @@ function showAgentHelp(): void {
console.log(' - A connection token for SDK/CLI access');
console.log();
console.log(chalk.bold('Register Options:'));
console.log(' ' + chalk.yellow('--server') + ' ' + 'Accounts server URL (default: https://accounts.atxp.ai)');
console.log(' ' + chalk.yellow('--answer') + ' ' + 'Provide the challenge answer non-interactively');
console.log(' ' + chalk.yellow('--server') + ' ' + 'Accounts server URL (default: https://accounts.atxp.ai)');
console.log(' ' + chalk.yellow('--answer') + ' ' + 'Provide the challenge answer non-interactively');
console.log(' ' + chalk.yellow('--registration-id') + ' ' + 'Resume a previous challenge (skip fetching a new one)');
console.log();
console.log(chalk.bold('Examples:'));
console.log(' npx atxp agent create');
console.log(' npx atxp agent list');
console.log(' npx atxp agent register');
console.log(' npx atxp agent register --server http://localhost:8016');
console.log(' npx atxp agent register --registration-id reg_xxx --answer "535.00"');
console.log(' CONNECTION_TOKEN=<agent_token> npx atxp email inbox');
}

Expand Down Expand Up @@ -150,42 +152,53 @@ function promptForInput(prompt: string): Promise<string> {
async function registerAgent(): Promise<void> {
const baseUrl = getArgValue('--server') || getBaseUrl();
const presetAnswer = getArgValue('--answer');
const presetRegistrationId = getArgValue('--registration-id');

// Step 1: Get challenge
console.log(chalk.gray(`Requesting challenge from ${baseUrl}...`));
let registrationId: string;

const challengeRes = await fetch(`${baseUrl}/agents/register`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
});
if (presetRegistrationId) {
// Resume a previous challenge — skip fetching a new one
registrationId = presetRegistrationId;
console.log(chalk.gray(`Resuming registration ${registrationId}...`));
} else {
// Step 1: Get challenge
console.log(chalk.gray(`Requesting challenge from ${baseUrl}...`));

if (!challengeRes.ok) {
const body = await challengeRes.json().catch(() => ({})) as Record<string, string>;
console.error(chalk.red(`Error: ${body.error_description || body.error || challengeRes.statusText}`));
process.exit(1);
}
const challengeRes = await fetch(`${baseUrl}/agents/register`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
});

const challenge = await challengeRes.json() as {
registration_id: string;
challenge: string;
instructions: string;
expires_at: string;
};
if (!challengeRes.ok) {
const body = await challengeRes.json().catch(() => ({})) as Record<string, string>;
console.error(chalk.red(`Error: ${body.error_description || body.error || challengeRes.statusText}`));
process.exit(1);
}

// Decode base64 challenge and instructions
const decodedChallenge = Buffer.from(challenge.challenge, 'base64').toString('utf-8');
const decodedInstructions = Buffer.from(challenge.instructions, 'base64').toString('utf-8');
const challenge = await challengeRes.json() as {
registration_id: string;
challenge: string;
instructions: string;
expires_at: string;
};

console.log();
console.log(chalk.bold('Challenge:'));
console.log(' ' + chalk.yellow(decodedChallenge));
console.log();
console.log(chalk.bold('Instructions:'));
console.log(' ' + decodedInstructions);
console.log();
console.log(chalk.gray(`Registration ID: ${challenge.registration_id}`));
console.log(chalk.gray(`Expires at: ${challenge.expires_at}`));
console.log();
registrationId = challenge.registration_id;

// Decode base64 challenge and instructions
const decodedChallenge = Buffer.from(challenge.challenge, 'base64').toString('utf-8');
const decodedInstructions = Buffer.from(challenge.instructions, 'base64').toString('utf-8');

console.log();
console.log(chalk.bold('Challenge:'));
console.log(' ' + chalk.yellow(decodedChallenge));
console.log();
console.log(chalk.bold('Instructions:'));
console.log(' ' + decodedInstructions);
console.log();
console.log(chalk.gray(`Registration ID: ${registrationId}`));
console.log(chalk.gray(`Expires at: ${challenge.expires_at}`));
console.log();
}

// Step 2: Get answer
let answer: string;
Expand All @@ -208,7 +221,7 @@ async function registerAgent(): Promise<void> {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
registration_id: challenge.registration_id,
registration_id: registrationId,
answer,
}),
});
Expand Down
Loading