@obol/cli 0.3.1 → 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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@obol/cli",
3
- "version": "0.3.1",
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/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)}`);
@@ -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
+ });