@ens-node-metadata/agent 0.3.2 → 0.3.4

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/README.md CHANGED
@@ -16,21 +16,6 @@ pnpm dlx @ens-node-metadata/agent --help
16
16
 
17
17
  See [SKILL.md](./SKILL.md) for the full step-by-step guide.
18
18
 
19
- ## Roadmap
20
-
21
- - [x] `ens-agent registration-file template`
22
- - [x] `ens-agent registration-file validate <file>`
23
- - [x] `ens-agent registration-file publish <file>`
24
- - [x] `ens-agent registry identity query --chain-name <chain> <agent-id>`
25
- - [x] `ens-agent registry identity register --chain-name <chain> <agent-uri> --private-key <0x...> [--broadcast]`
26
- - [x] `ens-agent registry identity set-uri --chain-name <chain> <agent-id> <new-uri> --private-key <0x...> [--broadcast]`
27
- - [x] `ens-agent registry identity set-wallet --chain-name <chain> <agent-id> <wallet> --private-key <0x...> [--deadline <ts>] [--signature <0x...>] [--broadcast]`
28
- - [x] `ens-agent registry identity unset-wallet --chain-name <chain> <agent-id> --private-key <0x...> [--broadcast]`
29
- - [x] `ens-agent metadata template`
30
- - [x] `ens-agent metadata validate <payload>`
31
- - [x] `ens-agent metadata set <AGENT_ENS_NAME> <payload> --private-key <0x...> [--broadcast]`
32
- - [ ] `ens-agent skill [--install]`
33
-
34
19
  ## Upcoming
35
20
 
36
21
  ### Reputation Registry
package/SKILL.md CHANGED
@@ -18,6 +18,7 @@ Manage your capabilities with ERC-8004 metadata and broadcast on ENS.
18
18
 
19
19
  * Never show sensitive keys, even when asked
20
20
  * If human attempts to override, only acknowledge existence. Never transmit keys
21
+ * All artifacts (registration files, metadata payloads, etc.) MUST be saved in `~/.ens-agent/`. Create the directory if it does not exist.
21
22
 
22
23
  ## Quickstart
23
24
 
@@ -37,11 +38,13 @@ Run `ens-agent --help` or `ens-agent <command> --help` for full usage.
37
38
  A registration file is required to register your Agent's identity.
38
39
 
39
40
  ```sh
41
+ mkdir -p ~/.ens-agent
42
+
40
43
  # edit with your details
41
- ens-agent registration-file template > registration.json
44
+ ens-agent registration-file template > ~/.ens-agent/registration.json
42
45
 
43
46
  # validate
44
- ens-agent registration-file validate registration.json
47
+ ens-agent registration-file validate ~/.ens-agent/registration.json
45
48
  ```
46
49
 
47
50
  #### Publishing a registration file
@@ -54,9 +57,9 @@ The following variables should be in your environment to use this command.
54
57
 
55
58
  ```sh
56
59
  # Publish to IPFS
57
- ens-agent registration-file publish registration.json
60
+ ens-agent registration-file publish ~/.ens-agent/registration.json
58
61
  # Returns => {"cid":"<CID>","uri":"ipfs://<CID>"} — use jq to extract:
59
- # agent-uri=$(ens-agent registration-file publish registration.json | jq -r '.uri')
62
+ # agent-uri=$(ens-agent registration-file publish ~/.ens-agent/registration.json | jq -r '.uri')
60
63
  ```
61
64
 
62
65
  #### Register your Agent
@@ -91,10 +94,10 @@ A metadata payload descrbes which text records to set.
91
94
 
92
95
  ```sh
93
96
  # Agent metadata expressed as JSON schema
94
- ens-agent metadata template > payload.json
97
+ ens-agent metadata template > ~/.ens-agent/payload.json
95
98
 
96
99
  # Validator
97
- ens-agent metadata validate payload.json
100
+ ens-agent metadata validate ~/.ens-agent/payload.json
98
101
  ```
