@agentvalet/register 0.4.5 → 0.4.7
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 +218 -22
- 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";
|
|
@@ -1374,12 +1374,205 @@ function showCredentials(config) {
|
|
|
1374
1374
|
console.log("");
|
|
1375
1375
|
}
|
|
1376
1376
|
|
|
1377
|
+
// src/commands/list.ts
|
|
1378
|
+
import { Command } from "commander";
|
|
1379
|
+
import chalk8 from "chalk";
|
|
1380
|
+
|
|
1381
|
+
// src/lib/api.ts
|
|
1382
|
+
async function request(path7, options) {
|
|
1383
|
+
const config = getStoredConfig();
|
|
1384
|
+
const token = config.cliToken;
|
|
1385
|
+
if (!token) {
|
|
1386
|
+
throw new Error(
|
|
1387
|
+
"Not authenticated.\nRun 'npx @agentvalet/register' to register and authenticate."
|
|
1388
|
+
);
|
|
1389
|
+
}
|
|
1390
|
+
const proxyUrl = config.proxyUrl ?? "https://api.agentvalet.ai";
|
|
1391
|
+
const response = await fetch(`${proxyUrl}/functions/v1${path7}`, {
|
|
1392
|
+
method: options.method,
|
|
1393
|
+
headers: {
|
|
1394
|
+
"Authorization": `Bearer ${token}`,
|
|
1395
|
+
"Content-Type": "application/json"
|
|
1396
|
+
},
|
|
1397
|
+
body: options.body ? JSON.stringify(options.body) : void 0
|
|
1398
|
+
});
|
|
1399
|
+
if (!response.ok) {
|
|
1400
|
+
const text = await response.text();
|
|
1401
|
+
throw new Error(`API error ${response.status}: ${text}`);
|
|
1402
|
+
}
|
|
1403
|
+
return response.json();
|
|
1404
|
+
}
|
|
1405
|
+
async function revokeAgent(agentId) {
|
|
1406
|
+
return request("/revoke-agent", { method: "POST", body: { agentId } });
|
|
1407
|
+
}
|
|
1408
|
+
async function listAgents() {
|
|
1409
|
+
return request("/list-agents", { method: "GET" });
|
|
1410
|
+
}
|
|
1411
|
+
|
|
1412
|
+
// src/commands/list.ts
|
|
1413
|
+
function listCommand() {
|
|
1414
|
+
return new Command("list").description("List all registered agents").action(async () => {
|
|
1415
|
+
const config = getStoredConfig();
|
|
1416
|
+
if (!config.cliToken) {
|
|
1417
|
+
process.stderr.write(
|
|
1418
|
+
chalk8.red("\n \u2717 No agent registered.\n") + chalk8.dim(" Run the following command first:\n\n npx @agentvalet/register\n\n")
|
|
1419
|
+
);
|
|
1420
|
+
process.exit(1);
|
|
1421
|
+
}
|
|
1422
|
+
try {
|
|
1423
|
+
const agents = await listAgents();
|
|
1424
|
+
if (agents.length === 0) {
|
|
1425
|
+
console.log("No agents registered yet. Run: npx @agentvalet/register");
|
|
1426
|
+
return;
|
|
1427
|
+
}
|
|
1428
|
+
const maxNameLen = Math.max(...agents.map((a) => a.name.length), 4);
|
|
1429
|
+
const header = `${"ID".padEnd(30)} ${"NAME".padEnd(maxNameLen)} STATUS`;
|
|
1430
|
+
console.log(header);
|
|
1431
|
+
console.log("-".repeat(header.length));
|
|
1432
|
+
for (const agent of agents) {
|
|
1433
|
+
const status = agent.status === "active" ? chalk8.green("\u2713 active") : agent.status === "suspended" ? chalk8.yellow("\u26A0 suspended") : chalk8.red("\u2717 revoked");
|
|
1434
|
+
console.log(`${agent.id.padEnd(30)} ${agent.name.padEnd(maxNameLen)} ${status}`);
|
|
1435
|
+
}
|
|
1436
|
+
} catch (err) {
|
|
1437
|
+
console.error(chalk8.red(String(err)));
|
|
1438
|
+
process.exit(1);
|
|
1439
|
+
}
|
|
1440
|
+
});
|
|
1441
|
+
}
|
|
1442
|
+
|
|
1443
|
+
// src/commands/revoke.ts
|
|
1444
|
+
import { Command as Command2 } from "commander";
|
|
1445
|
+
import chalk9 from "chalk";
|
|
1446
|
+
import * as readline from "readline";
|
|
1447
|
+
function revokeCommand() {
|
|
1448
|
+
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) => {
|
|
1449
|
+
const config = getStoredConfig();
|
|
1450
|
+
if (!config.cliToken) {
|
|
1451
|
+
process.stderr.write(
|
|
1452
|
+
chalk9.red("\n \u2717 No agent registered.\n") + chalk9.dim(" Run the following command first:\n\n npx @agentvalet/register\n\n")
|
|
1453
|
+
);
|
|
1454
|
+
process.exit(1);
|
|
1455
|
+
}
|
|
1456
|
+
const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
|
|
1457
|
+
const confirmed = await new Promise((resolve4) => {
|
|
1458
|
+
rl.question(
|
|
1459
|
+
chalk9.yellow(`Revoke ${opts.agentId}? This cascades to all child agents and cannot be undone. (y/N) `),
|
|
1460
|
+
(ans) => {
|
|
1461
|
+
rl.close();
|
|
1462
|
+
resolve4(ans.trim().toLowerCase() === "y");
|
|
1463
|
+
}
|
|
1464
|
+
);
|
|
1465
|
+
});
|
|
1466
|
+
if (!confirmed) {
|
|
1467
|
+
console.log("Cancelled.");
|
|
1468
|
+
return;
|
|
1469
|
+
}
|
|
1470
|
+
try {
|
|
1471
|
+
const result = await revokeAgent(opts.agentId);
|
|
1472
|
+
console.log(chalk9.green(`Revoked ${result.revokedAgentIds.length} agent(s)`));
|
|
1473
|
+
if (result.revokedAgentIds.length > 1) {
|
|
1474
|
+
console.log("Revoked:", result.revokedAgentIds.join(", "));
|
|
1475
|
+
}
|
|
1476
|
+
} catch (err) {
|
|
1477
|
+
console.error(chalk9.red(String(err)));
|
|
1478
|
+
process.exit(1);
|
|
1479
|
+
}
|
|
1480
|
+
});
|
|
1481
|
+
}
|
|
1482
|
+
|
|
1483
|
+
// src/commands/inject.ts
|
|
1484
|
+
import { Command as Command3 } from "commander";
|
|
1485
|
+
import chalk10 from "chalk";
|
|
1486
|
+
import { readFile as readFile5 } from "fs/promises";
|
|
1487
|
+
|
|
1488
|
+
// src/lib/claude-config.ts
|
|
1489
|
+
import { homedir } from "os";
|
|
1490
|
+
import { join as join2 } from "path";
|
|
1491
|
+
import { readFile as readFile3, writeFile as writeFile6, mkdir as mkdir4, access } from "fs/promises";
|
|
1492
|
+
var CLAUDE_CONFIG_PATH = join2(homedir(), ".claude", "config");
|
|
1493
|
+
async function writeKeyToClaudeConfig(agentId, privateKeyPem) {
|
|
1494
|
+
let config = {};
|
|
1495
|
+
try {
|
|
1496
|
+
await access(CLAUDE_CONFIG_PATH);
|
|
1497
|
+
const raw = await readFile3(CLAUDE_CONFIG_PATH, "utf-8");
|
|
1498
|
+
config = JSON.parse(raw);
|
|
1499
|
+
} catch {
|
|
1500
|
+
}
|
|
1501
|
+
config.agent_keys = config.agent_keys ?? {};
|
|
1502
|
+
config.agent_keys[agentId] = Buffer.from(privateKeyPem).toString("base64");
|
|
1503
|
+
await mkdir4(join2(homedir(), ".claude"), { recursive: true });
|
|
1504
|
+
await writeFile6(CLAUDE_CONFIG_PATH, JSON.stringify(config, null, 2), "utf-8");
|
|
1505
|
+
}
|
|
1506
|
+
|
|
1507
|
+
// src/lib/env-writer.ts
|
|
1508
|
+
import { readFile as readFile4, writeFile as writeFile7, access as access2 } from "fs/promises";
|
|
1509
|
+
var ENV_VAR_NAME = (agentId) => `AGENTVALET_PRIVATE_KEY_${agentId.replace(/-/g, "_").toUpperCase()}`;
|
|
1510
|
+
async function writeKeyToEnvLocal(agentId, privateKeyPem) {
|
|
1511
|
+
const varName = ENV_VAR_NAME(agentId);
|
|
1512
|
+
const b64Key = Buffer.from(privateKeyPem).toString("base64");
|
|
1513
|
+
const line = `
|
|
1514
|
+
# AgentValet private key for ${agentId} (base64-encoded PEM)
|
|
1515
|
+
${varName}=${b64Key}
|
|
1516
|
+
`;
|
|
1517
|
+
let existing = "";
|
|
1518
|
+
try {
|
|
1519
|
+
await access2(".env.local");
|
|
1520
|
+
existing = await readFile4(".env.local", "utf-8");
|
|
1521
|
+
} catch {
|
|
1522
|
+
}
|
|
1523
|
+
if (existing.includes(varName)) {
|
|
1524
|
+
const lines = existing.split("\n");
|
|
1525
|
+
const filtered = lines.filter((l) => !l.startsWith(`${varName}=`));
|
|
1526
|
+
await writeFile7(".env.local", filtered.join("\n") + line, "utf-8");
|
|
1527
|
+
} else {
|
|
1528
|
+
await writeFile7(".env.local", existing + line, "utf-8");
|
|
1529
|
+
}
|
|
1530
|
+
}
|
|
1531
|
+
|
|
1532
|
+
// src/commands/inject.ts
|
|
1533
|
+
function injectCommand() {
|
|
1534
|
+
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) => {
|
|
1535
|
+
let privateKeyPem;
|
|
1536
|
+
try {
|
|
1537
|
+
privateKeyPem = await readFile5(opts.keyFile, "utf-8");
|
|
1538
|
+
} catch {
|
|
1539
|
+
console.error(chalk10.red(`Could not read key file: ${opts.keyFile}`));
|
|
1540
|
+
process.exit(1);
|
|
1541
|
+
}
|
|
1542
|
+
if (!privateKeyPem.includes("BEGIN PRIVATE KEY")) {
|
|
1543
|
+
console.error(chalk10.red("File does not appear to be a PEM private key"));
|
|
1544
|
+
process.exit(1);
|
|
1545
|
+
}
|
|
1546
|
+
try {
|
|
1547
|
+
if (opts.target === "claude-code") {
|
|
1548
|
+
await writeKeyToClaudeConfig(opts.agentId, privateKeyPem);
|
|
1549
|
+
console.log(chalk10.green("Key injected into ~/.claude/config"));
|
|
1550
|
+
} else if (opts.target === "env-local") {
|
|
1551
|
+
await writeKeyToEnvLocal(opts.agentId, privateKeyPem);
|
|
1552
|
+
console.log(chalk10.green("Key appended to .env.local"));
|
|
1553
|
+
} else {
|
|
1554
|
+
console.error(chalk10.red(`Unknown target: ${opts.target}. Use 'claude-code' or 'env-local'`));
|
|
1555
|
+
process.exit(1);
|
|
1556
|
+
}
|
|
1557
|
+
} catch (err) {
|
|
1558
|
+
console.error(chalk10.red(String(err)));
|
|
1559
|
+
process.exit(1);
|
|
1560
|
+
}
|
|
1561
|
+
if (opts.target === "env-local") {
|
|
1562
|
+
console.log(chalk10.dim("Add .env.local to .gitignore \u2014 do not commit private keys to git."));
|
|
1563
|
+
} else {
|
|
1564
|
+
console.log(chalk10.dim("The key is stored in ~/.claude/config \u2014 it is NOT committed to git."));
|
|
1565
|
+
}
|
|
1566
|
+
console.log(chalk10.green("Done. Your agent is ready to use."));
|
|
1567
|
+
});
|
|
1568
|
+
}
|
|
1569
|
+
|
|
1377
1570
|
// src/index.ts
|
|
1378
1571
|
function collectScope(value, previous) {
|
|
1379
1572
|
return [...previous, value];
|
|
1380
1573
|
}
|
|
1381
|
-
var program = new
|
|
1382
|
-
program.name("agentvalet-register").description("Self-register an AI agent with AgentValet").version("0.4.
|
|
1574
|
+
var program = new Command4();
|
|
1575
|
+
program.name("agentvalet-register").description("Self-register an AI agent with AgentValet").version("0.4.7").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) => {
|
|
1383
1576
|
const isJson = !!opts.json;
|
|
1384
1577
|
let ownerId = opts.owner ?? process.env.AGENTVALET_OWNER ?? "";
|
|
1385
1578
|
let agentName = opts.name ?? "";
|
|
@@ -1405,7 +1598,7 @@ program.name("agentvalet-register").description("Self-register an AI agent with
|
|
|
1405
1598
|
console.error(JSON.stringify({ error: "--owner or AGENTVALET_OWNER is required" }));
|
|
1406
1599
|
process.exit(3);
|
|
1407
1600
|
}
|
|
1408
|
-
console.error(
|
|
1601
|
+
console.error(chalk11.red("Error: --owner or AGENTVALET_OWNER environment variable is required"));
|
|
1409
1602
|
process.exit(3);
|
|
1410
1603
|
}
|
|
1411
1604
|
const scopeMap = /* @__PURE__ */ new Map();
|
|
@@ -1413,7 +1606,7 @@ program.name("agentvalet-register").description("Self-register an AI agent with
|
|
|
1413
1606
|
const colon = s.indexOf(":");
|
|
1414
1607
|
if (colon === -1) {
|
|
1415
1608
|
console.error(
|
|
1416
|
-
isJson ? JSON.stringify({ error: `Invalid scope format: ${s} (expected platform:scope)` }) :
|
|
1609
|
+
isJson ? JSON.stringify({ error: `Invalid scope format: ${s} (expected platform:scope)` }) : chalk11.red(`Invalid scope format: ${s} (expected platform:scope)`)
|
|
1417
1610
|
);
|
|
1418
1611
|
process.exit(3);
|
|
1419
1612
|
}
|
|
@@ -1436,11 +1629,11 @@ program.name("agentvalet-register").description("Self-register an AI agent with
|
|
|
1436
1629
|
});
|
|
1437
1630
|
} catch (err) {
|
|
1438
1631
|
const msg = err instanceof Error ? err.message : String(err);
|
|
1439
|
-
console.error(isJson ? JSON.stringify({ error: msg }) :
|
|
1632
|
+
console.error(isJson ? JSON.stringify({ error: msg }) : chalk11.red(`Registration failed: ${msg}`));
|
|
1440
1633
|
process.exit(3);
|
|
1441
1634
|
}
|
|
1442
1635
|
if (!isJson) {
|
|
1443
|
-
console.log(
|
|
1636
|
+
console.log(chalk11.cyan(`
|
|
1444
1637
|
Approve at: https://app.agentvalet.ai/agents
|
|
1445
1638
|
`));
|
|
1446
1639
|
}
|
|
@@ -1448,7 +1641,7 @@ Approve at: https://app.agentvalet.ai/agents
|
|
|
1448
1641
|
if (isJson) {
|
|
1449
1642
|
console.log(JSON.stringify({ status: "pending", token }));
|
|
1450
1643
|
} else {
|
|
1451
|
-
console.log(
|
|
1644
|
+
console.log(chalk11.yellow("Registration submitted (--no-wait). Token:"), token);
|
|
1452
1645
|
}
|
|
1453
1646
|
process.exit(0);
|
|
1454
1647
|
}
|
|
@@ -1459,14 +1652,14 @@ Approve at: https://app.agentvalet.ai/agents
|
|
|
1459
1652
|
});
|
|
1460
1653
|
} catch (err) {
|
|
1461
1654
|
const msg = err instanceof Error ? err.message : String(err);
|
|
1462
|
-
console.error(isJson ? JSON.stringify({ error: msg }) :
|
|
1655
|
+
console.error(isJson ? JSON.stringify({ error: msg }) : chalk11.red(`Wait failed: ${msg}`));
|
|
1463
1656
|
process.exit(3);
|
|
1464
1657
|
}
|
|
1465
1658
|
if (result.status === "rejected") {
|
|
1466
1659
|
if (isJson) {
|
|
1467
1660
|
console.log(JSON.stringify({ status: "rejected" }));
|
|
1468
1661
|
} else {
|
|
1469
|
-
console.log(
|
|
1662
|
+
console.log(chalk11.red("\nRegistration denied by owner."));
|
|
1470
1663
|
}
|
|
1471
1664
|
process.exit(1);
|
|
1472
1665
|
}
|
|
@@ -1474,7 +1667,7 @@ Approve at: https://app.agentvalet.ai/agents
|
|
|
1474
1667
|
if (isJson) {
|
|
1475
1668
|
console.log(JSON.stringify({ status: "timeout" }));
|
|
1476
1669
|
} else {
|
|
1477
|
-
console.log(
|
|
1670
|
+
console.log(chalk11.yellow("\nTimed out waiting for approval."));
|
|
1478
1671
|
}
|
|
1479
1672
|
process.exit(2);
|
|
1480
1673
|
}
|
|
@@ -1493,7 +1686,7 @@ Approve at: https://app.agentvalet.ai/agents
|
|
|
1493
1686
|
}));
|
|
1494
1687
|
} catch (err) {
|
|
1495
1688
|
const msg = err instanceof Error ? err.message : String(err);
|
|
1496
|
-
console.error(isJson ? JSON.stringify({ error: msg }) :
|
|
1689
|
+
console.error(isJson ? JSON.stringify({ error: msg }) : chalk11.red(`Failed to save output: ${msg}`));
|
|
1497
1690
|
process.exit(3);
|
|
1498
1691
|
}
|
|
1499
1692
|
const keyWritten = !!privateKey;
|
|
@@ -1503,23 +1696,23 @@ Approve at: https://app.agentvalet.ai/agents
|
|
|
1503
1696
|
if (isJson) {
|
|
1504
1697
|
console.log(JSON.stringify({ status: "approved", agentId, keyPath: keyWritten ? keyPath : null, envPath }));
|
|
1505
1698
|
} else {
|
|
1506
|
-
console.log(
|
|
1699
|
+
console.log(chalk11.green(`
|
|
1507
1700
|
Approved! Agent ID: ${agentId}`));
|
|
1508
1701
|
if (keyWritten) {
|
|
1509
|
-
console.log(
|
|
1702
|
+
console.log(chalk11.gray(`Key: ${keyPath}`));
|
|
1510
1703
|
} else {
|
|
1511
|
-
console.log(
|
|
1704
|
+
console.log(chalk11.yellow(`Key: not written \u2014 copy it from the dashboard and paste into ${keyPath}`));
|
|
1512
1705
|
}
|
|
1513
|
-
console.log(
|
|
1706
|
+
console.log(chalk11.gray(`Env file: ${envPath}`));
|
|
1514
1707
|
console.log(`
|
|
1515
1708
|
Source the env file before calling any tool:`);
|
|
1516
|
-
console.log(
|
|
1709
|
+
console.log(chalk11.cyan(` source ${envPath}`));
|
|
1517
1710
|
}
|
|
1518
1711
|
if (keyWritten) {
|
|
1519
1712
|
try {
|
|
1520
1713
|
if (grantedPlatforms && grantedPlatforms.length > 0) {
|
|
1521
1714
|
writePermissionsFromEvent(agentId, resolvedOwnerId, grantedPlatforms);
|
|
1522
|
-
if (!isJson) console.log(
|
|
1715
|
+
if (!isJson) console.log(chalk11.gray(`Permissions: .claude/agentvalet-permissions.md`));
|
|
1523
1716
|
} else {
|
|
1524
1717
|
await runRefresh({
|
|
1525
1718
|
envFile: opts.output,
|
|
@@ -1527,10 +1720,10 @@ Source the env file before calling any tool:`);
|
|
|
1527
1720
|
ifStale: false,
|
|
1528
1721
|
quiet: isJson
|
|
1529
1722
|
});
|
|
1530
|
-
if (!isJson) console.log(
|
|
1723
|
+
if (!isJson) console.log(chalk11.gray(`Permissions: .claude/agentvalet-permissions.md`));
|
|
1531
1724
|
}
|
|
1532
1725
|
} catch {
|
|
1533
|
-
if (!isJson) console.log(
|
|
1726
|
+
if (!isJson) console.log(chalk11.yellow(`Permissions: run 'agentvalet-register refresh' to generate`));
|
|
1534
1727
|
}
|
|
1535
1728
|
}
|
|
1536
1729
|
process.exit(0);
|
|
@@ -1545,13 +1738,16 @@ program.command("refresh").description("Refresh approved permissions and update
|
|
|
1545
1738
|
});
|
|
1546
1739
|
} catch (err) {
|
|
1547
1740
|
const msg = err instanceof Error ? err.message : String(err);
|
|
1548
|
-
console.error(
|
|
1741
|
+
console.error(chalk11.red(`Refresh failed: ${msg}`));
|
|
1549
1742
|
process.exit(3);
|
|
1550
1743
|
}
|
|
1551
1744
|
});
|
|
1552
1745
|
program.command("mcp-server").description("Start the AgentValet MCP server (stdio transport)").action(async () => {
|
|
1553
1746
|
await import("./mcp-server-SBGWYBP7.js");
|
|
1554
1747
|
});
|
|
1748
|
+
program.addCommand(listCommand());
|
|
1749
|
+
program.addCommand(revokeCommand());
|
|
1750
|
+
program.addCommand(injectCommand());
|
|
1555
1751
|
program.parseAsync().catch((err) => {
|
|
1556
1752
|
console.error(err);
|
|
1557
1753
|
process.exit(3);
|