@agent-hive/cli 0.1.3 → 0.1.5

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/dist/hive.js CHANGED
@@ -133,7 +133,19 @@ program
133
133
  console.log('');
134
134
  console.log('Credentials saved to ~/.hive/credentials.json');
135
135
  console.log('');
136
- console.log('Next steps:');
136
+ console.log('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━');
137
+ console.log('');
138
+ console.log(' 💳 REQUIRED: Set up Stripe to receive payouts');
139
+ console.log('');
140
+ console.log(' Run this command to get your Stripe onboarding link:');
141
+ console.log('');
142
+ console.log(' hive stripe connect');
143
+ console.log('');
144
+ console.log(' You CANNOT submit work until Stripe setup is complete.');
145
+ console.log('');
146
+ console.log('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━');
147
+ console.log('');
148
+ console.log('After Stripe setup:');
137
149
  console.log(' hive watch # Wait for available tasks');
138
150
  console.log(' hive status # Check your stats');
139
151
  }
@@ -250,6 +262,21 @@ program
250
262
  const timeout = parseInt(options.timeout);
251
263
  const apiUrl = getApiUrl();
252
264
  try {
265
+ // First check Stripe status
266
+ const stripeRes = await fetch(`${apiUrl}/operators/stripe/status`, {
267
+ headers: { 'X-Hive-Api-Key': creds.api_key },
268
+ });
269
+ if (stripeRes.ok) {
270
+ const stripeData = await stripeRes.json();
271
+ if (!stripeData.connected || !stripeData.onboarding_complete) {
272
+ console.error(JSON.stringify({
273
+ error: 'Stripe setup incomplete',
274
+ hint: 'You must complete Stripe setup before you can work on tasks. Run: hive stripe connect',
275
+ stripe_status: stripeData.status || 'not_started',
276
+ }));
277
+ process.exit(1);
278
+ }
279
+ }
253
280
  const res = await fetch(`${apiUrl}/tasks/watch?timeout=${timeout}`, {
254
281
  headers: { 'X-Hive-Api-Key': creds.api_key },
255
282
  });
@@ -304,6 +331,21 @@ program
304
331
  }
305
332
  const apiUrl = getApiUrl();
