@agentvalet/register 0.5.6 → 0.6.1

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/index.js +161 -19
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -10,8 +10,8 @@ import {
10
10
 
11
11
  // src/index.ts
12
12
  import { createRequire as createRequire2 } from "module";
13
- import { Command as Command6 } from "commander";
14
- import chalk13 from "chalk";
13
+ import { Command as Command7 } from "commander";
14
+ import chalk14 from "chalk";
15
15
 
16
16
  // src/wizard.ts
17
17
  import prompts from "prompts";
@@ -2468,13 +2468,154 @@ function installCommand() {
2468
2468
  });
2469
2469
  }
2470
2470
 
2471
+ // src/commands/claim.ts
2472
+ import { Command as Command6 } from "commander";
2473
+ import { generateKeyPairSync } from "crypto";
2474
+ import { mkdirSync as mkdirSync3, writeFileSync as writeFileSync4, existsSync as existsSync8 } from "fs";
2475
+ import { homedir as homedir3 } from "os";
2476
+ import { join as join3 } from "path";
2477
+ import chalk13 from "chalk";
2478
+ var DEFAULT_PROXY_URL = "https://api.agentvalet.ai";
2479
+ function resolveAgentDir(label) {
2480
+ const root = join3(homedir3(), ".agentvalet");
2481
+ return label ? join3(root, label) : root;
2482
+ }
2483
+ function sanitiseLabel(label) {
2484
+ return label.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "");
2485
+ }
2486
+ async function postBind(proxyUrl, bindSecret, publicKeyPem) {
2487
+ const url = `${proxyUrl.replace(/\/$/, "")}/v1/invites/bind`;
2488
+ const res = await fetch(url, {
2489
+ method: "POST",
2490
+ headers: { "Content-Type": "application/json" },
2491
+ body: JSON.stringify({ bind_secret: bindSecret, public_key_pem: publicKeyPem })
2492
+ });
2493
+ if (!res.ok) {
2494
+ let detail = `HTTP ${res.status}`;
2495
+ try {
2496
+ const body = await res.json();
2497
+ if (body.error) detail = body.error;
2498
+ } catch {
2499
+ }
2500
+ if (res.status === 410) {
2501
+ throw new Error(
2502
+ `Bind secret rejected (${detail}). It was either already used or expired \u2014 ask the inviting manager to re-issue.`
2503
+ );
2504
+ }
2505
+ throw new Error(`Invite bind failed: ${detail}`);
2506
+ }
2507
+ return await res.json();
2508
+ }
2509
+ function claimCommand() {
2510
+ return new Command6("claim").description("Bind an AgentValet agent from a one-shot invite secret").argument("<bind_secret>", "The bsec_\u2026 value shown on the AgentValet claim page").option("--label <name>", "Save under ~/.agentvalet/<label>/ for multi-agent machines").option("--api-url <url>", "AgentValet proxy URL", DEFAULT_PROXY_URL).option("--json", "Machine-readable JSON output").action(async (bindSecret, opts) => {
2511
+ const isJson = !!opts.json;
2512
+ const rawLabel = opts.label?.trim() ?? "";
2513
+ const label = rawLabel ? sanitiseLabel(rawLabel) : null;
2514
+ if (rawLabel && label !== rawLabel.toLowerCase()) {
2515
+ if (!isJson) {
2516
+ console.error(chalk13.yellow(`Note: label sanitised to "${label}"`));
2517
+ }
2518
+ }
2519
+ if (!bindSecret.startsWith("bsec_")) {
2520
+ const msg = "bind_secret should start with 'bsec_'";
2521
+ console.error(isJson ? JSON.stringify({ error: msg }) : chalk13.red(msg));
2522
+ process.exit(3);
2523
+ }
2524
+ const agentDir = resolveAgentDir(label);
2525
+ const keyPath = join3(agentDir, "agent.key");
2526
+ const identityPath = join3(agentDir, "agent.json");
2527
+ if (existsSync8(keyPath)) {
2528
+ const msg = label ? `An agent already exists at ${keyPath}. Pick a different --label or remove the directory first.` : `A default agent already exists at ${keyPath}. Pass --label <name> to claim alongside it without overwriting.`;
2529
+ console.error(isJson ? JSON.stringify({ error: msg }) : chalk13.red(msg));
2530
+ process.exit(3);
2531
+ }
2532
+ const proxyUrl = opts.apiUrl.replace(/\/$/, "");
2533
+ const { publicKey, privateKey } = generateKeyPairSync("rsa", {
2534
+ modulusLength: 2048,
2535
+ publicKeyEncoding: { type: "spki", format: "pem" },
2536
+ privateKeyEncoding: { type: "pkcs8", format: "pem" }
2537
+ });
2538
+ let payload;
2539
+ try {
2540
+ payload = await postBind(proxyUrl, bindSecret, publicKey);
2541
+ } catch (err) {
2542
+ const msg = err instanceof Error ? err.message : String(err);
2543
+ console.error(isJson ? JSON.stringify({ error: msg }) : chalk13.red(msg));
2544
+ process.exit(3);
2545
+ }
2546
+ if (!payload.agent_id || !payload.owner_id || !payload.proxy_url) {
2547
+ const msg = "Bind succeeded but response was missing required fields";
2548
+ console.error(isJson ? JSON.stringify({ error: msg }) : chalk13.red(msg));
2549
+ process.exit(3);
2550
+ }
2551
+ const identity = {
2552
+ agent_id: payload.agent_id,
2553
+ owner_id: payload.owner_id,
2554
+ proxy_url: payload.proxy_url,
2555
+ label,
2556
+ bound_at: (/* @__PURE__ */ new Date()).toISOString()
2557
+ };
2558
+ mkdirSync3(agentDir, { recursive: true, mode: 448 });
2559
+ writeFileSync4(keyPath, privateKey, { mode: 384 });
2560
+ writeFileSync4(identityPath, JSON.stringify(identity, null, 2));
2561
+ const mcpServerName = label ? `agentvalet-${label}` : "agentvalet";
2562
+ const mcpEnv = label ? {
2563
+ AGENT_ID: payload.agent_id,
2564
+ OWNER_ID: payload.owner_id,
2565
+ PROXY_URL: payload.proxy_url,
2566
+ AGENT_PRIVATE_KEY_PATH: keyPath
2567
+ } : {
2568
+ // For the default install, mcp-server picks up agent.key from
2569
+ // ~/.agentvalet/ automatically — only PROXY_URL is needed.
2570
+ PROXY_URL: payload.proxy_url
2571
+ };
2572
+ if (isJson) {
2573
+ console.log(JSON.stringify({
2574
+ status: "bound",
2575
+ agent_id: payload.agent_id,
2576
+ owner_id: payload.owner_id,
2577
+ proxy_url: payload.proxy_url,
2578
+ key_path: keyPath,
2579
+ identity_path: identityPath,
2580
+ label,
2581
+ mcp_server_name: mcpServerName
2582
+ }));
2583
+ return;
2584
+ }
2585
+ console.log(chalk13.green(`
2586
+ \u2713 Bound as ${payload.agent_id}`));
2587
+ console.log(chalk13.gray(` owner: ${payload.owner_id}`));
2588
+ console.log(chalk13.gray(` proxy: ${payload.proxy_url}`));
2589
+ console.log(chalk13.gray(` key: ${keyPath}`));
2590
+ console.log(chalk13.gray(` identity: ${identityPath}`));
2591
+ console.log(chalk13.cyan("\nAdd this to your Claude Desktop / Claude Code MCP config:"));
2592
+ const snippet = {
2593
+ mcpServers: {
2594
+ [mcpServerName]: {
2595
+ command: "npx",
2596
+ args: ["-y", "@agentvalet/mcp-server"],
2597
+ env: mcpEnv
2598
+ }
2599
+ }
2600
+ };
2601
+ console.log(JSON.stringify(snippet, null, 2));
2602
+ if (label) {
2603
+ console.log(chalk13.gray(`
2604
+ Keep the named entry (${mcpServerName}) so it lives alongside any existing AgentValet agents on this machine.`));
2605
+ } else {
2606
+ console.log(chalk13.gray(`
2607
+ Or run 'agentvalet-register inject' to write this into ~/.claude.json automatically.`));
2608
+ }
2609
+ });
2610
+ }
2611
+
2471
2612
  // src/index.ts
