Skip to content

Commit 1ebda95

Browse files
authored
Merge pull request #47 from atxp-dev/naveen/skill.md-refinements
docs: optimize SKILL.md for discovery platforms and tone down securit…
2 parents da168ea + a3a6c03 commit 1ebda95

7 files changed

Lines changed: 242 additions & 167 deletions

File tree

packages/atxp/package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,8 @@
1919
"build": "tsc && cp -r src/vendor/*.cjs dist/vendor/",
2020
"dev": "tsx src/index.ts",
2121
"typecheck": "tsc --noEmit",
22-
"lint": "eslint . --ext .ts",
23-
"lint:fix": "eslint . --ext .ts --fix",
22+
"lint": "eslint . --ext .ts --ignore-pattern 'src/vendor/'",
23+
"lint:fix": "eslint . --ext .ts --fix --ignore-pattern 'src/vendor/'",
2424
"test": "vitest run",
2525
"prepublishOnly": "npm run build"
2626
},
Lines changed: 105 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -1,72 +1,142 @@
11
import chalk from 'chalk';
2+
import open from 'open';
23
import { getConnection } from '../config.js';
34

4-
const ACCOUNT_URL = 'https://accounts.atxp.ai/me';
5+
const DEFAULT_AMOUNT = 10;
6+
const MIN_AMOUNT = 1;
7+
const MAX_AMOUNT = 1000;
58

