@agent-hive/cli 0.1.4 → 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.
Files changed (2) hide show
  1. package/dist/hive.js +67 -18
  2. package/package.json +1 -1
package/dist/hive.js CHANGED
@@ -368,7 +368,7 @@ program
368
368
  });
369
369
  program
370
370
  .command('submit <task-id> <file>')
371
- .description('Submit work for a task')
371
+ .description('Submit work for a task (supports text and binary files like PDFs)')
372
372
  .action(async (taskId, file) => {
373
373
  const creds = getCredentials();
374
374
  if (!creds) {
@@ -379,34 +379,83 @@ program
379
379
  console.error(JSON.stringify({ error: `File not found: ${file}` }));
380
380
  process.exit(1);
381
381
  }
382
- const content = readFileSync(file, 'utf-8');
383
382
  const apiUrl = getApiUrl();
384
- // 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);
385
386
  const crypto = await import('crypto');
386
- const contentHash = crypto.createHash('md5').update(content).digest('hex').slice(0, 8);
387
- const idempotencyKey = `${taskId}-${contentHash}`;
388
387
  try {
389
- const res = await fetch(`${apiUrl}/tasks/${taskId}/submissions`, {
390
- method: 'POST',
391
- headers: {
392
- 'X-Hive-Api-Key': creds.api_key,
393
- 'Content-Type': 'application/json',
394
- },
395
- body: JSON.stringify({
396
- output: { content, content_type: 'text/plain' },
397
- idempotency_key: idempotencyKey,
398
- }),
399
- });
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
+ }
400
449
  if (!res.ok) {
401
450
  const data = await res.json();
402
- console.error(JSON.stringify({ error: data.error || 'Submission failed' }));
451
+ console.error(JSON.stringify({ error: data.error || 'Submission failed', hint: data.hint }));
403
452
  process.exit(1);
404
453
  }
405
454
  const data = await res.json();
406
455
  console.log(JSON.stringify(data, null, 2));
407
456
  }
408
457
  catch (err) {
409
- console.error(JSON.stringify({ error: 'Failed to submit work' }));
458
+ console.error(JSON.stringify({ error: 'Failed to submit work', details: String(err) }));
410
459
  process.exit(1);
411
460
  }
412
461
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agent-hive/cli",
3
- "version": "0.1.4",
3
+ "version": "0.1.5",
4
4
  "description": "CLI tools for Hive marketplace agents",
5
5
  "type": "module",
6
6
  "bin": {