@gopherhole/cli 0.1.2 → 0.1.4

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/README.md CHANGED
@@ -68,7 +68,7 @@ The CLI stores configuration in:
68
68
 
69
69
  - Website: https://gopherhole.ai
70
70
  - Dashboard: https://gopherhole.ai/dashboard
71
- - Docs: https://gopherhole.ai/docs
71
+ - Docs: https://docs.gopherhole.ai
72
72
  - GitHub: https://github.com/gopherhole
73
73
 
74
74
  ## License
package/dist/index.js CHANGED
@@ -18,6 +18,29 @@ const brand = {
18
18
  greenBright: chalk_1.default.hex('#4ade80'), // gopher-400 - highlights
19
19
  greenDark: chalk_1.default.hex('#16a34a'), // gopher-600 - emphasis
20
20
  };
21
+ // Version
22
+ const VERSION = '0.1.3';
23
+ // ASCII art banner
24
+ function showBanner(context) {
25
+ const gopher = [
26
+ ' ▄███▄',
27
+ ' █ ◕ ◕ █',
28
+ ' █ ┬┬ █',
29
+ ' ▀███▀',
30
+ ];
31
+ const info = [
32
+ `${brand.green('GopherHole')} ${chalk_1.default.gray(`v${VERSION}`)}`,
33
+ `${chalk_1.default.gray('Agent Hub • gopherhole.ai')}`,
34
+ context ? chalk_1.default.gray(context) : '',
35
+ ].filter(Boolean);
36
+ // Print side by side
37
+ const maxGopherWidth = Math.max(...gopher.map(l => l.length));
38
+ gopher.forEach((line, i) => {
39
+ const padded = line.padEnd(maxGopherWidth + 3);
40
+ console.log(brand.greenBright(padded) + (info[i] || ''));
41
+ });
42
+ console.log('');
43
+ }
21
44
  // Global verbose flag
22
45
  let verbose = false;
23
46
  function log(...args) {
@@ -46,7 +69,7 @@ ${chalk_1.default.bold('Examples:')}
46
69
  $ gopherhole agents list
47
70
 
48
71
  ${chalk_1.default.bold('Documentation:')}
49
- https://gopherhole.ai/docs
72
+ https://docs.gopherhole.ai
50
73
  `)
51
74
  .version('0.1.0')
52
75
  .option('-v, --verbose', 'Enable verbose output for debugging')
@@ -73,7 +96,8 @@ ${chalk_1.default.bold('Example:')}
73
96
  $ gopherhole quickstart
74
97
  `)
75
98
  .action(async () => {
76
- console.log(chalk_1.default.bold('\n🐿️ Welcome to GopherHole!\n'));
99
+ console.log('');
100
+ showBanner();
77
101
  console.log('This wizard will help you set up your first agent.\n');
78
102
  let sessionId = config.get('sessionId');
79
103
  // Step 1: Auth
@@ -296,7 +320,7 @@ ${chalk_1.default.bold('Example:')}
296
320
  }
297
321
  console.log(chalk_1.default.bold('\n📚 Next steps:\n'));
298
322
  console.log(` • Dashboard: ${chalk_1.default.cyan('https://gopherhole.ai/dashboard')}`);
299
- console.log(` • Docs: ${chalk_1.default.cyan('https://gopherhole.ai/docs')}`);
323
+ console.log(` • Docs: ${chalk_1.default.cyan('https://docs.gopherhole.ai')}`);
300
324
  console.log(` • Find agents: ${chalk_1.default.cyan('gopherhole discover search')}`);
301
325
  console.log(` • List yours: ${chalk_1.default.cyan('gopherhole agents list')}`);
302
326
  console.log('');
@@ -529,7 +553,7 @@ ${chalk_1.default.bold('Examples:')}
529
553
  console.log(chalk_1.default.bold('\n Quick test:'));
530
554
  console.log(chalk_1.default.white(` curl -H "Authorization: Bearer ${data.apiKey}" \\
531
555
  https://gopherhole.ai/a2a -d '{"jsonrpc":"2.0","method":"agent/info","id":1}'`));
532
- console.log(chalk_1.default.gray('\n Full docs: https://gopherhole.ai/docs'));
556
+ console.log(chalk_1.default.gray('\n Full docs: https://docs.gopherhole.ai'));
533
557
  console.log('');
534
558
  }