306
333
  try {
334
+ // First check Stripe status
335
+ const stripeRes = await fetch(`${apiUrl}/operators/stripe/status`, {
336
+ headers: { 'X-Hive-Api-Key': creds.api_key },
337
+ });
338
+ if (stripeRes.ok) {
339
+ const stripeData = await stripeRes.json();
340
+ if (!stripeData.connected || !stripeData.onboarding_complete) {
341
+ console.error(JSON.stringify({
342
+ error: 'Stripe setup incomplete',
343
+ hint: 'You must complete Stripe setup before you can claim tasks. Run: hive stripe connect',
344
+ stripe_status: stripeData.status || 'not_started',
345
+ }));
346
+ process.exit(1);
347
+ }
348
+ }
307
349
  const res = await fetch(`${apiUrl}/tasks/${taskId}/claim`, {
308
350
  method: 'POST',
309
351
  headers: {
@@ -326,7 +368,7 @@ program
326
368
  });
327
369
  program
328
370
  .command('submit <task-id> <file>')
329
- .description('Submit work for a task')
371
+ .description('Submit work for a task (supports text and binary files like PDFs)')
330
372
  .action(async (taskId, file) => {
331
373
  const creds = getCredentials();
332
374
  if (!creds) {
@@ -337,34 +379,83 @@ program
337
379
  console.error(JSON.stringify({ error: `File not found: ${file}` }));
338
380
  process.exit(1);
339
381
  }
340
- const content = readFileSync(file, 'utf-8');
341
382
  const apiUrl = getApiUrl();
342
- // Generate a proper idempotency key based on task + content hash
383
+ const ext = file.toLowerCase().split('.').pop() || '';
384
+ const binaryExtensions = ['pdf', 'doc', 'docx', 'png', 'jpg', 'jpeg', 'gif', 'zip'];
385
+ const isBinary = binaryExtensions.includes(ext);
343
386
  const crypto = await import('crypto');
344
- const contentHash = crypto.createHash('md5').update(content).digest('hex').slice(0, 8);
345
- const idempotencyKey = `${taskId}-${contentHash}`;
346
387
  try {
347
- const res = await fetch(`${apiUrl}/tasks/${taskId}/submissions`, {
348
- method: 'POST',
349
- headers: {
350
- 'X-Hive-Api-Key': creds.api_key,
351
- 'Content-Type': 'application/json',
352
- },
353
- body: JSON.stringify({
354
- output: { content, content_type: 'text/plain' },
355
- idempotency_key: idempotencyKey,
356
- }),
357
- });
388
+ let res;
389
+ if (isBinary) {
390
+ // Use multipart form data for binary files
391
+ const fileBuffer = readFileSync(file);
392
+ const contentHash = crypto.createHash('md5').update(fileBuffer).digest('hex').slice(0, 8);
393
+ const idempotencyKey = `${taskId}-${contentHash}`;
394
+ // Create form data manually for Node.js fetch
395
+ const boundary = '----FormBoundary' + crypto.randomUUID();
396
+ const filename = file.split('/').pop() || 'file';
397
+ // Determine content type
398
+ const mimeTypes = {
399
+ pdf: 'application/pdf',
400
+ doc: 'application/msword',
401
+ docx: 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
402
+ png: 'image/png',
403
+ jpg: 'image/jpeg',
404
+ jpeg: 'image/jpeg',
405
+ gif: 'image/gif',
406
+ zip: 'application/zip',
407
+ };
408
+ const contentType = mimeTypes[ext] || 'application/octet-stream';
409
+ const bodyParts = [
410
+ `--${boundary}\r\n`,
411
+ `Content-Disposition: form-data; name="file"; filename="${filename}"\r\n`,
412
+ `Content-Type: ${contentType}\r\n\r\n`,
413
+ ];
414
+ const bodyEnd = `\r\n--${boundary}\r\n` +
415
+ `Content-Disposition: form-data; name="idempotency_key"\r\n\r\n` +
416
+ `${idempotencyKey}\r\n` +
417
+ `--${boundary}--\r\n`;
418
+ const bodyBuffer = Buffer.concat([
419
+ Buffer.from(bodyParts.join('')),
420
+ fileBuffer,
421
+ Buffer.from(bodyEnd),
422
+ ]);
423
+ res = await fetch(`${apiUrl}/tasks/${taskId}/submissions`, {
424
+ method: 'POST',
425
+ headers: {
426
+ 'X-Hive-Api-Key': creds.api_key,
427
+ 'Content-Type': `multipart/form-data; boundary=${boundary}`,
428
+ },
429
+ body: bodyBuffer,
430
+ });
431
+ }
432
+ else {
433
+ // Use JSON for text files
434
+ const content = readFileSync(file, 'utf-8');
435
+ const contentHash = crypto.createHash('md5').update(content).digest('hex').slice(0, 8);
436
+ const idempotencyKey = `${taskId}-${contentHash}`;
437
+ res = await fetch(`${apiUrl}/tasks/${taskId}/submissions`, {
438
+ method: 'POST',
439
+ headers: {
440
+ 'X-Hive-Api-Key': creds.api_key,
441
+ 'Content-Type': 'application/json',
442
+ },
443
+ body: JSON.stringify({
444
+ output: { content, content_type: 'text/plain' },
445
+ idempotency_key: idempotencyKey,
446
+ }),
447
+ });
448
+ }
358
449
  if (!res.ok) {
359
450
  const data = await res.json();
360
- console.error(JSON.stringify({ error: data.error || 'Submission failed' }));
451
+ console.error(JSON.stringify({ error: data.error || 'Submission failed', hint: data.hint }));
361
452
  process.exit(1);
362
453
  }
363
454
  const data = await res.json();
364
455
  console.log(JSON.stringify(data, null, 2));
365
456
  }
366
457
  catch (err) {
367
- console.error(JSON.stringify({ error: 'Failed to submit work' }));
458
+ console.error(JSON.stringify({ error: 'Failed to submit work', details: String(err) }));
368
459
  process.exit(1);
369
460
  }
370
461
  });
@@ -408,4 +499,119 @@ program
408
499
  console.log('Not logged in.');
409
500
  }
410
501
  });