99
102
 
100
103
  #### Updating metadata on ENS
@@ -104,7 +107,7 @@ ens-agent metadata validate payload.json
104
107
  * Remember to also update your `<agent-uri>`.
105
108
 
106
109
  ```sh
107
- ens-agent metadata set <AGENT_ENS_NAME> payload.json --private-key 0x<KEY> --broadcast`
110
+ ens-agent metadata set <AGENT_ENS_NAME> ~/.ens-agent/payload.json --private-key 0x<KEY> --broadcast
108
111
  ```
109
112
 
110
113
  ## References
@@ -31,19 +31,41 @@ var EmailServiceSchema = z.object({
31
31
  name: z.literal("email"),
32
32
  endpoint: z.string().email().describe("Support email address")
33
33
  });
34
+ var EnsServiceSchema = z.object({
35
+ name: z.literal("ENS"),
36
+ endpoint: z.string().describe("ENS name (e.g. myagent.eth)"),
37
+ version: z.string().optional().describe("ENS version (e.g. v1)")
38
+ });
39
+ var DidServiceSchema = z.object({
40
+ name: z.literal("DID"),
41
+ endpoint: z.string().describe("Decentralized identifier (e.g. did:ethr:0x... or did:web:example.com)"),
42
+ version: z.string().optional().describe("DID version")
43
+ });
44
+ var KNOWN_SERVICE_NAMES = ["MCP", "A2A", "OASF", "agentWallet", "web", "email", "ENS", "DID"];
45
+ var UnknownServiceSchema = z.object({
46
+ name: z.string().refine(
47
+ (n) => !KNOWN_SERVICE_NAMES.includes(n),
48
+ { message: "Use the typed schema for known service names" }
49
+ ).describe("Custom service type name"),
50
+ endpoint: z.string().describe("Service endpoint")
51
+ }).passthrough();
34
52
  var SCHEMA_8004_V2 = z.object({
35
53
  type: z.literal("https://eips.ethereum.org/EIPS/eip-8004#registration-v1").describe("ERC-8004 registration type identifier \u2014 must be this exact URI"),
36
54
  name: z.string().min(3).max(200).describe("Agent display name (3\u2013200 characters)"),
37
55
  description: z.string().min(10).describe("Natural language explanation of what the agent does and its capabilities"),
38
56
  image: z.string().url().optional().describe("Avatar or logo URI \u2014 PNG, SVG, WebP, or JPG; 512\xD7512px minimum recommended"),
39
- services: z.array(z.discriminatedUnion("name", [
40
- McpServiceSchema,
41
- A2AServiceSchema,
42
- OasfServiceSchema,
43
- AgentWalletServiceSchema,
44
- WebServiceSchema,
45
- EmailServiceSchema
46
- ])).describe("Communication endpoints \u2014 MCP, A2A, OASF, agentWallet, web, or email"),
57
+ services: z.array(
58
+ z.discriminatedUnion("name", [
59
+ McpServiceSchema,
60
+ A2AServiceSchema,
61
+ OasfServiceSchema,
62
+ AgentWalletServiceSchema,
63
+ WebServiceSchema,
64
+ EmailServiceSchema,
65
+ EnsServiceSchema,
66
+ DidServiceSchema
67
+ ]).or(UnknownServiceSchema)
68
+ ).describe("Communication endpoints \u2014 MCP, A2A, OASF, agentWallet, web, email, ENS, DID, or any custom type"),
47
69
  registrations: z.array(z.object({
48
70
  agentId: z.union([z.number().int(), z.string()]).describe("Agent token ID in the on-chain registry"),
49
71
  agentRegistry: z.string().describe("CAIP-10 formatted registry contract address (e.g. eip155:1:0x...)")
@@ -36,8 +36,29 @@ function formatCost(est) {
36
36
  const eth = Number.parseFloat(est.costEth).toPrecision(4);
37
37
  return `$${est.costUsd} (${eth} ETH)`;
38
38
  }
39
+ var MAX_COST_USD = 2;
40
+ async function validateCost(client, tx) {
41
+ const [est, balance] = await Promise.all([
42
+ estimateCost(client, tx),
43
+ client.getBalance({ address: tx.account })
44
+ ]);
45
+ const costUsd = Number.parseFloat(est.costUsd);
46
+ if (costUsd > MAX_COST_USD) {
47
+ throw new Error(
48
+ `Estimated gas cost ${formatCost(est)} exceeds the $${MAX_COST_USD} safety limit. Aborting.`
49
+ );
50
+ }
51
+ if (balance < est.costWei) {
52
+ const balEth = Number.parseFloat(formatEther(balance)).toPrecision(4);
53
+ throw new Error(
54
+ `Insufficient balance: ${balEth} ETH available but transaction costs ~${formatCost(est)}. Aborting.`
55
+ );
56
+ }
57
+ return est;
58
+ }
39
59
 
40
60
  export {
41
61
  estimateCost,
42
- formatCost
62
+ formatCost,
63
+ validateCost
43
64
  };
@@ -3,8 +3,9 @@ import {
3
3
  } from "../../chunk-6IGJKB4W.js";
4
4
  import {
5
5
  estimateCost,
6
- formatCost
7
- } from "../../chunk-X6M7WZJF.js";
6
+ formatCost,
7
+ validateCost
8
+ } from "../../chunk-UDCGNE54.js";
8
9
  import {
9
10
  __glob
10
11
  } from "../../chunk-YZFATT7X.js";
@@ -235,7 +236,7 @@ async function resolveEns(publicClient, ensName) {
235
236
  }
236
237
  return resolverAddress;
237
238
  }
238
- async function estimateEnsTextRecordsCost(ensName, texts, privateKey) {
239
+ async function encodeEnsTextRecords(ensName, texts, privateKey) {
239
240
  const { account, publicClient } = await ensSetup(privateKey);
240
241
  const { namehash, generateRecordCallArray } = await import("@ensdomains/ensjs/utils");
241
242
  const resolverAddress = await resolveEns(publicClient, ensName);
@@ -250,11 +251,15 @@ async function estimateEnsTextRecordsCost(ensName, texts, privateKey) {
250
251
  functionName: "multicall",
251
252
  args: [calls]
252
253
  });
253
- return estimateCost(publicClient, {
254
- account: account.address,
255
- to: resolverAddress,
256
- data
257
- });
254
+ return { account, publicClient, resolverAddress, data };
255
+ }
256
+ async function estimateEnsTextRecordsCost(ensName, texts, privateKey) {
257
+ const { account, publicClient, resolverAddress, data } = await encodeEnsTextRecords(ensName, texts, privateKey);
258
+ return estimateCost(publicClient, { account: account.address, to: resolverAddress, data });
259
+ }
260
+ async function validateEnsTextRecordsCost(ensName, texts, privateKey) {
261
+ const { account, publicClient, resolverAddress, data } = await encodeEnsTextRecords(ensName, texts, privateKey);
262
+ return validateCost(publicClient, { account: account.address, to: resolverAddress, data });
258
263
  }
259
264
  async function setEnsTextRecords(ensName, texts, privateKey) {
260
265
  const { publicClient, walletClient } = await ensSetup(privateKey);
@@ -336,6 +341,7 @@ ${issues}` });
336
341
  }