2472
2613
  var require2 = createRequire2(import.meta.url);
2473
2614
  var { version } = require2("../package.json");
2474
2615
  function collectScope(value, previous) {
2475
2616
  return [...previous, value];
2476
2617
  }
2477
- var program = new Command6();
2618
+ var program = new Command7();
2478
2619
  program.name("agentvalet-register").description("Self-register an AI agent with AgentValet").version(version).option("--owner <uuid>", "Owner ID (or set AGENTVALET_OWNER env var)").option("--name <name>", "Agent name").option("--description <desc>", "Agent description").option("--scope <platform:scope>", "Requested scope, repeatable", collectScope, []).option("--api-url <url>", "AgentValet API base URL", "https://api.agentvalet.ai").option("--json", "Machine-readable JSON output").option("--no-wait", "Register only, do not wait for approval").option("--timeout <seconds>", "Approval wait timeout in seconds", "300").option("--project", "Write project-scoped MCP configs (.mcp.json, .cursor/mcp.json) instead of user-scoped (~/.claude.json, ~/.cursor/mcp.json)").action(async (opts) => {
2479
2620
  const isJson = !!opts.json;
2480
2621
  let ownerId = opts.owner ?? process.env.AGENTVALET_OWNER ?? "";
@@ -2508,7 +2649,7 @@ program.name("agentvalet-register").description("Self-register an AI agent with
2508
2649
  console.error(JSON.stringify({ error: "--owner or AGENTVALET_OWNER is required" }));
2509
2650
  process.exit(3);
2510
2651
  }
2511
- console.error(chalk13.red("Error: --owner or AGENTVALET_OWNER environment variable is required"));
2652
+ console.error(chalk14.red("Error: --owner or AGENTVALET_OWNER environment variable is required"));
2512
2653
  process.exit(3);
2513
2654
  }
2514
2655
  const scopeMap = /* @__PURE__ */ new Map();
@@ -2516,7 +2657,7 @@ program.name("agentvalet-register").description("Self-register an AI agent with
2516
2657
  const colon = s.indexOf(":");
2517
2658
  if (colon === -1) {
2518
2659
  console.error(
2519
- isJson ? JSON.stringify({ error: `Invalid scope format: ${s} (expected platform:scope)` }) : chalk13.red(`Invalid scope format: ${s} (expected platform:scope)`)
2660
+ isJson ? JSON.stringify({ error: `Invalid scope format: ${s} (expected platform:scope)` }) : chalk14.red(`Invalid scope format: ${s} (expected platform:scope)`)
2520
2661
  );
2521
2662
  process.exit(3);
2522
2663
  }
@@ -2539,11 +2680,11 @@ program.name("agentvalet-register").description("Self-register an AI agent with
2539
2680
  });
2540
2681
  } catch (err) {
2541
2682
  const msg = err instanceof Error ? err.message : String(err);
2542
- console.error(isJson ? JSON.stringify({ error: msg }) : chalk13.red(`Registration failed: ${msg}`));
2683
+ console.error(isJson ? JSON.stringify({ error: msg }) : chalk14.red(`Registration failed: ${msg}`));
2543
2684
  process.exit(3);
2544
2685
  }