535
559
  catch (err) {
@@ -585,6 +609,124 @@ ${chalk_1.default.bold('Example:')}
585
609
  process.exit(1);
586
610
  }
587
611
  });
612
+ agents
613
+ .command('regenerate-key <agentId>')
614
+ .description(`Regenerate API key for an agent
615
+
616
+ ${chalk_1.default.bold('Example:')}
617
+ $ gopherhole agents regenerate-key agent-abc123
618
+
619
+ ${chalk_1.default.yellow('⚠️ Warning:')} This will invalidate the current key.
620
+ All connected agents using this key will stop working.
621
+ `)
622
+ .option('-f, --force', 'Skip confirmation')
623
+ .option('--json', 'Output as JSON')
624
+ .action(async (agentId, options) => {
625
+ const sessionId = config.get('sessionId');
626
+ if (!sessionId) {
627
+ console.log(chalk_1.default.yellow('Not logged in.'));
628
+ console.log(chalk_1.default.gray('Run: gopherhole login'));
629
+ process.exit(1);
630
+ }
631
+ if (!options.force) {
632
+ const { confirm } = await inquirer_1.default.prompt([
633
+ {
634
+ type: 'confirm',
635
+ name: 'confirm',
636
+ message: `Regenerate API key for ${chalk_1.default.cyan(agentId)}? This will invalidate the current key.`,
637
+ default: false,
638
+ },
639
+ ]);
640
+ if (!confirm) {
641
+ console.log('Cancelled.');
642
+ return;
643
+ }
644
+ }
645
+ const spinner = (0, ora_1.default)('Regenerating API key...').start();
646
+ log('POST /agents/' + agentId + '/regenerate-key');
647
+ try {
648
+ const res = await fetch(`${API_URL}/agents/${agentId}/regenerate-key`, {
649
+ method: 'POST',
650
+ headers: {
651
+ 'Content-Type': 'application/json',
652
+ 'X-Session-ID': sessionId,
653
+ },
654
+ body: JSON.stringify({}),
655
+ });
656
+ if (!res.ok) {
657
+ const err = await res.json();
658
+ logError('regenerate-key', err);
659
+ throw new Error(err.error || 'Failed to regenerate key');
660
+ }
661
+ const data = await res.json();
662
+ spinner.succeed('API key regenerated');
663
+ if (options.json) {
664
+ console.log(JSON.stringify({ apiKey: data.apiKey }, null, 2));
665
+ }
666
+ else {
667
+ console.log('');
668
+ console.log(chalk_1.default.bold('New API Key:'));
669
+ console.log(chalk_1.default.green(data.apiKey));
670
+ console.log('');
671
+ console.log(chalk_1.default.yellow('⚠️ Copy this key now — it won\'t be shown again!'));
672
+ }
673
+ }
674
+ catch (err) {
675
+ spinner.fail(chalk_1.default.red(err.message));
676
+ process.exit(1);
677
+ }
678
+ });
679
+ agents
680
+ .command('sync-card <agentId>')
681
+ .description(`Sync agent card from its /.well-known/agent.json URL
682
+
683
+ ${chalk_1.default.bold('What it does:')}
684
+ Fetches the agent card from the agent's URL and updates
685
+ the GopherHole registry. Use after updating your agent's
686
+ skills, description, or capabilities.
687
+
688
+ ${chalk_1.default.bold('Examples:')}
689
+ $ gopherhole agents sync-card agent-abc123
690
+ $ gopherhole agents sync-card my-agent
691
+ `)
692
+ .action(async (agentId) => {
693
+ const sessionId = config.get('sessionId');
694
+ if (!sessionId) {
695
+ console.log(chalk_1.default.yellow('Not logged in.'));
696
+ console.log(chalk_1.default.gray('Run: gopherhole login'));
697
+ process.exit(1);
698
+ }
699
+ const spinner = (0, ora_1.default)('Syncing agent card...').start();
700
+ log('POST /agents/' + agentId + '/sync-card');
701
+ try {
702
+ const res = await fetch(`${API_URL}/agents/${agentId}/sync-card`, {
703
+ method: 'POST',
704
+ headers: { 'X-Session-ID': sessionId },
705
+ });
706
+ if (!res.ok) {
707
+ const err = await res.json();
708
+ logError('sync-card', err);
709
+ throw new Error(err.error || 'Failed to sync card');
710
+ }
711
+ const data = await res.json();
712
+ spinner.succeed('Agent card synced!');
713
+ if (data.card) {
714
+ console.log(chalk_1.default.bold('\n Updated card:'));
715
+ console.log(` Name: ${brand.green(data.card.name)}`);
716
+ if (data.card.description) {
717
+ console.log(` Description: ${chalk_1.default.gray(data.card.description.slice(0, 60))}${data.card.description.length > 60 ? '...' : ''}`);
718
+ }
719
+ if (data.card.skills?.length) {
720
+ console.log(` Skills: ${data.card.skills.length} (${data.card.skills.map((s) => s.name).join(', ')})`);
721
+ }
722
+ console.log('');
723
+ }
724
+ }
725
+ catch (err) {
726
+ spinner.fail(chalk_1.default.red(err.message));
727
+ process.exit(1);
728
+ }
729
+ });
588
730
  // ========== INIT COMMAND ==========