6-
/**
7-
* Extract the connection_token from the ATXP_CONNECTION string.
8-
* Connection string format: https://accounts.atxp.ai?connection_token=<token>
9-
*/
10-
function getConnectionToken(connectionString: string): string | null {
11-
try {
12-
const url = new URL(connectionString);
13-
return url.searchParams.get('connection_token');
14-
} catch {
15-
return null;
16-
}
17-
}
18-
19-
export async function depositCommand(): Promise<void> {
9+
function getAccountsAuth(): { baseUrl: string; token: string } {
2010
const connection = getConnection();
21-
2211
if (!connection) {
2312
console.error(chalk.red('Not logged in.'));
2413
console.error(`Run: ${chalk.cyan('npx atxp login')}`);
2514
process.exit(1);
2615
}
27-
28-
const token = getConnectionToken(connection);
16+
const url = new URL(connection);
17+
const token = url.searchParams.get('connection_token');
2918
if (!token) {
30-
console.error(chalk.red('Error: Could not extract connection token.'));
31-
console.error('Your ATXP_CONNECTION may be malformed. Try logging in again:');
32-
console.error(chalk.cyan(' npx atxp login --force'));
19+
console.error(chalk.red('Invalid connection string: missing connection_token'));
3320
process.exit(1);
3421
}
22+
return { baseUrl: `${url.protocol}//${url.host}`, token };
23+
}
24+
25+
function getArgValue(flag: string): string | undefined {
26+
const index = process.argv.findIndex((arg) => arg === flag);
27+
return index !== -1 ? process.argv[index + 1] : undefined;
28+
}
29+
30+
function showFundHelp(): void {
31+
console.log(chalk.bold('Fund Commands:'));
32+
console.log();
33+
console.log(' ' + chalk.cyan('npx atxp fund') + ' ' + 'Show funding options for your account');
34+
console.log(' ' + chalk.cyan('npx atxp fund --amount 100') + ' ' + 'Request a $100 payment link (agents only)');
35+
console.log();
36+
console.log(chalk.bold('Options:'));
37+
console.log(' ' + chalk.yellow('--amount') + ' ' + `Suggested amount in USD ($${MIN_AMOUNT}-$${MAX_AMOUNT}, default: $${DEFAULT_AMOUNT})`);
38+
console.log(' ' + chalk.yellow('--open') + ' ' + 'Open the payment link in your browser');
39+
console.log();
40+
console.log(chalk.bold('How it works:'));
41+
console.log(' Shows all available ways to fund your account:');
42+
console.log(' - Crypto deposit addresses (USDC on supported chains)');
43+
console.log(' - Payment link (agent accounts only) - shareable Stripe link');
44+
console.log(' The payer can adjust the amount at checkout.');
45+
}
46+
47+
export async function depositCommand(): Promise<void> {
48+
if (process.argv.includes('--help') || process.argv.includes('-h')) {
49+
showFundHelp();
50+
return;
51+
}
52+
53+
const { baseUrl, token } = getAccountsAuth();
54+
55+
// Parse amount for payment link
56+
const amountStr = getArgValue('--amount');
57+
let amount = DEFAULT_AMOUNT;
58+
if (amountStr) {
59+
amount = parseFloat(amountStr);
60+
if (isNaN(amount) || amount < MIN_AMOUNT || amount > MAX_AMOUNT) {
61+
console.error(chalk.red(`Invalid amount: must be between $${MIN_AMOUNT} and $${MAX_AMOUNT}`));
62+
process.exit(1);
63+
}
64+
}
65+
66+
const shouldOpen = process.argv.includes('--open');
67+
68+
console.log(chalk.gray('Fetching funding options...'));
3569

3670
try {
37-
const credentials = Buffer.from(`${token}:`).toString('base64');
38-
const response = await fetch(ACCOUNT_URL, {
71+
const res = await fetch(`${baseUrl}/api/funding/fund`, {
72+
method: 'POST',
3973
headers: {
40-
'Authorization': `Basic ${credentials}`,
74+
'Authorization': `Bearer ${token}`,
4175
'Content-Type': 'application/json',
4276
},
77+
body: JSON.stringify({ amount }),
4378
});
4479

45-
if (!response.ok) {
46-
console.error(chalk.red(`Error: ${response.status} ${response.statusText}`));
80+
if (!res.ok) {
81+
const body = await res.json().catch(() => ({})) as Record<string, string>;
82+
console.error(chalk.red(`Error: ${body.error || res.statusText}`));
4783
process.exit(1);
4884
}
4985

50-
const data = await response.json();
86+
const data = await res.json() as {
87+
paymentLink: {
88+
url: string;
89+
paymentLinkId: string;
90+
suggestedAmount: number;
91+
minAmount: number;
92+
maxAmount: number;
93+
} | null;
94+
cryptoDeposit: Array<{
95+
address: string;
96+
network: string;
97+
currency: string;
98+
}>;
99+
};
51100

52-
if (data.sources && Array.isArray(data.sources) && data.sources.length > 0) {
101+
console.log();
102+
103+
// Display crypto deposit addresses
104+
if (data.cryptoDeposit && data.cryptoDeposit.length > 0) {
53105
console.log(chalk.bold('Fund via USDC:'));
54-
for (const source of data.sources) {
55-
const chain = source.chain.charAt(0).toUpperCase() + source.chain.slice(1);
106+
for (const source of data.cryptoDeposit) {
107+
const chain = source.network.charAt(0).toUpperCase() + source.network.slice(1);
56108
console.log(` ${chalk.cyan(chain)}: ${source.address}`);
57109
}
58110
console.log();
59-
console.log(chalk.bold('Fund via credit card or other payment methods:'));
60-
console.log(` ${chalk.underline('https://accounts.atxp.ai/fund')}`);
61-
} else {
62-
console.log(chalk.yellow('No deposit addresses found for this account.'));
111+
}
112+
113+
// Display payment link (agent accounts only)
114+
if (data.paymentLink) {
115+
console.log(chalk.bold('Fund via payment link:'));
116+
console.log(' ' + chalk.bold('Suggested:') + ' ' + chalk.green(`$${data.paymentLink.suggestedAmount.toFixed(2)}`));
117+
console.log(' ' + chalk.bold('Range:') + ' ' + chalk.gray(`$${data.paymentLink.minAmount} - $${data.paymentLink.maxAmount}`));
118+
console.log(' ' + chalk.bold('URL:') + ' ' + chalk.cyan.underline(data.paymentLink.url));
119+
console.log();
120+
console.log(chalk.gray('Share this link with anyone to fund your account.'));
121+
console.log(chalk.gray('The payer can adjust the amount at checkout.'));
122+
123+
if (shouldOpen) {
124+
console.log();
125+
console.log(chalk.gray('Opening in browser...'));
126+
await open(data.paymentLink.url);
127+
}
128+
}
129+
130+
// If neither is available
131+
if ((!data.cryptoDeposit || data.cryptoDeposit.length === 0) && !data.paymentLink) {
132+
console.log(chalk.yellow('No funding options found for this account.'));
63133
console.log();
64134
console.log(chalk.bold('Fund via credit card or other payment methods:'));
65135
console.log(` ${chalk.underline('https://accounts.atxp.ai/fund')}`);
66136
}
67137
} catch (error) {
68138
const errorMessage = error instanceof Error ? error.message : String(error);
69-
console.error(chalk.red(`Error fetching funding info: ${errorMessage}`));
139+
console.error(chalk.red(`Error fetching funding options: ${errorMessage}`));
70140
process.exit(1);
71141
}
72142
}

packages/atxp/src/commands/topup.ts

Lines changed: 0 additions & 118 deletions
This file was deleted.

0 commit comments

Comments
 (0)