@gopherhole/cli 0.6.0 → 0.6.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/dist/index.js CHANGED
@@ -20,7 +20,7 @@ const brand = {
20
20
  greenDark: chalk_1.default.hex('#16a34a'), // gopher-600 - emphasis
21
21
  };
22
22
  // Version
23
- const VERSION = '0.6.0';
23
+ const VERSION = '0.6.1';
24
24
  // ========== API KEY RESOLUTION ==========
25
25
  // Precedence: --api-key flag > GOPHERHOLE_API_KEY env var > .env file in cwd
26
26
  async function resolveApiKey(flagValue) {
@@ -2577,6 +2577,65 @@ ${chalk_1.default.bold('Examples:')}
2577
2577
  process.exit(1);
2578
2578
  }
2579
2579
  });
2580
+ // ========== REQUEST ACCESS (agent-to-agent via API key) ==========
2581
+ program
2582
+ .command('request-access <agentId>')
2583
+ .description(`Request access to another agent (agent-to-agent, uses API key)
2584
+
2585
+ If the target has auto-approve enabled, access is granted immediately.
2586
+ Otherwise it's queued for manual approval by the target tenant.
2587
+
2588
+ ${chalk_1.default.bold('Examples:')}
2589
+ $ gopherhole request-access agent-abc123
2590
+ $ gopherhole request-access agent-abc123 --reason "Need data feed"
2591
+ $ gopherhole request-access agent-abc123 --scopes "messages:send,memory:read"
2592
+ `)
2593
+ .option('--api-key <key>', 'API key (overrides env / .env)')
2594
+ .option('--scopes <scopes>', 'Comma-separated scopes to request (default: messages:send)')
2595
+ .option('--reason <text>', 'Reason for the request (shown to target tenant)')
2596
+ .action(async (agentId, options) => {
2597
+ const apiKey = await resolveApiKey(options.apiKey);
2598
+ if (!apiKey) {
2599
+ console.error(chalk_1.default.red('No API key found.'));
2600
+ console.error(chalk_1.default.gray('Set GOPHERHOLE_API_KEY, pass --api-key, or run gopherhole init'));
2601
+ process.exit(1);
2602
+ }
2603
+ const scopes = options.scopes
2604
+ ? options.scopes.split(',').map((s) => s.trim())
2605
+ : ['messages:send'];
2606
+ const spinner = (0, ora_1.default)(`Requesting access to ${agentId}...`).start();
2607
+ try {
2608
+ const res = await fetch(`${API_URL}/access/request`, {
2609
+ method: 'POST',
2610
+ headers: {
2611
+ 'Content-Type': 'application/json',
2612
+ Authorization: `Bearer ${apiKey}`,
2613
+ },
2614
+ body: JSON.stringify({
2615
+ targetAgentId: agentId,
2616
+ scopes,
2617
+ reason: options.reason,
2618
+ }),
2619
+ });
2620
+ if (!res.ok) {
2621
+ const err = await res.json().catch(() => ({}));
2622
+ throw new Error(err.error || `HTTP ${res.status}`);
2623
+ }
2624
+ const data = await res.json();
2625
+ if (data.grant.status === 'approved') {
2626
+ spinner.succeed(`Access granted immediately (auto-approved). You can now message ${chalk_1.default.cyan(agentId)}.`);
2627
+ }
2628
+ else {
2629
+ spinner.succeed(`Access request submitted (pending approval).`);
2630
+ }
2631
+ console.log(` Grant ID: ${chalk_1.default.cyan(data.grant.id)}`);
2632
+ console.log(` Status: ${data.grant.status}`);
2633
+ }
2634
+ catch (err) {
2635
+ spinner.fail(chalk_1.default.red(err.message));
2636
+ process.exit(1);
2637
+ }
2638
+ });
2580
2639
  // ========== MEMORY COMMANDS (agent-to-agent via memory agent) ==========
2581
2640
  const MEMORY_AGENT = process.env.GOPHERHOLE_MEMORY_AGENT || 'agent-memory-official';
2582
2641
  const memory = program
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gopherhole/cli",
3
- "version": "0.6.0",
3
+ "version": "0.6.2",
4
4
  "description": "GopherHole CLI - Connect AI agents to the world",
5
5
  "main": "dist/index.js",