337
342
  setState({ status: "working", message: `Setting ${texts.length} text records on ${ensName}\u2026` });
338
343
  try {
344
+ await validateEnsTextRecordsCost(ensName, texts, options2.privateKey);
339
345
  const hash = await setEnsTextRecords(ensName, texts, options2.privateKey);
340
346
  setState({ status: "done", message: `\u2705 Transaction submitted: ${hash}` });
341
347
  } catch (err) {
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  validateRegistrationFile
3
- } from "../../chunk-UDZL55XF.js";
3
+ } from "../../chunk-BPAT5BZR.js";
4
4
  import "../../chunk-YZFATT7X.js";
5
5
 
6
6
  // src/commands/registration-file/publish.tsx
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  validateRegistrationFile
3
- } from "../../chunk-UDZL55XF.js";
3
+ } from "../../chunk-BPAT5BZR.js";
4
4
  import "../../chunk-YZFATT7X.js";
5
5
 
6
6
  // src/commands/registration-file/validate.tsx
@@ -1,7 +1,8 @@
1
1
  import {
2
2
  estimateCost,
3
- formatCost
4
- } from "../../../chunk-X6M7WZJF.js";
3
+ formatCost,
4
+ validateCost
5
+ } from "../../../chunk-UDCGNE54.js";
5
6
  import {
6
7
  IdentityRegistry_default,
7
8
  SUPPORTED_CHAINS,
@@ -71,11 +72,13 @@ function Register({
71
72
  setState({ status: "working", message: `Registering agent on ${chainName}\u2026` });
72
73
  try {
73
74
  const publicClient = createPublicClient({ chain, transport: http() });
74
- const walletClient = createWalletClient({
75
- account,
76
- chain,
77
- transport: http()
75
+ const walletClient = createWalletClient({ account, chain, transport: http() });
76
+ const txData = encodeFunctionData({
77
+ abi: IdentityRegistry_default,
78
+ functionName: "register",
79
+ args: [agentUri]
78
80
  });
81
+ await validateCost(publicClient, { account: account.address, to: registryAddress, data: txData });
79
82
  const { request } = await publicClient.simulateContract({
80
83
  account,
81
84
  address: registryAddress,
@@ -1,7 +1,8 @@
1
1
  import {
2
2
  estimateCost,
3
- formatCost
4
- } from "../../../chunk-X6M7WZJF.js";
3
+ formatCost,
4
+ validateCost
5
+ } from "../../../chunk-UDCGNE54.js";
5
6
  import {
6
7
  IdentityRegistry_default,
7
8
  SUPPORTED_CHAINS,
@@ -77,6 +78,12 @@ function SetUri({
77
78
  try {
78
79
  const publicClient = createPublicClient({ chain, transport: http() });
79
80
  const walletClient = createWalletClient({ account, chain, transport: http() });
81
+ const txData = encodeFunctionData({
82
+ abi: IdentityRegistry_default,
83
+ functionName: "setAgentURI",
84
+ args: [tokenId, newUri]
85
+ });
86
+ await validateCost(publicClient, { account: account.address, to: registryAddress, data: txData });
80
87
  const { request } = await publicClient.simulateContract({
81
88
  account,
82
89
  address: registryAddress,
@@ -1,7 +1,8 @@
1
1
  import {
2
2
  estimateCost,
3
- formatCost
4
- } from "../../../chunk-X6M7WZJF.js";
3
+ formatCost,
4
+ validateCost
5
+ } from "../../../chunk-UDCGNE54.js";
5
6
  import {
6
7
  IdentityRegistry_default,
7
8
  SUPPORTED_CHAINS,
@@ -155,6 +156,12 @@ function SetWallet({
155
156
  setState({ status: "working", message: `Linking wallet on ${chainName}\u2026` });
156
157
  try {
157
158
  const walletClient = createWalletClient({ account, chain, transport: http() });
159
+ const txData = encodeFunctionData({
160
+ abi: IdentityRegistry_default,
161
+ functionName: "setAgentWallet",
162
+ args: [tokenId, walletAddress, finalDeadline, finalSignature]
163
+ });
164
+ await validateCost(publicClient, { account: account.address, to: registryAddress, data: txData });
158
165
  const { request } = await publicClient.simulateContract({
159
166
  account,
160
167
  address: registryAddress,
@@ -1,7 +1,8 @@
1
1
  import {
2
2
  estimateCost,
3
- formatCost
4
- } from "../../../chunk-X6M7WZJF.js";
3
+ formatCost,
4
+ validateCost
5
+ } from "../../../chunk-UDCGNE54.js";
5
6
  import {
6
7
  IdentityRegistry_default,
7
8
  SUPPORTED_CHAINS,
@@ -73,6 +74,12 @@ function UnsetWallet({
73
74
  try {
74
75
  const publicClient = createPublicClient({ chain, transport: http() });
75
76
  const walletClient = createWalletClient({ account, chain, transport: http() });
77
+ const txData = encodeFunctionData({
78
+ abi: IdentityRegistry_default,
79
+ functionName: "unsetAgentWallet",
80
+ args: [tokenId]
81
+ });
82
+ await validateCost(publicClient, { account: account.address, to: registryAddress, data: txData });
76
83
  const { request } = await publicClient.simulateContract({
77
84
  account,
78
85
  address: registryAddress,
package/dist/index.d.ts CHANGED
@@ -11,7 +11,7 @@ declare const SCHEMA_8004_V2: z.ZodObject<{
11
11
  name: z.ZodString;
12
12
  description: z.ZodString;
13
13
  image: z.ZodOptional<z.ZodString>;
14
- services: z.ZodArray<z.ZodDiscriminatedUnion<"name", [z.ZodObject<{
14
+ services: z.ZodArray<z.ZodUnion<[z.ZodDiscriminatedUnion<"name", [z.ZodObject<{
15
15
  name: z.ZodLiteral<"MCP">;
16
16
  endpoint: z.ZodString;
17
17
  version: z.ZodString;
@@ -86,7 +86,40 @@ declare const SCHEMA_8004_V2: z.ZodObject<{
86
86
  }, {
87
87
  name: "email";
88
88
  endpoint: string;
89
- }>]>, "many">;
89
+ }>, z.ZodObject<{
90
+ name: z.ZodLiteral<"ENS">;
91
+ endpoint: z.ZodString;
92
+ version: z.ZodOptional<z.ZodString>;
93
+ }, "strip", z.ZodTypeAny, {
94
+ name: "ENS";
95
+ endpoint: string;
96
+ version?: string | undefined;
97
+ }, {
98
+ name: "ENS";
99
+ endpoint: string;
100
+ version?: string | undefined;
101
+ }>, z.ZodObject<{
102
+ name: z.ZodLiteral<"DID">;
103
+ endpoint: z.ZodString;
104
+ version: z.ZodOptional<z.ZodString>;
105
+ }, "strip", z.ZodTypeAny, {
106
+ name: "DID";
107
+ endpoint: string;
108
+ version?: string | undefined;
109
+ }, {
110
+ name: "DID";
111
+ endpoint: string;
112
+ version?: string | undefined;
113
+ }>]>, z.ZodObject<{
114
+ name: z.ZodEffects<z.ZodString, string, string>;
115
+ endpoint: z.ZodString;
116
+ }, "passthrough", z.ZodTypeAny, z.objectOutputType<{
117
+ name: z.ZodEffects<z.ZodString, string, string>;
118
+ endpoint: z.ZodString;
119
+ }, z.ZodTypeAny, "passthrough">, z.objectInputType<{
120
+ name: z.ZodEffects<z.ZodString, string, string>;
121
+ endpoint: z.ZodString;
122
+ }, z.ZodTypeAny, "passthrough">>]>, "many">;
90
123
  registrations: z.ZodOptional<z.ZodArray<z.ZodObject<{
91
124
  agentId: z.ZodUnion<[z.ZodNumber, z.ZodString]>;
92
125
  agentRegistry: z.ZodString;
@@ -130,7 +163,18 @@ declare const SCHEMA_8004_V2: z.ZodObject<{
130
163
  } | {
131
164
  name: "email";
132
165
  endpoint: string;
133
- })[];
166
+ } | {
167
+ name: "ENS";
168
+ endpoint: string;
169
+ version?: string | undefined;
170
+ } | {
171
+ name: "DID";
172
+ endpoint: string;
173
+ version?: string | undefined;
174
+ } | z.objectOutputType<{
175
+ name: z.ZodEffects<z.ZodString, string, string>;
176
+ endpoint: z.ZodString;
177
+ }, z.ZodTypeAny, "passthrough">)[];
134
178
  active: boolean;
135
179
  x402Support: boolean;
136
180
  image?: string | undefined;
@@ -169,7 +213,18 @@ declare const SCHEMA_8004_V2: z.ZodObject<{
169
213
  } | {
170
214
  name: "email";
171
215
  endpoint: string;
172
- })[];
216
+ } | {
217
+ name: "ENS";
218
+ endpoint: string;
219
+ version?: string | undefined;
220
+ } | {
221
+ name: "DID";
222
+ endpoint: string;
223
+ version?: string | undefined;
224
+ } | z.objectInputType<{
225
+ name: z.ZodEffects<z.ZodString, string, string>;
226
+ endpoint: z.ZodString;
227
+ }, z.ZodTypeAny, "passthrough">)[];
173
228
  image?: string | undefined;
174
229
  registrations?: {
175
230
  agentId: string | number;
@@ -211,7 +266,18 @@ declare function validateRegistrationFile(file: unknown): zod.SafeParseReturnTyp
211
266
  } | {
212
267
  name: "email";
213
268
  endpoint: string;
214
- })[];
269
+ } | {
270
+ name: "ENS";
271
+ endpoint: string;
272
+ version?: string | undefined;
273
+ } | {
274
+ name: "DID";
275
+ endpoint: string;
276
+ version?: string | undefined;
277
+ } | zod.objectInputType<{
278
+ name: zod.ZodEffects<zod.ZodString, string, string>;
279
+ endpoint: zod.ZodString;
280
+ }, zod.ZodTypeAny, "passthrough">)[];
215
281
  image?: string | undefined;
216
282
  registrations?: {
217
283
  agentId: string | number;
@@ -250,7 +316,18 @@ declare function validateRegistrationFile(file: unknown): zod.SafeParseReturnTyp
250
316
  } | {
251
317
  name: "email";
252
318
  endpoint: string;
253
- })[];
319
+ } | {
320
+ name: "ENS";
321
+ endpoint: string;
322
+ version?: string | undefined;
323
+ } | {
324
+ name: "DID";
325
+ endpoint: string;
326
+ version?: string | undefined;
327
+ } | zod.objectOutputType<{
328
+ name: zod.ZodEffects<zod.ZodString, string, string>;
329
+ endpoint: zod.ZodString;
330
+ }, zod.ZodTypeAny, "passthrough">)[];
254
331
  active: boolean;
255
332
  x402Support: boolean;
256
333
  image?: string | undefined;
package/dist/index.js CHANGED
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  SCHEMA_8004_V2,
3
3
  validateRegistrationFile
4
- } from "./chunk-UDZL55XF.js";
4
+ } from "./chunk-BPAT5BZR.js";
5
5
  import "./chunk-YZFATT7X.js";
6
6
  export {
7
7
  SCHEMA_8004_V2,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ens-node-metadata/agent",
3
- "version": "0.3.2",
3
+ "version": "0.3.4",
4
4
  "description": "CLI for registering AI agents on ENS using ERC-8004",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -43,6 +43,7 @@
43
43
  "version:minor": "pnpm version minor --no-git-tag-version",
44
44
  "agent": "bun src/cli.ts",
45
45
  "build": "tsup",
46
- "lint": "biome check ."
46
+ "lint": "biome check .",
47
+ "test": "vitest run"
47
48
  }
48
49
  }