@agentvalet/register 0.4.5 → 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 +231 -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,218 @@ 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/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
|
+
|
|
1377
1583
|
// src/index.ts
|
|
1378
1584
|
function collectScope(value, previous) {
|
|
1379
1585
|
return [...previous, value];
|
|
1380
1586
|
}
|
|
1381
|
-
var program = new
|
|
1382
|
-
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) => {
|
|
1383
1589
|
const isJson = !!opts.json;
|
|
1384
1590
|
let ownerId = opts.owner ?? process.env.AGENTVALET_OWNER ?? "";
|
|
1385
1591
|
let agentName = opts.name ?? "";
|
|
@@ -1405,7 +1611,7 @@ program.name("agentvalet-register").description("Self-register an AI agent with
|
|
|
1405
1611
|
console.error(JSON.stringify({ error: "--owner or AGENTVALET_OWNER is required" }));
|
|
1406
1612
|
process.exit(3);
|
|
1407
1613
|
}
|
|
1408
|
-
console.error(
|
|
1614
|
+
console.error(chalk11.red("Error: --owner or AGENTVALET_OWNER environment variable is required"));
|
|
1409
1615
|
process.exit(3);
|
|
1410
1616
|
}
|
|
1411
1617
|
const scopeMap = /* @__PURE__ */ new Map();
|
|
@@ -1413,7 +1619,7 @@ program.name("agentvalet-register").description("Self-register an AI agent with
|
|
|
1413
1619
|
const colon = s.indexOf(":");
|
|
1414
1620
|
if (colon === -1) {
|
|
1415
1621
|
console.error(
|
|
1416
|
-
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)`)
|
|
1417
1623
|
);
|
|
1418
1624
|
process.exit(3);
|
|
1419
1625
|
}
|
|
@@ -1436,11 +1642,11 @@ program.name("agentvalet-register").description("Self-register an AI agent with
|
|
|
1436
1642
|
});
|
|
1437
1643
|
} catch (err) {
|
|
1438
1644
|
const msg = err instanceof Error ? err.message : String(err);
|
|
1439
|
-
console.error(isJson ? JSON.stringify({ error: msg }) :
|
|
1645
|
+
console.error(isJson ? JSON.stringify({ error: msg }) : chalk11.red(`Registration failed: ${msg}`));
|
|
1440
1646
|
process.exit(3);
|
|
1441
1647
|
}
|
|
1442
1648
|
if (!isJson) {
|
|
1443
|
-
console.log(
|
|
1649
|
+
console.log(chalk11.cyan(`
|
|
1444
1650
|
Approve at: https://app.agentvalet.ai/agents
|
|
1445
1651
|
`));
|
|
1446
1652
|
}
|
|
@@ -1448,7 +1654,7 @@ Approve at: https://app.agentvalet.ai/agents
|
|
|
1448
1654
|
if (isJson) {
|
|
1449
1655
|
console.log(JSON.stringify({ status: "pending", token }));
|
|
1450
1656
|
} else {
|
|
1451
|
-
console.log(
|
|
1657
|
+
console.log(chalk11.yellow("Registration submitted (--no-wait). Token:"), token);
|
|
1452
1658
|
}
|
|
1453
1659
|
process.exit(0);
|
|
1454
1660
|
}
|
|
@@ -1459,14 +1665,14 @@ Approve at: https://app.agentvalet.ai/agents
|
|
|
1459
1665
|
});
|
|
1460
1666
|
} catch (err) {
|
|
1461
1667
|
const msg = err instanceof Error ? err.message : String(err);
|
|
1462
|
-
console.error(isJson ? JSON.stringify({ error: msg }) :
|
|
1668
|
+
console.error(isJson ? JSON.stringify({ error: msg }) : chalk11.red(`Wait failed: ${msg}`));
|
|
1463
1669
|
process.exit(3);
|
|
1464
1670
|
}
|
|
1465
1671
|
if (result.status === "rejected") {
|
|
1466
1672
|
if (isJson) {
|
|
1467
1673
|
console.log(JSON.stringify({ status: "rejected" }));
|
|
1468
1674
|
} else {
|
|
1469
|
-
console.log(
|
|
1675
|
+
console.log(chalk11.red("\nRegistration denied by owner."));
|
|
1470
1676
|
}
|
|
1471
1677
|
process.exit(1);
|
|
1472
1678
|
}
|
|
@@ -1474,7 +1680,7 @@ Approve at: https://app.agentvalet.ai/agents
|
|
|
1474
1680
|
if (isJson) {
|
|
1475
1681
|
console.log(JSON.stringify({ status: "timeout" }));
|
|
1476
1682
|
} else {
|
|
1477
|
-
console.log(
|
|
1683
|
+
console.log(chalk11.yellow("\nTimed out waiting for approval."));
|
|
1478
1684
|
}
|
|
1479
1685
|
process.exit(2);
|
|
1480
1686
|
}
|
|
@@ -1493,7 +1699,7 @@ Approve at: https://app.agentvalet.ai/agents
|
|
|
1493
1699
|
}));
|
|
1494
1700
|
} catch (err) {
|
|
1495
1701
|
const msg = err instanceof Error ? err.message : String(err);
|
|
1496
|
-
console.error(isJson ? JSON.stringify({ error: msg }) :
|
|
1702
|
+
console.error(isJson ? JSON.stringify({ error: msg }) : chalk11.red(`Failed to save output: ${msg}`));
|
|
1497
1703
|
process.exit(3);
|
|
1498
1704
|
}
|
|
1499
1705
|
const keyWritten = !!privateKey;
|
|
@@ -1503,23 +1709,23 @@ Approve at: https://app.agentvalet.ai/agents
|
|
|
1503
1709
|
if (isJson) {
|
|
1504
1710
|
console.log(JSON.stringify({ status: "approved", agentId, keyPath: keyWritten ? keyPath : null, envPath }));
|
|
1505
1711
|
} else {
|
|
1506
|
-
console.log(
|
|
1712
|
+
console.log(chalk11.green(`
|
|
1507
1713
|
Approved! Agent ID: ${agentId}`));
|
|
1508
1714
|
if (keyWritten) {
|
|
1509
|
-
console.log(
|
|
1715
|
+
console.log(chalk11.gray(`Key: ${keyPath}`));
|
|
1510
1716
|
} else {
|
|
1511
|
-
console.log(
|
|
1717
|
+
console.log(chalk11.yellow(`Key: not written \u2014 copy it from the dashboard and paste into ${keyPath}`));
|
|
1512
1718
|
}
|
|
1513
|
-
console.log(
|
|
1719
|
+
console.log(chalk11.gray(`Env file: ${envPath}`));
|
|
1514
1720
|
console.log(`
|
|
1515
1721
|
Source the env file before calling any tool:`);
|
|
1516
|
-
console.log(
|
|
1722
|
+
console.log(chalk11.cyan(` source ${envPath}`));
|
|
1517
1723
|
}
|
|
1518
1724
|
if (keyWritten) {
|
|
1519
1725
|
try {
|
|
1520
1726
|
if (grantedPlatforms && grantedPlatforms.length > 0) {
|
|
1521
1727
|
writePermissionsFromEvent(agentId, resolvedOwnerId, grantedPlatforms);
|
|
1522
|
-
if (!isJson) console.log(
|
|
1728
|
+
if (!isJson) console.log(chalk11.gray(`Permissions: .claude/agentvalet-permissions.md`));
|
|
1523
1729
|
} else {
|
|
1524
1730
|
await runRefresh({
|
|
1525
1731
|
envFile: opts.output,
|
|
@@ -1527,10 +1733,10 @@ Source the env file before calling any tool:`);
|
|
|
1527
1733
|
ifStale: false,
|
|
1528
1734
|
quiet: isJson
|
|
1529
1735
|
});
|
|
1530
|
-
if (!isJson) console.log(
|
|
1736
|
+
if (!isJson) console.log(chalk11.gray(`Permissions: .claude/agentvalet-permissions.md`));
|
|
1531
1737
|
}
|
|
1532
1738
|
} catch {
|
|
1533
|
-
if (!isJson) console.log(
|
|
1739
|
+
if (!isJson) console.log(chalk11.yellow(`Permissions: run 'agentvalet-register refresh' to generate`));
|
|
1534
1740
|
}
|
|
1535
1741
|
}
|
|
1536
1742
|
process.exit(0);
|
|
@@ -1545,13 +1751,16 @@ program.command("refresh").description("Refresh approved permissions and update
|
|
|
1545
1751
|
});
|
|
1546
1752
|
} catch (err) {
|
|
1547
1753
|
const msg = err instanceof Error ? err.message : String(err);
|
|
1548
|
-
console.error(
|
|
1754
|
+
console.error(chalk11.red(`Refresh failed: ${msg}`));
|
|
1549
1755
|
process.exit(3);
|
|
1550
1756
|
}
|
|
1551
1757
|
});
|
|
1552
1758
|
program.command("mcp-server").description("Start the AgentValet MCP server (stdio transport)").action(async () => {
|
|
1553
1759
|
await import("./mcp-server-SBGWYBP7.js");
|
|
1554
1760
|
});
|
|
1761
|
+
program.addCommand(listCommand());
|
|
1762
|
+
program.addCommand(revokeCommand());
|
|
1763
|
+
program.addCommand(injectCommand());
|
|
1555
1764
|
program.parseAsync().catch((err) => {
|
|
1556
1765
|
console.error(err);
|
|
1557
1766
|
process.exit(3);
|