@agentvalet/register 0.4.6 → 0.4.8
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 +268 -63
- 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 as
|
|
5
|
-
import
|
|
4
|
+
import { Command as Command5 } from "commander";
|
|
5
|
+
import chalk12 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((resolve5) => setTimeout(resolve5, ms));
|
|
170
170
|
}
|
|
171
171
|
|
|
172
172
|
// src/save.ts
|
|
@@ -1378,33 +1378,20 @@ function showCredentials(config) {
|
|
|
1378
1378
|
import { Command } from "commander";
|
|
1379
1379
|
import chalk8 from "chalk";
|
|
1380
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
1381
|
// src/lib/api.ts
|
|
1401
1382
|
async function request(path7, options) {
|
|
1402
|
-
const config =
|
|
1403
|
-
|
|
1404
|
-
|
|
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}`, {
|
|
1405
1392
|
method: options.method,
|
|
1406
1393
|
headers: {
|
|
1407
|
-
"Authorization": `Bearer ${
|
|
1394
|
+
"Authorization": `Bearer ${token}`,
|
|
1408
1395
|
"Content-Type": "application/json"
|
|
1409
1396
|
},
|
|
1410
1397
|
body: options.body ? JSON.stringify(options.body) : void 0
|
|
@@ -1426,7 +1413,7 @@ async function listAgents() {
|
|
|
1426
1413
|
function listCommand() {
|
|
1427
1414
|
return new Command("list").description("List all registered agents").action(async () => {
|
|
1428
1415
|
const config = getStoredConfig();
|
|
1429
|
-
if (!config.
|
|
1416
|
+
if (!config.cliToken) {
|
|
1430
1417
|
process.stderr.write(
|
|
1431
1418
|
chalk8.red("\n \u2717 No agent registered.\n") + chalk8.dim(" Run the following command first:\n\n npx @agentvalet/register\n\n")
|
|
1432
1419
|
);
|
|
@@ -1460,19 +1447,19 @@ import * as readline from "readline";
|
|
|
1460
1447
|
function revokeCommand() {
|
|
1461
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) => {
|
|
1462
1449
|
const config = getStoredConfig();
|
|
1463
|
-
if (!config.
|
|
1450
|
+
if (!config.cliToken) {
|
|
1464
1451
|
process.stderr.write(
|
|
1465
1452
|
chalk9.red("\n \u2717 No agent registered.\n") + chalk9.dim(" Run the following command first:\n\n npx @agentvalet/register\n\n")
|
|
1466
1453
|
);
|
|
1467
1454
|
process.exit(1);
|
|
1468
1455
|
}
|
|
1469
1456
|
const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
|
|
1470
|
-
const confirmed = await new Promise((
|
|
1457
|
+
const confirmed = await new Promise((resolve5) => {
|
|
1471
1458
|
rl.question(
|
|
1472
1459
|
chalk9.yellow(`Revoke ${opts.agentId}? This cascades to all child agents and cannot be undone. (y/N) `),
|
|
1473
1460
|
(ans) => {
|
|
1474
1461
|
rl.close();
|
|
1475
|
-
|
|
1462
|
+
resolve5(ans.trim().toLowerCase() === "y");
|
|
1476
1463
|
}
|
|
1477
1464
|
);
|
|
1478
1465
|
});
|
|
@@ -1496,29 +1483,29 @@ function revokeCommand() {
|
|
|
1496
1483
|
// src/commands/inject.ts
|
|
1497
1484
|
import { Command as Command3 } from "commander";
|
|
1498
1485
|
import chalk10 from "chalk";
|
|
1499
|
-
import { readFile as
|
|
1486
|
+
import { readFile as readFile5 } from "fs/promises";
|
|
1500
1487
|
|
|
1501
1488
|
// src/lib/claude-config.ts
|
|
1502
|
-
import { homedir
|
|
1503
|
-
import { join as
|
|
1504
|
-
import { readFile as
|
|
1505
|
-
var CLAUDE_CONFIG_PATH =
|
|
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");
|
|
1506
1493
|
async function writeKeyToClaudeConfig(agentId, privateKeyPem) {
|
|
1507
1494
|
let config = {};
|
|
1508
1495
|
try {
|
|
1509
1496
|
await access(CLAUDE_CONFIG_PATH);
|
|
1510
|
-
const raw = await
|
|
1497
|
+
const raw = await readFile3(CLAUDE_CONFIG_PATH, "utf-8");
|
|
1511
1498
|
config = JSON.parse(raw);
|
|
1512
1499
|
} catch {
|
|
1513
1500
|
}
|
|
1514
1501
|
config.agent_keys = config.agent_keys ?? {};
|
|
1515
1502
|
config.agent_keys[agentId] = Buffer.from(privateKeyPem).toString("base64");
|
|
1516
|
-
await
|
|
1517
|
-
await
|
|
1503
|
+
await mkdir4(join2(homedir(), ".claude"), { recursive: true });
|
|
1504
|
+
await writeFile6(CLAUDE_CONFIG_PATH, JSON.stringify(config, null, 2), "utf-8");
|
|
1518
1505
|
}
|
|
1519
1506
|
|
|
1520
1507
|
// src/lib/env-writer.ts
|
|
1521
|
-
import { readFile as
|
|
1508
|
+
import { readFile as readFile4, writeFile as writeFile7, access as access2 } from "fs/promises";
|
|
1522
1509
|
var ENV_VAR_NAME = (agentId) => `AGENTVALET_PRIVATE_KEY_${agentId.replace(/-/g, "_").toUpperCase()}`;
|
|
1523
1510
|
async function writeKeyToEnvLocal(agentId, privateKeyPem) {
|
|
1524
1511
|
const varName = ENV_VAR_NAME(agentId);
|
|
@@ -1530,15 +1517,15 @@ ${varName}=${b64Key}
|
|
|
1530
1517
|
let existing = "";
|
|
1531
1518
|
try {
|
|
1532
1519
|
await access2(".env.local");
|
|
1533
|
-
existing = await
|
|
1520
|
+
existing = await readFile4(".env.local", "utf-8");
|
|
1534
1521
|
} catch {
|
|
1535
1522
|
}
|
|
1536
1523
|
if (existing.includes(varName)) {
|
|
1537
1524
|
const lines = existing.split("\n");
|
|
1538
1525
|
const filtered = lines.filter((l) => !l.startsWith(`${varName}=`));
|
|
1539
|
-
await
|
|
1526
|
+
await writeFile7(".env.local", filtered.join("\n") + line, "utf-8");
|
|
1540
1527
|
} else {
|
|
1541
|
-
await
|
|
1528
|
+
await writeFile7(".env.local", existing + line, "utf-8");
|
|
1542
1529
|
}
|
|
1543
1530
|
}
|
|
1544
1531
|
|
|
@@ -1547,7 +1534,7 @@ function injectCommand() {
|
|
|
1547
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) => {
|
|
1548
1535
|
let privateKeyPem;
|
|
1549
1536
|
try {
|
|
1550
|
-
privateKeyPem = await
|
|
1537
|
+
privateKeyPem = await readFile5(opts.keyFile, "utf-8");
|
|
1551
1538
|
} catch {
|
|
1552
1539
|
console.error(chalk10.red(`Could not read key file: ${opts.keyFile}`));
|
|
1553
1540
|
process.exit(1);
|
|
@@ -1580,12 +1567,229 @@ function injectCommand() {
|
|
|
1580
1567
|
});
|
|
1581
1568
|
}
|
|
1582
1569
|
|
|
1570
|
+
// src/commands/uninstall.ts
|
|
1571
|
+
import { Command as Command4 } from "commander";
|
|
1572
|
+
import chalk11 from "chalk";
|
|
1573
|
+
import { existsSync as existsSync7, readFileSync as readFileSync4, writeFileSync as writeFileSync3, rmSync } from "fs";
|
|
1574
|
+
import { resolve as resolve4, join as join3 } from "path";
|
|
1575
|
+
import { homedir as homedir2 } from "os";
|
|
1576
|
+
import { createSign as createSign2, createPrivateKey as createPrivateKey2 } from "crypto";
|
|
1577
|
+
var CLAUDE_START2 = "<!-- agentvalet:start -->";
|
|
1578
|
+
var CLAUDE_END2 = "<!-- agentvalet:end -->";
|
|
1579
|
+
var HOOK_MARKER2 = "agentvalet/register refresh";
|
|
1580
|
+
function signJwt2(agentId, ownerId, privateKeyPem) {
|
|
1581
|
+
const now = Math.floor(Date.now() / 1e3);
|
|
1582
|
+
const b64 = (s) => Buffer.from(s).toString("base64url");
|
|
1583
|
+
const header = b64(JSON.stringify({ alg: "RS256", typ: "JWT" }));
|
|
1584
|
+
const payload = b64(JSON.stringify({ agent_id: agentId, owner_id: ownerId, iat: now, exp: now + 300 }));
|
|
1585
|
+
const signingInput = `${header}.${payload}`;
|
|
1586
|
+
const sign = createSign2("RSA-SHA256");
|
|
1587
|
+
sign.update(signingInput);
|
|
1588
|
+
return `${signingInput}.${sign.sign(createPrivateKey2(privateKeyPem), "base64url")}`;
|
|
1589
|
+
}
|
|
1590
|
+
function stripClaudeMd() {
|
|
1591
|
+
const path7 = resolve4("CLAUDE.md");
|
|
1592
|
+
if (!existsSync7(path7)) return;
|
|
1593
|
+
let content = readFileSync4(path7, "utf-8");
|
|
1594
|
+
content = content.replace(new RegExp(`${CLAUDE_START2}[\\s\\S]*?${CLAUDE_END2}`, "m"), "");
|
|
1595
|
+
content = content.replace(/^@\.claude\/agentvalet-permissions\.md\s*$/m, "");
|
|
1596
|
+
content = content.replace(/(\r?\n){3,}/g, "\n\n").trim();
|
|
1597
|
+
writeFileSync3(path7, content ? content + "\n" : "", "utf-8");
|
|
1598
|
+
}
|
|
1599
|
+
function stripSettingsJson() {
|
|
1600
|
+
const path7 = resolve4(".claude/settings.local.json");
|
|
1601
|
+
if (!existsSync7(path7)) return;
|
|
1602
|
+
try {
|
|
1603
|
+
const settings = JSON.parse(readFileSync4(path7, "utf-8"));
|
|
1604
|
+
const hooks = settings.hooks ?? {};
|
|
1605
|
+
const ups = hooks.UserPromptSubmit ?? [];
|
|
1606
|
+
hooks.UserPromptSubmit = ups.filter(
|
|
1607
|
+
(e) => !e.hooks?.some((h) => h.command?.includes(HOOK_MARKER2))
|
|
1608
|
+
);
|
|
1609
|
+
settings.hooks = hooks;
|
|
1610
|
+
const perms = settings.permissions ?? {};
|
|
1611
|
+
const allow = perms.allow ?? [];
|
|
1612
|
+
perms.allow = allow.filter((e) => !e.startsWith("mcp__agentvalet__"));
|
|
1613
|
+
settings.permissions = perms;
|
|
1614
|
+
writeFileSync3(path7, JSON.stringify(settings, null, 2) + "\n", "utf-8");
|
|
1615
|
+
} catch {
|
|
1616
|
+
}
|
|
1617
|
+
}
|
|
1618
|
+
function stripMcpJson() {
|
|
1619
|
+
const path7 = resolve4(".mcp.json");
|
|
1620
|
+
if (!existsSync7(path7)) return;
|
|
1621
|
+
try {
|
|
1622
|
+
const config = JSON.parse(readFileSync4(path7, "utf-8"));
|
|
1623
|
+
const servers = config.mcpServers ?? {};
|
|
1624
|
+
delete servers["agentvalet"];
|
|
1625
|
+
config.mcpServers = servers;
|
|
1626
|
+
writeFileSync3(path7, JSON.stringify(config, null, 2) + "\n", "utf-8");
|
|
1627
|
+
} catch {
|
|
1628
|
+
}
|
|
1629
|
+
}
|
|
1630
|
+
function deleteIfExists(p) {
|
|
1631
|
+
const abs = resolve4(p);
|
|
1632
|
+
if (existsSync7(abs)) {
|
|
1633
|
+
rmSync(abs, { recursive: true, force: true });
|
|
1634
|
+
return abs;
|
|
1635
|
+
}
|
|
1636
|
+
return null;
|
|
1637
|
+
}
|
|
1638
|
+
function cleanLocally() {
|
|
1639
|
+
const removed = [];
|
|
1640
|
+
const r = (p) => {
|
|
1641
|
+
const f = deleteIfExists(p);
|
|
1642
|
+
if (f) removed.push(f);
|
|
1643
|
+
};
|
|
1644
|
+
r(".env.agentvalet");
|
|
1645
|
+
r(".agentvalet");
|
|
1646
|
+
r("agentvalet.key");
|
|
1647
|
+
r(".claude/agentvalet-permissions.md");
|
|
1648
|
+
stripClaudeMd();
|
|
1649
|
+
stripSettingsJson();
|
|
1650
|
+
stripMcpJson();
|
|
1651
|
+
try {
|
|
1652
|
+
saveConfig({ lastAgentId: "", lastKeyPath: "" });
|
|
1653
|
+
} catch {
|
|
1654
|
+
}
|
|
1655
|
+
const oldConfig = join3(homedir2(), ".agentvalet", "config.json");
|
|
1656
|
+
if (existsSync7(oldConfig)) {
|
|
1657
|
+
rmSync(oldConfig, { force: true });
|
|
1658
|
+
removed.push(oldConfig);
|
|
1659
|
+
}
|
|
1660
|
+
if (removed.length > 0) {
|
|
1661
|
+
console.log(chalk11.green(" \u2713 Removed local files:"));
|
|
1662
|
+
for (const f of removed) console.log(chalk11.dim(` ${f}`));
|
|
1663
|
+
}
|
|
1664
|
+
console.log(chalk11.green(" \u2713 Cleaned CLAUDE.md, .mcp.json, .claude/settings.local.json"));
|
|
1665
|
+
}
|
|
1666
|
+
async function pollForApproval(apiUrl, revocationToken, timeoutMs) {
|
|
1667
|
+
const streamUrl = `${apiUrl}/v1/revoke-request/stream/${revocationToken}`;
|
|
1668
|
+
const deadline = Date.now() + timeoutMs;
|
|
1669
|
+
return new Promise((resolve5) => {
|
|
1670
|
+
let settled = false;
|
|
1671
|
+
function done(result) {
|
|
1672
|
+
if (!settled) {
|
|
1673
|
+
settled = true;
|
|
1674
|
+
resolve5(result);
|
|
1675
|
+
}
|
|
1676
|
+
}
|
|
1677
|
+
function connect() {
|
|
1678
|
+
if (Date.now() > deadline) {
|
|
1679
|
+
done("timeout");
|
|
1680
|
+
return;
|
|
1681
|
+
}
|
|
1682
|
+
fetch(streamUrl, { headers: { Accept: "text/event-stream" } }).then(async (res) => {
|
|
1683
|
+
if (!res.ok || !res.body) {
|
|
1684
|
+
done("timeout");
|
|
1685
|
+
return;
|
|
1686
|
+
}
|
|
1687
|
+
const reader = res.body.getReader();
|
|
1688
|
+
const decoder = new TextDecoder();
|
|
1689
|
+
let buf = "";
|
|
1690
|
+
while (true) {
|
|
1691
|
+
const { done: streamDone, value } = await reader.read();
|
|
1692
|
+
if (streamDone) break;
|
|
1693
|
+
buf += decoder.decode(value, { stream: true });
|
|
1694
|
+
const lines = buf.split("\n");
|
|
1695
|
+
buf = lines.pop() ?? "";
|
|
1696
|
+
for (const line of lines) {
|
|
1697
|
+
if (!line.startsWith("data: ")) continue;
|
|
1698
|
+
try {
|
|
1699
|
+
const evt = JSON.parse(line.slice(6));
|
|
1700
|
+
if (evt.status === "approved") {
|
|
1701
|
+
done("approved");
|
|
1702
|
+
return;
|
|
1703
|
+
}
|
|
1704
|
+
if (evt.status === "rejected") {
|
|
1705
|
+
done("rejected");
|
|
1706
|
+
return;
|
|
1707
|
+
}
|
|
1708
|
+
if (evt.status === "timeout") {
|
|
1709
|
+
done("timeout");
|
|
1710
|
+
return;
|
|
1711
|
+
}
|
|
1712
|
+
} catch {
|
|
1713
|
+
}
|
|
1714
|
+
}
|
|
1715
|
+
}
|
|
1716
|
+
if (!settled) setTimeout(connect, 1e3);
|
|
1717
|
+
}).catch(() => {
|
|
1718
|
+
if (!settled) setTimeout(connect, 2e3);
|
|
1719
|
+
});
|
|
1720
|
+
}
|
|
1721
|
+
connect();
|
|
1722
|
+
setTimeout(() => done("timeout"), timeoutMs);
|
|
1723
|
+
});
|
|
1724
|
+
}
|
|
1725
|
+
function uninstallCommand() {
|
|
1726
|
+
return new Command4("uninstall").description("Request agent revocation (requires owner approval) and remove all local files").option("--local-only", "Skip the server-side revoke request \u2014 just clean local files").option("--timeout <seconds>", "Seconds to wait for owner approval", "300").action(async (opts) => {
|
|
1727
|
+
const timeoutMs = parseInt(opts.timeout, 10) * 1e3;
|
|
1728
|
+
const creds = tryResolveAgent();
|
|
1729
|
+
if (opts.localOnly || !creds) {
|
|
1730
|
+
if (!creds) console.log(chalk11.dim(" No agent credentials found \u2014 cleaning local files only."));
|
|
1731
|
+
cleanLocally();
|
|
1732
|
+
console.log(chalk11.dim("\n To register a new agent: npx @agentvalet/register"));
|
|
1733
|
+
return;
|
|
1734
|
+
}
|
|
1735
|
+
let privateKeyPem;
|
|
1736
|
+
try {
|
|
1737
|
+
privateKeyPem = readFileSync4(creds.keyPath, "utf-8").trim();
|
|
1738
|
+
} catch {
|
|
1739
|
+
}
|
|
1740
|
+
if (!privateKeyPem) {
|
|
1741
|
+
console.log(chalk11.yellow(" \u26A0 Private key not found \u2014 cannot submit revocation request."));
|
|
1742
|
+
console.log(chalk11.dim(" Use --local-only to clean local files without revoking."));
|
|
1743
|
+
process.exit(1);
|
|
1744
|
+
}
|
|
1745
|
+
console.log(chalk11.dim(`
|
|
1746
|
+
Submitting revocation request for ${creds.agentId}...`));
|
|
1747
|
+
const jwt = signJwt2(creds.agentId, creds.ownerId, privateKeyPem);
|
|
1748
|
+
let revocationToken;
|
|
1749
|
+
try {
|
|
1750
|
+
const res = await fetch(`${creds.apiUrl}/v1/revoke-request`, {
|
|
1751
|
+
method: "POST",
|
|
1752
|
+
headers: { Authorization: `Bearer ${jwt}`, "Content-Type": "application/json" },
|
|
1753
|
+
body: JSON.stringify({ reason: "CLI uninstall" })
|
|
1754
|
+
});
|
|
1755
|
+
const body = await res.json();
|
|
1756
|
+
if (!res.ok || !body.revocation_token) {
|
|
1757
|
+
throw new Error(body.error ?? `HTTP ${res.status}`);
|
|
1758
|
+
}
|
|
1759
|
+
revocationToken = body.revocation_token;
|
|
1760
|
+
} catch (err) {
|
|
1761
|
+
console.error(chalk11.red(` \u2717 Failed to submit revocation request: ${err instanceof Error ? err.message : err}`));
|
|
1762
|
+
process.exit(1);
|
|
1763
|
+
}
|
|
1764
|
+
console.log(chalk11.green(" \u2713 Revocation request submitted"));
|
|
1765
|
+
console.log("");
|
|
1766
|
+
console.log(chalk11.yellow(" ACTION REQUIRED:"));
|
|
1767
|
+
console.log(chalk11.yellow(` Open ${creds.apiUrl.replace("api.", "app.")}/agents and approve the uninstall request.`));
|
|
1768
|
+
console.log(chalk11.dim(` Waiting up to ${opts.timeout}s for approval...
|
|
1769
|
+
`));
|
|
1770
|
+
const result = await pollForApproval(creds.apiUrl, revocationToken, timeoutMs);
|
|
1771
|
+
if (result === "rejected") {
|
|
1772
|
+
console.log(chalk11.red("\n \u2717 Owner rejected the uninstall request. Agent remains active."));
|
|
1773
|
+
process.exit(1);
|
|
1774
|
+
}
|
|
1775
|
+
if (result === "timeout") {
|
|
1776
|
+
console.log(chalk11.yellow("\n \u26A0 Timed out waiting for owner approval."));
|
|
1777
|
+
console.log(chalk11.dim(" The request remains pending in your dashboard. Run again to resume."));
|
|
1778
|
+
process.exit(1);
|
|
1779
|
+
}
|
|
1780
|
+
console.log(chalk11.green("\n \u2713 Approved \u2014 cleaning local files...\n"));
|
|
1781
|
+
cleanLocally();
|
|
1782
|
+
console.log("");
|
|
1783
|
+
console.log(chalk11.dim(" Agent revoked. To register a new agent: npx @agentvalet/register"));
|
|
1784
|
+
});
|
|
1785
|
+
}
|
|
1786
|
+
|
|
1583
1787
|
// src/index.ts
|
|
1584
1788
|
function collectScope(value, previous) {
|
|
1585
1789
|
return [...previous, value];
|
|
1586
1790
|
}
|
|
1587
|
-
var program = new
|
|
1588
|
-
program.name("agentvalet-register").description("Self-register an AI agent with AgentValet").version("0.4.
|
|
1791
|
+
var program = new Command5();
|
|
1792
|
+
program.name("agentvalet-register").description("Self-register an AI agent with AgentValet").version("0.4.8").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) => {
|
|
1589
1793
|
const isJson = !!opts.json;
|
|
1590
1794
|
let ownerId = opts.owner ?? process.env.AGENTVALET_OWNER ?? "";
|
|
1591
1795
|
let agentName = opts.name ?? "";
|
|
@@ -1611,7 +1815,7 @@ program.name("agentvalet-register").description("Self-register an AI agent with
|
|
|
1611
1815
|
console.error(JSON.stringify({ error: "--owner or AGENTVALET_OWNER is required" }));
|
|
1612
1816
|
process.exit(3);
|
|
1613
1817
|
}
|
|
1614
|
-
console.error(
|
|
1818
|
+
console.error(chalk12.red("Error: --owner or AGENTVALET_OWNER environment variable is required"));
|
|
1615
1819
|
process.exit(3);
|
|
1616
1820
|
}
|
|
1617
1821
|
const scopeMap = /* @__PURE__ */ new Map();
|
|
@@ -1619,7 +1823,7 @@ program.name("agentvalet-register").description("Self-register an AI agent with
|
|
|
1619
1823
|
const colon = s.indexOf(":");
|
|
1620
1824
|
if (colon === -1) {
|
|
1621
1825
|
console.error(
|
|
1622
|
-
isJson ? JSON.stringify({ error: `Invalid scope format: ${s} (expected platform:scope)` }) :
|
|
1826
|
+
isJson ? JSON.stringify({ error: `Invalid scope format: ${s} (expected platform:scope)` }) : chalk12.red(`Invalid scope format: ${s} (expected platform:scope)`)
|
|
1623
1827
|
);
|
|
1624
1828
|
process.exit(3);
|
|
1625
1829
|
}
|
|
@@ -1642,11 +1846,11 @@ program.name("agentvalet-register").description("Self-register an AI agent with
|
|
|
1642
1846
|
});
|
|
1643
1847
|
} catch (err) {
|
|
1644
1848
|
const msg = err instanceof Error ? err.message : String(err);
|
|
1645
|
-
console.error(isJson ? JSON.stringify({ error: msg }) :
|
|
1849
|
+
console.error(isJson ? JSON.stringify({ error: msg }) : chalk12.red(`Registration failed: ${msg}`));
|
|
1646
1850
|
process.exit(3);
|
|
1647
1851
|
}
|
|
1648
1852
|
if (!isJson) {
|
|
1649
|
-
console.log(
|
|
1853
|
+
console.log(chalk12.cyan(`
|
|
1650
1854
|
Approve at: https://app.agentvalet.ai/agents
|
|
1651
1855
|
`));
|
|
1652
1856
|
}
|
|
@@ -1654,7 +1858,7 @@ Approve at: https://app.agentvalet.ai/agents
|
|
|
1654
1858
|
if (isJson) {
|
|
1655
1859
|
console.log(JSON.stringify({ status: "pending", token }));
|
|
1656
1860
|
} else {
|
|
1657
|
-
console.log(
|
|
1861
|
+
console.log(chalk12.yellow("Registration submitted (--no-wait). Token:"), token);
|
|
1658
1862
|
}
|
|
1659
1863
|
process.exit(0);
|
|
1660
1864
|
}
|
|
@@ -1665,14 +1869,14 @@ Approve at: https://app.agentvalet.ai/agents
|
|
|
1665
1869
|
});
|
|
1666
1870
|
} catch (err) {
|
|
1667
1871
|
const msg = err instanceof Error ? err.message : String(err);
|
|
1668
|
-
console.error(isJson ? JSON.stringify({ error: msg }) :
|
|
1872
|
+
console.error(isJson ? JSON.stringify({ error: msg }) : chalk12.red(`Wait failed: ${msg}`));
|
|
1669
1873
|
process.exit(3);
|
|
1670
1874
|
}
|
|
1671
1875
|
if (result.status === "rejected") {
|
|
1672
1876
|
if (isJson) {
|
|
1673
1877
|
console.log(JSON.stringify({ status: "rejected" }));
|
|
1674
1878
|
} else {
|
|
1675
|
-
console.log(
|
|
1879
|
+
console.log(chalk12.red("\nRegistration denied by owner."));
|
|
1676
1880
|
}
|
|
1677
1881
|
process.exit(1);
|
|
1678
1882
|
}
|
|
@@ -1680,7 +1884,7 @@ Approve at: https://app.agentvalet.ai/agents
|
|
|
1680
1884
|
if (isJson) {
|
|
1681
1885
|
console.log(JSON.stringify({ status: "timeout" }));
|
|
1682
1886
|
} else {
|
|
1683
|
-
console.log(
|
|
1887
|
+
console.log(chalk12.yellow("\nTimed out waiting for approval."));
|
|
1684
1888
|
}
|
|
1685
1889
|
process.exit(2);
|
|
1686
1890
|
}
|
|
@@ -1699,7 +1903,7 @@ Approve at: https://app.agentvalet.ai/agents
|
|
|
1699
1903
|
}));
|
|
1700
1904
|
} catch (err) {
|
|
1701
1905
|
const msg = err instanceof Error ? err.message : String(err);
|
|
1702
|
-
console.error(isJson ? JSON.stringify({ error: msg }) :
|
|
1906
|
+
console.error(isJson ? JSON.stringify({ error: msg }) : chalk12.red(`Failed to save output: ${msg}`));
|
|
1703
1907
|
process.exit(3);
|
|
1704
1908
|
}
|
|
1705
1909
|
const keyWritten = !!privateKey;
|
|
@@ -1709,23 +1913,23 @@ Approve at: https://app.agentvalet.ai/agents
|
|
|
1709
1913
|
if (isJson) {
|
|
1710
1914
|
console.log(JSON.stringify({ status: "approved", agentId, keyPath: keyWritten ? keyPath : null, envPath }));
|
|
1711
1915
|
} else {
|
|
1712
|
-
console.log(
|
|
1916
|
+
console.log(chalk12.green(`
|
|
1713
1917
|
Approved! Agent ID: ${agentId}`));
|
|
1714
1918
|
if (keyWritten) {
|
|
1715
|
-
console.log(
|
|
1919
|
+
console.log(chalk12.gray(`Key: ${keyPath}`));
|
|
1716
1920
|
} else {
|
|
1717
|
-
console.log(
|
|
1921
|
+
console.log(chalk12.yellow(`Key: not written \u2014 copy it from the dashboard and paste into ${keyPath}`));
|
|
1718
1922
|
}
|
|
1719
|
-
console.log(
|
|
1923
|
+
console.log(chalk12.gray(`Env file: ${envPath}`));
|
|
1720
1924
|
console.log(`
|
|
1721
1925
|
Source the env file before calling any tool:`);
|
|
1722
|
-
console.log(
|
|
1926
|
+
console.log(chalk12.cyan(` source ${envPath}`));
|
|
1723
1927
|
}
|
|
1724
1928
|
if (keyWritten) {
|
|
1725
1929
|
try {
|
|
1726
1930
|
if (grantedPlatforms && grantedPlatforms.length > 0) {
|
|
1727
1931
|
writePermissionsFromEvent(agentId, resolvedOwnerId, grantedPlatforms);
|
|
1728
|
-
if (!isJson) console.log(
|
|
1932
|
+
if (!isJson) console.log(chalk12.gray(`Permissions: .claude/agentvalet-permissions.md`));
|
|
1729
1933
|
} else {
|
|
1730
1934
|
await runRefresh({
|
|
1731
1935
|
envFile: opts.output,
|
|
@@ -1733,10 +1937,10 @@ Source the env file before calling any tool:`);
|
|
|
1733
1937
|
ifStale: false,
|
|
1734
1938
|
quiet: isJson
|
|
1735
1939
|
});
|
|
1736
|
-
if (!isJson) console.log(
|
|
1940
|
+
if (!isJson) console.log(chalk12.gray(`Permissions: .claude/agentvalet-permissions.md`));
|
|
1737
1941
|
}
|
|
1738
1942
|
} catch {
|
|
1739
|
-
if (!isJson) console.log(
|
|
1943
|
+
if (!isJson) console.log(chalk12.yellow(`Permissions: run 'agentvalet-register refresh' to generate`));
|
|
1740
1944
|
}
|
|
1741
1945
|
}
|
|
1742
1946
|
process.exit(0);
|
|
@@ -1751,7 +1955,7 @@ program.command("refresh").description("Refresh approved permissions and update
|
|
|
1751
1955
|
});
|
|
1752
1956
|
} catch (err) {
|
|
1753
1957
|
const msg = err instanceof Error ? err.message : String(err);
|
|
1754
|
-
console.error(
|
|
1958
|
+
console.error(chalk12.red(`Refresh failed: ${msg}`));
|
|
1755
1959
|
process.exit(3);
|
|
1756
1960
|
}
|
|
1757
1961
|
});
|
|
@@ -1761,6 +1965,7 @@ program.command("mcp-server").description("Start the AgentValet MCP server (stdi
|
|
|
1761
1965
|
program.addCommand(listCommand());
|
|
1762
1966
|
program.addCommand(revokeCommand());
|
|
1763
1967
|
program.addCommand(injectCommand());
|
|
1968
|
+
program.addCommand(uninstallCommand());
|
|
1764
1969
|
program.parseAsync().catch((err) => {
|
|
1765
1970
|
console.error(err);
|
|
1766
1971
|
process.exit(3);
|