6
6
  "bin": {
@@ -22,7 +22,7 @@
22
22
  "author": "GopherHole",
23
23
  "license": "MIT",
24
24
  "dependencies": {
25
- "@gopherhole/sdk": "^0.7.2",
25
+ "@gopherhole/sdk": "^0.7.4",
26
26
  "chalk": "^5.3.0",
27
27
  "commander": "^12.0.0",
28
28
  "conf": "^12.0.0",
@@ -38,4 +38,4 @@
38
38
  "ts-node": "^10.9.2",
39
39
  "typescript": "^5.3.0"
40
40
  }
41
- }
41
+ }
package/src/index.ts CHANGED
@@ -20,7 +20,7 @@ const brand = {
20
20
  };
21
21
 
22
22
  // Version
23
- const VERSION = '0.6.0';
23
+ const VERSION = '0.6.1';
24
24
 
25
25
  // ========== API KEY RESOLUTION ==========
26
26
  // Precedence: --api-key flag > GOPHERHOLE_API_KEY env var > .env file in cwd
@@ -2807,6 +2807,70 @@ ${chalk.bold('Examples:')}
2807
2807
  }
2808
2808
  });
2809
2809
 
2810
+ // ========== REQUEST ACCESS (agent-to-agent via API key) ==========
2811
+
2812
+ program
2813
+ .command('request-access <agentId>')
2814
+ .description(`Request access to another agent (agent-to-agent, uses API key)
2815
+
2816
+ If the target has auto-approve enabled, access is granted immediately.
2817
+ Otherwise it's queued for manual approval by the target tenant.
2818
+
2819
+ ${chalk.bold('Examples:')}
2820
+ $ gopherhole request-access agent-abc123
2821
+ $ gopherhole request-access agent-abc123 --reason "Need data feed"
2822
+ $ gopherhole request-access agent-abc123 --scopes "messages:send,memory:read"
2823
+ `)
2824
+ .option('--api-key <key>', 'API key (overrides env / .env)')
2825
+ .option('--scopes <scopes>', 'Comma-separated scopes to request (default: messages:send)')
2826
+ .option('--reason <text>', 'Reason for the request (shown to target tenant)')
2827
+ .action(async (agentId, options) => {
2828
+ const apiKey = await resolveApiKey(options.apiKey);
2829
+ if (!apiKey) {
2830
+ console.error(chalk.red('No API key found.'));
2831
+ console.error(chalk.gray('Set GOPHERHOLE_API_KEY, pass --api-key, or run gopherhole init'));
2832
+ process.exit(1);
2833
+ }
2834
+
2835
+ const scopes = options.scopes
2836
+ ? options.scopes.split(',').map((s: string) => s.trim())
2837
+ : ['messages:send'];
2838
+
2839
+ const spinner = ora(`Requesting access to ${agentId}...`).start();
2840
+ try {
2841
+ const res = await fetch(`${API_URL}/access/request`, {
2842
+ method: 'POST',
2843
+ headers: {
2844
+ 'Content-Type': 'application/json',
2845
+ Authorization: `Bearer ${apiKey}`,
2846
+ },
2847
+ body: JSON.stringify({
2848
+ targetAgentId: agentId,
2849
+ scopes,
2850
+ reason: options.reason,
2851
+ }),
2852
+ });
2853
+
2854
+ if (!res.ok) {
2855
+ const err = await res.json().catch(() => ({}));
2856
+ throw new Error((err as any).error || `HTTP ${res.status}`);
2857
+ }
2858
+
2859
+ const data = await res.json() as { grant: { id: string; status: string } };
2860
+
2861
+ if (data.grant.status === 'approved') {
2862
+ spinner.succeed(`Access granted immediately (auto-approved). You can now message ${chalk.cyan(agentId)}.`);
2863
+ } else {
2864
+ spinner.succeed(`Access request submitted (pending approval).`);
2865
+ }
2866
+ console.log(` Grant ID: ${chalk.cyan(data.grant.id)}`);
2867
+ console.log(` Status: ${data.grant.status}`);
2868
+ } catch (err) {
2869
+ spinner.fail(chalk.red((err as Error).message));
2870
+ process.exit(1);
2871
+ }
2872
+ });
2873
+
2810
2874
  // ========== MEMORY COMMANDS (agent-to-agent via memory agent) ==========
2811
2875
 
2812
2876
  const MEMORY_AGENT = process.env.GOPHERHOLE_MEMORY_AGENT || 'agent-memory-official';