@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.
- package/dist/index.js +161 -19
- 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
|
|
14
|
-
import
|
|
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
|
|
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(
|
|
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)` }) :
|
|
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 }) :
|
|
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(
|
|
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(
|
|
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 }) :
|
|
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(
|
|
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(
|
|
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 }) :
|
|
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(
|
|
2749
|
+
console.log(chalk14.green(`
|
|
2609
2750
|
Approved! Agent ID: ${agentId}`));
|
|
2610
2751
|
if (keyWritten) {
|
|
2611
|
-
console.log(
|
|
2752
|
+
console.log(chalk14.gray(`Key: ${keyPath}`));
|
|
2612
2753
|
} else {
|
|
2613
|
-
console.log(
|
|
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(
|
|
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(
|
|
2764
|
+
if (!isJson) console.log(chalk14.gray(`Permissions: .claude/agentvalet-permissions.md`));
|
|
2624
2765
|
}
|
|
2625
2766
|
} catch {
|
|
2626
|
-
if (!isJson) console.log(
|
|
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(
|
|
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);
|