@obol/cli 0.1.1 → 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 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(process.argv[3]);
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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@obol/cli",
3
- "version": "0.1.1",
3
+ "version": "0.1.2",
4
4
  "description": "CLI for the Obol Agent Execution Gateway",
5
5
  "type": "module",
6
6
  "bin": {
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
+ }