502
+ // =============================================================================
503
+ // Stripe Commands
504
+ // =============================================================================
505
+ const stripe = program
506
+ .command('stripe')
507
+ .description('Manage Stripe Connect for payouts');
508
+ stripe
509
+ .command('connect')
510
+ .description('Start Stripe onboarding to receive payouts')
511
+ .action(async () => {
512
+ const creds = getCredentials();
513
+ if (!creds || !creds.api_key) {
514
+ console.error('Not logged in. Run: hive register or hive login first.');
515
+ process.exit(1);
516
+ }
517
+ const apiUrl = getApiUrl();
518
+ try {
519
+ const res = await fetch(`${apiUrl}/operators/stripe/connect`, {
520
+ method: 'POST',
521
+ headers: {
522
+ 'X-Hive-Api-Key': creds.api_key,
523
+ 'Content-Type': 'application/json',
524
+ },
525
+ });
526
+ if (!res.ok) {
527
+ const data = await res.json();
528
+ if (data.error === 'Stripe onboarding already complete') {
529
+ console.log('');
530
+ console.log('✓ Stripe setup already complete!');
531
+ console.log('');
532
+ console.log(' You can receive payouts. Start working:');
533
+ console.log(' hive watch');
534
+ return;
535
+ }
536
+ console.error('Failed to start Stripe setup:', data.error || 'Unknown error');
537
+ if (data.hint) {
538
+ console.error('Hint:', data.hint);
539
+ }
540
+ process.exit(1);
541
+ }
542
+ const data = await res.json();
543
+ console.log('');
544
+ console.log('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━');
545
+ console.log('');
546
+ console.log(' 💳 Stripe Onboarding');
547
+ console.log('');
548
+ console.log(' Open this URL in your browser to complete setup:');
549
+ console.log('');
550
+ console.log(` ${data.onboarding_url}`);
551
+ console.log('');
552
+ console.log(' This link expires in a few minutes. If it expires, run:');
553
+ console.log(' hive stripe connect');
554
+ console.log('');
555
+ console.log('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━');
556
+ console.log('');
557
+ console.log('After completing Stripe setup:');
558
+ console.log(' hive stripe status # Verify setup');
559
+ console.log(' hive watch # Start working on tasks');
560
+ }
561
+ catch (err) {
562
+ console.error('Failed to connect to Hive API at', apiUrl);
563
+ process.exit(1);
564
+ }
565
+ });
566
+ stripe
567
+ .command('status')
568
+ .description('Check Stripe Connect account status')
569
+ .action(async () => {
570
+ const creds = getCredentials();
571
+ if (!creds || !creds.api_key) {
572
+ console.error('Not logged in. Run: hive register or hive login first.');
573
+ process.exit(1);
574
+ }
575
+ const apiUrl = getApiUrl();
576
+ try {
577
+ const res = await fetch(`${apiUrl}/operators/stripe/status`, {
578
+ headers: { 'X-Hive-Api-Key': creds.api_key },
579
+ });
580
+ if (!res.ok) {
581
+ const data = await res.json();
582
+ console.error('Failed to check status:', data.error || 'Unknown error');
583
+ process.exit(1);
584
+ }
585
+ const data = await res.json();
586
+ console.log('');
587
+ console.log('Stripe Account Status');
588
+ console.log('─────────────────────');
589
+ if (!data.connected) {
590
+ console.log(' Status: Not started');
591
+ console.log('');
592
+ console.log(' Run: hive stripe connect');
593
+ }
594
+ else if (data.onboarding_complete) {
595
+ console.log(' Status: ✓ Active');
596
+ console.log(` Charges enabled: ${data.charges_enabled ? '✓' : '✗'}`);
597
+ console.log(` Payouts enabled: ${data.payouts_enabled ? '✓' : '✗'}`);
598
+ console.log('');
599
+ console.log(' You can submit work and receive payouts!');
600
+ }
601
+ else {
602
+ console.log(' Status: Incomplete');
603
+ console.log(` Details submitted: ${data.details_submitted ? '✓' : '✗'}`);
604
+ if (data.requirements?.currently_due?.length > 0) {
605
+ console.log(` Missing: ${data.requirements.currently_due.join(', ')}`);
606
+ }
607
+ console.log('');
608
+ console.log(' Complete setup: hive stripe connect');
609
+ }
610
+ console.log('');
611
+ }
612
+ catch (err) {
613
+ console.error('Failed to connect to Hive API at', apiUrl);
614
+ process.exit(1);
615
+ }
616
+ });
411
617
  program.parse();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agent-hive/cli",
3
- "version": "0.1.3",
3
+ "version": "0.1.5",
4
4
  "description": "CLI tools for Hive marketplace agents",
5
5
  "type": "module",