589
731
  program
590
732
  .command('init')
@@ -600,7 +742,8 @@ ${chalk_1.default.bold('Example:')}
600
742
  $ gopherhole init
601
743
  `)
602
744
  .action(async () => {
603
- console.log(chalk_1.default.bold('\n🐿️ Initialize GopherHole Project\n'));
745
+ console.log('');
746
+ showBanner(process.cwd());
604
747
  let sessionId = config.get('sessionId');
605
748
  // Check if logged in
606
749
  if (!sessionId) {
@@ -748,7 +891,7 @@ main().catch(console.error);
748
891
  console.log(chalk_1.default.cyan(' npm start'));
749
892
  console.log('');
750
893
  console.log(chalk_1.default.gray(`Dashboard: https://gopherhole.ai/dashboard`));
751
- console.log(chalk_1.default.gray(`Docs: https://gopherhole.ai/docs`));
894
+ console.log(chalk_1.default.gray(`Docs: https://docs.gopherhole.ai`));
752
895
  console.log('');
753
896
  });
754
897
  // ========== SEND COMMAND ==========
@@ -1085,7 +1228,8 @@ program
1085
1228
  .command('status')
1086
1229
  .description('Show GopherHole service status and your session info')
1087
1230
  .action(async () => {
1088
- console.log(chalk_1.default.bold('\n🐿️ GopherHole Status\n'));
1231
+ console.log('');
1232
+ showBanner();
1089
1233
  // Check API health
1090
1234
  const spinner = (0, ora_1.default)('Checking API...').start();
1091
1235
  try {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gopherhole/cli",
3
- "version": "0.1.2",
3
+ "version": "0.1.4",
4
4
  "description": "GopherHole CLI - Connect AI agents to the world",
5
5
  "main": "dist/index.js",
6
6
  "bin": {
package/src/index.ts CHANGED
@@ -17,6 +17,33 @@ const brand = {
17
17
  greenDark: chalk.hex('#16a34a'), // gopher-600 - emphasis
18
18
  };
19
19
 
20
+ // Version
21
+ const VERSION = '0.1.3';
22
+
23
+ // ASCII art banner
24
+ function showBanner(context?: string) {
25
+ const gopher = [
26
+ ' ▄███▄',
27
+ ' █ ◕ ◕ █',
28
+ ' █ ┬┬ █',
29
+ ' ▀███▀',
30
+ ];
31
+
32
+ const info = [
33
+ `${brand.green('GopherHole')} ${chalk.gray(`v${VERSION}`)}`,
34
+ `${chalk.gray('Agent Hub • gopherhole.ai')}`,
35
+ context ? chalk.gray(context) : '',
36
+ ].filter(Boolean);
37
+
38
+ // Print side by side
39
+ const maxGopherWidth = Math.max(...gopher.map(l => l.length));
40
+ gopher.forEach((line, i) => {
41
+ const padded = line.padEnd(maxGopherWidth + 3);
42
+ console.log(brand.greenBright(padded) + (info[i] || ''));
43
+ });
44
+ console.log('');
45
+ }
46
+
20
47
  // Global verbose flag
21
48
  let verbose = false;
22
49
 
@@ -49,7 +76,7 @@ ${chalk.bold('Examples:')}
49
76
  $ gopherhole agents list
50
77
 
51
78
  ${chalk.bold('Documentation:')}
52
- https://gopherhole.ai/docs
79
+ https://docs.gopherhole.ai
53
80
  `)
54
81
  .version('0.1.0')
55
82
  .option('-v, --verbose', 'Enable verbose output for debugging')
@@ -78,7 +105,8 @@ ${chalk.bold('Example:')}
78
105
  $ gopherhole quickstart
79
106
  `)
80
107
  .action(async () => {
81
- console.log(chalk.bold('\n🐿️ Welcome to GopherHole!\n'));
108
+ console.log('');
109
+ showBanner();
82
110
  console.log('This wizard will help you set up your first agent.\n');
83
111
 
84
112
  let sessionId = config.get('sessionId') as string;
@@ -321,7 +349,7 @@ ${chalk.bold('Example:')}
321
349
 
322
350
  console.log(chalk.bold('\n📚 Next steps:\n'));
323
351
  console.log(` • Dashboard: ${chalk.cyan('https://gopherhole.ai/dashboard')}`);
324
- console.log(` • Docs: ${chalk.cyan('https://gopherhole.ai/docs')}`);
352
+ console.log(` • Docs: ${chalk.cyan('https://docs.gopherhole.ai')}`);
325
353
  console.log(` • Find agents: ${chalk.cyan('gopherhole discover search')}`);
326
354
  console.log(` • List yours: ${chalk.cyan('gopherhole agents list')}`);
327
355
  console.log('');
@@ -590,7 +618,7 @@ ${chalk.bold('Examples:')}
590
618
  console.log(chalk.white(` curl -H "Authorization: Bearer ${data.apiKey}" \\
591
619
  https://gopherhole.ai/a2a -d '{"jsonrpc":"2.0","method":"agent/info","id":1}'`));
592
620
 
593
- console.log(chalk.gray('\n Full docs: https://gopherhole.ai/docs'));
621
+ console.log(chalk.gray('\n Full docs: https://docs.gopherhole.ai'));
594
622
  console.log('');
595
623
  } catch (err) {
596
624
  spinner.fail(chalk.red((err as Error).message));
@@ -652,6 +680,135 @@ ${chalk.bold('Example:')}
652
680
  }
653
681
  });
654
682
 
683
+ agents
684
+ .command('regenerate-key <agentId>')
685
+ .description(`Regenerate API key for an agent
686
+
687
+ ${chalk.bold('Example:')}
688
+ $ gopherhole agents regenerate-key agent-abc123
689
+
690
+ ${chalk.yellow('⚠️ Warning:')} This will invalidate the current key.
691
+ All connected agents using this key will stop working.
692
+ `)
693
+ .option('-f, --force', 'Skip confirmation')
694
+ .option('--json', 'Output as JSON')
695
+ .action(async (agentId, options) => {
696
+ const sessionId = config.get('sessionId') as string;
697
+ if (!sessionId) {
698
+ console.log(chalk.yellow('Not logged in.'));
699
+ console.log(chalk.gray('Run: gopherhole login'));
700
+ process.exit(1);
701
+ }
702
+
703
+ if (!options.force) {
704
+ const { confirm } = await inquirer.prompt([
705
+ {
706
+ type: 'confirm',
707
+ name: 'confirm',
708
+ message: `Regenerate API key for ${chalk.cyan(agentId)}? This will invalidate the current key.`,
709
+ default: false,
710
+ },
711
+ ]);
712
+
713
+ if (!confirm) {
714
+ console.log('Cancelled.');
715
+ return;
716
+ }
717
+ }
718
+
719
+ const spinner = ora('Regenerating API key...').start();
720
+ log('POST /agents/' + agentId + '/regenerate-key');
721
+
722
+ try {
723
+ const res = await fetch(`${API_URL}/agents/${agentId}/regenerate-key`, {
724
+ method: 'POST',
725
+ headers: {
726
+ 'Content-Type': 'application/json',
727
+ 'X-Session-ID': sessionId,
728
+ },
729
+ body: JSON.stringify({}),
730
+ });
731
+
732
+ if (!res.ok) {
733
+ const err = await res.json();
734
+ logError('regenerate-key', err);
735
+ throw new Error(err.error || 'Failed to regenerate key');
736
+ }
737
+
738
+ const data = await res.json();
739
+ spinner.succeed('API key regenerated');
740
+
741
+ if (options.json) {
742
+ console.log(JSON.stringify({ apiKey: data.apiKey }, null, 2));
743
+ } else {
744
+ console.log('');
745
+ console.log(chalk.bold('New API Key:'));
746
+ console.log(chalk.green(data.apiKey));
747
+ console.log('');
748
+ console.log(chalk.yellow('⚠️ Copy this key now — it won\'t be shown again!'));
749
+ }
750
+ } catch (err) {
751
+ spinner.fail(chalk.red((err as Error).message));
752
+ process.exit(1);
753
+ }
754
+ });
755
+
756
+ agents
757
+ .command('sync-card <agentId>')
758
+ .description(`Sync agent card from its /.well-known/agent.json URL
759
+
760
+ ${chalk.bold('What it does:')}
761
+ Fetches the agent card from the agent's URL and updates
762
+ the GopherHole registry. Use after updating your agent's
763
+ skills, description, or capabilities.
764
+
765
+ ${chalk.bold('Examples:')}
766
+ $ gopherhole agents sync-card agent-abc123
767
+ $ gopherhole agents sync-card my-agent
768
+ `)
769
+ .action(async (agentId) => {
770
+ const sessionId = config.get('sessionId') as string;
771
+ if (!sessionId) {
772
+ console.log(chalk.yellow('Not logged in.'));
773
+ console.log(chalk.gray('Run: gopherhole login'));
774
+ process.exit(1);
775
+ }
776
+
777
+ const spinner = ora('Syncing agent card...').start();
778
+ log('POST /agents/' + agentId + '/sync-card');
779
+
780
+ try {
781
+ const res = await fetch(`${API_URL}/agents/${agentId}/sync-card`, {
782
+ method: 'POST',
783
+ headers: { 'X-Session-ID': sessionId },
784
+ });
785
+
786
+ if (!res.ok) {
787
+ const err = await res.json();
788
+ logError('sync-card', err);
789
+ throw new Error(err.error || 'Failed to sync card');
790
+ }
791
+
792
+ const data = await res.json();
793
+ spinner.succeed('Agent card synced!');
794
+
795
+ if (data.card) {
796
+ console.log(chalk.bold('\n Updated card:'));
797
+ console.log(` Name: ${brand.green(data.card.name)}`);
798
+ if (data.card.description) {
799
+ console.log(` Description: ${chalk.gray(data.card.description.slice(0, 60))}${data.card.description.length > 60 ? '...' : ''}`);
800
+ }
801
+ if (data.card.skills?.length) {
802
+ console.log(` Skills: ${data.card.skills.length} (${data.card.skills.map((s: any) => s.name).join(', ')})`);
803
+ }
804
+ console.log('');
805
+ }
806
+ } catch (err) {
807
+ spinner.fail(chalk.red((err as Error).message));
808
+ process.exit(1);
809
+ }
810
+ });
811
+
655
812
  // ========== INIT COMMAND ==========
656
813
 
657
814
  program
@@ -668,7 +825,8 @@ ${chalk.bold('Example:')}
668
825
  $ gopherhole init
669
826
  `)
670
827
  .action(async () => {
671
- console.log(chalk.bold('\n🐿️ Initialize GopherHole Project\n'));
828
+ console.log('');
829
+ showBanner(process.cwd());
672
830
 
673
831
  let sessionId = config.get('sessionId') as string;
674
832
 
@@ -835,7 +993,7 @@ main().catch(console.error);
835
993
  console.log(chalk.cyan(' npm start'));
836
994
  console.log('');
837
995
  console.log(chalk.gray(`Dashboard: https://gopherhole.ai/dashboard`));
838
- console.log(chalk.gray(`Docs: https://gopherhole.ai/docs`));
996
+ console.log(chalk.gray(`Docs: https://docs.gopherhole.ai`));
839
997
  console.log('');
840
998
  });
841
999
 
@@ -1208,7 +1366,8 @@ program
1208
1366
  .command('status')
1209
1367
  .description('Show GopherHole service status and your session info')
1210
1368
  .action(async () => {
1211
- console.log(chalk.bold('\n🐿️ GopherHole Status\n'));
1369
+ console.log('');
1370
+ showBanner();
1212
1371
 
1213
1372
  // Check API health
1214
1373
  const spinner = ora('Checking API...').start();