@agentvalet/register 1.5.0 → 1.7.0

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 +126 -28
  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 Command7 } from "commander";
14
- import chalk14 from "chalk";
13
+ import { Command as Command8 } from "commander";
14
+ import chalk15 from "chalk";
15
15
 
16
16
  // src/wizard.ts
17
17
  import prompts from "prompts";
@@ -765,6 +765,14 @@ function parseEnvFile(content) {
765
765
  }
766
766
  return result;
767
767
  }
768
+ function resolveAgent(envFile = ".env.agentvalet") {
769
+ const creds = tryResolveAgent(envFile);
770
+ if (!creds) {
771
+ process.stderr.write(NO_AGENT_MSG + "\n");
772
+ process.exit(1);
773
+ }
774
+ return creds;
775
+ }
768
776
  function tryResolveAgent(envFile = ".env.agentvalet") {
769
777
  let agentId;
770
778
  let ownerId;
@@ -1255,6 +1263,7 @@ async function browserLogin() {
1255
1263
  }
1256
1264
 
1257
1265
  // src/api/agentvalet.ts
1266
+ import { generateKeyPairSync } from "crypto";
1258
1267
  var API_URL2 = process.env.AGENTVALET_API_URL ?? "https://api.agentvalet.ai";
1259
1268
  var FUNCTIONS_URL2 = `${API_URL2}/functions/v1`;
1260
1269
  var baseHeaders = {
@@ -1287,6 +1296,20 @@ async function registerAgent2(params, apiKey) {
1287
1296
  clearTimeout(timeout);
1288
1297
  }
1289
1298
  }
1299
+ async function registerAgentWithLocalKey(params, apiKey) {
1300
+ const { publicKey, privateKey } = generateKeyPairSync("rsa", {
1301
+ modulusLength: 2048,
1302
+ publicKeyEncoding: { type: "spki", format: "pem" },
1303
+ privateKeyEncoding: { type: "pkcs8", format: "pem" }
1304
+ });
1305
+ const agent = await registerAgent2({ ...params, public_key_pem: publicKey }, apiKey);
1306
+ if (agent.private_key_pem || agent.public_key_pem?.trim() !== publicKey.trim()) {
1307
+ throw new Error(
1308
+ `The server did not accept this machine's public key, so agent ${agent.agent_id} cannot use it. Delete that agent in the dashboard and try again later, or report this to AgentValet support.`
1309
+ );
1310
+ }
1311
+ return { agent, privateKeyPem: privateKey };
1312
+ }
1290
1313
 
1291
1314
  // src/config/local.ts
1292
1315
  import { mkdir as mkdir2, writeFile as writeFile2, appendFile, readFile } from "fs/promises";
@@ -1688,13 +1711,14 @@ async function registerAgentFlow(apiKey, ownerId, scope = "user", presetName) {
1688
1711
  const agentType = resolveAgentType(detectedAtRegister);
1689
1712
  const spinner = ora(" Registering agent...").start();
1690
1713
  let agent;
1714
+ let privateKeyPem;
1691
1715
  try {
1692
- agent = await registerAgent2({
1716
+ ({ agent, privateKeyPem } = await registerAgentWithLocalKey({
1693
1717
  owner_id: ownerId,
1694
1718
  name: agentName.trim(),
1695
1719
  source: "cli",
1696
1720
  agent_type: agentType
1697
- }, apiKey);
1721
+ }, apiKey));
1698
1722
  spinner.succeed(` Agent registered: ${chalk7.bold(agent.agent_id)}`);
1699
1723
  } catch (err) {
1700
1724
  spinner.fail(` Registration failed: ${err.message}`);
@@ -1707,7 +1731,7 @@ async function registerAgentFlow(apiKey, ownerId, scope = "user", presetName) {
1707
1731
  agentId: agent.agent_id,
1708
1732
  agentName: agent.agent_name,
1709
1733
  proxyUrl,
1710
- privateKeyPem: agent.private_key_pem
1734
+ privateKeyPem
1711
1735
  });
1712
1736
  saveConfig({ lastAgentId: agent.agent_id, lastKeyPath: keyPath });
1713
1737
  } catch (err) {
@@ -1803,7 +1827,7 @@ async function registerAgentFlow(apiKey, ownerId, scope = "user", presetName) {
1803
1827
  console.log(
1804
1828
  ` Dashboard: ${chalk7.cyan.underline("https://app.agentvalet.ai")}`
1805
1829
  );
1806
- console.log(chalk7.dim(" Approve this agent in your dashboard to activate it."));
1830
+ console.log(chalk7.dim(" The agent is active but has no access yet. Grant it platforms on its page in the dashboard."));
1807
1831
  console.log("");
1808
1832
  if (shouldSetup) {
1809
1833
  if (scope === "user") {
@@ -2439,13 +2463,13 @@ function injectCommand() {
2439
2463
  // src/commands/install.ts
2440
2464
  import { writeFile as writeFile9, mkdir as mkdir6 } from "fs/promises";
2441
2465
  import path7 from "path";
2442
- import { generateKeyPairSync } from "crypto";
2466
+ import { generateKeyPairSync as generateKeyPairSync2 } from "crypto";
2443
2467
  import { Command as Command5 } from "commander";
2444
2468
  import chalk12 from "chalk";
2445
2469
  import prompts4 from "prompts";
2446
2470
  var API_URL3 = process.env.AGENTVALET_API_URL ?? "https://api.agentvalet.ai";
2447
2471
  async function bindInstallToken(proxyUrl, bootstrapToken) {
2448
- const { publicKey, privateKey } = generateKeyPairSync("rsa", {
2472
+ const { publicKey, privateKey } = generateKeyPairSync2("rsa", {
2449
2473
  modulusLength: 2048,
2450
2474
  publicKeyEncoding: { type: "spki", format: "pem" },
2451
2475
  privateKeyEncoding: { type: "pkcs8", format: "pem" }
@@ -2640,7 +2664,7 @@ function installCommand() {
2640
2664
 
2641
2665
  // src/commands/claim.ts
2642
2666
  import { Command as Command6 } from "commander";
2643
- import { generateKeyPairSync as generateKeyPairSync2 } from "crypto";
2667
+ import { generateKeyPairSync as generateKeyPairSync3 } from "crypto";
2644
2668
  import { mkdirSync as mkdirSync3, writeFileSync as writeFileSync4, existsSync as existsSync9 } from "fs";
2645
2669
  import { homedir as homedir3 } from "os";
2646
2670
  import { join as join5 } from "path";
@@ -2700,7 +2724,7 @@ function claimCommand() {
2700
2724
  process.exit(3);
2701
2725
  }
2702
2726
  const proxyUrl = opts.apiUrl.replace(/\/$/, "");
2703
- const { publicKey, privateKey } = generateKeyPairSync2("rsa", {
2727
+ const { publicKey, privateKey } = generateKeyPairSync3("rsa", {
2704
2728
  modulusLength: 2048,
2705
2729
  publicKeyEncoding: { type: "spki", format: "pem" },
2706
2730
  privateKeyEncoding: { type: "pkcs8", format: "pem" }
@@ -2779,13 +2803,85 @@ Or run 'agentvalet-register inject' to write this into ~/.claude.json automatica
2779
2803
  });
2780
2804
  }
2781
2805
 
2806
+ // src/commands/git-credential.ts
2807
+ import { Command as Command7 } from "commander";
2808
+ import { readFileSync as readFileSync6 } from "fs";
2809
+ import { execFileSync } from "child_process";
2810
+ import chalk14 from "chalk";
2811
+ var GIT_USERNAME = "agentvalet";
2812
+ function parseCredentialInput(input) {
2813
+ const out = {};
2814
+ for (const raw of input.split("\n")) {
2815
+ const line = raw.replace(/\r$/, "");
2816
+ if (line === "") break;
2817
+ const eq = line.indexOf("=");
2818
+ if (eq <= 0) continue;
2819
+ out[line.slice(0, eq)] = line.slice(eq + 1);
2820
+ }
2821
+ return out;
2822
+ }
2823
+ function respondToCredentialRequest(action, request2, creds, privateKeyPem) {
2824
+ if (action !== "get") return "";
2825
+ let proxyHost;
2826
+ try {
2827
+ proxyHost = new URL(creds.apiUrl).host.toLowerCase();
2828
+ } catch {
2829
+ return "";
2830
+ }
2831
+ if ((request2.host ?? "").toLowerCase() !== proxyHost) return "";
2832
+ const jwt = signJwt(creds.agentId, creds.ownerId, privateKeyPem);
2833
+ return `username=${GIT_USERNAME}
2834
+ password=${jwt}
2835
+ `;
2836
+ }
2837
+ var GIT_HELPER_COMMAND = "npx --yes @agentvalet/register git-credential";
2838
+ function gitConfigLine(apiUrl) {
2839
+ const origin = new URL(apiUrl).origin;
2840
+ return [`credential.${origin}.helper`, `!${GIT_HELPER_COMMAND}`];
2841
+ }
2842
+ async function readStdin() {
2843
+ const chunks = [];
2844
+ for await (const c of process.stdin) chunks.push(Buffer.isBuffer(c) ? c : Buffer.from(c));
2845
+ return Buffer.concat(chunks).toString("utf8");
2846
+ }
2847
+ function gitCredentialCommand() {
2848
+ return new Command7("git-credential").description("git credential helper: answers the AgentValet proxy with this agent's JWT (used via `npx @agentvalet/register git-setup`)").argument("<action>", "get | store | erase (supplied by git)").action(async (action) => {
2849
+ const creds = resolveAgent();
2850
+ const request2 = parseCredentialInput(await readStdin());
2851
+ if (action !== "get") return;
2852
+ const pem = readFileSync6(creds.keyPath, "utf8");
2853
+ const reply = respondToCredentialRequest(action, request2, creds, pem);
2854
+ if (reply) process.stdout.write(reply);
2855
+ });
2856
+ }
2857
+ function gitSetupCommand() {
2858
+ return new Command7("git-setup").description("Configure git to authenticate to the AgentValet proxy with this agent's key").option("--local", "Write to the current repository's .git/config instead of the global config").option("--print", "Print the git config command instead of running it").action((opts) => {
2859
+ const creds = resolveAgent();
2860
+ const [key, value] = gitConfigLine(creds.apiUrl);
2861
+ const args = ["config", opts.local ? "--local" : "--global", key, value];
2862
+ if (opts.print) {
2863
+ process.stdout.write(`git ${args.map((a) => /\s|!/.test(a) ? JSON.stringify(a) : a).join(" ")}
2864
+ `);
2865
+ return;
2866
+ }
2867
+ execFileSync("git", args, { stdio: "inherit" });
2868
+ const origin = new URL(creds.apiUrl).origin;
2869
+ process.stderr.write(
2870
+ chalk14.green("\n \u2713 git will authenticate to ") + origin + chalk14.green(" as agent ") + creds.agentId + "\n" + chalk14.dim(`
2871
+ Use remotes of the form ${origin}/git/<owner>/<repo>.git
2872
+
2873
+ `)
2874
+ );
2875
+ });
2876
+ }
2877
+
2782
2878
  // src/index.ts
2783
2879
  var require2 = createRequire2(import.meta.url);
2784
2880
  var { version } = require2("../package.json");
2785
2881
  function collectScope(value, previous) {
2786
2882
  return [...previous, value];
2787
2883
  }
2788
- var program = new Command7();
2884
+ var program = new Command8();
2789
2885
  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)").option("--force", "Replace an existing agent's key (a timestamped backup is written first)").action(async (opts) => {
2790
2886
  const isJson = !!opts.json;
2791
2887
  let ownerId = opts.owner ?? process.env.AGENTVALET_OWNER ?? "";
@@ -2819,7 +2915,7 @@ program.name("agentvalet-register").description("Self-register an AI agent with
2819
2915
  console.error(JSON.stringify({ error: "--owner or AGENTVALET_OWNER is required" }));
2820
2916
  process.exit(3);
2821
2917
  }
2822
- console.error(chalk14.red("Error: --owner or AGENTVALET_OWNER environment variable is required"));
2918
+ console.error(chalk15.red("Error: --owner or AGENTVALET_OWNER environment variable is required"));
2823
2919
  process.exit(3);
2824
2920
  }
2825
2921
  const scopeMap = /* @__PURE__ */ new Map();
@@ -2827,7 +2923,7 @@ program.name("agentvalet-register").description("Self-register an AI agent with
2827
2923
  const colon = s.indexOf(":");
2828
2924
  if (colon === -1) {
2829
2925
  console.error(
2830
- isJson ? JSON.stringify({ error: `Invalid scope format: ${s} (expected platform:scope)` }) : chalk14.red(`Invalid scope format: ${s} (expected platform:scope)`)
2926
+ isJson ? JSON.stringify({ error: `Invalid scope format: ${s} (expected platform:scope)` }) : chalk15.red(`Invalid scope format: ${s} (expected platform:scope)`)
2831
2927
  );
2832
2928
  process.exit(3);
2833
2929
  }
@@ -2850,11 +2946,11 @@ program.name("agentvalet-register").description("Self-register an AI agent with
2850
2946
  });
2851
2947
  } catch (err) {
2852
2948
  const msg = err instanceof Error ? err.message : String(err);
2853
- console.error(isJson ? JSON.stringify({ error: msg }) : chalk14.red(`Registration failed: ${msg}`));
2949
+ console.error(isJson ? JSON.stringify({ error: msg }) : chalk15.red(`Registration failed: ${msg}`));
2854
2950
  process.exit(3);
2855
2951
  }
2856
2952
  if (!isJson) {
2857
- console.log(chalk14.cyan(`
2953
+ console.log(chalk15.cyan(`
2858
2954
  Approve at: https://app.agentvalet.ai/agents
2859
2955
  `));
2860
2956
  }
@@ -2862,7 +2958,7 @@ Approve at: https://app.agentvalet.ai/agents
2862
2958
  if (isJson) {
2863
2959
  console.log(JSON.stringify({ status: "pending", token }));
2864
2960
  } else {
2865
- console.log(chalk14.yellow("Registration submitted (--no-wait). Token:"), token);
2961
+ console.log(chalk15.yellow("Registration submitted (--no-wait). Token:"), token);
2866
2962
  }
2867
2963
  process.exit(0);
2868
2964
  }
@@ -2873,14 +2969,14 @@ Approve at: https://app.agentvalet.ai/agents
2873
2969
  });
2874
2970
  } catch (err) {
2875
2971
  const msg = err instanceof Error ? err.message : String(err);
2876
- console.error(isJson ? JSON.stringify({ error: msg }) : chalk14.red(`Wait failed: ${msg}`));
2972
+ console.error(isJson ? JSON.stringify({ error: msg }) : chalk15.red(`Wait failed: ${msg}`));
2877
2973
  process.exit(3);
2878
2974
  }
2879
2975
  if (result.status === "rejected") {
2880
2976
  if (isJson) {
2881
2977
  console.log(JSON.stringify({ status: "rejected" }));
2882
2978
  } else {
2883
- console.log(chalk14.red("\nRegistration denied by owner."));
2979
+ console.log(chalk15.red("\nRegistration denied by owner."));
2884
2980
  }
2885
2981
  process.exit(1);
2886
2982
  }
@@ -2888,7 +2984,7 @@ Approve at: https://app.agentvalet.ai/agents
2888
2984
  if (isJson) {
2889
2985
  console.log(JSON.stringify({ status: "timeout" }));
2890
2986
  } else {
2891
- console.log(chalk14.yellow("\nTimed out waiting for approval."));
2987
+ console.log(chalk15.yellow("\nTimed out waiting for approval."));
2892
2988
  }
2893
2989
  process.exit(2);
2894
2990
  }
@@ -2908,10 +3004,10 @@ Approve at: https://app.agentvalet.ai/agents
2908
3004
  } catch (err) {
2909
3005
  const msg = err instanceof Error ? err.message : String(err);
2910
3006
  if (err instanceof KeyClobberError) {
2911
- console.error(isJson ? JSON.stringify({ error: msg, existing_agent_id: err.existingAgentId }) : chalk14.red(msg));
3007
+ console.error(isJson ? JSON.stringify({ error: msg, existing_agent_id: err.existingAgentId }) : chalk15.red(msg));
2912
3008
  process.exit(3);
2913
3009
  }
2914
- console.error(isJson ? JSON.stringify({ error: msg }) : chalk14.red(`Failed to save output: ${msg}`));
3010
+ console.error(isJson ? JSON.stringify({ error: msg }) : chalk15.red(`Failed to save output: ${msg}`));
2915
3011
  process.exit(3);
2916
3012
  }
2917
3013
  } else {
@@ -2921,25 +3017,25 @@ Approve at: https://app.agentvalet.ai/agents
2921
3017
  if (isJson) {
2922
3018
  console.log(JSON.stringify({ status: "approved", agentId, keyPath: keyWritten ? keyPath : null }));
2923
3019
  } else {
2924
- console.log(chalk14.green(`
3020
+ console.log(chalk15.green(`
2925
3021
  Approved! Agent ID: ${agentId}`));
2926
3022
  if (keyWritten) {
2927
- console.log(chalk14.gray(`Key: ${keyPath}`));
3023
+ console.log(chalk15.gray(`Key: ${keyPath}`));
2928
3024
  } else {
2929
- console.log(chalk14.yellow(`Key: not written \u2014 copy it from the dashboard and paste into ${keyPath}`));
3025
+ console.log(chalk15.yellow(`Key: not written \u2014 copy it from the dashboard and paste into ${keyPath}`));
2930
3026
  }
2931
3027
  }
2932
3028
  if (keyWritten) {
2933
3029
  try {
2934
3030
  if (grantedPlatforms && grantedPlatforms.length > 0) {
2935
3031
  writePermissionsFromEvent(agentId, resolvedOwnerId, grantedPlatforms);
2936
- if (!isJson) console.log(chalk14.gray(`Permissions: .claude/agentvalet-permissions.md`));
3032
+ if (!isJson) console.log(chalk15.gray(`Permissions: .claude/agentvalet-permissions.md`));
2937
3033
  } else {
2938
3034
  await runRefresh({ envFile: ".env.agentvalet", outputPath: ".claude/agentvalet-permissions.md", ifStale: false, quiet: isJson });
2939
- if (!isJson) console.log(chalk14.gray(`Permissions: .claude/agentvalet-permissions.md`));
3035
+ if (!isJson) console.log(chalk15.gray(`Permissions: .claude/agentvalet-permissions.md`));
2940
3036
  }
2941
3037
  } catch {
2942
- if (!isJson) console.log(chalk14.yellow(`Permissions: run 'agentvalet-register refresh' to generate`));
3038
+ if (!isJson) console.log(chalk15.yellow(`Permissions: run 'agentvalet-register refresh' to generate`));
2943
3039
  }
2944
3040
  }
2945
3041
  process.exit(0);
@@ -2954,7 +3050,7 @@ program.command("refresh").description("Refresh approved permissions and update
2954
3050
  });
2955
3051
  } catch (err) {
2956
3052
  const msg = err instanceof Error ? err.message : String(err);
2957
- console.error(chalk14.red(`Refresh failed: ${msg}`));
3053
+ console.error(chalk15.red(`Refresh failed: ${msg}`));
2958
3054
  process.exit(3);
2959
3055
  }
2960
3056
  });
@@ -2964,6 +3060,8 @@ program.command("mcp-server").description("Start the AgentValet MCP server (stdi
2964
3060
  });
2965
3061
  program.addCommand(listCommand());
2966
3062
  program.addCommand(revokeCommand());
3063
+ program.addCommand(gitCredentialCommand());
3064
+ program.addCommand(gitSetupCommand());
2967
3065
  program.addCommand(injectCommand());
2968
3066
  program.addCommand(uninstallCommand());
2969
3067
  program.addCommand(installCommand());
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agentvalet/register",
3
- "version": "1.5.0",
3
+ "version": "1.7.0",
4
4
  "description": "Self-register AI agents with AgentValet",
5
5
  "type": "module",
6
6
  "bin": {