@obol/cli 0.1.0 → 0.1.2
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/bin/obol.js +14 -1
- package/package.json +1 -1
- package/src/api.js +8 -0
- package/src/credits.js +68 -0
- package/src/setup.js +1 -14
package/bin/obol.js
CHANGED
|
@@ -3,11 +3,13 @@
|
|
|
3
3
|
import { runSetup } from '../src/setup.js';
|
|
4
4
|
import { runStatus } from '../src/status.js';
|
|
5
5
|
import { runConnect } from '../src/connect.js';
|
|
6
|
+
import { runCreditsBuy } from '../src/credits.js';
|
|
6
7
|
import { getBalance, getTiers } from '../src/api.js';
|
|
7
8
|
import { loadEnv } from '../src/config.js';
|
|
8
9
|
import pc from 'picocolors';
|
|
9
10
|
|
|
10
11
|
const command = process.argv[2];
|
|
12
|
+
const subcommand = process.argv[3];
|
|
11
13
|
|
|
12
14
|
async function main() {
|
|
13
15
|
switch (command) {
|
|
@@ -20,7 +22,17 @@ async function main() {
|
|
|
20
22
|
break;
|
|
21
23
|
|
|
22
24
|
case 'connect':
|
|
23
|
-
await runConnect(
|
|
25
|
+
await runConnect(subcommand);
|
|
26
|
+
break;
|
|
27
|
+
|
|
28
|
+
case 'credits':
|
|
29
|
+
if (subcommand === 'buy') {
|
|
30
|
+
await runCreditsBuy();
|
|
31
|
+
} else {
|
|
32
|
+
console.log(`\n ${pc.bold('obol credits')} commands:\n`);
|
|
33
|
+
console.log(` ${pc.green('buy')} Purchase credits via Stripe\n`);
|
|
34
|
+
console.log(` Usage: ${pc.dim('npx @obol/cli credits buy')}\n`);
|
|
35
|
+
}
|
|
24
36
|
break;
|
|
25
37
|
|
|
26
38
|
case 'balance': {
|
|
@@ -73,6 +85,7 @@ async function main() {
|
|
|
73
85
|
${pc.green('setup')} Set up a new agent (interactive wizard)
|
|
74
86
|
${pc.green('status')} Check agent health, balance & connections
|
|
75
87
|
${pc.green('connect')} ${pc.dim('<provider>')} Add a service API key (github, slack, etc.)
|
|
88
|
+
${pc.green('credits buy')} Purchase credits via Stripe
|
|
76
89
|
${pc.green('balance')} Check your credit balance
|
|
77
90
|
${pc.green('tiers')} Show credit purchase tiers
|
|
78
91
|
${pc.green('help')} Show this help message
|
package/package.json
CHANGED
package/src/api.js
CHANGED
|
@@ -96,6 +96,14 @@ export async function getTiers(gatewayUrl) {
|
|
|
96
96
|
return request(`${gatewayUrl}/v1/credits/tiers`);
|
|
97
97
|
}
|
|
98
98
|
|
|
99
|
+
export async function createCheckout(gatewayUrl, jwt, amountUsd) {
|
|
100
|
+
return request(`${gatewayUrl}/v1/credits/checkout`, {
|
|
101
|
+
method: 'POST',
|
|
102
|
+
headers: jwtHeaders(jwt),
|
|
103
|
+
body: JSON.stringify({ amount_usdc: amountUsd }),
|
|
104
|
+
});
|
|
105
|
+
}
|
|
106
|
+
|
|
99
107
|
export async function getAgentInfo(gatewayUrl, adminKey, agentId) {
|
|
100
108
|
return request(`${gatewayUrl}/v1/agents/${agentId}`, {
|
|
101
109
|
headers: adminHeaders(adminKey),
|
package/src/credits.js
ADDED
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import * as p from '@clack/prompts';
|
|
2
|
+
import pc from 'picocolors';
|
|
3
|
+
import { getTiers, createCheckout } from './api.js';
|
|
4
|
+
import { loadEnv } from './config.js';
|
|
5
|
+
|
|
6
|
+
export async function runCreditsBuy() {
|
|
7
|
+
const env = loadEnv();
|
|
8
|
+
|
|
9
|
+
if (!env.OBOL_GATEWAY_URL || !env.OBOL_JWT_TOKEN) {
|
|
10
|
+
console.log();
|
|
11
|
+
p.log.warn('No agent configured yet.');
|
|
12
|
+
p.log.info(`Run ${pc.green('npx @obol/cli setup')} first.`);
|
|
13
|
+
console.log();
|
|
14
|
+
return;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
const url = env.OBOL_GATEWAY_URL;
|
|
18
|
+
|
|
19
|
+
console.log();
|
|
20
|
+
p.intro(pc.bgGreen(pc.black(' Buy Credits ')));
|
|
21
|
+
|
|
22
|
+
// Fetch tiers
|
|
23
|
+
const s = p.spinner();
|
|
24
|
+
s.start('Loading credit tiers...');
|
|
25
|
+
let tiers;
|
|
26
|
+
try {
|
|
27
|
+
const data = await getTiers(url);
|
|
28
|
+
tiers = data.tiers;
|
|
29
|
+
s.stop(pc.green(`${tiers.length} tiers available`));
|
|
30
|
+
} catch (err) {
|
|
31
|
+
s.stop(pc.red(`Couldn't load tiers: ${err.message}`));
|
|
32
|
+
return;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
// Pick a tier
|
|
36
|
+
const tier = await p.select({
|
|
37
|
+
message: 'Which credit pack?',
|
|
38
|
+
options: tiers.map(t => ({
|
|
39
|
+
value: t,
|
|
40
|
+
label: `${t.name} — $${t.price_usd}`,
|
|
41
|
+
hint: t.bonus_pct > 0 ? `${t.credits_usdc} credits (+${t.bonus_pct}% bonus)` : `${t.credits_usdc} credits`,
|
|
42
|
+
})),
|
|
43
|
+
});
|
|
44
|
+
if (p.isCancel(tier)) { p.cancel('Cancelled.'); return; }
|
|
45
|
+
|
|
46
|
+
const confirmed = await p.confirm({
|
|
47
|
+
message: `Purchase ${pc.bold(tier.name)} for ${pc.green('$' + tier.price_usd)}? (${tier.credits_usdc} credits)`,
|
|
48
|
+
});
|
|
49
|
+
if (p.isCancel(confirmed) || !confirmed) { p.cancel('Cancelled.'); return; }
|
|
50
|
+
|
|
51
|
+
// Create checkout
|
|
52
|
+
s.start('Creating Stripe checkout...');
|
|
53
|
+
try {
|
|
54
|
+
const result = await createCheckout(url, env.OBOL_JWT_TOKEN, tier.price_usd);
|
|
55
|
+
s.stop(pc.green('Checkout created!'));
|
|
56
|
+
|
|
57
|
+
console.log();
|
|
58
|
+
p.log.info(`Tier: ${pc.bold(result.tier)} — $${result.amount_usd} → ${pc.green(result.credits_usdc + ' credits')}`);
|
|
59
|
+
p.log.info(`Payment Intent: ${pc.dim(result.payment_intent_id)}`);
|
|
60
|
+
console.log();
|
|
61
|
+
p.log.warn('Stripe Checkout requires a browser to complete payment.');
|
|
62
|
+
p.log.info(`Use the Stripe Dashboard or integrate Stripe.js in your app to confirm payment intent: ${pc.cyan(result.payment_intent_id)}`);
|
|
63
|
+
} catch (err) {
|
|
64
|
+
s.stop(pc.red(`Couldn't create checkout: ${err.message}`));
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
p.outro(pc.dim('Credits are added to your balance once payment completes.'));
|
|
68
|
+
}
|
package/src/setup.js
CHANGED
|
@@ -13,20 +13,7 @@ export async function runSetup() {
|
|
|
13
13
|
|
|
14
14
|
p.log.info("Let's get your agent connected. This takes about 60 seconds.");
|
|
15
15
|
|
|
16
|
-
|
|
17
|
-
const gatewayUrl = await p.text({
|
|
18
|
-
message: "Where's your Obol gateway?",
|
|
19
|
-
placeholder: 'https://www.obolagents.com',
|
|
20
|
-
defaultValue: 'https://www.obolagents.com',
|
|
21
|
-
validate: (val) => {
|
|
22
|
-
const v = val || 'https://www.obolagents.com';
|
|
23
|
-
if (!v.startsWith('http://') && !v.startsWith('https://')) {
|
|
24
|
-
return 'Should start with http:// or https://';
|
|
25
|
-
}
|
|
26
|
-
},
|
|
27
|
-
});
|
|
28
|
-
if (p.isCancel(gatewayUrl)) return cancelled();
|
|
29
|
-
const url = (gatewayUrl || 'https://www.obolagents.com').replace(/\/+$/, '');
|
|
16
|
+
const url = 'https://www.obolagents.com';
|
|
30
17
|
|
|
31
18
|
// Verify connectivity
|
|
32
19
|
const healthSpin = p.spinner();
|