@agentvalet/register 0.2.2 → 0.3.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/README.md +35 -70
- package/dist/index.js +435 -21
- package/package.json +5 -2
- /package/dist/{mcp-server-DMQWPHYT.js → mcp-server-LUNOQPUO.js} +0 -0
package/README.md
CHANGED
|
@@ -1,91 +1,56 @@
|
|
|
1
1
|
# @agentvalet/register
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Register your AI agent with AgentValet in 30 seconds.
|
|
4
4
|
|
|
5
|
-
##
|
|
5
|
+
## Usage
|
|
6
6
|
|
|
7
7
|
```bash
|
|
8
|
-
|
|
9
|
-
npx @agentvalet/register --name "My Agent" --scope slack:chat:write
|
|
10
|
-
|
|
11
|
-
# Or install globally:
|
|
12
|
-
npm install -g @agentvalet/register
|
|
13
|
-
agentvalet-register --name "My Agent" --scope slack:chat:write
|
|
8
|
+
npx @agentvalet/register
|
|
14
9
|
```
|
|
15
10
|
|
|
16
|
-
|
|
11
|
+
No installation required. Authenticate with GitHub, and your agent is registered automatically.
|
|
17
12
|
|
|
18
|
-
|
|
13
|
+
## What it does
|
|
19
14
|
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
15
|
+
1. Opens your browser to authenticate with GitHub
|
|
16
|
+
2. Creates your AgentValet account (or finds your existing one)
|
|
17
|
+
3. Registers this machine as an agent
|
|
18
|
+
4. Writes config to `.agentvalet/` in the current directory
|
|
19
|
+
5. Outputs the environment variables you need
|
|
23
20
|
|
|
24
|
-
##
|
|
25
|
-
|
|
26
|
-
| Flag | Default | Description |
|
|
27
|
-
|------|---------|-------------|
|
|
28
|
-
| `--owner <uuid>` | `AGENTVALET_OWNER` env | Owner ID from https://agentvalet.ai/settings |
|
|
29
|
-
| `--name <name>` | prompted | Agent name |
|
|
30
|
-
| `--description <desc>` | — | Agent description |
|
|
31
|
-
| `--scope <platform:scope>` | — | Repeatable, e.g. `--scope slack:chat:write --scope gmail:send` |
|
|
32
|
-
| `--api-url <url>` | `https://api.agentvalet.ai` | AgentValet API base URL |
|
|
33
|
-
| `--output <path>` | `./.env.agentvalet` | Path to write env vars |
|
|
34
|
-
| `--key-path <path>` | `./agentvalet.key` | Path to write private key |
|
|
35
|
-
| `--json` | — | Machine-readable JSON output |
|
|
36
|
-
| `--no-wait` | — | Register only, don't wait for approval |
|
|
37
|
-
| `--timeout <seconds>` | `300` | Approval wait timeout |
|
|
38
|
-
|
|
39
|
-
## Exit codes
|
|
40
|
-
|
|
41
|
-
| Code | Meaning |
|
|
42
|
-
|------|---------|
|
|
43
|
-
| `0` | Approved |
|
|
44
|
-
| `1` | Denied |
|
|
45
|
-
| `2` | Timeout |
|
|
46
|
-
| `3` | Network or other error |
|
|
47
|
-
|
|
48
|
-
## Integration examples
|
|
49
|
-
|
|
50
|
-
**Claude Code (`CLAUDE.md`):**
|
|
51
|
-
```markdown
|
|
52
|
-
On startup, register with AgentValet:
|
|
53
|
-
npx @agentvalet/register --owner {uuid} --name "Claude Code Agent" --scope slack:chat:write
|
|
54
|
-
|
|
55
|
-
Then source ./.env.agentvalet before calling any tool.
|
|
56
|
-
```
|
|
21
|
+
## Requirements
|
|
57
22
|
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
subprocess.run([
|
|
62
|
-
"npx", "@agentvalet/register",
|
|
63
|
-
"--name", "MyAgent",
|
|
64
|
-
"--owner", owner_id,
|
|
65
|
-
"--scope", "slack:chat:write",
|
|
66
|
-
])
|
|
67
|
-
```
|
|
23
|
+
- Node.js 18+
|
|
24
|
+
- A GitHub account
|
|
25
|
+
- An internet connection
|
|
68
26
|
|
|
69
|
-
|
|
27
|
+
## After registration
|
|
70
28
|
|
|
71
|
-
|
|
29
|
+
Approve your agent in the AgentValet dashboard to activate it:
|
|
30
|
+
https://app.agentvalet.ai/agents
|
|
31
|
+
|
|
32
|
+
## Commands
|
|
72
33
|
|
|
73
34
|
```bash
|
|
74
|
-
npx @agentvalet/register
|
|
75
|
-
|
|
35
|
+
npx @agentvalet/register # Register a new agent (GitHub onboarding)
|
|
36
|
+
npx @agentvalet/register refresh # Refresh approved permissions
|
|
76
37
|
```
|
|
77
38
|
|
|
78
|
-
##
|
|
39
|
+
## What gets written
|
|
40
|
+
|
|
41
|
+
- `.agentvalet/config.json` — agent ID, proxy URL, registration timestamp
|
|
42
|
+
- `.agentvalet/agent.key` — private key (mode 0600, never shared)
|
|
43
|
+
|
|
44
|
+
`.agentvalet/` is automatically added to your `.gitignore`.
|
|
79
45
|
|
|
80
|
-
|
|
81
|
-
2. Prints the approval URL — the owner approves in the dashboard
|
|
82
|
-
3. Waits for approval via SSE (with polling fallback)
|
|
83
|
-
4. On approval, writes the private key to `--key-path` and env vars to `--output`
|
|
46
|
+
## Advanced: existing owner ID
|
|
84
47
|
|
|
85
|
-
|
|
48
|
+
If you already have an AgentValet owner ID, pass it directly:
|
|
49
|
+
|
|
50
|
+
```bash
|
|
51
|
+
AGENTVALET_OWNER=<your-owner-id> npx @agentvalet/register
|
|
52
|
+
```
|
|
86
53
|
|
|
87
|
-
##
|
|
54
|
+
## GitHub OAuth App
|
|
88
55
|
|
|
89
|
-
|
|
90
|
-
- Docs: https://agentvalet.ai/docs
|
|
91
|
-
- GitHub: https://github.com/MCSEdwin/agentvalet
|
|
56
|
+
The GitHub Device Flow uses AgentValet's OAuth App (client ID is public — the Device Flow does not use or expose the client secret). No secrets are stored on your machine.
|
package/dist/index.js
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
// src/index.ts
|
|
4
4
|
import { Command } from "commander";
|
|
5
|
-
import
|
|
5
|
+
import chalk5 from "chalk";
|
|
6
6
|
|
|
7
7
|
// src/wizard.ts
|
|
8
8
|
import prompts from "prompts";
|
|
@@ -422,7 +422,7 @@ function ensureMcpJson() {
|
|
|
422
422
|
if (!agentId || !ownerId || !keyPath) return;
|
|
423
423
|
servers["agent-authority"] = {
|
|
424
424
|
command: "npx",
|
|
425
|
-
args: ["-y", "@agentvalet/register", "mcp-server"],
|
|
425
|
+
args: ["-y", "@agentvalet/register@0.2.2", "mcp-server"],
|
|
426
426
|
env: {
|
|
427
427
|
AGENT_ID: agentId,
|
|
428
428
|
OWNER_ID: ownerId,
|
|
@@ -434,6 +434,416 @@ function ensureMcpJson() {
|
|
|
434
434
|
writeFileSync(mcpJsonPath, JSON.stringify(mcpConfig, null, 2) + "\n", "utf-8");
|
|
435
435
|
}
|
|
436
436
|
|
|
437
|
+
// src/commands/onboard.ts
|
|
438
|
+
import chalk4 from "chalk";
|
|
439
|
+
import ora from "ora";
|
|
440
|
+
import prompts2 from "prompts";
|
|
441
|
+
|
|
442
|
+
// src/auth/github-device-flow.ts
|
|
443
|
+
import { createOAuthDeviceAuth } from "@octokit/auth-oauth-device";
|
|
444
|
+
import open from "open";
|
|
445
|
+
import chalk2 from "chalk";
|
|
446
|
+
var GITHUB_CLIENT_ID = process.env.AGENTVALET_GITHUB_CLIENT_ID ?? "Ov23liXXXXXXXXXXXXXX";
|
|
447
|
+
async function authenticateWithGitHub() {
|
|
448
|
+
const auth = createOAuthDeviceAuth({
|
|
449
|
+
clientType: "oauth-app",
|
|
450
|
+
clientId: GITHUB_CLIENT_ID,
|
|
451
|
+
scopes: ["user:email", "read:user"],
|
|
452
|
+
onVerification(verification) {
|
|
453
|
+
console.log("");
|
|
454
|
+
console.log(chalk2.bold(" Authenticate with GitHub"));
|
|
455
|
+
console.log("");
|
|
456
|
+
console.log(` 1. Open: ${chalk2.cyan.underline(verification.verification_uri)}`);
|
|
457
|
+
console.log(` 2. Enter code: ${chalk2.bold.yellow(verification.user_code)}`);
|
|
458
|
+
console.log("");
|
|
459
|
+
open(verification.verification_uri).catch(() => {
|
|
460
|
+
console.log(chalk2.dim(" (Could not open browser \u2014 navigate to the URL above manually)"));
|
|
461
|
+
});
|
|
462
|
+
console.log(chalk2.dim(" Waiting for authorisation..."));
|
|
463
|
+
}
|
|
464
|
+
});
|
|
465
|
+
const tokenAuth = await auth({ type: "oauth" });
|
|
466
|
+
return {
|
|
467
|
+
token: tokenAuth.token,
|
|
468
|
+
scopes: tokenAuth.scopes ?? []
|
|
469
|
+
};
|
|
470
|
+
}
|
|
471
|
+
async function getGitHubUser(token) {
|
|
472
|
+
const response = await fetch("https://api.github.com/user", {
|
|
473
|
+
headers: {
|
|
474
|
+
Authorization: `Bearer ${token}`,
|
|
475
|
+
Accept: "application/vnd.github.v3+json"
|
|
476
|
+
}
|
|
477
|
+
});
|
|
478
|
+
if (!response.ok) {
|
|
479
|
+
throw new Error(`GitHub API error: ${response.status}`);
|
|
480
|
+
}
|
|
481
|
+
const user = await response.json();
|
|
482
|
+
if (!user.email) {
|
|
483
|
+
const emailsResponse = await fetch("https://api.github.com/user/emails", {
|
|
484
|
+
headers: {
|
|
485
|
+
Authorization: `Bearer ${token}`,
|
|
486
|
+
Accept: "application/vnd.github.v3+json"
|
|
487
|
+
}
|
|
488
|
+
});
|
|
489
|
+
if (emailsResponse.ok) {
|
|
490
|
+
const emails = await emailsResponse.json();
|
|
491
|
+
user.email = emails.find((e) => e.primary && e.verified)?.email ?? emails[0]?.email ?? null;
|
|
492
|
+
}
|
|
493
|
+
}
|
|
494
|
+
return user;
|
|
495
|
+
}
|
|
496
|
+
|
|
497
|
+
// src/api/agentvalet.ts
|
|
498
|
+
var API_BASE = process.env.AGENTVALET_API_URL ?? "https://api.agentvalet.ai";
|
|
499
|
+
async function createOrFindAccount(params) {
|
|
500
|
+
const controller = new AbortController();
|
|
501
|
+
const timeout = setTimeout(() => controller.abort(), 1e4);
|
|
502
|
+
try {
|
|
503
|
+
const response = await fetch(`${API_BASE}/v1/cli/account`, {
|
|
504
|
+
method: "POST",
|
|
505
|
+
headers: { "Content-Type": "application/json" },
|
|
506
|
+
body: JSON.stringify(params),
|
|
507
|
+
signal: controller.signal
|
|
508
|
+
});
|
|
509
|
+
if (!response.ok) {
|
|
510
|
+
const error = await response.json().catch(() => ({}));
|
|
511
|
+
throw new Error(`Account creation failed: ${response.status} ${error.message ?? ""}`);
|
|
512
|
+
}
|
|
513
|
+
return response.json();
|
|
514
|
+
} catch (err) {
|
|
515
|
+
clearTimeout(timeout);
|
|
516
|
+
if (err?.name === "AbortError") throw new Error("Request timed out \u2014 is the AgentValet API reachable?");
|
|
517
|
+
throw err;
|
|
518
|
+
} finally {
|
|
519
|
+
clearTimeout(timeout);
|
|
520
|
+
}
|
|
521
|
+
}
|
|
522
|
+
async function registerAgent2(params, apiKey) {
|
|
523
|
+
const controller = new AbortController();
|
|
524
|
+
const timeout = setTimeout(() => controller.abort(), 1e4);
|
|
525
|
+
try {
|
|
526
|
+
const response = await fetch(`${API_BASE}/v1/cli/register-agent`, {
|
|
527
|
+
method: "POST",
|
|
528
|
+
headers: {
|
|
529
|
+
"Content-Type": "application/json",
|
|
530
|
+
"Authorization": `Bearer ${apiKey}`
|
|
531
|
+
},
|
|
532
|
+
body: JSON.stringify(params),
|
|
533
|
+
signal: controller.signal
|
|
534
|
+
});
|
|
535
|
+
if (!response.ok) {
|
|
536
|
+
const error = await response.json().catch(() => ({}));
|
|
537
|
+
throw new Error(`Agent registration failed: ${response.status} ${error.message ?? ""}`);
|
|
538
|
+
}
|
|
539
|
+
return response.json();
|
|
540
|
+
} catch (err) {
|
|
541
|
+
clearTimeout(timeout);
|
|
542
|
+
if (err?.name === "AbortError") throw new Error("Request timed out \u2014 is the AgentValet API reachable?");
|
|
543
|
+
throw err;
|
|
544
|
+
} finally {
|
|
545
|
+
clearTimeout(timeout);
|
|
546
|
+
}
|
|
547
|
+
}
|
|
548
|
+
|
|
549
|
+
// src/config/store.ts
|
|
550
|
+
import Conf from "conf";
|
|
551
|
+
var store = new Conf({
|
|
552
|
+
projectName: "agentvalet"
|
|
553
|
+
});
|
|
554
|
+
function getStoredConfig() {
|
|
555
|
+
return store.store;
|
|
556
|
+
}
|
|
557
|
+
function saveConfig(config) {
|
|
558
|
+
store.set(config);
|
|
559
|
+
}
|
|
560
|
+
function clearConfig() {
|
|
561
|
+
store.clear();
|
|
562
|
+
}
|
|
563
|
+
function isAuthenticated() {
|
|
564
|
+
return !!store.get("apiKey");
|
|
565
|
+
}
|
|
566
|
+
|
|
567
|
+
// src/config/local.ts
|
|
568
|
+
import { mkdir as mkdir2, writeFile as writeFile2, appendFile, readFile } from "fs/promises";
|
|
569
|
+
import path from "path";
|
|
570
|
+
async function writeLocalConfig(config) {
|
|
571
|
+
const dir = path.join(process.cwd(), ".agentvalet");
|
|
572
|
+
await mkdir2(dir, { recursive: true });
|
|
573
|
+
await writeFile2(
|
|
574
|
+
path.join(dir, "config.json"),
|
|
575
|
+
JSON.stringify({
|
|
576
|
+
agent_id: config.agentId,
|
|
577
|
+
agent_name: config.agentName,
|
|
578
|
+
proxy_url: config.proxyUrl,
|
|
579
|
+
registered_at: (/* @__PURE__ */ new Date()).toISOString()
|
|
580
|
+
}, null, 2),
|
|
581
|
+
{ encoding: "utf8", mode: 384 }
|
|
582
|
+
);
|
|
583
|
+
await writeFile2(
|
|
584
|
+
path.join(dir, "agent.key"),
|
|
585
|
+
config.privateKeyPem,
|
|
586
|
+
{ encoding: "utf8", mode: 384 }
|
|
587
|
+
);
|
|
588
|
+
if (process.platform === "win32") {
|
|
589
|
+
console.warn(" Note: file permissions (0o600) are not enforced on Windows. Keep .agentvalet/ in a secure location.");
|
|
590
|
+
}
|
|
591
|
+
const gitignorePath = path.join(process.cwd(), ".gitignore");
|
|
592
|
+
const gitignoreContent = await readFile(gitignorePath, "utf8").catch(() => null);
|
|
593
|
+
if (gitignoreContent !== null) {
|
|
594
|
+
const lines = gitignoreContent.split("\n").map((l) => l.trim());
|
|
595
|
+
if (!lines.includes(".agentvalet/")) {
|
|
596
|
+
await appendFile(gitignorePath, "\n# AgentValet\n.agentvalet/\n");
|
|
597
|
+
}
|
|
598
|
+
}
|
|
599
|
+
}
|
|
600
|
+
|
|
601
|
+
// src/output/env.ts
|
|
602
|
+
import chalk3 from "chalk";
|
|
603
|
+
import { appendFile as appendFile2, writeFile as writeFile3 } from "fs/promises";
|
|
604
|
+
import { existsSync as existsSync2 } from "fs";
|
|
605
|
+
import path2 from "path";
|
|
606
|
+
function formatEnvBlock(vars) {
|
|
607
|
+
return Object.entries(vars).map(([key, value]) => {
|
|
608
|
+
const truncated = value.length > 60 ? value.substring(0, 40) + "..." + value.substring(value.length - 10) : value;
|
|
609
|
+
return ` ${chalk3.dim(key + "=")}${chalk3.white(truncated)}`;
|
|
610
|
+
}).join("\n");
|
|
611
|
+
}
|
|
612
|
+
|
|
613
|
+
// src/config/ide.ts
|
|
614
|
+
import { mkdir as mkdir3, writeFile as writeFile4, readFile as readFile2 } from "fs/promises";
|
|
615
|
+
import { existsSync as existsSync3 } from "fs";
|
|
616
|
+
import path3 from "path";
|
|
617
|
+
function buildMcpEntry(params) {
|
|
618
|
+
return {
|
|
619
|
+
command: "npx",
|
|
620
|
+
args: ["-y", "@agentvalet/register", "mcp-server"],
|
|
621
|
+
env: {
|
|
622
|
+
AGENT_ID: params.agentId,
|
|
623
|
+
OWNER_ID: params.ownerId,
|
|
624
|
+
PROXY_URL: params.proxyUrl,
|
|
625
|
+
AGENT_PRIVATE_KEY_PATH: params.keyPath
|
|
626
|
+
}
|
|
627
|
+
};
|
|
628
|
+
}
|
|
629
|
+
async function mergeJsonFile(filePath, key, value) {
|
|
630
|
+
let existing = {};
|
|
631
|
+
if (existsSync3(filePath)) {
|
|
632
|
+
try {
|
|
633
|
+
const text = await readFile2(filePath, "utf8");
|
|
634
|
+
existing = JSON.parse(text);
|
|
635
|
+
} catch {
|
|
636
|
+
}
|
|
637
|
+
}
|
|
638
|
+
const mcpServers = existing.mcpServers ?? {};
|
|
639
|
+
mcpServers[key] = value;
|
|
640
|
+
existing.mcpServers = mcpServers;
|
|
641
|
+
await writeFile4(filePath, JSON.stringify(existing, null, 2) + "\n", "utf8");
|
|
642
|
+
}
|
|
643
|
+
async function writeIdeConfigs(params) {
|
|
644
|
+
const cwd = process.cwd();
|
|
645
|
+
const written = [];
|
|
646
|
+
const entry = buildMcpEntry(params);
|
|
647
|
+
const claudeMcpPath = path3.join(cwd, ".mcp.json");
|
|
648
|
+
if (existsSync3(claudeMcpPath) || existsSync3(path3.join(cwd, "CLAUDE.md"))) {
|
|
649
|
+
try {
|
|
650
|
+
await mergeJsonFile(claudeMcpPath, "agentvalet", entry);
|
|
651
|
+
written.push(".mcp.json");
|
|
652
|
+
} catch (err) {
|
|
653
|
+
console.warn(` Warning: could not write .mcp.json: ${err.message}`);
|
|
654
|
+
}
|
|
655
|
+
}
|
|
656
|
+
const cursorDir = path3.join(cwd, ".cursor");
|
|
657
|
+
const cursorMcpPath = path3.join(cursorDir, "mcp.json");
|
|
658
|
+
if (existsSync3(cursorDir)) {
|
|
659
|
+
try {
|
|
660
|
+
await mkdir3(cursorDir, { recursive: true });
|
|
661
|
+
await mergeJsonFile(cursorMcpPath, "agentvalet", entry);
|
|
662
|
+
written.push(".cursor/mcp.json");
|
|
663
|
+
} catch (err) {
|
|
664
|
+
console.warn(` Warning: could not write .cursor/mcp.json: ${err.message}`);
|
|
665
|
+
}
|
|
666
|
+
}
|
|
667
|
+
return written;
|
|
668
|
+
}
|
|
669
|
+
|
|
670
|
+
// src/commands/onboard.ts
|
|
671
|
+
import os from "os";
|
|
672
|
+
import path4 from "path";
|
|
673
|
+
async function runOnboard() {
|
|
674
|
+
console.log("");
|
|
675
|
+
console.log(chalk4.bold(" AgentValet \u2014 Agent Registration"));
|
|
676
|
+
console.log(chalk4.dim(" agentvalet.ai"));
|
|
677
|
+
console.log("");
|
|
678
|
+
if (isAuthenticated()) {
|
|
679
|
+
const stored = getStoredConfig();
|
|
680
|
+
console.log(
|
|
681
|
+
chalk4.green(" \u2713 Already authenticated as") + chalk4.bold(` ${stored.email}`)
|
|
682
|
+
);
|
|
683
|
+
const { action } = await prompts2({
|
|
684
|
+
type: "select",
|
|
685
|
+
name: "action",
|
|
686
|
+
message: "What would you like to do?",
|
|
687
|
+
choices: [
|
|
688
|
+
{ title: "Register a new agent for this directory", value: "register" },
|
|
689
|
+
{ title: "Show my credentials", value: "show" },
|
|
690
|
+
{ title: "Sign out and use a different account", value: "signout" }
|
|
691
|
+
]
|
|
692
|
+
});
|
|
693
|
+
if (action === void 0) {
|
|
694
|
+
process.exit(0);
|
|
695
|
+
}
|
|
696
|
+
if (action === "show") {
|
|
697
|
+
showCredentials(stored);
|
|
698
|
+
return;
|
|
699
|
+
}
|
|
700
|
+
if (action === "signout") {
|
|
701
|
+
clearConfig();
|
|
702
|
+
console.log(chalk4.dim(" Signed out. Run again to re-authenticate."));
|
|
703
|
+
return;
|
|
704
|
+
}
|
|
705
|
+
await registerAgentFlow(stored.apiKey, stored.ownerId);
|
|
706
|
+
return;
|
|
707
|
+
}
|
|
708
|
+
let spinner = ora();
|
|
709
|
+
let githubToken;
|
|
710
|
+
try {
|
|
711
|
+
const result = await authenticateWithGitHub();
|
|
712
|
+
githubToken = result.token;
|
|
713
|
+
} catch (err) {
|
|
714
|
+
console.error(chalk4.red(` \u2717 Authentication failed: ${err.message}`));
|
|
715
|
+
process.exit(1);
|
|
716
|
+
}
|
|
717
|
+
spinner = ora(" Fetching your GitHub profile...").start();
|
|
718
|
+
let githubUser;
|
|
719
|
+
try {
|
|
720
|
+
githubUser = await getGitHubUser(githubToken);
|
|
721
|
+
spinner.succeed(` GitHub: ${chalk4.bold("@" + githubUser.login)}`);
|
|
722
|
+
} catch (err) {
|
|
723
|
+
spinner.fail(` Failed to fetch GitHub profile: ${err.message}`);
|
|
724
|
+
process.exit(1);
|
|
725
|
+
}
|
|
726
|
+
if (!githubUser.email) {
|
|
727
|
+
const { email } = await prompts2({
|
|
728
|
+
type: "text",
|
|
729
|
+
name: "email",
|
|
730
|
+
message: "Your email address (not visible on GitHub):",
|
|
731
|
+
validate: (v) => v.includes("@") || "Please enter a valid email"
|
|
732
|
+
});
|
|
733
|
+
if (email === void 0) {
|
|
734
|
+
process.exit(0);
|
|
735
|
+
}
|
|
736
|
+
githubUser.email = email;
|
|
737
|
+
}
|
|
738
|
+
spinner = ora(" Setting up your AgentValet account...").start();
|
|
739
|
+
let account;
|
|
740
|
+
try {
|
|
741
|
+
account = await createOrFindAccount({
|
|
742
|
+
github_token: githubToken,
|
|
743
|
+
github_username: githubUser.login,
|
|
744
|
+
email: githubUser.email,
|
|
745
|
+
display_name: githubUser.name ?? githubUser.login,
|
|
746
|
+
avatar_url: githubUser.avatar_url
|
|
747
|
+
});
|
|
748
|
+
if (account.is_new_account) {
|
|
749
|
+
spinner.succeed(" AgentValet account created");
|
|
750
|
+
} else {
|
|
751
|
+
spinner.succeed(" Existing AgentValet account found");
|
|
752
|
+
}
|
|
753
|
+
} catch (err) {
|
|
754
|
+
spinner.fail(` Account setup failed: ${err.message}`);
|
|
755
|
+
process.exit(1);
|
|
756
|
+
}
|
|
757
|
+
saveConfig({
|
|
758
|
+
apiKey: account.owner_id,
|
|
759
|
+
ownerId: account.owner_id,
|
|
760
|
+
orgId: account.org_id,
|
|
761
|
+
proxyUrl: account.proxy_url,
|
|
762
|
+
githubUsername: githubUser.login,
|
|
763
|
+
email: githubUser.email
|
|
764
|
+
});
|
|
765
|
+
await registerAgentFlow(account.owner_id, account.owner_id);
|
|
766
|
+
}
|
|
767
|
+
async function registerAgentFlow(apiKey, ownerId) {
|
|
768
|
+
const hostname = os.hostname().split(".")[0];
|
|
769
|
+
const dirName = process.cwd().split("/").pop() ?? process.cwd().split("\\").pop() ?? "agent";
|
|
770
|
+
const { agentName } = await prompts2({
|
|
771
|
+
type: "text",
|
|
772
|
+
name: "agentName",
|
|
773
|
+
message: "Name for this agent:",
|
|
774
|
+
initial: `${hostname} \u2014 ${dirName}`,
|
|
775
|
+
validate: (v) => v.trim().length > 0 || "Agent name is required"
|
|
776
|
+
});
|
|
777
|
+
if (agentName === void 0) {
|
|
778
|
+
process.exit(0);
|
|
779
|
+
}
|
|
780
|
+
const spinner = ora(" Registering agent...").start();
|
|
781
|
+
let agent;
|
|
782
|
+
try {
|
|
783
|
+
agent = await registerAgent2({
|
|
784
|
+
owner_id: ownerId,
|
|
785
|
+
name: agentName.trim(),
|
|
786
|
+
source: "cli"
|
|
787
|
+
}, apiKey);
|
|
788
|
+
spinner.succeed(` Agent registered: ${chalk4.bold(agent.agent_id)}`);
|
|
789
|
+
} catch (err) {
|
|
790
|
+
spinner.fail(` Registration failed: ${err.message}`);
|
|
791
|
+
process.exit(1);
|
|
792
|
+
}
|
|
793
|
+
try {
|
|
794
|
+
await writeLocalConfig({
|
|
795
|
+
agentId: agent.agent_id,
|
|
796
|
+
agentName: agent.agent_name,
|
|
797
|
+
proxyUrl: getStoredConfig().proxyUrl,
|
|
798
|
+
privateKeyPem: agent.private_key_pem
|
|
799
|
+
});
|
|
800
|
+
} catch (err) {
|
|
801
|
+
console.error(chalk4.red(` \u2717 Failed to write local config: ${err.message}`));
|
|
802
|
+
console.log(chalk4.dim(" Agent was registered \u2014 run again to save config locally."));
|
|
803
|
+
process.exit(1);
|
|
804
|
+
}
|
|
805
|
+
const ideResults = await writeIdeConfigs({
|
|
806
|
+
agentId: agent.agent_id,
|
|
807
|
+
ownerId,
|
|
808
|
+
proxyUrl: getStoredConfig().proxyUrl,
|
|
809
|
+
keyPath: path4.join(process.cwd(), ".agentvalet", "agent.key")
|
|
810
|
+
});
|
|
811
|
+
if (ideResults.length > 0) {
|
|
812
|
+
for (const r of ideResults) {
|
|
813
|
+
console.log(chalk4.dim(` MCP config written: ${r}`));
|
|
814
|
+
}
|
|
815
|
+
}
|
|
816
|
+
console.log("");
|
|
817
|
+
console.log(chalk4.bold.green(" \u2713 All done!"));
|
|
818
|
+
console.log("");
|
|
819
|
+
console.log(" Set these in your environment:");
|
|
820
|
+
console.log("");
|
|
821
|
+
console.log(formatEnvBlock({
|
|
822
|
+
AGENT_ID: agent.agent_id,
|
|
823
|
+
OWNER_ID: ownerId,
|
|
824
|
+
PROXY_URL: getStoredConfig().proxyUrl,
|
|
825
|
+
AGENT_PRIVATE_KEY_PATH: path4.join(process.cwd(), ".agentvalet", "agent.key")
|
|
826
|
+
}));
|
|
827
|
+
console.log("");
|
|
828
|
+
console.log(chalk4.dim(" Private key also saved to: .agentvalet/agent.key"));
|
|
829
|
+
console.log(chalk4.dim(" Add .agentvalet/ to your .gitignore"));
|
|
830
|
+
console.log("");
|
|
831
|
+
console.log(
|
|
832
|
+
` Dashboard: ${chalk4.cyan.underline("https://app.agentvalet.ai")}`
|
|
833
|
+
);
|
|
834
|
+
console.log(chalk4.dim(" Approve this agent in your dashboard to activate it."));
|
|
835
|
+
console.log("");
|
|
836
|
+
}
|
|
837
|
+
function showCredentials(config) {
|
|
838
|
+
console.log("");
|
|
839
|
+
console.log(" Your AgentValet credentials:");
|
|
840
|
+
console.log("");
|
|
841
|
+
console.log(` Owner ID: ${chalk4.bold(config.ownerId)}`);
|
|
842
|
+
console.log(` Proxy URL: ${chalk4.bold(config.proxyUrl)}`);
|
|
843
|
+
console.log(` Email: ${chalk4.bold(config.email)}`);
|
|
844
|
+
console.log("");
|
|
845
|
+
}
|
|
846
|
+
|
|
437
847
|
// src/index.ts
|
|
438
848
|
function collectScope(value, previous) {
|
|
439
849
|
return [...previous, value];
|
|
@@ -445,6 +855,10 @@ program.name("agentvalet-register").description("Self-register an AI agent with
|
|
|
445
855
|
let agentName = opts.name ?? "";
|
|
446
856
|
let description = opts.description ?? "";
|
|
447
857
|
let scopes = opts.scope;
|
|
858
|
+
if (!ownerId && !isAuthenticated()) {
|
|
859
|
+
await runOnboard();
|
|
860
|
+
return;
|
|
861
|
+
}
|
|
448
862
|
if (!agentName) {
|
|
449
863
|
if (isJson) {
|
|
450
864
|
console.error(JSON.stringify({ error: "--name is required in non-interactive mode" }));
|
|
@@ -461,7 +875,7 @@ program.name("agentvalet-register").description("Self-register an AI agent with
|
|
|
461
875
|
console.error(JSON.stringify({ error: "--owner or AGENTVALET_OWNER is required" }));
|
|
462
876
|
process.exit(3);
|
|
463
877
|
}
|
|
464
|
-
console.error(
|
|
878
|
+
console.error(chalk5.red("Error: --owner or AGENTVALET_OWNER environment variable is required"));
|
|
465
879
|
process.exit(3);
|
|
466
880
|
}
|
|
467
881
|
const scopeMap = /* @__PURE__ */ new Map();
|
|
@@ -469,7 +883,7 @@ program.name("agentvalet-register").description("Self-register an AI agent with
|
|
|
469
883
|
const colon = s.indexOf(":");
|
|
470
884
|
if (colon === -1) {
|
|
471
885
|
console.error(
|
|
472
|
-
isJson ? JSON.stringify({ error: `Invalid scope format: ${s} (expected platform:scope)` }) :
|
|
886
|
+
isJson ? JSON.stringify({ error: `Invalid scope format: ${s} (expected platform:scope)` }) : chalk5.red(`Invalid scope format: ${s} (expected platform:scope)`)
|
|
473
887
|
);
|
|
474
888
|
process.exit(3);
|
|
475
889
|
}
|
|
@@ -492,11 +906,11 @@ program.name("agentvalet-register").description("Self-register an AI agent with
|
|
|
492
906
|
});
|
|
493
907
|
} catch (err) {
|
|
494
908
|
const msg = err instanceof Error ? err.message : String(err);
|
|
495
|
-
console.error(isJson ? JSON.stringify({ error: msg }) :
|
|
909
|
+
console.error(isJson ? JSON.stringify({ error: msg }) : chalk5.red(`Registration failed: ${msg}`));
|
|
496
910
|
process.exit(3);
|
|
497
911
|
}
|
|
498
912
|
if (!isJson) {
|
|
499
|
-
console.log(
|
|
913
|
+
console.log(chalk5.cyan(`
|
|
500
914
|
Approve at: https://agentvalet.ai/registrations
|
|
501
915
|
`));
|
|
502
916
|
}
|
|
@@ -504,7 +918,7 @@ Approve at: https://agentvalet.ai/registrations
|
|
|
504
918
|
if (isJson) {
|
|
505
919
|
console.log(JSON.stringify({ status: "pending", token }));
|
|
506
920
|
} else {
|
|
507
|
-
console.log(
|
|
921
|
+
console.log(chalk5.yellow("Registration submitted (--no-wait). Token:"), token);
|
|
508
922
|
}
|
|
509
923
|
process.exit(0);
|
|
510
924
|
}
|
|
@@ -515,14 +929,14 @@ Approve at: https://agentvalet.ai/registrations
|
|
|
515
929
|
});
|
|
516
930
|
} catch (err) {
|
|
517
931
|
const msg = err instanceof Error ? err.message : String(err);
|
|
518
|
-
console.error(isJson ? JSON.stringify({ error: msg }) :
|
|
932
|
+
console.error(isJson ? JSON.stringify({ error: msg }) : chalk5.red(`Wait failed: ${msg}`));
|
|
519
933
|
process.exit(3);
|
|
520
934
|
}
|
|
521
935
|
if (result.status === "rejected") {
|
|
522
936
|
if (isJson) {
|
|
523
937
|
console.log(JSON.stringify({ status: "rejected" }));
|
|
524
938
|
} else {
|
|
525
|
-
console.log(
|
|
939
|
+
console.log(chalk5.red("\nRegistration denied by owner."));
|
|
526
940
|
}
|
|
527
941
|
process.exit(1);
|
|
528
942
|
}
|
|
@@ -530,7 +944,7 @@ Approve at: https://agentvalet.ai/registrations
|
|
|
530
944
|
if (isJson) {
|
|
531
945
|
console.log(JSON.stringify({ status: "timeout" }));
|
|
532
946
|
} else {
|
|
533
|
-
console.log(
|
|
947
|
+
console.log(chalk5.yellow("\nTimed out waiting for approval."));
|
|
534
948
|
}
|
|
535
949
|
process.exit(2);
|
|
536
950
|
}
|
|
@@ -549,30 +963,30 @@ Approve at: https://agentvalet.ai/registrations
|
|
|
549
963
|
}));
|
|
550
964
|
} catch (err) {
|
|
551
965
|
const msg = err instanceof Error ? err.message : String(err);
|
|
552
|
-
console.error(isJson ? JSON.stringify({ error: msg }) :
|
|
966
|
+
console.error(isJson ? JSON.stringify({ error: msg }) : chalk5.red(`Failed to save output: ${msg}`));
|
|
553
967
|
process.exit(3);
|
|
554
968
|
}
|
|
555
969
|
const keyWritten = !!privateKey;
|
|
556
970
|
if (isJson) {
|
|
557
971
|
console.log(JSON.stringify({ status: "approved", agentId, keyPath: keyWritten ? keyPath : null, envPath }));
|
|
558
972
|
} else {
|
|
559
|
-
console.log(
|
|
973
|
+
console.log(chalk5.green(`
|
|
560
974
|
Approved! Agent ID: ${agentId}`));
|
|
561
975
|
if (keyWritten) {
|
|
562
|
-
console.log(
|
|
976
|
+
console.log(chalk5.gray(`Key: ${keyPath}`));
|
|
563
977
|
} else {
|
|
564
|
-
console.log(
|
|
978
|
+
console.log(chalk5.yellow(`Key: not written \u2014 copy it from the dashboard and paste into ${keyPath}`));
|
|
565
979
|
}
|
|
566
|
-
console.log(
|
|
980
|
+
console.log(chalk5.gray(`Env file: ${envPath}`));
|
|
567
981
|
console.log(`
|
|
568
982
|
Source the env file before calling any tool:`);
|
|
569
|
-
console.log(
|
|
983
|
+
console.log(chalk5.cyan(` source ${envPath}`));
|
|
570
984
|
}
|
|
571
985
|
if (keyWritten) {
|
|
572
986
|
try {
|
|
573
987
|
if (grantedPlatforms && grantedPlatforms.length > 0) {
|
|
574
988
|
writePermissionsFromEvent(agentId, resolvedOwnerId, grantedPlatforms);
|
|
575
|
-
if (!isJson) console.log(
|
|
989
|
+
if (!isJson) console.log(chalk5.gray(`Permissions: .claude/agentvalet-permissions.md`));
|
|
576
990
|
} else {
|
|
577
991
|
await runRefresh({
|
|
578
992
|
envFile: opts.output,
|
|
@@ -580,10 +994,10 @@ Source the env file before calling any tool:`);
|
|
|
580
994
|
ifStale: false,
|
|
581
995
|
quiet: isJson
|
|
582
996
|
});
|
|
583
|
-
if (!isJson) console.log(
|
|
997
|
+
if (!isJson) console.log(chalk5.gray(`Permissions: .claude/agentvalet-permissions.md`));
|
|
584
998
|
}
|
|
585
999
|
} catch {
|
|
586
|
-
if (!isJson) console.log(
|
|
1000
|
+
if (!isJson) console.log(chalk5.yellow(`Permissions: run 'agentvalet-register refresh' to generate`));
|
|
587
1001
|
}
|
|
588
1002
|
}
|
|
589
1003
|
process.exit(0);
|
|
@@ -598,12 +1012,12 @@ program.command("refresh").description("Refresh approved permissions and update
|
|
|
598
1012
|
});
|
|
599
1013
|
} catch (err) {
|
|
600
1014
|
const msg = err instanceof Error ? err.message : String(err);
|
|
601
|
-
console.error(
|
|
1015
|
+
console.error(chalk5.red(`Refresh failed: ${msg}`));
|
|
602
1016
|
process.exit(3);
|
|
603
1017
|
}
|
|
604
1018
|
});
|
|
605
1019
|
program.command("mcp-server").description("Start the AgentValet MCP server (stdio transport)").action(async () => {
|
|
606
|
-
await import("./mcp-server-
|
|
1020
|
+
await import("./mcp-server-LUNOQPUO.js");
|
|
607
1021
|
});
|
|
608
1022
|
program.parseAsync().catch((err) => {
|
|
609
1023
|
console.error(err);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@agentvalet/register",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.1",
|
|
4
4
|
"description": "Self-register AI agents with AgentValet",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
"README.md"
|
|
12
12
|
],
|
|
13
13
|
"scripts": {
|
|
14
|
-
"build": "tsup src/index.ts --format esm --dts --clean",
|
|
14
|
+
"build": "tsup src/index.ts --format esm --dts --clean --shims",
|
|
15
15
|
"dev": "tsx src/index.ts",
|
|
16
16
|
"test": "vitest run",
|
|
17
17
|
"typecheck": "tsc --noEmit",
|
|
@@ -19,9 +19,12 @@
|
|
|
19
19
|
},
|
|
20
20
|
"dependencies": {
|
|
21
21
|
"@modelcontextprotocol/sdk": "^1.29.0",
|
|
22
|
+
"@octokit/auth-oauth-device": "^7.0.0",
|
|
22
23
|
"chalk": "^5.3.0",
|
|
23
24
|
"commander": "^12.0.0",
|
|
25
|
+
"conf": "^13.0.0",
|
|
24
26
|
"jose": "^6.2.2",
|
|
27
|
+
"open": "^10.0.0",
|
|
25
28
|
"ora": "^8.0.1",
|
|
26
29
|
"prompts": "^2.4.2",
|
|
27
30
|
"undici": "^6.0.0"
|
|
File without changes
|