@agentvalet/register 0.4.10 → 0.4.12

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 CHANGED
@@ -1,6 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
 
3
3
  // src/index.ts
4
+ import { createRequire } from "module";
4
5
  import { Command as Command5 } from "commander";
5
6
  import chalk12 from "chalk";
6
7
 
@@ -192,9 +193,23 @@ async function saveOutput(opts) {
192
193
 
193
194
  // src/commands/refresh.ts
194
195
  import { readFileSync as readFileSync3, writeFileSync as writeFileSync2, existsSync as existsSync3, mkdirSync, statSync } from "fs";
195
- import { createSign, createPrivateKey } from "crypto";
196
196
  import { dirname as dirname2, resolve as resolve3 } from "path";
197
197
 
198
+ // src/lib/jwt.ts
199
+ import { createSign, createPrivateKey } from "crypto";
200
+ function signJwt(agentId, ownerId, privateKeyPem) {
201
+ const now = Math.floor(Date.now() / 1e3);
202
+ const b64 = (s) => Buffer.from(s).toString("base64url");
203
+ const header = b64(JSON.stringify({ alg: "RS256", typ: "JWT" }));
204
+ const payload = b64(
205
+ JSON.stringify({ agent_id: agentId, owner_id: ownerId, iat: now, exp: now + 300 })
206
+ );
207
+ const signingInput = `${header}.${payload}`;
208
+ const sign = createSign("RSA-SHA256");
209
+ sign.update(signingInput);
210
+ return `${signingInput}.${sign.sign(createPrivateKey(privateKeyPem), "base64url")}`;
211
+ }
212
+
198
213
  // src/lib/skill-writer.ts
199
214
  import { existsSync, writeFileSync } from "fs";
200
215
  import { execSync } from "child_process";
@@ -500,19 +515,6 @@ var CLAUDE_START = "<!-- agentvalet:start -->";
500
515
  var CLAUDE_END = "<!-- agentvalet:end -->";
501
516
  var HOOK_COMMAND = "npx @agentvalet/register refresh --if-stale --quiet 2>/dev/null || true";
502
517
  var HOOK_MARKER = "agentvalet/register refresh";
503
- function base64url(input) {
504
- return Buffer.from(input).toString("base64url");
505
- }
506
- function signJwt(agentId, ownerId, privateKeyPem) {
507
- const now = Math.floor(Date.now() / 1e3);
508
- const header = base64url(JSON.stringify({ alg: "RS256", typ: "JWT" }));
509
- const payload = base64url(JSON.stringify({ agent_id: agentId, owner_id: ownerId, iat: now, exp: now + 300 }));
510
- const signingInput = `${header}.${payload}`;
511
- const sign = createSign("RSA-SHA256");
512
- sign.update(signingInput);
513
- const signature = sign.sign(createPrivateKey(privateKeyPem), "base64url");
514
- return `${signingInput}.${signature}`;
515
- }
516
518
  function writePermissionsFromEvent(agentId, ownerId, platforms, outputPath = "./.claude/agentvalet-permissions.md") {
517
519
  const content = generatePermissionsFile(agentId, ownerId, platforms);
518
520
  const resolvedPath = resolve3(outputPath);
@@ -1529,20 +1531,9 @@ import chalk11 from "chalk";
1529
1531
  import { existsSync as existsSync7, readFileSync as readFileSync4, writeFileSync as writeFileSync3, rmSync } from "fs";
1530
1532
  import { resolve as resolve4, join as join3 } from "path";
1531
1533
  import { homedir as homedir2 } from "os";
1532
- import { createSign as createSign2, createPrivateKey as createPrivateKey2 } from "crypto";
1533
1534
  var CLAUDE_START2 = "<!-- agentvalet:start -->";
1534
1535
  var CLAUDE_END2 = "<!-- agentvalet:end -->";
1535
1536
  var HOOK_MARKER2 = "agentvalet/register refresh";
1536
- function signJwt2(agentId, ownerId, privateKeyPem) {
1537
- const now = Math.floor(Date.now() / 1e3);
1538
- const b64 = (s) => Buffer.from(s).toString("base64url");
1539
- const header = b64(JSON.stringify({ alg: "RS256", typ: "JWT" }));
1540
- const payload = b64(JSON.stringify({ agent_id: agentId, owner_id: ownerId, iat: now, exp: now + 300 }));
1541
- const signingInput = `${header}.${payload}`;
1542
- const sign = createSign2("RSA-SHA256");
1543
- sign.update(signingInput);
1544
- return `${signingInput}.${sign.sign(createPrivateKey2(privateKeyPem), "base64url")}`;
1545
- }
1546
1537
  function stripClaudeMd() {
1547
1538
  const path7 = resolve4("CLAUDE.md");
1548
1539
  if (!existsSync7(path7)) return;
@@ -1619,6 +1610,7 @@ function cleanLocally() {
1619
1610
  }
1620
1611
  console.log(chalk11.green(" \u2713 Cleaned CLAUDE.md, .mcp.json, .claude/settings.local.json"));
1621
1612
  }
1613
+ var SSE_READ_TIMEOUT_MS = 25e3;
1622
1614
  async function pollForApproval(apiUrl, revocationToken, timeoutMs) {
1623
1615
  const streamUrl = `${apiUrl}/v1/revoke-request/stream/${revocationToken}`;
1624
1616
  const deadline = Date.now() + timeoutMs;
@@ -1631,47 +1623,64 @@ async function pollForApproval(apiUrl, revocationToken, timeoutMs) {
1631
1623
  }
1632
1624
  }
1633
1625
  function connect() {
1634
- if (Date.now() > deadline) {
1626
+ if (settled || Date.now() > deadline) {
1635
1627
  done("timeout");
1636
1628
  return;
1637
1629
  }
1638
- fetch(streamUrl, { headers: { Accept: "text/event-stream" } }).then(async (res) => {
1630
+ const controller = new AbortController();
1631
+ let readTimer = setTimeout(() => controller.abort(), SSE_READ_TIMEOUT_MS);
1632
+ function resetReadTimer() {
1633
+ clearTimeout(readTimer);
1634
+ readTimer = setTimeout(() => controller.abort(), SSE_READ_TIMEOUT_MS);
1635
+ }
1636
+ fetch(streamUrl, { signal: controller.signal, headers: { Accept: "text/event-stream" } }).then(async (res) => {
1639
1637
  if (!res.ok || !res.body) {
1640
- done("timeout");
1638
+ clearTimeout(readTimer);
1639
+ if (!settled) setTimeout(connect, 3e3);
1641
1640
  return;
1642
1641
  }
1643
1642
  const reader = res.body.getReader();
1644
1643
  const decoder = new TextDecoder();
1645
1644
  let buf = "";
1646
- while (true) {
1647
- const { done: streamDone, value } = await reader.read();
1648
- if (streamDone) break;
1649
- buf += decoder.decode(value, { stream: true });
1650
- const lines = buf.split("\n");
1651
- buf = lines.pop() ?? "";
1652
- for (const line of lines) {
1653
- if (!line.startsWith("data: ")) continue;
1654
- try {
1655
- const evt = JSON.parse(line.slice(6));
1656
- if (evt.status === "approved") {
1657
- done("approved");
1658
- return;
1645
+ try {
1646
+ while (true) {
1647
+ const { done: streamDone, value } = await reader.read();
1648
+ resetReadTimer();
1649
+ if (streamDone) break;
1650
+ buf += decoder.decode(value, { stream: true });
1651
+ const lines = buf.split("\n");
1652
+ buf = lines.pop() ?? "";
1653
+ for (const line of lines) {
1654
+ if (line.startsWith(":")) continue;
1655
+ if (!line.startsWith("data: ")) continue;
1656
+ try {
1657
+ const evt = JSON.parse(line.slice(6));
1658
+ if (evt.status === "approved") {
1659
+ clearTimeout(readTimer);
1660
+ done("approved");
1661
+ return;
1662
+ }
1663
+ if (evt.status === "rejected") {
1664
+ clearTimeout(readTimer);
1665
+ done("rejected");
1666
+ return;
1667
+ }
1668
+ if (evt.status === "timeout") {
1669
+ clearTimeout(readTimer);
1670
+ done("timeout");
1671
+ return;
1672
+ }
1673
+ } catch {
1659
1674
  }
1660
- if (evt.status === "rejected") {
1661
- done("rejected");
1662
- return;
1663
- }
1664
- if (evt.status === "timeout") {
1665
- done("timeout");
1666
- return;
1667
- }
1668
- } catch {
1669
1675
  }
1670
1676
  }
1677
+ } finally {
1678
+ clearTimeout(readTimer);
1671
1679
  }
1672
1680
  if (!settled) setTimeout(connect, 1e3);
1673
1681
  }).catch(() => {
1674
- if (!settled) setTimeout(connect, 2e3);
1682
+ clearTimeout(readTimer);
1683
+ if (!settled) setTimeout(connect, 1e3);
1675
1684
  });
1676
1685
  }
1677
1686
  connect();
@@ -1700,7 +1709,7 @@ function uninstallCommand() {
1700
1709
  }
1701
1710
  console.log(chalk11.dim(`
1702
1711
  Submitting revocation request for ${creds.agentId}...`));
1703
- const jwt = signJwt2(creds.agentId, creds.ownerId, privateKeyPem);
1712
+ const jwt = signJwt(creds.agentId, creds.ownerId, privateKeyPem);
1704
1713
  let revocationToken;
1705
1714
  try {
1706
1715
  const res = await fetch(`${creds.apiUrl}/v1/revoke-request`, {
@@ -1747,11 +1756,13 @@ function uninstallCommand() {
1747
1756
  }
1748
1757
 
1749
1758
  // src/index.ts
1759
+ var require2 = createRequire(import.meta.url);
1760
+ var { version } = require2("../package.json");
1750
1761
  function collectScope(value, previous) {
1751
1762
  return [...previous, value];
1752
1763
  }
1753
1764
  var program = new Command5();
1754
- 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) => {
1765
+ program.name("agentvalet-register").description("Self-register an AI agent with AgentValet").version(version).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) => {
1755
1766
  const isJson = !!opts.json;
1756
1767
  let ownerId = opts.owner ?? process.env.AGENTVALET_OWNER ?? "";
1757
1768
  let agentName = opts.name ?? "";
@@ -1922,7 +1933,8 @@ program.command("refresh").description("Refresh approved permissions and update
1922
1933
  }
1923
1934
  });
1924
1935
  program.command("mcp-server").description("Start the AgentValet MCP server (stdio transport)").action(async () => {
1925
- await import("./mcp-server-SBGWYBP7.js");
1936
+ const { mcpServerCommand } = await import("./mcp-server-R3LG4PNM.js");
1937
+ await mcpServerCommand();
1926
1938
  });
1927
1939
  program.addCommand(listCommand());
1928
1940
  program.addCommand(revokeCommand());
@@ -0,0 +1,46 @@
1
+ // src/commands/mcp-server.ts
2
+ import { spawn } from "child_process";
3
+ import { createRequire } from "module";
4
+ function resolveMcpServerBin() {
5
+ try {
6
+ const require2 = createRequire(import.meta.url);
7
+ return require2.resolve("@agentvalet/mcp-server/dist/index.js");
8
+ } catch {
9
+ try {
10
+ const require2 = createRequire(import.meta.url);
11
+ const pkgRoot = require2.resolve("@agentvalet/mcp-server/package.json");
12
+ return pkgRoot.replace("package.json", "dist/index.js");
13
+ } catch {
14
+ throw new Error(
15
+ "@agentvalet/mcp-server is not installed. Run: npx @agentvalet/register"
16
+ );
17
+ }
18
+ }
19
+ }
20
+ async function mcpServerCommand() {
21
+ let binPath;
22
+ try {
23
+ binPath = resolveMcpServerBin();
24
+ } catch (err) {
25
+ process.stderr.write(
26
+ `[agentvalet] ${err instanceof Error ? err.message : String(err)}
27
+ `
28
+ );
29
+ process.exit(1);
30
+ }
31
+ const child = spawn(process.execPath, [binPath], {
32
+ stdio: "inherit",
33
+ env: process.env
34
+ });
35
+ child.on("error", (err) => {
36
+ process.stderr.write(`[agentvalet] Failed to start MCP server: ${err.message}
37
+ `);
38
+ process.exit(1);
39
+ });
40
+ child.on("exit", (code) => {
41
+ process.exit(code ?? 0);
42
+ });
43
+ }
44
+ export {
45
+ mcpServerCommand
46
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agentvalet/register",
3
- "version": "0.4.10",
3
+ "version": "0.4.12",
4
4
  "description": "Self-register AI agents with AgentValet",
5
5
  "type": "module",
6
6
  "bin": {
@@ -10,14 +10,8 @@
10
10
  "dist",
11
11
  "README.md"
12
12
  ],
13
- "scripts": {
14
- "build": "tsup src/index.ts --format esm --dts --clean --shims",
15
- "dev": "tsx src/index.ts",
16
- "test": "vitest run",
17
- "typecheck": "tsc --noEmit",
18
- "prepublishOnly": "pnpm build"
19
- },
20
13
  "dependencies": {
14
+ "@agentvalet/mcp-server": "*",
21
15
  "@modelcontextprotocol/sdk": "^1.29.0",
22
16
  "@octokit/auth-oauth-device": "^7.0.0",
23
17
  "chalk": "^5.3.0",
@@ -54,5 +48,11 @@
54
48
  "valet",
55
49
  "agentvalet"
56
50
  ],
57
- "license": "MIT"
58
- }
51
+ "license": "MIT",
52
+ "scripts": {
53
+ "build": "tsup src/index.ts --format esm --dts --clean --shims",
54
+ "dev": "tsx src/index.ts",
55
+ "test": "vitest run",
56
+ "typecheck": "tsc --noEmit"
57
+ }
58
+ }
@@ -1,139 +0,0 @@
1
- // src/commands/mcp-server.ts
2
- import { readFileSync } from "fs";
3
- import { Server } from "@modelcontextprotocol/sdk/server/index.js";
4
- import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
5
- import { CallToolRequestSchema, ListToolsRequestSchema } from "@modelcontextprotocol/sdk/types.js";
6
- import { SignJWT, importPKCS8 } from "jose";
7
- if (!process.env.AGENT_PRIVATE_KEY && process.env.AGENT_PRIVATE_KEY_PATH) {
8
- try {
9
- process.env.AGENT_PRIVATE_KEY = readFileSync(process.env.AGENT_PRIVATE_KEY_PATH, "utf-8").trim();
10
- } catch (err) {
11
- process.stderr.write(`[agentvalet] Cannot read AGENT_PRIVATE_KEY_PATH: ${err instanceof Error ? err.message : err}
12
- `);
13
- process.exit(1);
14
- }
15
- }
16
- var REQUIRED = ["AGENT_PRIVATE_KEY", "AGENT_ID", "OWNER_ID", "PROXY_URL"];
17
- for (const key of REQUIRED) {
18
- if (!process.env[key]) {
19
- process.stderr.write(`[agentvalet] Missing env var: ${key}
20
- `);
21
- process.exit(1);
22
- }
23
- }
24
- var AGENT_PRIVATE_KEY_RAW = process.env.AGENT_PRIVATE_KEY;
25
- var AGENT_ID = process.env.AGENT_ID;
26
- var OWNER_ID = process.env.OWNER_ID;
27
- var PROXY_URL = process.env.PROXY_URL.replace(/\/$/, "");
28
- var _privateKey = null;
29
- var _keyError = null;
30
- async function getPrivateKey() {
31
- if (_keyError) throw new Error(_keyError);
32
- if (_privateKey) return _privateKey;
33
- if (AGENT_PRIVATE_KEY_RAW === "PENDING_FIRST_CALL") return null;
34
- const raw = AGENT_PRIVATE_KEY_RAW.trim();
35
- const pem = raw.startsWith("-----") ? raw.replace(/\\n/g, "\n") : `-----BEGIN PRIVATE KEY-----
36
- ${raw}
37
- -----END PRIVATE KEY-----`;
38
- try {
39
- _privateKey = await importPKCS8(pem, "RS256");
40
- return _privateKey;
41
- } catch (err) {
42
- _keyError = `Invalid private key: ${err instanceof Error ? err.message : err}`;
43
- throw new Error(_keyError);
44
- }
45
- }
46
- async function signJWT() {
47
- const key = await getPrivateKey();
48
- if (!key) throw new Error("Private key not loaded");
49
- return new SignJWT({ agent_id: AGENT_ID, owner_id: OWNER_ID }).setProtectedHeader({ alg: "RS256" }).setIssuedAt().setExpirationTime("60s").sign(key);
50
- }
51
- function fetchWithTimeout(url, init, ms = 15e3) {
52
- const ac = new AbortController();
53
- const t = setTimeout(() => ac.abort(), ms);
54
- return fetch(url, { ...init, signal: ac.signal }).finally(() => clearTimeout(t));
55
- }
56
- async function bearerFetch(url, init) {
57
- const token = await signJWT();
58
- return fetchWithTimeout(url, {
59
- ...init,
60
- headers: { Authorization: `Bearer ${token}`, "Content-Type": "application/json", ...init.headers }
61
- });
62
- }
63
- function errResult(msg) {
64
- return { content: [{ type: "text", text: msg }], isError: true };
65
- }
66
- var ALLOWED_METHODS = ["GET", "POST", "PUT", "PATCH", "DELETE"];
67
- var server = new Server(
68
- { name: "agentvalet", version: "1.0.0" },
69
- { capabilities: { tools: {} } }
70
- );
71
- server.setRequestHandler(ListToolsRequestSchema, async () => ({
72
- tools: [
73
- {
74
- name: "list_platforms",
75
- description: "List the platforms and permission scopes this agent has access to.",
76
- inputSchema: { type: "object", properties: {} }
77
- },
78
- {
79
- name: "use_platform",
80
- description: "Call an external platform API through the AgentValet proxy.",
81
- inputSchema: {
82
- type: "object",
83
- properties: {
84
- platform: { type: "string", description: "Platform ID (e.g. slack, github)" },
85
- endpoint: { type: "string", description: "API path on the target platform" },
86
- method: { type: "string", enum: ["GET", "POST", "PUT", "PATCH", "DELETE"] },
87
- scope: { type: "string", description: "Permission scope required" },
88
- data: { type: "object", description: "Optional request body" }
89
- },
90
- required: ["platform", "endpoint", "method", "scope"]
91
- }
92
- }
93
- ]
94
- }));
95
- server.setRequestHandler(CallToolRequestSchema, async (request) => {
96
- const { name, arguments: args } = request.params;
97
- if (name === "list_platforms") {
98
- if (AGENT_PRIVATE_KEY_RAW === "PENDING_FIRST_CALL") {
99
- return errResult("Agent not yet activated \u2014 owner confirmation pending. Retry in 60 seconds.");
100
- }
101
- try {
102
- const res = await bearerFetch(`${PROXY_URL}/v1/agent/permissions`, { method: "GET", headers: {} });
103
- const body = await res.text();
104
- if (!res.ok) return errResult(`Proxy error ${res.status}: ${body}`);
105
- return { content: [{ type: "text", text: body }] };
106
- } catch (e) {
107
- return errResult(`Error: ${e instanceof Error ? e.message : e}`);
108
- }
109
- }
110
- if (name === "use_platform") {
111
- if (AGENT_PRIVATE_KEY_RAW === "PENDING_FIRST_CALL") {
112
- return errResult("Agent not yet activated \u2014 owner confirmation pending. Retry in 60 seconds.");
113
- }
114
- if (!args || typeof args.platform !== "string" || typeof args.endpoint !== "string" || typeof args.method !== "string" || typeof args.scope !== "string") {
115
- return errResult("Missing required args: platform, endpoint, method, scope");
116
- }
117
- if (!ALLOWED_METHODS.includes(args.method)) return errResult(`Invalid method: ${args.method}`);
118
- try {
119
- const res = await bearerFetch(`${PROXY_URL}/v1/actions`, {
120
- method: "POST",
121
- body: JSON.stringify({
122
- platform: args.platform,
123
- endpoint: args.endpoint,
124
- method: args.method,
125
- scope: args.scope,
126
- ...args.data !== void 0 && { data: args.data }
127
- })
128
- });
129
- const body = await res.text();
130
- if (!res.ok) return errResult(`Proxy error ${res.status}: ${body}`);
131
- return { content: [{ type: "text", text: body }] };
132
- } catch (e) {
133
- return errResult(`Error: ${e instanceof Error ? e.message : e}`);
134
- }
135
- }
136
- return errResult(`Unknown tool: ${name}`);
137
- });
138
- var transport = new StdioServerTransport();
139
- await server.connect(transport);