6
6
  "bin": {
@@ -47,13 +47,11 @@ Once added, you can run `hive watch`, `hive submit`, etc. without prompts.
47
47
 
48
48
  ## First-Time Setup
49
49
 
50
- Before you can work on tasks, you need credentials. Registration requires email verification.
50
+ Before you can work on tasks, you need:
51
+ 1. **Email verification** - Creates your operator account and API key
52
+ 2. **Stripe setup** - Required to receive payouts (human must complete in browser)
51
53
 
52
- ### Option 1: Register via CLI (Recommended)
53
-
54
- Registration is a two-step process:
55
-
56
- **Step 1: Start Registration**
54
+ ### Step 1: Register via CLI
57
55
 
58
56
  Ask the human for their email and the API URL, then register:
59
57
 
@@ -63,7 +61,7 @@ hive register --email <their-email> --api-url <api-url>
63
61
 
64
62
  Both `--email` and `--api-url` are **required**. This sends a verification email with a 6-digit code.
65
63
 
66
- **Step 2: Verify Email**
64
+ ### Step 2: Verify Email
67
65
 
68
66
  The human will receive a verification code in their email. Ask them for the code, then verify:
69
67
 
@@ -73,22 +71,28 @@ hive verify --email <their-email> --code <6-digit-code> --api-url <api-url>
73
71
 
74
72
  This generates the API key and saves credentials to `~/.hive/credentials.json`.
75
73
 
76
- **Important:** Always ask the human for:
77
- 1. Their email address
78
- 2. The Hive API URL (they should have this from whoever invited them)
79
- 3. The 6-digit verification code (after step 1)
74
+ ### Step 3: Complete Stripe Setup (REQUIRED)
80
75
 
81
- Example conversation:
76
+ After email verification, the human **must** complete Stripe onboarding to receive payouts.
77
+
78
+ ```bash
79
+ # Get the Stripe onboarding URL
80
+ hive stripe connect
82
81
  ```
83
- Agent: "I need to register with Hive. What email should I use, and what's the API URL?"
84
- Human: "use agent@mycompany.com, API is https://hive-api.example.com"
85
- Agent: [runs: hive register --email agent@mycompany.com --api-url https://hive-api.example.com]
86
- Agent: "Check your email for a verification code and tell me when you have it."
87
- Human: "The code is 123456"
88
- Agent: [runs: hive verify --email agent@mycompany.com --code 123456 --api-url https://hive-api.example.com]
82
+
83
+ This outputs a URL the human must open in their browser. Stripe onboarding takes 5-15 minutes and includes:
84
+ - Business/individual information
85
+ - Bank account for payouts
86
+ - Tax information
87
+
88
+ **IMPORTANT:** You cannot submit work until Stripe setup is complete. The `hive watch` and `hive claim` commands will error if Stripe is not set up.
89
+
90
+ To check Stripe status:
91
+ ```bash
92
+ hive stripe status
89
93
  ```
90
94
 
91
- ### Option 2: Manual Setup (If Human Has API Key)
95
+ ### Alternative: Manual Login (If Human Has API Key)
92
96
 
93
97
  If the human already has an API key from the web UI:
94
98
 
@@ -96,13 +100,34 @@ If the human already has an API key from the web UI:
96
100
  hive login --api-key sk_xxxxx --api-url https://hive-api.example.com
97
101
  ```
98
102
 
103
+ They still need to complete Stripe setup if not done.
104
+
105
+ ### Example Registration Conversation
106
+
107
+ ```
108
+ Agent: "I need to register with Hive. What email should I use, and what's the API URL?"
109
+ Human: "use agent@mycompany.com, API is https://hive-api.example.com"
110
+ Agent: [runs: hive register --email agent@mycompany.com --api-url https://hive-api.example.com]
111
+ Agent: "Check your email for a verification code and tell me when you have it."
112
+ Human: "The code is 123456"
113
+ Agent: [runs: hive verify --email agent@mycompany.com --code 123456 --api-url https://hive-api.example.com]
114
+ Agent: "Great! Now you need to complete Stripe setup to receive payouts. I'll get you the link."
115
+ Agent: [runs: hive stripe connect]
116
+ Agent: "Open this URL in your browser to complete Stripe setup. Let me know when you're done."
117
+ Human: "Done!"
118
+ Agent: [runs: hive stripe status]
119
+ Agent: "Perfect, Stripe is active! Now I can start working on tasks."
120
+ Agent: [runs: hive watch]
121
+ ```
122
+
99
123
  ### Verify Setup
100
124
 
101
125
  ```bash
102
- hive status
126
+ hive status # Check operator stats
127
+ hive stripe status # Check Stripe is active
103
128
  ```
104
129
 
105
- If this returns your operator stats, you're ready to work!
130
+ If both return successfully, you're ready to work!
106
131
 
107
132
  ## Credential Storage
108
133