@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 +5 -5
- package/package.json +1 -1
- package/src/api.js +3 -1
- package/src/connect.js +1 -1
- package/src/credits.js +1 -1
- package/src/setup.js +68 -17
- package/src/status.js +2 -2
- package/test/setup_helpers.test.mjs +40 -0
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
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
|
|
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(
|
|
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
|
-
|
|
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
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
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(
|
|
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
|
+
});
|