@obol/cli 0.3.0 → 0.3.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
@@ -31,14 +31,14 @@ async function main() {
31
31
  } else {
32
32
  console.log(`\n ${pc.bold('obol credits')} commands:\n`);
33
33
  console.log(` ${pc.green('buy')} Purchase credits via Stripe\n`);
34
- console.log(` Usage: ${pc.dim('npx @obol/cli credits buy')}\n`);
34
+ console.log(` Usage: ${pc.dim('npx -y -p @obol/cli obol credits buy')}\n`);
35
35
  }
36
36
  break;
37
37
 
38
38
  case 'token': {
39
39
  const env = loadEnv();
40
40
  if (!env.OBOL_JWT_TOKEN) {
41
- console.log(pc.red('\n No agent configured yet. Run: npx @obol/cli setup\n'));
41
+ console.log(pc.red('\n No agent configured yet. Run: npx -y -p @obol/cli obol setup\n'));
42
42
  process.exit(1);
43
43
  }
44
44
  // Try to refresh the token (in case it's expired)
@@ -151,7 +151,7 @@ async function main() {
151
151
  case 'test': {
152
152
  const env = loadEnv();
153
153
  if (!env.OBOL_GATEWAY_URL || !env.OBOL_JWT_TOKEN) {
154
- console.log(pc.red('\n No account configured. Run: npx @obol/cli setup\n'));
154
+ console.log(pc.red('\n No account configured. Run: npx -y -p @obol/cli obol setup\n'));
155
155
  process.exit(1);
156
156
  }
157
157
  console.log(`\n ${pc.bold('Obol Connection Test')}\n`);
@@ -176,7 +176,7 @@ async function main() {
176
176
  const color = bal.balance_usdc > 0 ? pc.green : pc.yellow;
177
177
  console.log(` ${color(bal.balance_usdc > 0 ? '✓' : '!')} Balance ${color(balStr)} USDC`);
178
178
  if (bal.balance_usdc === 0 && (env.OBOL_PAYMENT_MODE || '').toLowerCase() !== 'x402') {
179
- console.log(`\n ${pc.yellow('Buy credits to start executing:')} ${pc.green('npx @obol/cli credits buy')}`);
179
+ console.log(`\n ${pc.yellow('Buy credits to start executing:')} ${pc.green('npx -y -p @obol/cli obol credits buy')}`);
180
180
  } else if ((env.OBOL_PAYMENT_MODE || '').toLowerCase() === 'x402') {
181
181
  console.log(`\n ${pc.green('Automatic agent payments are enabled via x402.')}`);
182
182
  }
@@ -223,7 +223,7 @@ async function main() {
223
223
  ${pc.green('help')} Show this help message
224
224
 
225
225
  ${pc.bold('Quick start:')}
226
- ${pc.dim('$')} npx @obol/cli setup
226
+ ${pc.dim('$')} npx -y -p @obol/cli obol setup
227
227
  `);
228
228
  break;
229
229
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@obol/cli",
3
- "version": "0.3.0",
3
+ "version": "0.3.2",
4
4
  "description": "CLI for the Obol Agent Execution Gateway",
5
5
  "type": "module",
6
6
  "bin": {
package/src/api.js CHANGED
@@ -45,11 +45,13 @@ export async function checkHealth(gatewayUrl) {
45
45
  return request(`${gatewayUrl}/healthz`);
46
46
  }
47
47
 
48
- export async function signup(gatewayUrl, agentId, services, referralCode, setupKey) {
48
+ export async function signup(gatewayUrl, agentId, services, referralCode, setupKey, preferredPaymentMode, walletAddress) {
49
49
  const body = { agent_id: agentId };
50
50
  if (services && services.length > 0) body.services = services;
51
51
  if (referralCode) body.referral_code = referralCode;
52
52
  if (setupKey) body.setup_key = setupKey;
53
+ if (preferredPaymentMode) body.preferred_payment_mode = preferredPaymentMode;
54
+ if (walletAddress) body.wallet_address = walletAddress;
53
55
  return request(`${gatewayUrl}/v1/signup`, {
54
56
  method: 'POST',
55
57
  headers: { 'Content-Type': 'application/json' },
package/src/connect.js CHANGED
@@ -19,7 +19,7 @@ export async function runConnect(providerArg) {
19
19
  if (!env.OBOL_GATEWAY_URL || !env.OBOL_JWT_TOKEN) {
20
20
  console.log();
21
21
  p.log.warn('No agent configured yet.');
22
- p.log.info(`Run ${pc.green('npx @obol/cli setup')} first.`);
22
+ p.log.info(`Run ${pc.green('npx -y -p @obol/cli obol setup')} first.`);
23
23
  console.log();
24
24
  return;
25
25
  }
package/src/credits.js CHANGED
@@ -9,7 +9,7 @@ export async function runCreditsBuy() {
9
9
  if (!env.OBOL_GATEWAY_URL || !env.OBOL_AGENT_ID || !env.OBOL_JWT_TOKEN) {
10
10
  console.log();
11
11
  p.log.warn('No agent configured yet.');
12
- p.log.info(`Run ${pc.green('npx @obol/cli setup')} first.`);
12
+ p.log.info(`Run ${pc.green('npx -y -p @obol/cli obol setup')} first.`);
13
13
  console.log();
14
14
  process.exit(1);
15
15
  }
package/src/setup.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import { execSync } from 'node:child_process';
2
2
  import { existsSync, readFileSync, writeFileSync } from 'node:fs';
3
- import { resolve } from 'node:path';
3
+ import { basename, resolve } from 'node:path';
4
4
  import * as p from '@clack/prompts';
5
5
  import pc from 'picocolors';
6
6
  import { checkHealth, listConnections, listEndpoints, signup, storeBYOK, validateReferralCode } from './api.js';
@@ -10,6 +10,30 @@ const cheers = ['Nice!', 'Boom!', "Let's go.", 'Easy.', 'Done.'];
10
10
  const cheer = () => cheers[Math.floor(Math.random() * cheers.length)];
11
11
  const PYTHON_SDK_INSTALL_CMD = 'python3 -m pip install "git+https://github.com/kineticSum/obol-gateway.git#subdirectory=sdk/python"';
12
12
 
13
+ export function preferredJsPaymentMode(existingEnv = {}) {
14
+ return existingEnv.OBOL_PAYMENT_MODE || 'x402';
15
+ }
16
+
17
+ export function ensureJsProjectManifest(agentId, cwd = process.cwd()) {
18
+ const packageJsonPath = resolve(cwd, 'package.json');
19
+ if (existsSync(packageJsonPath)) return packageJsonPath;
20
+
21
+ const rawName = basename(cwd) || agentId || 'obol-agent';
22
+ const packageName = rawName
23
+ .toLowerCase()
24
+ .replace(/[^a-z0-9._-]+/g, '-')
25
+ .replace(/^-+|-+$/g, '')
26
+ || 'obol-agent';
27
+
28
+ const manifest = {
29
+ name: packageName,
30
+ private: true,
31
+ type: 'module',
32
+ };
33
+ writeFileSync(packageJsonPath, JSON.stringify(manifest, null, 2) + '\n');
34
+ return packageJsonPath;
35
+ }
36
+
13
37
  export async function runSetup() {
14
38
  console.log();
15
39
  p.intro(pc.bgGreen(pc.black(' Welcome to Obol! ')));
@@ -138,7 +162,7 @@ export async function runSetup() {
138
162
  }
139
163
 
140
164
  // --- Payment Mode ---
141
- let paymentMode = existingEnv.OBOL_PAYMENT_MODE || 'credits';
165
+ let paymentMode = preferredJsPaymentMode(existingEnv);
142
166
  let x402PrivateKey = existingEnv.OBOL_X402_PRIVATE_KEY || '';
143
167
  let walletAddress = existingEnv.OBOL_WALLET_ADDRESS || '';
144
168
 
@@ -217,7 +241,15 @@ export async function runSetup() {
217
241
  let jwt;
218
242
  let setupKey = existingEnv.OBOL_AGENT_ID === agentId ? existingEnv.OBOL_SETUP_KEY || '' : '';
219
243
  try {
220
- const result = await signup(url, agentId, services, referralCode?.trim() || undefined, setupKey);
244
+ const result = await signup(
245
+ url,
246
+ agentId,
247
+ services,
248
+ referralCode?.trim() || undefined,
249
+ setupKey,
250
+ paymentMode,
251
+ walletAddress || undefined,
252
+ );
221
253
  jwt = result.token;
222
254
  setupKey = result.setup_key || setupKey;
223
255
 
@@ -299,10 +331,23 @@ export async function runSetup() {
299
331
  // 4. Detect project type and install SDK
300
332
  let sdkInstalled = false;
301
333
  let integrationFile = null;
334
+ let projectReady = true;
302
335
 
303
- const hasPackageJson = existsSync(resolve(process.cwd(), 'package.json'));
336
+ let hasPackageJson = existsSync(resolve(process.cwd(), 'package.json'));
304
337
 
305
338
  if (lang === 'js') {
339
+ if (!hasPackageJson) {
340
+ s.start('Preparing this folder for JavaScript setup...');
341
+ try {
342
+ const packageJsonPath = ensureJsProjectManifest(agentId);
343
+ hasPackageJson = true;
344
+ s.stop(pc.green(`Created ${packageJsonPath}`));
345
+ } catch (err) {
346
+ projectReady = false;
347
+ s.stop(pc.yellow(`Could not create package.json automatically: ${err.message}`));
348
+ }
349
+ }
350
+
306
351
  if (hasPackageJson) {
307
352
  s.start('Installing @obol/sdk...');
308
353
  try {
@@ -310,19 +355,22 @@ export async function runSetup() {
310
355
  s.stop(pc.green('SDK installed! ') + cheer());
311
356
  sdkInstalled = true;
312
357
  } catch {
358
+ projectReady = false;
313
359
  s.stop(pc.yellow('Could not auto-install SDK. Run manually: npm install @obol/sdk'));
314
360
  }
315
- } else {
316
- p.log.info(`Install the SDK when you're ready: ${pc.green('npm install @obol/sdk')}`);
317
361
  }
318
362
 
319
363
  // Generate integration file
320
- const obolFile = resolve(process.cwd(), 'obol.js');
321
- if (!existsSync(obolFile)) {
322
- s.start('Generating integration file...');
323
- writeFileSync(obolFile, jsIntegrationFile(agentId, services, paymentMode));
324
- s.stop(pc.green('Created obol.js'));
325
- integrationFile = 'obol.js';
364
+ if (hasPackageJson) {
365
+ const obolFile = resolve(process.cwd(), 'obol.js');
366
+ if (!existsSync(obolFile)) {
367
+ s.start('Generating integration file...');
368
+ writeFileSync(obolFile, jsIntegrationFile(agentId, services, paymentMode));
369
+ s.stop(pc.green('Created obol.js'));
370
+ integrationFile = 'obol.js';
371
+ }
372
+ } else {
373
+ projectReady = false;
326
374
  }
327
375
  } else if (lang === 'python') {
328
376
  s.start('Installing the Obol Python SDK from GitHub...');
@@ -366,7 +414,7 @@ export async function runSetup() {
366
414
 
367
415
  // --- Summary ---
368
416
  console.log();
369
- p.log.success(pc.bold(`Your agent is connected to Obol!`));
417
+ p.log.success(pc.bold(projectReady ? 'Your agent is connected to Obol!' : 'Your Obol account is ready.'));
370
418
  console.log();
371
419
 
372
420
  if (sdkInstalled) {
@@ -377,6 +425,9 @@ export async function runSetup() {
377
425
  }
378
426
  console.log(` ${pc.dim('Config saved:')} ${pc.green(envPath)}`);
379
427
  console.log(` ${pc.dim('Payment mode:')} ${pc.green(paymentMode === 'x402' ? 'Automatic USDC (x402)' : 'Credits via Stripe')}`);
428
+ if (lang === 'js' && !sdkInstalled) {
429
+ console.log(` ${pc.dim('Project status:')} ${pc.yellow('Install @obol/sdk before importing obol.js')}`);
430
+ }
380
431
  if (paymentMode === 'x402') {
381
432
  if (walletAddress) {
382
433
  console.log(` ${pc.dim('Wallet:')} ${pc.green(walletAddress)}`);
@@ -393,7 +444,7 @@ export async function runSetup() {
393
444
  } else {
394
445
  p.log.warn(pc.bold(pc.yellow('Your balance is $0.00 — buy credits before your agent can execute.')));
395
446
  console.log();
396
- console.log(` ${pc.dim('1.')} ${pc.bold('Buy credits')} ${pc.dim('(required)')}: ${pc.green('npx @obol/cli credits buy')}`);
447
+ console.log(` ${pc.dim('1.')} ${pc.bold('Buy credits')} ${pc.dim('(required)')}: ${pc.green('npx -y -p @obol/cli obol credits buy')}`);
397
448
  console.log(` ${pc.dim('or visit:')} ${pc.cyan('obolagents.com/dashboard')}`);
398
449
  console.log(` ${pc.dim('2.')} ${pc.bold('Run your agent')}: Obol will draw from your credit balance automatically.`);
399
450
  }
@@ -407,12 +458,12 @@ export async function runSetup() {
407
458
  console.log(` ${pc.cyan("result = obol.execute(2, 'Create issue ...', idempotency_key='...')")}`);
408
459
  }
409
460
  console.log();
410
- console.log(` ${pc.dim('Dashboard:')} ${pc.green('npx @obol/cli token')} → paste at ${pc.cyan('obolagents.com/dashboard')}`);
411
- console.log(` ${pc.dim('Token:')} Refreshes automatically — run ${pc.green('npx @obol/cli test')} anytime to verify.`);
461
+ console.log(` ${pc.dim('Dashboard:')} ${pc.green('npx -y -p @obol/cli obol token')} → paste at ${pc.cyan('obolagents.com/dashboard')}`);
462
+ console.log(` ${pc.dim('Token:')} Refreshes automatically — run ${pc.green('npx -y -p @obol/cli obol test')} anytime to verify.`);
412
463
  console.log(` ${pc.dim('Setup key:')} Saved in ${pc.green('.env')} so you can safely reconnect this account later.`);
413
464
  console.log();
414
465
 
415
- p.log.info(`${pc.bold('Earn credits by referring other agents!')} Run ${pc.green('npx @obol/cli referral code')} to get started.`);
466
+ p.log.info(`${pc.bold('Earn credits by referring other agents!')} Run ${pc.green('npx -y -p @obol/cli obol referral code')} to get started.`);
416
467
  console.log();
417
468
 
418
469
  p.outro('Go build something awesome. ' + pc.green('⚡'));
package/src/status.js CHANGED
@@ -9,7 +9,7 @@ export async function runStatus() {
9
9
  if (!env.OBOL_GATEWAY_URL || !env.OBOL_AGENT_ID) {
10
10
  console.log();
11
11
  p.log.warn('No agent configured yet.');
12
- p.log.info(`Run ${pc.green('npx @obol/cli setup')} to get started.`);
12
+ p.log.info(`Run ${pc.green('npx -y -p @obol/cli obol setup')} to get started.`);
13
13
  console.log();
14
14
  return;
15
15
  }
@@ -48,7 +48,7 @@ export async function runStatus() {
48
48
  const conns = data.connections || data || [];
49
49
  if (conns.length === 0) {
50
50
  s.stop(pc.dim('No services connected yet'));
51
- p.log.info(`Add one with ${pc.green('npx @obol/cli connect github')}`);
51
+ p.log.info(`Add one with ${pc.green('npx -y -p @obol/cli obol connect github')}`);
52
52
  } else {
53
53
  const names = conns.map(c => pc.green(c.provider)).join(', ');
54
54
  s.stop(`${pc.bold('Services:')} ${names} (${conns.length} connected)`);
@@ -0,0 +1,40 @@
1
+ import test from 'node:test';
2
+ import assert from 'node:assert/strict';
3
+ import { existsSync, mkdtempSync, readFileSync, rmSync, writeFileSync } from 'node:fs';
4
+ import { tmpdir } from 'node:os';
5
+ import { join } from 'node:path';
6
+
7
+ import { ensureJsProjectManifest, preferredJsPaymentMode } from '../src/setup.js';
8
+
9
+ test('preferredJsPaymentMode defaults to x402 for fresh JS onboarding', () => {
10
+ assert.equal(preferredJsPaymentMode({}), 'x402');
11
+ assert.equal(preferredJsPaymentMode({ OBOL_PAYMENT_MODE: 'credits' }), 'credits');
12
+ assert.equal(preferredJsPaymentMode({ OBOL_PAYMENT_MODE: 'x402' }), 'x402');
13
+ });
14
+
15
+ test('ensureJsProjectManifest creates a runnable package.json when missing', () => {
16
+ const dir = mkdtempSync(join(tmpdir(), 'obol-setup-helper-'));
17
+ try {
18
+ const packageJsonPath = ensureJsProjectManifest('agent-123', dir);
19
+ assert.equal(existsSync(packageJsonPath), true);
20
+ const manifest = JSON.parse(readFileSync(packageJsonPath, 'utf8'));
21
+ assert.equal(manifest.private, true);
22
+ assert.equal(manifest.type, 'module');
23
+ assert.ok(manifest.name);
24
+ } finally {
25
+ rmSync(dir, { recursive: true, force: true });
26
+ }
27
+ });
28
+
29
+ test('ensureJsProjectManifest preserves an existing package.json', () => {
30
+ const dir = mkdtempSync(join(tmpdir(), 'obol-setup-helper-existing-'));
31
+ const packageJsonPath = join(dir, 'package.json');
32
+ try {
33
+ writeFileSync(packageJsonPath, '{"name":"already-here","private":true}\n');
34
+ const returnedPath = ensureJsProjectManifest('agent-456', dir);
35
+ assert.equal(returnedPath, packageJsonPath);
36
+ assert.equal(readFileSync(packageJsonPath, 'utf8'), '{"name":"already-here","private":true}\n');
37
+ } finally {
38
+ rmSync(dir, { recursive: true, force: true });
39
+ }
40
+ });