@agentvalet/register 0.4.4 → 0.4.6
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 +415 -180
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
3
|
// src/index.ts
|
|
4
|
-
import { Command } from "commander";
|
|
5
|
-
import
|
|
4
|
+
import { Command as Command4 } from "commander";
|
|
5
|
+
import chalk11 from "chalk";
|
|
6
6
|
|
|
7
7
|
// src/wizard.ts
|
|
8
8
|
import prompts from "prompts";
|
|
@@ -166,7 +166,7 @@ function parseEvent(data) {
|
|
|
166
166
|
return null;
|
|
167
167
|
}
|
|
168
168
|
function sleep(ms) {
|
|
169
|
-
return new Promise((
|
|
169
|
+
return new Promise((resolve4) => setTimeout(resolve4, ms));
|
|
170
170
|
}
|
|
171
171
|
|
|
172
172
|
// src/save.ts
|
|
@@ -191,9 +191,9 @@ async function saveOutput(opts) {
|
|
|
191
191
|
}
|
|
192
192
|
|
|
193
193
|
// src/commands/refresh.ts
|
|
194
|
-
import { readFileSync as
|
|
194
|
+
import { readFileSync as readFileSync3, writeFileSync as writeFileSync2, existsSync as existsSync3, mkdirSync, statSync } from "fs";
|
|
195
195
|
import { createSign, createPrivateKey } from "crypto";
|
|
196
|
-
import { dirname as dirname2, resolve as
|
|
196
|
+
import { dirname as dirname2, resolve as resolve3 } from "path";
|
|
197
197
|
|
|
198
198
|
// src/lib/skill-writer.ts
|
|
199
199
|
import { existsSync, writeFileSync } from "fs";
|
|
@@ -410,6 +410,10 @@ To refresh this file: \`npx @agentvalet/register refresh\`
|
|
|
410
410
|
`;
|
|
411
411
|
}
|
|
412
412
|
|
|
413
|
+
// src/lib/require-agent.ts
|
|
414
|
+
import { existsSync as existsSync2, readFileSync as readFileSync2 } from "fs";
|
|
415
|
+
import { resolve as resolve2, join } from "path";
|
|
416
|
+
|
|
413
417
|
// src/config/store.ts
|
|
414
418
|
import Conf from "conf";
|
|
415
419
|
var store = new Conf({
|
|
@@ -428,24 +432,11 @@ function isAuthenticated() {
|
|
|
428
432
|
return !!store.get("apiKey");
|
|
429
433
|
}
|
|
430
434
|
|
|
431
|
-
// src/
|
|
432
|
-
|
|
433
|
-
var
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
function base64url(input) {
|
|
437
|
-
return Buffer.from(input).toString("base64url");
|
|
438
|
-
}
|
|
439
|
-
function signJwt(agentId, ownerId, privateKeyPem) {
|
|
440
|
-
const now = Math.floor(Date.now() / 1e3);
|
|
441
|
-
const header = base64url(JSON.stringify({ alg: "RS256", typ: "JWT" }));
|
|
442
|
-
const payload = base64url(JSON.stringify({ agent_id: agentId, owner_id: ownerId, iat: now, exp: now + 300 }));
|
|
443
|
-
const signingInput = `${header}.${payload}`;
|
|
444
|
-
const sign = createSign("RSA-SHA256");
|
|
445
|
-
sign.update(signingInput);
|
|
446
|
-
const signature = sign.sign(createPrivateKey(privateKeyPem), "base64url");
|
|
447
|
-
return `${signingInput}.${signature}`;
|
|
448
|
-
}
|
|
435
|
+
// src/lib/require-agent.ts
|
|
436
|
+
import chalk3 from "chalk";
|
|
437
|
+
var NO_AGENT_MSG = chalk3.red("\n \u2717 No agent registered.\n") + chalk3.dim(
|
|
438
|
+
" Run the following command first to register an agent in this directory:\n\n npx @agentvalet/register\n"
|
|
439
|
+
);
|
|
449
440
|
function parseEnvFile(content) {
|
|
450
441
|
const result = {};
|
|
451
442
|
for (const line of content.split("\n")) {
|
|
@@ -457,42 +448,68 @@ function parseEnvFile(content) {
|
|
|
457
448
|
}
|
|
458
449
|
return result;
|
|
459
450
|
}
|
|
460
|
-
function
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
}
|
|
468
|
-
async function runRefresh(options) {
|
|
469
|
-
const outputPath = resolve2(options.outputPath);
|
|
470
|
-
if (options.ifStale) {
|
|
451
|
+
function resolveAgent(envFile = ".env.agentvalet") {
|
|
452
|
+
let agentId;
|
|
453
|
+
let ownerId;
|
|
454
|
+
let apiUrl = "https://api.agentvalet.ai";
|
|
455
|
+
let keyPath;
|
|
456
|
+
const envPath = resolve2(envFile);
|
|
457
|
+
if (existsSync2(envPath)) {
|
|
471
458
|
try {
|
|
472
|
-
const
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
459
|
+
const vars = parseEnvFile(readFileSync2(envPath, "utf-8"));
|
|
460
|
+
agentId = vars["AGENTVALET_AGENT_ID"];
|
|
461
|
+
ownerId = vars["AGENTVALET_OWNER_ID"];
|
|
462
|
+
apiUrl = vars["AGENTVALET_API_URL"] ?? apiUrl;
|
|
463
|
+
keyPath = vars["AGENTVALET_PRIVATE_KEY_PATH"];
|
|
464
|
+
} catch {
|
|
465
|
+
}
|
|
466
|
+
}
|
|
467
|
+
if (!agentId || !ownerId || !keyPath) {
|
|
468
|
+
const localConfigPath = join(process.cwd(), ".agentvalet", "config.json");
|
|
469
|
+
if (existsSync2(localConfigPath)) {
|
|
470
|
+
try {
|
|
471
|
+
const local = JSON.parse(readFileSync2(localConfigPath, "utf-8"));
|
|
472
|
+
agentId = agentId ?? local["agent_id"];
|
|
473
|
+
apiUrl = local["proxy_url"] ?? apiUrl;
|
|
474
|
+
keyPath = keyPath ?? join(process.cwd(), ".agentvalet", "agent.key");
|
|
475
|
+
} catch {
|
|
476
|
+
}
|
|
477
|
+
}
|
|
478
|
+
try {
|
|
479
|
+
const global = getStoredConfig();
|
|
480
|
+
if (!ownerId) ownerId = global.ownerId ?? void 0;
|
|
481
|
+
} catch {
|
|
482
|
+
}
|
|
483
|
+
}
|
|
484
|
+
if (!agentId || !ownerId || !keyPath) {
|
|
485
|
+
try {
|
|
486
|
+
const global = getStoredConfig();
|
|
487
|
+
agentId = agentId ?? global.lastAgentId ?? void 0;
|
|
488
|
+
ownerId = ownerId ?? global.ownerId ?? void 0;
|
|
489
|
+
keyPath = keyPath ?? global.lastKeyPath ?? void 0;
|
|
490
|
+
apiUrl = global.proxyUrl ?? apiUrl;
|
|
481
491
|
} catch {
|
|
482
492
|
}
|
|
483
493
|
}
|
|
494
|
+
if (!agentId || !ownerId || !keyPath) {
|
|
495
|
+
process.stderr.write(NO_AGENT_MSG + "\n");
|
|
496
|
+
process.exit(1);
|
|
497
|
+
}
|
|
498
|
+
return { agentId, ownerId, keyPath, apiUrl };
|
|
499
|
+
}
|
|
500
|
+
function tryResolveAgent(envFile = ".env.agentvalet") {
|
|
484
501
|
let agentId;
|
|
485
502
|
let ownerId;
|
|
486
503
|
let apiUrl = "https://api.agentvalet.ai";
|
|
487
504
|
let keyPath;
|
|
488
|
-
const envPath = resolve2(
|
|
505
|
+
const envPath = resolve2(envFile);
|
|
489
506
|
if (existsSync2(envPath)) {
|
|
490
507
|
try {
|
|
491
|
-
const
|
|
492
|
-
agentId =
|
|
493
|
-
ownerId =
|
|
494
|
-
apiUrl =
|
|
495
|
-
keyPath =
|
|
508
|
+
const vars = parseEnvFile(readFileSync2(envPath, "utf-8"));
|
|
509
|
+
agentId = vars["AGENTVALET_AGENT_ID"];
|
|
510
|
+
ownerId = vars["AGENTVALET_OWNER_ID"];
|
|
511
|
+
apiUrl = vars["AGENTVALET_API_URL"] ?? apiUrl;
|
|
512
|
+
keyPath = vars["AGENTVALET_PRIVATE_KEY_PATH"];
|
|
496
513
|
} catch {
|
|
497
514
|
}
|
|
498
515
|
}
|
|
@@ -507,32 +524,72 @@ async function runRefresh(options) {
|
|
|
507
524
|
} catch {
|
|
508
525
|
}
|
|
509
526
|
}
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
}
|
|
527
|
+
try {
|
|
528
|
+
const global = getStoredConfig();
|
|
529
|
+
if (!ownerId) ownerId = global.ownerId ?? void 0;
|
|
530
|
+
} catch {
|
|
515
531
|
}
|
|
516
532
|
}
|
|
517
533
|
if (!agentId || !ownerId || !keyPath) {
|
|
518
534
|
try {
|
|
519
535
|
const global = getStoredConfig();
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
536
|
+
agentId = agentId ?? global.lastAgentId ?? void 0;
|
|
537
|
+
ownerId = ownerId ?? global.ownerId ?? void 0;
|
|
538
|
+
keyPath = keyPath ?? global.lastKeyPath ?? void 0;
|
|
539
|
+
apiUrl = global.proxyUrl ?? apiUrl;
|
|
524
540
|
} catch {
|
|
525
541
|
}
|
|
526
542
|
}
|
|
527
|
-
if (!agentId || !ownerId || !keyPath)
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
543
|
+
if (!agentId || !ownerId || !keyPath) return null;
|
|
544
|
+
return { agentId, ownerId, keyPath, apiUrl };
|
|
545
|
+
}
|
|
546
|
+
|
|
547
|
+
// src/commands/refresh.ts
|
|
548
|
+
var CLAUDE_START = "<!-- agentvalet:start -->";
|
|
549
|
+
var CLAUDE_END = "<!-- agentvalet:end -->";
|
|
550
|
+
var HOOK_COMMAND = "npx @agentvalet/register refresh --if-stale --quiet 2>/dev/null || true";
|
|
551
|
+
var HOOK_MARKER = "agentvalet/register refresh";
|
|
552
|
+
function base64url(input) {
|
|
553
|
+
return Buffer.from(input).toString("base64url");
|
|
554
|
+
}
|
|
555
|
+
function signJwt(agentId, ownerId, privateKeyPem) {
|
|
556
|
+
const now = Math.floor(Date.now() / 1e3);
|
|
557
|
+
const header = base64url(JSON.stringify({ alg: "RS256", typ: "JWT" }));
|
|
558
|
+
const payload = base64url(JSON.stringify({ agent_id: agentId, owner_id: ownerId, iat: now, exp: now + 300 }));
|
|
559
|
+
const signingInput = `${header}.${payload}`;
|
|
560
|
+
const sign = createSign("RSA-SHA256");
|
|
561
|
+
sign.update(signingInput);
|
|
562
|
+
const signature = sign.sign(createPrivateKey(privateKeyPem), "base64url");
|
|
563
|
+
return `${signingInput}.${signature}`;
|
|
564
|
+
}
|
|
565
|
+
function writePermissionsFromEvent(agentId, ownerId, platforms, outputPath = "./.claude/agentvalet-permissions.md") {
|
|
566
|
+
const content = generatePermissionsFile(agentId, ownerId, platforms);
|
|
567
|
+
const resolvedPath = resolve3(outputPath);
|
|
568
|
+
mkdirSync(dirname2(resolvedPath), { recursive: true });
|
|
569
|
+
writeFileSync2(resolvedPath, content, "utf-8");
|
|
570
|
+
embedInClaudeMd(content);
|
|
571
|
+
ensureHook();
|
|
572
|
+
}
|
|
573
|
+
async function runRefresh(options) {
|
|
574
|
+
const outputPath = resolve3(options.outputPath);
|
|
575
|
+
if (options.ifStale) {
|
|
576
|
+
try {
|
|
577
|
+
const stat = statSync(outputPath);
|
|
578
|
+
const fileIsFresh = Date.now() - stat.mtimeMs < 36e5;
|
|
579
|
+
const claudeMdPath = resolve3("CLAUDE.md");
|
|
580
|
+
const claudeMd = existsSync3(claudeMdPath) ? readFileSync3(claudeMdPath, "utf-8") : "";
|
|
581
|
+
const blockStart = claudeMd.indexOf(CLAUDE_START);
|
|
582
|
+
const blockEnd = claudeMd.indexOf(CLAUDE_END);
|
|
583
|
+
const blockContent = blockStart !== -1 && blockEnd !== -1 ? claudeMd.slice(blockStart, blockEnd) : "";
|
|
584
|
+
const blockHasPlatforms = blockContent.includes("### ");
|
|
585
|
+
if (fileIsFresh && blockHasPlatforms) return;
|
|
586
|
+
} catch {
|
|
587
|
+
}
|
|
532
588
|
}
|
|
589
|
+
const { agentId, ownerId, keyPath, apiUrl } = resolveAgent(options.envFile);
|
|
533
590
|
let privateKeyPem;
|
|
534
591
|
try {
|
|
535
|
-
privateKeyPem =
|
|
592
|
+
privateKeyPem = readFileSync3(keyPath, "utf-8");
|
|
536
593
|
} catch {
|
|
537
594
|
throw new Error(`Cannot read private key: ${keyPath}`);
|
|
538
595
|
}
|
|
@@ -559,18 +616,18 @@ Run 'npx @agentvalet/register' in this directory first.`
|
|
|
559
616
|
}
|
|
560
617
|
}
|
|
561
618
|
function embedInClaudeMd(permissionsContent) {
|
|
562
|
-
const claudeMdPath =
|
|
619
|
+
const claudeMdPath = resolve3("CLAUDE.md");
|
|
563
620
|
const block = `${CLAUDE_START}
|
|
564
621
|
${permissionsContent.trimEnd()}
|
|
565
622
|
${CLAUDE_END}`;
|
|
566
|
-
if (!
|
|
623
|
+
if (!existsSync3(claudeMdPath)) {
|
|
567
624
|
writeFileSync2(claudeMdPath, `# Agent Instructions
|
|
568
625
|
|
|
569
626
|
${block}
|
|
570
627
|
`, "utf-8");
|
|
571
628
|
return;
|
|
572
629
|
}
|
|
573
|
-
const existing =
|
|
630
|
+
const existing = readFileSync3(claudeMdPath, "utf-8");
|
|
574
631
|
if (existing.includes(CLAUDE_START)) {
|
|
575
632
|
const replaced = existing.replace(
|
|
576
633
|
new RegExp(`${CLAUDE_START}[\\s\\S]*?${CLAUDE_END}`, "m"),
|
|
@@ -586,11 +643,11 @@ ${block}
|
|
|
586
643
|
}
|
|
587
644
|
}
|
|
588
645
|
function ensureHook() {
|
|
589
|
-
const settingsPath =
|
|
646
|
+
const settingsPath = resolve3(".claude/settings.local.json");
|
|
590
647
|
let settings = {};
|
|
591
|
-
if (
|
|
648
|
+
if (existsSync3(settingsPath)) {
|
|
592
649
|
try {
|
|
593
|
-
settings = JSON.parse(
|
|
650
|
+
settings = JSON.parse(readFileSync3(settingsPath, "utf-8"));
|
|
594
651
|
} catch {
|
|
595
652
|
return;
|
|
596
653
|
}
|
|
@@ -617,51 +674,20 @@ function ensureHook() {
|
|
|
617
674
|
ensureMcpJson();
|
|
618
675
|
}
|
|
619
676
|
function ensureMcpJson() {
|
|
620
|
-
const mcpJsonPath =
|
|
677
|
+
const mcpJsonPath = resolve3(".mcp.json");
|
|
621
678
|
let mcpConfig = {};
|
|
622
|
-
if (
|
|
679
|
+
if (existsSync3(mcpJsonPath)) {
|
|
623
680
|
try {
|
|
624
|
-
mcpConfig = JSON.parse(
|
|
681
|
+
mcpConfig = JSON.parse(readFileSync3(mcpJsonPath, "utf-8"));
|
|
625
682
|
} catch {
|
|
626
683
|
return;
|
|
627
684
|
}
|
|
628
685
|
}
|
|
629
686
|
const servers = mcpConfig.mcpServers ?? {};
|
|
630
687
|
if (servers["agentvalet"]) return;
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
let keyPath;
|
|
635
|
-
const envPath = resolve2(".env.agentvalet");
|
|
636
|
-
if (existsSync2(envPath)) {
|
|
637
|
-
try {
|
|
638
|
-
const envVars = parseEnvFile(readFileSync2(envPath, "utf-8"));
|
|
639
|
-
agentId = envVars["AGENTVALET_AGENT_ID"];
|
|
640
|
-
ownerId = envVars["AGENTVALET_OWNER_ID"];
|
|
641
|
-
apiUrl = envVars["AGENTVALET_API_URL"] ?? apiUrl;
|
|
642
|
-
keyPath = envVars["AGENTVALET_PRIVATE_KEY_PATH"];
|
|
643
|
-
} catch {
|
|
644
|
-
}
|
|
645
|
-
}
|
|
646
|
-
if (!agentId || !keyPath) {
|
|
647
|
-
const localConfigPath = join(process.cwd(), ".agentvalet", "config.json");
|
|
648
|
-
if (existsSync2(localConfigPath)) {
|
|
649
|
-
try {
|
|
650
|
-
const local = JSON.parse(readFileSync2(localConfigPath, "utf-8"));
|
|
651
|
-
agentId = agentId ?? local["agent_id"];
|
|
652
|
-
apiUrl = local["proxy_url"] ?? apiUrl;
|
|
653
|
-
keyPath = keyPath ?? join(process.cwd(), ".agentvalet", "agent.key");
|
|
654
|
-
} catch {
|
|
655
|
-
}
|
|
656
|
-
}
|
|
657
|
-
if (!ownerId) {
|
|
658
|
-
try {
|
|
659
|
-
ownerId = getStoredConfig().ownerId ?? void 0;
|
|
660
|
-
} catch {
|
|
661
|
-
}
|
|
662
|
-
}
|
|
663
|
-
}
|
|
664
|
-
if (!agentId || !ownerId || !keyPath) return;
|
|
688
|
+
const creds = tryResolveAgent();
|
|
689
|
+
if (!creds) return;
|
|
690
|
+
const { agentId, ownerId, apiUrl, keyPath } = creds;
|
|
665
691
|
servers["agentvalet"] = {
|
|
666
692
|
command: "npx",
|
|
667
693
|
args: ["-y", "@agentvalet/register", "mcp-server"],
|
|
@@ -677,14 +703,14 @@ function ensureMcpJson() {
|
|
|
677
703
|
}
|
|
678
704
|
|
|
679
705
|
// src/commands/onboard.ts
|
|
680
|
-
import
|
|
706
|
+
import chalk7 from "chalk";
|
|
681
707
|
import ora from "ora";
|
|
682
708
|
import prompts3 from "prompts";
|
|
683
709
|
|
|
684
710
|
// src/auth/github-device-flow.ts
|
|
685
711
|
import { createOAuthDeviceAuth } from "@octokit/auth-oauth-device";
|
|
686
712
|
import open from "open";
|
|
687
|
-
import
|
|
713
|
+
import chalk4 from "chalk";
|
|
688
714
|
var GITHUB_CLIENT_ID = process.env.AGENTVALET_GITHUB_CLIENT_ID ?? "Ov23liQcaW0HcqJxmLfF";
|
|
689
715
|
async function authenticateWithGitHub() {
|
|
690
716
|
const auth = createOAuthDeviceAuth({
|
|
@@ -693,15 +719,15 @@ async function authenticateWithGitHub() {
|
|
|
693
719
|
scopes: ["user:email", "read:user"],
|
|
694
720
|
onVerification(verification) {
|
|
695
721
|
console.log("");
|
|
696
|
-
console.log(
|
|
722
|
+
console.log(chalk4.bold(" Authenticate with GitHub"));
|
|
697
723
|
console.log("");
|
|
698
|
-
console.log(` 1. Open: ${
|
|
699
|
-
console.log(` 2. Enter code: ${
|
|
724
|
+
console.log(` 1. Open: ${chalk4.cyan.underline(verification.verification_uri)}`);
|
|
725
|
+
console.log(` 2. Enter code: ${chalk4.bold.yellow(verification.user_code)}`);
|
|
700
726
|
console.log("");
|
|
701
727
|
open(verification.verification_uri).catch(() => {
|
|
702
|
-
console.log(
|
|
728
|
+
console.log(chalk4.dim(" (Could not open browser \u2014 navigate to the URL above manually)"));
|
|
703
729
|
});
|
|
704
|
-
console.log(
|
|
730
|
+
console.log(chalk4.dim(" Waiting for authorisation..."));
|
|
705
731
|
}
|
|
706
732
|
});
|
|
707
733
|
const tokenAuth = await auth({ type: "oauth" });
|
|
@@ -853,20 +879,20 @@ async function writeLocalConfig(config) {
|
|
|
853
879
|
}
|
|
854
880
|
|
|
855
881
|
// src/output/env.ts
|
|
856
|
-
import
|
|
882
|
+
import chalk5 from "chalk";
|
|
857
883
|
import { appendFile as appendFile2, writeFile as writeFile3 } from "fs/promises";
|
|
858
|
-
import { existsSync as
|
|
884
|
+
import { existsSync as existsSync4 } from "fs";
|
|
859
885
|
import path3 from "path";
|
|
860
886
|
function formatEnvBlock(vars) {
|
|
861
887
|
return Object.entries(vars).map(([key, value]) => {
|
|
862
888
|
const truncated = value.length > 60 ? value.substring(0, 40) + "..." + value.substring(value.length - 10) : value;
|
|
863
|
-
return ` ${
|
|
889
|
+
return ` ${chalk5.dim(key + "=")}${chalk5.white(truncated)}`;
|
|
864
890
|
}).join("\n");
|
|
865
891
|
}
|
|
866
892
|
|
|
867
893
|
// src/config/ide.ts
|
|
868
894
|
import { mkdir as mkdir3, writeFile as writeFile4, readFile as readFile2, appendFile as appendFile3 } from "fs/promises";
|
|
869
|
-
import { existsSync as
|
|
895
|
+
import { existsSync as existsSync5 } from "fs";
|
|
870
896
|
import path4 from "path";
|
|
871
897
|
import os from "os";
|
|
872
898
|
function buildMcpEntry(params) {
|
|
@@ -883,7 +909,7 @@ function buildMcpEntry(params) {
|
|
|
883
909
|
}
|
|
884
910
|
async function mergeJsonFile(filePath, key, value) {
|
|
885
911
|
let existing = {};
|
|
886
|
-
if (
|
|
912
|
+
if (existsSync5(filePath)) {
|
|
887
913
|
try {
|
|
888
914
|
const text = await readFile2(filePath, "utf8");
|
|
889
915
|
existing = JSON.parse(text);
|
|
@@ -941,9 +967,9 @@ async function writeGlobalFrameworkConfigs(params) {
|
|
|
941
967
|
const written = [];
|
|
942
968
|
const codexDir = path4.join(os.homedir(), ".codex");
|
|
943
969
|
const codexConfigPath = path4.join(codexDir, "config.toml");
|
|
944
|
-
if (
|
|
970
|
+
if (existsSync5(codexDir)) {
|
|
945
971
|
try {
|
|
946
|
-
const existing =
|
|
972
|
+
const existing = existsSync5(codexConfigPath) ? await readFile2(codexConfigPath, "utf8") : "";
|
|
947
973
|
if (!existing.includes("[mcp_servers.agentvalet]")) {
|
|
948
974
|
const addition = `
|
|
949
975
|
[mcp_servers.agentvalet]
|
|
@@ -974,7 +1000,7 @@ async function writeIdeConfigs(params) {
|
|
|
974
1000
|
console.warn(` Warning: could not write .mcp.json: ${err.message}`);
|
|
975
1001
|
}
|
|
976
1002
|
const claudeMdPath = path4.join(cwd, "CLAUDE.md");
|
|
977
|
-
if (!
|
|
1003
|
+
if (!existsSync5(claudeMdPath)) {
|
|
978
1004
|
try {
|
|
979
1005
|
await writeFile4(claudeMdPath, buildClaudeMd(params.agentId, params.ownerId, params.proxyUrl), "utf8");
|
|
980
1006
|
written.push("CLAUDE.md");
|
|
@@ -1000,12 +1026,12 @@ async function writeIdeConfigs(params) {
|
|
|
1000
1026
|
}
|
|
1001
1027
|
|
|
1002
1028
|
// src/config/frameworks.ts
|
|
1003
|
-
import { existsSync as
|
|
1029
|
+
import { existsSync as existsSync6 } from "fs";
|
|
1004
1030
|
import { execSync as execSync2 } from "child_process";
|
|
1005
1031
|
import os2 from "os";
|
|
1006
1032
|
import path5 from "path";
|
|
1007
1033
|
import prompts2 from "prompts";
|
|
1008
|
-
import
|
|
1034
|
+
import chalk6 from "chalk";
|
|
1009
1035
|
function tryBinary(cmd) {
|
|
1010
1036
|
try {
|
|
1011
1037
|
execSync2(`${cmd} --version`, { stdio: "ignore", timeout: 3e3 });
|
|
@@ -1020,20 +1046,20 @@ function cursorInstalled() {
|
|
|
1020
1046
|
if (platform === "win32") {
|
|
1021
1047
|
const appData = process.env.APPDATA ?? path5.join(home, "AppData", "Roaming");
|
|
1022
1048
|
const localAppData = process.env.LOCALAPPDATA ?? path5.join(home, "AppData", "Local");
|
|
1023
|
-
return
|
|
1049
|
+
return existsSync6(path5.join(appData, "Cursor")) || existsSync6(path5.join(localAppData, "Programs", "cursor"));
|
|
1024
1050
|
}
|
|
1025
1051
|
if (platform === "darwin") {
|
|
1026
|
-
return
|
|
1052
|
+
return existsSync6(path5.join(home, "Library", "Application Support", "Cursor")) || existsSync6("/Applications/Cursor.app");
|
|
1027
1053
|
}
|
|
1028
|
-
return
|
|
1054
|
+
return existsSync6(path5.join(home, ".config", "Cursor")) || existsSync6("/usr/share/applications/cursor.desktop");
|
|
1029
1055
|
}
|
|
1030
1056
|
function detectFrameworks() {
|
|
1031
1057
|
const home = os2.homedir();
|
|
1032
1058
|
return {
|
|
1033
|
-
codex:
|
|
1034
|
-
claudeCode:
|
|
1035
|
-
cursor:
|
|
1036
|
-
openclaw:
|
|
1059
|
+
codex: existsSync6(path5.join(home, ".codex")) || tryBinary("codex"),
|
|
1060
|
+
claudeCode: existsSync6(path5.join(home, ".claude")) || tryBinary("claude"),
|
|
1061
|
+
cursor: existsSync6(path5.join(process.cwd(), ".cursor")) || cursorInstalled(),
|
|
1062
|
+
openclaw: existsSync6(path5.join(home, ".openclaw"))
|
|
1037
1063
|
};
|
|
1038
1064
|
}
|
|
1039
1065
|
async function frameworkSetupConsent(detected) {
|
|
@@ -1054,9 +1080,9 @@ async function frameworkSetupConsent(detected) {
|
|
|
1054
1080
|
}
|
|
1055
1081
|
if (items.length === 0) return false;
|
|
1056
1082
|
console.log("");
|
|
1057
|
-
console.log(
|
|
1083
|
+
console.log(chalk6.bold(" Detected agent frameworks"));
|
|
1058
1084
|
for (const item of items) {
|
|
1059
|
-
console.log(
|
|
1085
|
+
console.log(chalk6.dim(` ${item}`));
|
|
1060
1086
|
}
|
|
1061
1087
|
console.log("");
|
|
1062
1088
|
const { confirm } = await prompts2({
|
|
@@ -1074,13 +1100,13 @@ import path6 from "path";
|
|
|
1074
1100
|
import { writeFile as writeFile5 } from "fs/promises";
|
|
1075
1101
|
async function runOnboard() {
|
|
1076
1102
|
console.log("");
|
|
1077
|
-
console.log(
|
|
1078
|
-
console.log(
|
|
1103
|
+
console.log(chalk7.bold(" AgentValet \u2014 Agent Registration"));
|
|
1104
|
+
console.log(chalk7.dim(" app.agentvalet.ai"));
|
|
1079
1105
|
console.log("");
|
|
1080
1106
|
if (isAuthenticated()) {
|
|
1081
1107
|
const stored = getStoredConfig();
|
|
1082
1108
|
console.log(
|
|
1083
|
-
|
|
1109
|
+
chalk7.green(" \u2713 Already authenticated as") + chalk7.bold(` ${stored.email}`)
|
|
1084
1110
|
);
|
|
1085
1111
|
const { action } = await prompts3({
|
|
1086
1112
|
type: "select",
|
|
@@ -1101,7 +1127,7 @@ async function runOnboard() {
|
|
|
1101
1127
|
}
|
|
1102
1128
|
if (action === "signout") {
|
|
1103
1129
|
clearConfig();
|
|
1104
|
-
console.log(
|
|
1130
|
+
console.log(chalk7.dim(" Signed out. Run again to re-authenticate."));
|
|
1105
1131
|
return;
|
|
1106
1132
|
}
|
|
1107
1133
|
await registerAgentFlow(stored.cliToken, stored.ownerId);
|
|
@@ -1130,14 +1156,14 @@ async function runOnboard() {
|
|
|
1130
1156
|
const result = await authenticateWithGitHub();
|
|
1131
1157
|
githubToken = result.token;
|
|
1132
1158
|
} catch (err) {
|
|
1133
|
-
console.error(
|
|
1159
|
+
console.error(chalk7.red(` \u2717 Authentication failed: ${err.message}`));
|
|
1134
1160
|
process.exit(1);
|
|
1135
1161
|
}
|
|
1136
1162
|
spinner = ora(" Fetching your GitHub profile...").start();
|
|
1137
1163
|
let githubUser;
|
|
1138
1164
|
try {
|
|
1139
1165
|
githubUser = await getGitHubUser(githubToken);
|
|
1140
|
-
spinner.succeed(` GitHub: ${
|
|
1166
|
+
spinner.succeed(` GitHub: ${chalk7.bold("@" + githubUser.login)}`);
|
|
1141
1167
|
} catch (err) {
|
|
1142
1168
|
spinner.fail(` Failed to fetch GitHub profile: ${err.message}`);
|
|
1143
1169
|
process.exit(1);
|
|
@@ -1186,7 +1212,7 @@ async function runOnboard() {
|
|
|
1186
1212
|
}
|
|
1187
1213
|
async function ownerIdFlow() {
|
|
1188
1214
|
console.log("");
|
|
1189
|
-
console.log(
|
|
1215
|
+
console.log(chalk7.dim(" Find your Owner ID at: ") + chalk7.cyan.underline("https://app.agentvalet.ai/settings"));
|
|
1190
1216
|
console.log("");
|
|
1191
1217
|
const { ownerId } = await prompts3({
|
|
1192
1218
|
type: "text",
|
|
@@ -1201,10 +1227,10 @@ async function ownerIdFlow() {
|
|
|
1201
1227
|
let account;
|
|
1202
1228
|
try {
|
|
1203
1229
|
account = await getAccount(ownerId.trim());
|
|
1204
|
-
spinner.succeed(` Account verified \u2014 plan: ${
|
|
1230
|
+
spinner.succeed(` Account verified \u2014 plan: ${chalk7.bold(account.plan)}`);
|
|
1205
1231
|
} catch (err) {
|
|
1206
1232
|
spinner.fail(` Could not verify Owner ID: ${err.message}`);
|
|
1207
|
-
console.log(
|
|
1233
|
+
console.log(chalk7.dim(" Make sure you copied the full Owner ID from app.agentvalet.ai/settings"));
|
|
1208
1234
|
process.exit(1);
|
|
1209
1235
|
}
|
|
1210
1236
|
saveConfig({
|
|
@@ -1238,7 +1264,7 @@ async function registerAgentFlow(apiKey, ownerId) {
|
|
|
1238
1264
|
name: agentName.trim(),
|
|
1239
1265
|
source: "cli"
|
|
1240
1266
|
}, apiKey);
|
|
1241
|
-
spinner.succeed(` Agent registered: ${
|
|
1267
|
+
spinner.succeed(` Agent registered: ${chalk7.bold(agent.agent_id)}`);
|
|
1242
1268
|
} catch (err) {
|
|
1243
1269
|
spinner.fail(` Registration failed: ${err.message}`);
|
|
1244
1270
|
process.exit(1);
|
|
@@ -1254,8 +1280,8 @@ async function registerAgentFlow(apiKey, ownerId) {
|
|
|
1254
1280
|
});
|
|
1255
1281
|
saveConfig({ lastAgentId: agent.agent_id, lastKeyPath: keyPath });
|
|
1256
1282
|
} catch (err) {
|
|
1257
|
-
console.error(
|
|
1258
|
-
console.log(
|
|
1283
|
+
console.error(chalk7.red(` \u2717 Failed to write local config: ${err.message}`));
|
|
1284
|
+
console.log(chalk7.dim(" Agent was registered \u2014 run again to save config locally."));
|
|
1259
1285
|
process.exit(1);
|
|
1260
1286
|
}
|
|
1261
1287
|
try {
|
|
@@ -1273,7 +1299,7 @@ async function registerAgentFlow(apiKey, ownerId) {
|
|
|
1273
1299
|
const shouldSetup = await frameworkSetupConsent(detected);
|
|
1274
1300
|
if (shouldSetup) {
|
|
1275
1301
|
console.log("");
|
|
1276
|
-
console.log(
|
|
1302
|
+
console.log(chalk7.bold(" Configuring agent frameworks..."));
|
|
1277
1303
|
console.log("");
|
|
1278
1304
|
const ideResults = await writeIdeConfigs({
|
|
1279
1305
|
agentId: agent.agent_id,
|
|
@@ -1283,7 +1309,7 @@ async function registerAgentFlow(apiKey, ownerId) {
|
|
|
1283
1309
|
detected
|
|
1284
1310
|
});
|
|
1285
1311
|
for (const r of ideResults) {
|
|
1286
|
-
console.log(
|
|
1312
|
+
console.log(chalk7.green(` \u2713 ${r}`));
|
|
1287
1313
|
}
|
|
1288
1314
|
const globalResults = await writeGlobalFrameworkConfigs({
|
|
1289
1315
|
agentId: agent.agent_id,
|
|
@@ -1292,7 +1318,7 @@ async function registerAgentFlow(apiKey, ownerId) {
|
|
|
1292
1318
|
keyPath
|
|
1293
1319
|
});
|
|
1294
1320
|
for (const r of globalResults) {
|
|
1295
|
-
console.log(
|
|
1321
|
+
console.log(chalk7.green(` \u2713 ${r}`));
|
|
1296
1322
|
}
|
|
1297
1323
|
if (detected.codex) {
|
|
1298
1324
|
writeAgentsMd();
|
|
@@ -1310,11 +1336,11 @@ async function registerAgentFlow(apiKey, ownerId) {
|
|
|
1310
1336
|
ensureMcpServer();
|
|
1311
1337
|
} else if (shouldSetup === false) {
|
|
1312
1338
|
console.log("");
|
|
1313
|
-
console.log(
|
|
1314
|
-
console.log(
|
|
1339
|
+
console.log(chalk7.dim(" To configure agent frameworks manually:"));
|
|
1340
|
+
console.log(chalk7.dim(" https://docs.agentvalet.ai/setup"));
|
|
1315
1341
|
}
|
|
1316
1342
|
console.log("");
|
|
1317
|
-
console.log(
|
|
1343
|
+
console.log(chalk7.bold.green(" \u2713 All done!"));
|
|
1318
1344
|
console.log("");
|
|
1319
1345
|
console.log(" Set these in your environment:");
|
|
1320
1346
|
console.log("");
|
|
@@ -1325,35 +1351,241 @@ async function registerAgentFlow(apiKey, ownerId) {
|
|
|
1325
1351
|
AGENT_PRIVATE_KEY_PATH: path6.join(process.cwd(), ".agentvalet", "agent.key")
|
|
1326
1352
|
}));
|
|
1327
1353
|
console.log("");
|
|
1328
|
-
console.log(
|
|
1329
|
-
console.log(
|
|
1354
|
+
console.log(chalk7.dim(" Private key also saved to: .agentvalet/agent.key"));
|
|
1355
|
+
console.log(chalk7.dim(" Add .agentvalet/ to your .gitignore"));
|
|
1330
1356
|
console.log("");
|
|
1331
1357
|
console.log(
|
|
1332
|
-
` Dashboard: ${
|
|
1358
|
+
` Dashboard: ${chalk7.cyan.underline("https://app.agentvalet.ai")}`
|
|
1333
1359
|
);
|
|
1334
|
-
console.log(
|
|
1360
|
+
console.log(chalk7.dim(" Approve this agent in your dashboard to activate it."));
|
|
1335
1361
|
console.log("");
|
|
1336
1362
|
console.log(" Useful commands:");
|
|
1337
|
-
console.log(
|
|
1338
|
-
console.log(
|
|
1363
|
+
console.log(chalk7.dim(" npx @agentvalet/register \u2014 register another agent"));
|
|
1364
|
+
console.log(chalk7.dim(" npx @agentvalet/register refresh \u2014 refresh approved permissions"));
|
|
1339
1365
|
console.log("");
|
|
1340
1366
|
}
|
|
1341
1367
|
function showCredentials(config) {
|
|
1342
1368
|
console.log("");
|
|
1343
1369
|
console.log(" Your AgentValet credentials:");
|
|
1344
1370
|
console.log("");
|
|
1345
|
-
console.log(` Owner ID: ${
|
|
1346
|
-
console.log(` Proxy URL: ${
|
|
1347
|
-
console.log(` Email: ${
|
|
1371
|
+
console.log(` Owner ID: ${chalk7.bold(config.ownerId)}`);
|
|
1372
|
+
console.log(` Proxy URL: ${chalk7.bold(config.proxyUrl)}`);
|
|
1373
|
+
console.log(` Email: ${chalk7.bold(config.email)}`);
|
|
1348
1374
|
console.log("");
|
|
1349
1375
|
}
|
|
1350
1376
|
|
|
1377
|
+
// src/commands/list.ts
|
|
1378
|
+
import { Command } from "commander";
|
|
1379
|
+
import chalk8 from "chalk";
|
|
1380
|
+
|
|
1381
|
+
// src/lib/config.ts
|
|
1382
|
+
import { homedir } from "os";
|
|
1383
|
+
import { join as join2 } from "path";
|
|
1384
|
+
import { readFile as readFile3, writeFile as writeFile6, mkdir as mkdir4 } from "fs/promises";
|
|
1385
|
+
var CONFIG_PATH = join2(homedir(), ".agentvalet", "config.json");
|
|
1386
|
+
var DEFAULTS = {
|
|
1387
|
+
apiUrl: "https://app.agentvalet.ai",
|
|
1388
|
+
token: null
|
|
1389
|
+
};
|
|
1390
|
+
async function loadConfig() {
|
|
1391
|
+
try {
|
|
1392
|
+
const raw = await readFile3(CONFIG_PATH, "utf-8");
|
|
1393
|
+
return { ...DEFAULTS, ...JSON.parse(raw) };
|
|
1394
|
+
} catch (err) {
|
|
1395
|
+
if (err.code === "ENOENT") return { ...DEFAULTS };
|
|
1396
|
+
throw err;
|
|
1397
|
+
}
|
|
1398
|
+
}
|
|
1399
|
+
|
|
1400
|
+
// src/lib/api.ts
|
|
1401
|
+
async function request(path7, options) {
|
|
1402
|
+
const config = await loadConfig();
|
|
1403
|
+
if (!config.token) throw new Error("Not authenticated. Run: agentvalet login");
|
|
1404
|
+
const response = await fetch(`${config.apiUrl}/functions/v1${path7}`, {
|
|
1405
|
+
method: options.method,
|
|
1406
|
+
headers: {
|
|
1407
|
+
"Authorization": `Bearer ${config.token}`,
|
|
1408
|
+
"Content-Type": "application/json"
|
|
1409
|
+
},
|
|
1410
|
+
body: options.body ? JSON.stringify(options.body) : void 0
|
|
1411
|
+
});
|
|
1412
|
+
if (!response.ok) {
|
|
1413
|
+
const text = await response.text();
|
|
1414
|
+
throw new Error(`API error ${response.status}: ${text}`);
|
|
1415
|
+
}
|
|
1416
|
+
return response.json();
|
|
1417
|
+
}
|
|
1418
|
+
async function revokeAgent(agentId) {
|
|
1419
|
+
return request("/revoke-agent", { method: "POST", body: { agentId } });
|
|
1420
|
+
}
|
|
1421
|
+
async function listAgents() {
|
|
1422
|
+
return request("/list-agents", { method: "GET" });
|
|
1423
|
+
}
|
|
1424
|
+
|
|
1425
|
+
// src/commands/list.ts
|
|
1426
|
+
function listCommand() {
|
|
1427
|
+
return new Command("list").description("List all registered agents").action(async () => {
|
|
1428
|
+
const config = getStoredConfig();
|
|
1429
|
+
if (!config.ownerId) {
|
|
1430
|
+
process.stderr.write(
|
|
1431
|
+
chalk8.red("\n \u2717 No agent registered.\n") + chalk8.dim(" Run the following command first:\n\n npx @agentvalet/register\n\n")
|
|
1432
|
+
);
|
|
1433
|
+
process.exit(1);
|
|
1434
|
+
}
|
|
1435
|
+
try {
|
|
1436
|
+
const agents = await listAgents();
|
|
1437
|
+
if (agents.length === 0) {
|
|
1438
|
+
console.log("No agents registered yet. Run: npx @agentvalet/register");
|
|
1439
|
+
return;
|
|
1440
|
+
}
|
|
1441
|
+
const maxNameLen = Math.max(...agents.map((a) => a.name.length), 4);
|
|
1442
|
+
const header = `${"ID".padEnd(30)} ${"NAME".padEnd(maxNameLen)} STATUS`;
|
|
1443
|
+
console.log(header);
|
|
1444
|
+
console.log("-".repeat(header.length));
|
|
1445
|
+
for (const agent of agents) {
|
|
1446
|
+
const status = agent.status === "active" ? chalk8.green("\u2713 active") : agent.status === "suspended" ? chalk8.yellow("\u26A0 suspended") : chalk8.red("\u2717 revoked");
|
|
1447
|
+
console.log(`${agent.id.padEnd(30)} ${agent.name.padEnd(maxNameLen)} ${status}`);
|
|
1448
|
+
}
|
|
1449
|
+
} catch (err) {
|
|
1450
|
+
console.error(chalk8.red(String(err)));
|
|
1451
|
+
process.exit(1);
|
|
1452
|
+
}
|
|
1453
|
+
});
|
|
1454
|
+
}
|
|
1455
|
+
|
|
1456
|
+
// src/commands/revoke.ts
|
|
1457
|
+
import { Command as Command2 } from "commander";
|
|
1458
|
+
import chalk9 from "chalk";
|
|
1459
|
+
import * as readline from "readline";
|
|
1460
|
+
function revokeCommand() {
|
|
1461
|
+
return new Command2("revoke").description("Revoke an agent (cascades to all child agents)").requiredOption("--agent-id <agentId>", "Agent ID to revoke (agt_...)").action(async (opts) => {
|
|
1462
|
+
const config = getStoredConfig();
|
|
1463
|
+
if (!config.ownerId) {
|
|
1464
|
+
process.stderr.write(
|
|
1465
|
+
chalk9.red("\n \u2717 No agent registered.\n") + chalk9.dim(" Run the following command first:\n\n npx @agentvalet/register\n\n")
|
|
1466
|
+
);
|
|
1467
|
+
process.exit(1);
|
|
1468
|
+
}
|
|
1469
|
+
const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
|
|
1470
|
+
const confirmed = await new Promise((resolve4) => {
|
|
1471
|
+
rl.question(
|
|
1472
|
+
chalk9.yellow(`Revoke ${opts.agentId}? This cascades to all child agents and cannot be undone. (y/N) `),
|
|
1473
|
+
(ans) => {
|
|
1474
|
+
rl.close();
|
|
1475
|
+
resolve4(ans.trim().toLowerCase() === "y");
|
|
1476
|
+
}
|
|
1477
|
+
);
|
|
1478
|
+
});
|
|
1479
|
+
if (!confirmed) {
|
|
1480
|
+
console.log("Cancelled.");
|
|
1481
|
+
return;
|
|
1482
|
+
}
|
|
1483
|
+
try {
|
|
1484
|
+
const result = await revokeAgent(opts.agentId);
|
|
1485
|
+
console.log(chalk9.green(`Revoked ${result.revokedAgentIds.length} agent(s)`));
|
|
1486
|
+
if (result.revokedAgentIds.length > 1) {
|
|
1487
|
+
console.log("Revoked:", result.revokedAgentIds.join(", "));
|
|
1488
|
+
}
|
|
1489
|
+
} catch (err) {
|
|
1490
|
+
console.error(chalk9.red(String(err)));
|
|
1491
|
+
process.exit(1);
|
|
1492
|
+
}
|
|
1493
|
+
});
|
|
1494
|
+
}
|
|
1495
|
+
|
|
1496
|
+
// src/commands/inject.ts
|
|
1497
|
+
import { Command as Command3 } from "commander";
|
|
1498
|
+
import chalk10 from "chalk";
|
|
1499
|
+
import { readFile as readFile6 } from "fs/promises";
|
|
1500
|
+
|
|
1501
|
+
// src/lib/claude-config.ts
|
|
1502
|
+
import { homedir as homedir2 } from "os";
|
|
1503
|
+
import { join as join3 } from "path";
|
|
1504
|
+
import { readFile as readFile4, writeFile as writeFile7, mkdir as mkdir5, access } from "fs/promises";
|
|
1505
|
+
var CLAUDE_CONFIG_PATH = join3(homedir2(), ".claude", "config");
|
|
1506
|
+
async function writeKeyToClaudeConfig(agentId, privateKeyPem) {
|
|
1507
|
+
let config = {};
|
|
1508
|
+
try {
|
|
1509
|
+
await access(CLAUDE_CONFIG_PATH);
|
|
1510
|
+
const raw = await readFile4(CLAUDE_CONFIG_PATH, "utf-8");
|
|
1511
|
+
config = JSON.parse(raw);
|
|
1512
|
+
} catch {
|
|
1513
|
+
}
|
|
1514
|
+
config.agent_keys = config.agent_keys ?? {};
|
|
1515
|
+
config.agent_keys[agentId] = Buffer.from(privateKeyPem).toString("base64");
|
|
1516
|
+
await mkdir5(join3(homedir2(), ".claude"), { recursive: true });
|
|
1517
|
+
await writeFile7(CLAUDE_CONFIG_PATH, JSON.stringify(config, null, 2), "utf-8");
|
|
1518
|
+
}
|
|
1519
|
+
|
|
1520
|
+
// src/lib/env-writer.ts
|
|
1521
|
+
import { readFile as readFile5, writeFile as writeFile8, access as access2 } from "fs/promises";
|
|
1522
|
+
var ENV_VAR_NAME = (agentId) => `AGENTVALET_PRIVATE_KEY_${agentId.replace(/-/g, "_").toUpperCase()}`;
|
|
1523
|
+
async function writeKeyToEnvLocal(agentId, privateKeyPem) {
|
|
1524
|
+
const varName = ENV_VAR_NAME(agentId);
|
|
1525
|
+
const b64Key = Buffer.from(privateKeyPem).toString("base64");
|
|
1526
|
+
const line = `
|
|
1527
|
+
# AgentValet private key for ${agentId} (base64-encoded PEM)
|
|
1528
|
+
${varName}=${b64Key}
|
|
1529
|
+
`;
|
|
1530
|
+
let existing = "";
|
|
1531
|
+
try {
|
|
1532
|
+
await access2(".env.local");
|
|
1533
|
+
existing = await readFile5(".env.local", "utf-8");
|
|
1534
|
+
} catch {
|
|
1535
|
+
}
|
|
1536
|
+
if (existing.includes(varName)) {
|
|
1537
|
+
const lines = existing.split("\n");
|
|
1538
|
+
const filtered = lines.filter((l) => !l.startsWith(`${varName}=`));
|
|
1539
|
+
await writeFile8(".env.local", filtered.join("\n") + line, "utf-8");
|
|
1540
|
+
} else {
|
|
1541
|
+
await writeFile8(".env.local", existing + line, "utf-8");
|
|
1542
|
+
}
|
|
1543
|
+
}
|
|
1544
|
+
|
|
1545
|
+
// src/commands/inject.ts
|
|
1546
|
+
function injectCommand() {
|
|
1547
|
+
return new Command3("inject").description("Inject agent private key into Claude Code config or .env.local").requiredOption("--agent-id <agentId>", "Agent ID (agt_...)").requiredOption("--key-file <path>", "Path to the private key PEM file").option("--target <target>", "Injection target: claude-code or env-local", "claude-code").action(async (opts) => {
|
|
1548
|
+
let privateKeyPem;
|
|
1549
|
+
try {
|
|
1550
|
+
privateKeyPem = await readFile6(opts.keyFile, "utf-8");
|
|
1551
|
+
} catch {
|
|
1552
|
+
console.error(chalk10.red(`Could not read key file: ${opts.keyFile}`));
|
|
1553
|
+
process.exit(1);
|
|
1554
|
+
}
|
|
1555
|
+
if (!privateKeyPem.includes("BEGIN PRIVATE KEY")) {
|
|
1556
|
+
console.error(chalk10.red("File does not appear to be a PEM private key"));
|
|
1557
|
+
process.exit(1);
|
|
1558
|
+
}
|
|
1559
|
+
try {
|
|
1560
|
+
if (opts.target === "claude-code") {
|
|
1561
|
+
await writeKeyToClaudeConfig(opts.agentId, privateKeyPem);
|
|
1562
|
+
console.log(chalk10.green("Key injected into ~/.claude/config"));
|
|
1563
|
+
} else if (opts.target === "env-local") {
|
|
1564
|
+
await writeKeyToEnvLocal(opts.agentId, privateKeyPem);
|
|
1565
|
+
console.log(chalk10.green("Key appended to .env.local"));
|
|
1566
|
+
} else {
|
|
1567
|
+
console.error(chalk10.red(`Unknown target: ${opts.target}. Use 'claude-code' or 'env-local'`));
|
|
1568
|
+
process.exit(1);
|
|
1569
|
+
}
|
|
1570
|
+
} catch (err) {
|
|
1571
|
+
console.error(chalk10.red(String(err)));
|
|
1572
|
+
process.exit(1);
|
|
1573
|
+
}
|
|
1574
|
+
if (opts.target === "env-local") {
|
|
1575
|
+
console.log(chalk10.dim("Add .env.local to .gitignore \u2014 do not commit private keys to git."));
|
|
1576
|
+
} else {
|
|
1577
|
+
console.log(chalk10.dim("The key is stored in ~/.claude/config \u2014 it is NOT committed to git."));
|
|
1578
|
+
}
|
|
1579
|
+
console.log(chalk10.green("Done. Your agent is ready to use."));
|
|
1580
|
+
});
|
|
1581
|
+
}
|
|
1582
|
+
|
|
1351
1583
|
// src/index.ts
|
|
1352
1584
|
function collectScope(value, previous) {
|
|
1353
1585
|
return [...previous, value];
|
|
1354
1586
|
}
|
|
1355
|
-
var program = new
|
|
1356
|
-
program.name("agentvalet-register").description("Self-register an AI agent with AgentValet").version("0.4.
|
|
1587
|
+
var program = new Command4();
|
|
1588
|
+
program.name("agentvalet-register").description("Self-register an AI agent with AgentValet").version("0.4.6").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("--output <path>", "Path to write .env file", "./.env.agentvalet").option("--key-path <path>", "Path to write private key", "./agentvalet.key").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").action(async (opts) => {
|
|
1357
1589
|
const isJson = !!opts.json;
|
|
1358
1590
|
let ownerId = opts.owner ?? process.env.AGENTVALET_OWNER ?? "";
|
|
1359
1591
|
let agentName = opts.name ?? "";
|
|
@@ -1379,7 +1611,7 @@ program.name("agentvalet-register").description("Self-register an AI agent with
|
|
|
1379
1611
|
console.error(JSON.stringify({ error: "--owner or AGENTVALET_OWNER is required" }));
|
|
1380
1612
|
process.exit(3);
|
|
1381
1613
|
}
|
|
1382
|
-
console.error(
|
|
1614
|
+
console.error(chalk11.red("Error: --owner or AGENTVALET_OWNER environment variable is required"));
|
|
1383
1615
|
process.exit(3);
|
|
1384
1616
|
}
|
|
1385
1617
|
const scopeMap = /* @__PURE__ */ new Map();
|
|
@@ -1387,7 +1619,7 @@ program.name("agentvalet-register").description("Self-register an AI agent with
|
|
|
1387
1619
|
const colon = s.indexOf(":");
|
|
1388
1620
|
if (colon === -1) {
|
|
1389
1621
|
console.error(
|
|
1390
|
-
isJson ? JSON.stringify({ error: `Invalid scope format: ${s} (expected platform:scope)` }) :
|
|
1622
|
+
isJson ? JSON.stringify({ error: `Invalid scope format: ${s} (expected platform:scope)` }) : chalk11.red(`Invalid scope format: ${s} (expected platform:scope)`)
|
|
1391
1623
|
);
|
|
1392
1624
|
process.exit(3);
|
|
1393
1625
|
}
|
|
@@ -1410,11 +1642,11 @@ program.name("agentvalet-register").description("Self-register an AI agent with
|
|
|
1410
1642
|
});
|
|
1411
1643
|
} catch (err) {
|
|
1412
1644
|
const msg = err instanceof Error ? err.message : String(err);
|
|
1413
|
-
console.error(isJson ? JSON.stringify({ error: msg }) :
|
|
1645
|
+
console.error(isJson ? JSON.stringify({ error: msg }) : chalk11.red(`Registration failed: ${msg}`));
|
|
1414
1646
|
process.exit(3);
|
|
1415
1647
|
}
|
|
1416
1648
|
if (!isJson) {
|
|
1417
|
-
console.log(
|
|
1649
|
+
console.log(chalk11.cyan(`
|
|
1418
1650
|
Approve at: https://app.agentvalet.ai/agents
|
|
1419
1651
|
`));
|
|
1420
1652
|
}
|
|
@@ -1422,7 +1654,7 @@ Approve at: https://app.agentvalet.ai/agents
|
|
|
1422
1654
|
if (isJson) {
|
|
1423
1655
|
console.log(JSON.stringify({ status: "pending", token }));
|
|
1424
1656
|
} else {
|
|
1425
|
-
console.log(
|
|
1657
|
+
console.log(chalk11.yellow("Registration submitted (--no-wait). Token:"), token);
|
|
1426
1658
|
}
|
|
1427
1659
|
process.exit(0);
|
|
1428
1660
|
}
|
|
@@ -1433,14 +1665,14 @@ Approve at: https://app.agentvalet.ai/agents
|
|
|
1433
1665
|
});
|
|
1434
1666
|
} catch (err) {
|
|
1435
1667
|
const msg = err instanceof Error ? err.message : String(err);
|
|
1436
|
-
console.error(isJson ? JSON.stringify({ error: msg }) :
|
|
1668
|
+
console.error(isJson ? JSON.stringify({ error: msg }) : chalk11.red(`Wait failed: ${msg}`));
|
|
1437
1669
|
process.exit(3);
|
|
1438
1670
|
}
|
|
1439
1671
|
if (result.status === "rejected") {
|
|
1440
1672
|
if (isJson) {
|
|
1441
1673
|
console.log(JSON.stringify({ status: "rejected" }));
|
|
1442
1674
|
} else {
|
|
1443
|
-
console.log(
|
|
1675
|
+
console.log(chalk11.red("\nRegistration denied by owner."));
|
|
1444
1676
|
}
|
|
1445
1677
|
process.exit(1);
|
|
1446
1678
|
}
|
|
@@ -1448,7 +1680,7 @@ Approve at: https://app.agentvalet.ai/agents
|
|
|
1448
1680
|
if (isJson) {
|
|
1449
1681
|
console.log(JSON.stringify({ status: "timeout" }));
|
|
1450
1682
|
} else {
|
|
1451
|
-
console.log(
|
|
1683
|
+
console.log(chalk11.yellow("\nTimed out waiting for approval."));
|
|
1452
1684
|
}
|
|
1453
1685
|
process.exit(2);
|
|
1454
1686
|
}
|
|
@@ -1467,7 +1699,7 @@ Approve at: https://app.agentvalet.ai/agents
|
|
|
1467
1699
|
}));
|
|
1468
1700
|
} catch (err) {
|
|
1469
1701
|
const msg = err instanceof Error ? err.message : String(err);
|
|
1470
|
-
console.error(isJson ? JSON.stringify({ error: msg }) :
|
|
1702
|
+
console.error(isJson ? JSON.stringify({ error: msg }) : chalk11.red(`Failed to save output: ${msg}`));
|
|
1471
1703
|
process.exit(3);
|
|
1472
1704
|
}
|
|
1473
1705
|
const keyWritten = !!privateKey;
|
|
@@ -1477,23 +1709,23 @@ Approve at: https://app.agentvalet.ai/agents
|
|
|
1477
1709
|
if (isJson) {
|
|
1478
1710
|
console.log(JSON.stringify({ status: "approved", agentId, keyPath: keyWritten ? keyPath : null, envPath }));
|
|
1479
1711
|
} else {
|
|
1480
|
-
console.log(
|
|
1712
|
+
console.log(chalk11.green(`
|
|
1481
1713
|
Approved! Agent ID: ${agentId}`));
|
|
1482
1714
|
if (keyWritten) {
|
|
1483
|
-
console.log(
|
|
1715
|
+
console.log(chalk11.gray(`Key: ${keyPath}`));
|
|
1484
1716
|
} else {
|
|
1485
|
-
console.log(
|
|
1717
|
+
console.log(chalk11.yellow(`Key: not written \u2014 copy it from the dashboard and paste into ${keyPath}`));
|
|
1486
1718
|
}
|
|
1487
|
-
console.log(
|
|
1719
|
+
console.log(chalk11.gray(`Env file: ${envPath}`));
|
|
1488
1720
|
console.log(`
|
|
1489
1721
|
Source the env file before calling any tool:`);
|
|
1490
|
-
console.log(
|
|
1722
|
+
console.log(chalk11.cyan(` source ${envPath}`));
|
|
1491
1723
|
}
|
|
1492
1724
|
if (keyWritten) {
|
|
1493
1725
|
try {
|
|
1494
1726
|
if (grantedPlatforms && grantedPlatforms.length > 0) {
|
|
1495
1727
|
writePermissionsFromEvent(agentId, resolvedOwnerId, grantedPlatforms);
|
|
1496
|
-
if (!isJson) console.log(
|
|
1728
|
+
if (!isJson) console.log(chalk11.gray(`Permissions: .claude/agentvalet-permissions.md`));
|
|
1497
1729
|
} else {
|
|
1498
1730
|
await runRefresh({
|
|
1499
1731
|
envFile: opts.output,
|
|
@@ -1501,10 +1733,10 @@ Source the env file before calling any tool:`);
|
|
|
1501
1733
|
ifStale: false,
|
|
1502
1734
|
quiet: isJson
|
|
1503
1735
|
});
|
|
1504
|
-
if (!isJson) console.log(
|
|
1736
|
+
if (!isJson) console.log(chalk11.gray(`Permissions: .claude/agentvalet-permissions.md`));
|
|
1505
1737
|
}
|
|
1506
1738
|
} catch {
|
|
1507
|
-
if (!isJson) console.log(
|
|
1739
|
+
if (!isJson) console.log(chalk11.yellow(`Permissions: run 'agentvalet-register refresh' to generate`));
|
|
1508
1740
|
}
|
|
1509
1741
|
}
|
|
1510
1742
|
process.exit(0);
|
|
@@ -1519,13 +1751,16 @@ program.command("refresh").description("Refresh approved permissions and update
|
|
|
1519
1751
|
});
|
|
1520
1752
|
} catch (err) {
|
|
1521
1753
|
const msg = err instanceof Error ? err.message : String(err);
|
|
1522
|
-
console.error(
|
|
1754
|
+
console.error(chalk11.red(`Refresh failed: ${msg}`));
|
|
1523
1755
|
process.exit(3);
|
|
1524
1756
|
}
|
|
1525
1757
|
});
|
|
1526
1758
|
program.command("mcp-server").description("Start the AgentValet MCP server (stdio transport)").action(async () => {
|
|
1527
1759
|
await import("./mcp-server-SBGWYBP7.js");
|
|
1528
1760
|
});
|
|
1761
|
+
program.addCommand(listCommand());
|
|
1762
|
+
program.addCommand(revokeCommand());
|
|
1763
|
+
program.addCommand(injectCommand());
|
|
1529
1764
|
program.parseAsync().catch((err) => {
|
|
1530
1765
|
console.error(err);
|
|
1531
1766
|
process.exit(3);
|