2545
2686
  if (!isJson) {
2546
- console.log(chalk13.cyan(`
2687
+ console.log(chalk14.cyan(`
2547
2688
  Approve at: https://app.agentvalet.ai/agents
2548
2689
  `));
2549
2690
  }
@@ -2551,7 +2692,7 @@ Approve at: https://app.agentvalet.ai/agents
2551
2692
  if (isJson) {
2552
2693
  console.log(JSON.stringify({ status: "pending", token }));
2553
2694
  } else {
2554
- console.log(chalk13.yellow("Registration submitted (--no-wait). Token:"), token);
2695
+ console.log(chalk14.yellow("Registration submitted (--no-wait). Token:"), token);
2555
2696
  }
2556
2697
  process.exit(0);
2557
2698
  }
@@ -2562,14 +2703,14 @@ Approve at: https://app.agentvalet.ai/agents
2562
2703
  });
2563
2704
  } catch (err) {
2564
2705
  const msg = err instanceof Error ? err.message : String(err);
2565
- console.error(isJson ? JSON.stringify({ error: msg }) : chalk13.red(`Wait failed: ${msg}`));
2706
+ console.error(isJson ? JSON.stringify({ error: msg }) : chalk14.red(`Wait failed: ${msg}`));
2566
2707
  process.exit(3);
2567
2708
  }
2568
2709
  if (result.status === "rejected") {
2569
2710
  if (isJson) {
2570
2711
  console.log(JSON.stringify({ status: "rejected" }));
2571
2712
  } else {
2572
- console.log(chalk13.red("\nRegistration denied by owner."));
2713
+ console.log(chalk14.red("\nRegistration denied by owner."));
2573
2714
  }
2574
2715
  process.exit(1);
2575
2716
  }
@@ -2577,7 +2718,7 @@ Approve at: https://app.agentvalet.ai/agents
2577
2718
  if (isJson) {
2578
2719
  console.log(JSON.stringify({ status: "timeout" }));
2579
2720
  } else {
2580
- console.log(chalk13.yellow("\nTimed out waiting for approval."));
2721
+ console.log(chalk14.yellow("\nTimed out waiting for approval."));
2581
2722
  }
2582
2723
  process.exit(2);
2583
2724
  }
@@ -2595,7 +2736,7 @@ Approve at: https://app.agentvalet.ai/agents
2595
2736
  }));
2596
2737
  } catch (err) {
2597
2738
  const msg = err instanceof Error ? err.message : String(err);
2598
- console.error(isJson ? JSON.stringify({ error: msg }) : chalk13.red(`Failed to save output: ${msg}`));
2739
+ console.error(isJson ? JSON.stringify({ error: msg }) : chalk14.red(`Failed to save output: ${msg}`));
2599
2740
  process.exit(3);
2600
2741
  }
2601
2742
  } else {
@@ -2605,25 +2746,25 @@ Approve at: https://app.agentvalet.ai/agents
2605
2746
  if (isJson) {
2606
2747
  console.log(JSON.stringify({ status: "approved", agentId, keyPath: keyWritten ? keyPath : null }));
2607
2748
  } else {
2608
- console.log(chalk13.green(`
2749
+ console.log(chalk14.green(`
2609
2750
  Approved! Agent ID: ${agentId}`));
2610
2751
  if (keyWritten) {
2611
- console.log(chalk13.gray(`Key: ${keyPath}`));
2752
+ console.log(chalk14.gray(`Key: ${keyPath}`));
2612
2753
  } else {
2613
- console.log(chalk13.yellow(`Key: not written \u2014 copy it from the dashboard and paste into ${keyPath}`));
2754
+ console.log(chalk14.yellow(`Key: not written \u2014 copy it from the dashboard and paste into ${keyPath}`));
2614
2755
  }
2615
2756
  }
2616
2757
  if (keyWritten) {
2617
2758
  try {
2618
2759
  if (grantedPlatforms && grantedPlatforms.length > 0) {
2619
2760
  writePermissionsFromEvent(agentId, resolvedOwnerId, grantedPlatforms);
2620
- if (!isJson) console.log(chalk13.gray(`Permissions: .claude/agentvalet-permissions.md`));
2761
+ if (!isJson) console.log(chalk14.gray(`Permissions: .claude/agentvalet-permissions.md`));
2621
2762
  } else {
2622
2763
  await runRefresh({ envFile: ".env.agentvalet", outputPath: ".claude/agentvalet-permissions.md", ifStale: false, quiet: isJson });
2623
- if (!isJson) console.log(chalk13.gray(`Permissions: .claude/agentvalet-permissions.md`));
2764
+ if (!isJson) console.log(chalk14.gray(`Permissions: .claude/agentvalet-permissions.md`));
2624
2765
  }
2625
2766
  } catch {
2626
- if (!isJson) console.log(chalk13.yellow(`Permissions: run 'agentvalet-register refresh' to generate`));
2767
+ if (!isJson) console.log(chalk14.yellow(`Permissions: run 'agentvalet-register refresh' to generate`));
2627
2768
  }
2628
2769
  }
2629
2770
  process.exit(0);
@@ -2638,7 +2779,7 @@ program.command("refresh").description("Refresh approved permissions and update
2638
2779
  });
2639
2780
  } catch (err) {
2640
2781
  const msg = err instanceof Error ? err.message : String(err);
2641
- console.error(chalk13.red(`Refresh failed: ${msg}`));
2782
+ console.error(chalk14.red(`Refresh failed: ${msg}`));
2642
2783
  process.exit(3);
2643
2784
  }
2644
2785
  });
@@ -2651,6 +2792,7 @@ program.addCommand(revokeCommand());
2651
2792
  program.addCommand(injectCommand());
2652
2793
  program.addCommand(uninstallCommand());
2653
2794
  program.addCommand(installCommand());
2795
+ program.addCommand(claimCommand());
2654
2796
  program.parseAsync().catch((err) => {
2655
2797
  console.error(err);
2656
2798
  process.exit(3);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agentvalet/register",
3
- "version": "0.5.6",
3
+ "version": "0.6.1",
4
4
  "description": "Self-register AI agents with AgentValet",
5
5
  "type": "module",
6
6
  "bin": {