agentdex-cli 0.2.2 → 0.2.5

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/cli.js CHANGED
@@ -6,7 +6,7 @@ import inquirer from 'inquirer';
6
6
  import qrcode from 'qrcode-terminal';
7
7
  import { readFileSync } from 'fs';
8
8
  import { AgentdexClient } from './client.js';
9
- import { parseSecretKey, getNpub, getPubkeyHex, createProfileEvent, createKind0Event, publishToRelays, createNote } from './nostr.js';
9
+ import { parseSecretKey, getNpub, getPubkeyHex, createProfileEvent, createKind0Event, publishToRelays, createNote, updateKind0 } from './nostr.js';
10
10
  import { payInvoice } from './nwc.js';
11
11
  const program = new Command();
12
12
  program
@@ -42,8 +42,11 @@ program
42
42
  .option('--framework <fw>', 'Framework (e.g., langchain, openclaw)')
43
43
  .option('--model <model>', 'Model (e.g., claude-3.5-sonnet)')
44
44
  .option('--website <url>', 'Website URL')
45
- .option('--lightning <addr>', 'Lightning address')
45
+ .option('--lightning <addr>', 'Lightning address (sets lud16 in kind 0 profile)')
46
46
  .option('--owner-x <handle>', 'Owner X/Twitter handle (e.g., @username)')
47
+ .option('--portfolio <entry>', 'Portfolio URL (format: "url,name,description") — repeatable', (val, acc) => [...acc, val], [])
48
+ .option('--skill <skill>', 'Skill tag (repeatable)', (val, acc) => [...acc, val], [])
49
+ .option('--experience <exp>', 'Experience tag (repeatable)', (val, acc) => [...acc, val], [])
47
50
  .option('--nwc <uri>', 'Nostr Wallet Connect URI for auto-pay')
48
51
  .option('--api-key <key>', 'Agentdex API key')
49
52
  .option('--relay <url>', 'Additional relay (repeatable)', (val, acc) => [...acc, val], [])
@@ -71,6 +74,11 @@ program
71
74
  framework = answers.framework || framework;
72
75
  }
73
76
  const spinner = ora('Signing event...').start();
77
+ // Parse portfolio entries ("url,name,description")
78
+ const portfolio = (options.portfolio || []).map((entry) => {
79
+ const parts = entry.split(',').map((s) => s.trim());
80
+ return { url: parts[0], name: parts[1], description: parts[2] };
81
+ });
74
82
  const event = createProfileEvent(sk, {
75
83
  name,
76
84
  description,
@@ -81,6 +89,9 @@ program
81
89
  lightning: options.lightning,
82
90
  ownerX: options.ownerX,
83
91
  status: 'active',
92
+ portfolio: portfolio.length > 0 ? portfolio : undefined,
93
+ skills: options.skill?.length > 0 ? options.skill : undefined,
94
+ experience: options.experience?.length > 0 ? options.experience : undefined,
84
95
  });
85
96
  spinner.text = 'Registering on agentdex...';
86
97
  const client = new AgentdexClient({ apiKey: options.apiKey });
@@ -136,6 +147,14 @@ program
136
147
  console.log(chalk.gray(` Published to: ${published.join(', ')}`));
137
148
  console.log('');
138
149
  console.log(chalk.gray(` Run ${chalk.white('agentdex claim <name>')} to get ${chalk.hex('#D4A574')('<name>@agentdex.id')}`));
150
+ // Update kind 0 with lightning address if provided
151
+ if (options.lightning) {
152
+ try {
153
+ await updateKind0(sk, { lud16: options.lightning }, relays);
154
+ console.log(chalk.gray(` ⚡ Lightning address set in kind 0: ${options.lightning}`));
155
+ }
156
+ catch { }
157
+ }
139
158
  }
140
159
  return;
141
160
  }
@@ -161,6 +180,14 @@ program
161
180
  console.log('');
162
181
  console.log(chalk.gray(` Run ${chalk.white('agentdex claim <name>')} to get ${chalk.hex('#D4A574')('<name>@agentdex.id')}`));
163
182
  console.log('');
183
+ // Update kind 0 with lightning address if provided
184
+ if (options.lightning) {
185
+ try {
186
+ await updateKind0(sk, { lud16: options.lightning }, relays);
187
+ console.log(chalk.gray(` ⚡ Lightning address set in kind 0: ${options.lightning}`));
188
+ }
189
+ catch { }
190
+ }
164
191
  console.log(chalk.gray(' Next: Claim a NIP-05 name to get verified (first 100 free, then 5000 sats).'));
165
192
  }
166
193
  }
@@ -188,6 +215,7 @@ program
188
215
  .option('--key-file <path>', 'Path to JSON key file')
189
216
  .option('--nwc <uri>', 'Nostr Wallet Connect URI for auto-pay')
190
217
  .option('--api-key <key>', 'Agentdex API key')
218
+ .option('--lightning <addr>', 'Lightning address (lud16) to set in kind 0 profile')
191
219
  .option('--skip-kind0', 'Skip publishing kind 0 profile to relays')
192
220
  .option('--relay <url>', 'Additional relay', (val, acc) => [...acc, val], [])
193
221
  .option('--json', 'Output JSON')
@@ -211,7 +239,10 @@ program
211
239
  try {
212
240
  const kind0 = createKind0Event(sk, {
213
241
  name: claim.agent?.name || name,
242
+ about: claim.agent?.description || undefined,
243
+ picture: claim.agent?.avatarUrl || undefined,
214
244
  nip05: `${name}@agentdex.id`,
245
+ lud16: options.lightning || undefined,
215
246
  });
216
247
  const relays = ['wss://nos.lol', 'wss://relay.damus.io', ...(options.relay || [])];
217
248
  const published = await publishToRelays(kind0, relays);
package/dist/client.d.ts CHANGED
@@ -36,6 +36,8 @@ export interface ClaimResult {
36
36
  agent?: {
37
37
  id: string;
38
38
  name: string;
39
+ description?: string;
40
+ avatarUrl?: string;
39
41
  nip05Name: string;
40
42
  tier: string;
41
43
  };
package/dist/nostr.d.ts CHANGED
@@ -1,6 +1,11 @@
1
1
  /**
2
2
  * Nostr utilities — event creation, signing, publishing
3
3
  */
4
+ export interface PortfolioItem {
5
+ url: string;
6
+ name?: string;
7
+ description?: string;
8
+ }
4
9
  export interface AgentProfile {
5
10
  name: string;
6
11
  description?: string;
@@ -16,6 +21,9 @@ export interface AgentProfile {
16
21
  messagingPolicy?: string;
17
22
  messagingMinTrust?: number;
18
23
  messagingFee?: number;
24
+ portfolio?: PortfolioItem[];
25
+ skills?: string[];
26
+ experience?: string[];
19
27
  }
20
28
  /**
21
29
  * Parse a secret key from nsec, hex, or key file
@@ -37,6 +45,13 @@ export declare function createProfileEvent(sk: Uint8Array, profile: AgentProfile
37
45
  * Publish an event to Nostr relays
38
46
  */
39
47
  export declare function publishToRelays(event: object, relays?: string[]): Promise<string[]>;
48
+ /**
49
+ * Fetch existing kind 0, merge new fields, and republish.
50
+ * Used to set lud16 (lightning address) during registration.
51
+ */
52
+ export declare function updateKind0(sk: Uint8Array, updates: {
53
+ lud16?: string;
54
+ }, relays?: string[]): Promise<string[]>;
40
55
  /**
41
56
  * Build and sign a kind 0 profile metadata event (for NIP-05 verification).
42
57
  * After claiming a NIP-05 name, publish this to relays so Nostr clients
@@ -47,6 +62,7 @@ export declare function createKind0Event(sk: Uint8Array, profile: {
47
62
  about?: string;
48
63
  nip05?: string;
49
64
  picture?: string;
65
+ lud16?: string;
50
66
  }): import("nostr-tools").VerifiedEvent;
51
67
  /**
52
68
  * Create and sign a kind 1 note tagged #agentdex
package/dist/nostr.js CHANGED
@@ -58,8 +58,8 @@ export function createProfileEvent(sk, profile) {
58
58
  tags.push(['website', profile.website]);
59
59
  if (profile.avatar)
60
60
  tags.push(['avatar', profile.avatar]);
61
- if (profile.lightning)
62
- tags.push(['lightning', profile.lightning]);
61
+ // Lightning address belongs in kind 0 (lud16), not kind 31337
62
+ // Use --lightning flag to set lud16 in kind 0 during claim
63
63
  if (profile.human)
64
64
  tags.push(['human', profile.human]);
65
65
  if (profile.ownerX)
@@ -72,6 +72,26 @@ export function createProfileEvent(sk, profile) {
72
72
  tags.push(['messaging_min_trust', String(profile.messagingMinTrust)]);
73
73
  if (profile.messagingFee)
74
74
  tags.push(['messaging_fee', String(profile.messagingFee)]);
75
+ if (profile.portfolio) {
76
+ for (const item of profile.portfolio) {
77
+ const tag = ['portfolio', item.url];
78
+ if (item.name)
79
+ tag.push(item.name);
80
+ if (item.description)
81
+ tag.push(item.description);
82
+ tags.push(tag);
83
+ }
84
+ }
85
+ if (profile.skills) {
86
+ for (const skill of profile.skills) {
87
+ tags.push(['skill', skill]);
88
+ }
89
+ }
90
+ if (profile.experience) {
91
+ for (const exp of profile.experience) {
92
+ tags.push(['experience', exp]);
93
+ }
94
+ }
75
95
  const event = finalizeEvent({
76
96
  kind: 31337,
77
97
  created_at: Math.floor(Date.now() / 1000),
@@ -102,6 +122,42 @@ export async function publishToRelays(event, relays = DEFAULT_RELAYS) {
102
122
  }
103
123
  return published;
104
124
  }
125
+ /**
126
+ * Fetch existing kind 0, merge new fields, and republish.
127
+ * Used to set lud16 (lightning address) during registration.
128
+ */
129
+ export async function updateKind0(sk, updates, relays = DEFAULT_RELAYS) {
130
+ const pool = new SimplePool();
131
+ const pubkey = getPublicKey(sk);
132
+ try {
133
+ // Fetch existing kind 0
134
+ let existing = {};
135
+ try {
136
+ const events = await Promise.race([
137
+ pool.querySync(relays, { kinds: [0], authors: [pubkey] }),
138
+ new Promise((resolve) => setTimeout(() => resolve([]), 5000)),
139
+ ]);
140
+ if (events.length > 0) {
141
+ existing = JSON.parse(events[0].content);
142
+ }
143
+ }
144
+ catch { }
145
+ // Merge updates
146
+ if (updates.lud16)
147
+ existing.lud16 = updates.lud16;
148
+ const event = finalizeEvent({
149
+ kind: 0,
150
+ created_at: Math.floor(Date.now() / 1000),
151
+ tags: [],
152
+ content: JSON.stringify(existing),
153
+ }, sk);
154
+ const published = await publishToRelays(event, relays);
155
+ return published;
156
+ }
157
+ finally {
158
+ pool.close(relays);
159
+ }
160
+ }
105
161
  /**
106
162
  * Build and sign a kind 0 profile metadata event (for NIP-05 verification).
107
163
  * After claiming a NIP-05 name, publish this to relays so Nostr clients
@@ -117,6 +173,7 @@ export function createKind0Event(sk, profile) {
117
173
  ...(profile.about && { about: profile.about }),
118
174
  ...(profile.nip05 && { nip05: profile.nip05 }),
119
175
  ...(profile.picture && { picture: profile.picture }),
176
+ ...(profile.lud16 && { lud16: profile.lud16 }),
120
177
  }),
121
178
  }, sk);
122
179
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "agentdex-cli",
3
- "version": "0.2.2",
3
+ "version": "0.2.5",
4
4
  "description": "CLI and SDK for the agentdex AI agent directory",
5
5
  "type": "module",
6
6
  "bin": {
package/src/cli.ts CHANGED
@@ -7,7 +7,7 @@ import inquirer from 'inquirer';
7
7
  import qrcode from 'qrcode-terminal';
8
8
  import { readFileSync } from 'fs';
9
9
  import { AgentdexClient } from './client.js';
10
- import { parseSecretKey, getNpub, getPubkeyHex, createProfileEvent, createKind0Event, publishToRelays, createNote } from './nostr.js';
10
+ import { parseSecretKey, getNpub, getPubkeyHex, createProfileEvent, createKind0Event, publishToRelays, createNote, updateKind0 } from './nostr.js';
11
11
  import { payInvoice } from './nwc.js';
12
12
 
13
13
  const program = new Command();
@@ -47,8 +47,11 @@ program
47
47
  .option('--framework <fw>', 'Framework (e.g., langchain, openclaw)')
48
48
  .option('--model <model>', 'Model (e.g., claude-3.5-sonnet)')
49
49
  .option('--website <url>', 'Website URL')
50
- .option('--lightning <addr>', 'Lightning address')
50
+ .option('--lightning <addr>', 'Lightning address (sets lud16 in kind 0 profile)')
51
51
  .option('--owner-x <handle>', 'Owner X/Twitter handle (e.g., @username)')
52
+ .option('--portfolio <entry>', 'Portfolio URL (format: "url,name,description") — repeatable', (val: string, acc: string[]) => [...acc, val], [])
53
+ .option('--skill <skill>', 'Skill tag (repeatable)', (val: string, acc: string[]) => [...acc, val], [])
54
+ .option('--experience <exp>', 'Experience tag (repeatable)', (val: string, acc: string[]) => [...acc, val], [])
52
55
  .option('--nwc <uri>', 'Nostr Wallet Connect URI for auto-pay')
53
56
  .option('--api-key <key>', 'Agentdex API key')
54
57
  .option('--relay <url>', 'Additional relay (repeatable)', (val: string, acc: string[]) => [...acc, val], [])
@@ -80,6 +83,12 @@ program
80
83
 
81
84
  const spinner = ora('Signing event...').start();
82
85
 
86
+ // Parse portfolio entries ("url,name,description")
87
+ const portfolio = (options.portfolio || []).map((entry: string) => {
88
+ const parts = entry.split(',').map((s: string) => s.trim());
89
+ return { url: parts[0], name: parts[1], description: parts[2] };
90
+ });
91
+
83
92
  const event = createProfileEvent(sk, {
84
93
  name,
85
94
  description,
@@ -90,6 +99,9 @@ program
90
99
  lightning: options.lightning,
91
100
  ownerX: options.ownerX,
92
101
  status: 'active',
102
+ portfolio: portfolio.length > 0 ? portfolio : undefined,
103
+ skills: options.skill?.length > 0 ? options.skill : undefined,
104
+ experience: options.experience?.length > 0 ? options.experience : undefined,
93
105
  });
94
106
 
95
107
  spinner.text = 'Registering on agentdex...';
@@ -151,6 +163,13 @@ program
151
163
  console.log(chalk.gray(` Published to: ${published.join(', ')}`));
152
164
  console.log('');
153
165
  console.log(chalk.gray(` Run ${chalk.white('agentdex claim <name>')} to get ${chalk.hex('#D4A574')('<name>@agentdex.id')}`));
166
+ // Update kind 0 with lightning address if provided
167
+ if (options.lightning) {
168
+ try {
169
+ await updateKind0(sk, { lud16: options.lightning }, relays);
170
+ console.log(chalk.gray(` ⚡ Lightning address set in kind 0: ${options.lightning}`));
171
+ } catch {}
172
+ }
154
173
  }
155
174
  return;
156
175
  }
@@ -179,6 +198,13 @@ program
179
198
  console.log('');
180
199
  console.log(chalk.gray(` Run ${chalk.white('agentdex claim <name>')} to get ${chalk.hex('#D4A574')('<name>@agentdex.id')}`));
181
200
  console.log('');
201
+ // Update kind 0 with lightning address if provided
202
+ if (options.lightning) {
203
+ try {
204
+ await updateKind0(sk, { lud16: options.lightning }, relays);
205
+ console.log(chalk.gray(` ⚡ Lightning address set in kind 0: ${options.lightning}`));
206
+ } catch {}
207
+ }
182
208
  console.log(chalk.gray(' Next: Claim a NIP-05 name to get verified (first 100 free, then 5000 sats).'));
183
209
  }
184
210
  } catch (err) {
@@ -205,6 +231,7 @@ program
205
231
  .option('--key-file <path>', 'Path to JSON key file')
206
232
  .option('--nwc <uri>', 'Nostr Wallet Connect URI for auto-pay')
207
233
  .option('--api-key <key>', 'Agentdex API key')
234
+ .option('--lightning <addr>', 'Lightning address (lud16) to set in kind 0 profile')
208
235
  .option('--skip-kind0', 'Skip publishing kind 0 profile to relays')
209
236
  .option('--relay <url>', 'Additional relay', (val: string, acc: string[]) => [...acc, val], [])
210
237
  .option('--json', 'Output JSON')
@@ -233,7 +260,10 @@ program
233
260
  try {
234
261
  const kind0 = createKind0Event(sk, {
235
262
  name: claim.agent?.name || name,
263
+ about: claim.agent?.description || undefined,
264
+ picture: claim.agent?.avatarUrl || undefined,
236
265
  nip05: `${name}@agentdex.id`,
266
+ lud16: options.lightning || undefined,
237
267
  });
238
268
  const relays = ['wss://nos.lol', 'wss://relay.damus.io', ...(options.relay || [])];
239
269
  const published = await publishToRelays(kind0, relays);
package/src/client.ts CHANGED
@@ -38,7 +38,7 @@ export interface ClaimResult {
38
38
  // Free/successful claim
39
39
  claimed?: boolean;
40
40
  nip05?: string;
41
- agent?: { id: string; name: string; nip05Name: string; tier: string };
41
+ agent?: { id: string; name: string; description?: string; avatarUrl?: string; nip05Name: string; tier: string };
42
42
  next_steps?: Record<string, unknown>;
43
43
  // Paid claim (402)
44
44
  status?: string;
package/src/nostr.ts CHANGED
@@ -8,6 +8,12 @@ import { SimplePool } from 'nostr-tools/pool';
8
8
 
9
9
  const DEFAULT_RELAYS = ['wss://nos.lol', 'wss://relay.damus.io'];
10
10
 
11
+ export interface PortfolioItem {
12
+ url: string;
13
+ name?: string;
14
+ description?: string;
15
+ }
16
+
11
17
  export interface AgentProfile {
12
18
  name: string;
13
19
  description?: string;
@@ -23,6 +29,9 @@ export interface AgentProfile {
23
29
  messagingPolicy?: string;
24
30
  messagingMinTrust?: number;
25
31
  messagingFee?: number;
32
+ portfolio?: PortfolioItem[];
33
+ skills?: string[];
34
+ experience?: string[];
26
35
  }
27
36
 
28
37
  /**
@@ -76,13 +85,32 @@ export function createProfileEvent(sk: Uint8Array, profile: AgentProfile) {
76
85
  if (profile.model) tags.push(['model', profile.model]);
77
86
  if (profile.website) tags.push(['website', profile.website]);
78
87
  if (profile.avatar) tags.push(['avatar', profile.avatar]);
79
- if (profile.lightning) tags.push(['lightning', profile.lightning]);
88
+ // Lightning address belongs in kind 0 (lud16), not kind 31337
89
+ // Use --lightning flag to set lud16 in kind 0 during claim
80
90
  if (profile.human) tags.push(['human', profile.human]);
81
91
  if (profile.ownerX) tags.push(['owner_x', profile.ownerX]);
82
92
  if (profile.status) tags.push(['status', profile.status || 'active']);
83
93
  if (profile.messagingPolicy) tags.push(['messaging_policy', profile.messagingPolicy]);
84
94
  if (profile.messagingMinTrust) tags.push(['messaging_min_trust', String(profile.messagingMinTrust)]);
85
95
  if (profile.messagingFee) tags.push(['messaging_fee', String(profile.messagingFee)]);
96
+ if (profile.portfolio) {
97
+ for (const item of profile.portfolio) {
98
+ const tag = ['portfolio', item.url];
99
+ if (item.name) tag.push(item.name);
100
+ if (item.description) tag.push(item.description);
101
+ tags.push(tag);
102
+ }
103
+ }
104
+ if (profile.skills) {
105
+ for (const skill of profile.skills) {
106
+ tags.push(['skill', skill]);
107
+ }
108
+ }
109
+ if (profile.experience) {
110
+ for (const exp of profile.experience) {
111
+ tags.push(['experience', exp]);
112
+ }
113
+ }
86
114
 
87
115
  const event = finalizeEvent({
88
116
  kind: 31337,
@@ -121,12 +149,50 @@ export async function publishToRelays(event: object, relays: string[] = DEFAULT_
121
149
  return published;
122
150
  }
123
151
 
152
+ /**
153
+ * Fetch existing kind 0, merge new fields, and republish.
154
+ * Used to set lud16 (lightning address) during registration.
155
+ */
156
+ export async function updateKind0(sk: Uint8Array, updates: { lud16?: string }, relays: string[] = DEFAULT_RELAYS): Promise<string[]> {
157
+ const pool = new SimplePool();
158
+ const pubkey = getPublicKey(sk);
159
+
160
+ try {
161
+ // Fetch existing kind 0
162
+ let existing: Record<string, unknown> = {};
163
+ try {
164
+ const events = await Promise.race([
165
+ pool.querySync(relays, { kinds: [0], authors: [pubkey] }),
166
+ new Promise<any[]>((resolve) => setTimeout(() => resolve([]), 5000)),
167
+ ]);
168
+ if (events.length > 0) {
169
+ existing = JSON.parse(events[0].content);
170
+ }
171
+ } catch {}
172
+
173
+ // Merge updates
174
+ if (updates.lud16) existing.lud16 = updates.lud16;
175
+
176
+ const event = finalizeEvent({
177
+ kind: 0,
178
+ created_at: Math.floor(Date.now() / 1000),
179
+ tags: [],
180
+ content: JSON.stringify(existing),
181
+ }, sk);
182
+
183
+ const published = await publishToRelays(event, relays);
184
+ return published;
185
+ } finally {
186
+ pool.close(relays);
187
+ }
188
+ }
189
+
124
190
  /**
125
191
  * Build and sign a kind 0 profile metadata event (for NIP-05 verification).
126
192
  * After claiming a NIP-05 name, publish this to relays so Nostr clients
127
193
  * (njump, Damus, Primal) can verify the identity.
128
194
  */
129
- export function createKind0Event(sk: Uint8Array, profile: { name: string; about?: string; nip05?: string; picture?: string }) {
195
+ export function createKind0Event(sk: Uint8Array, profile: { name: string; about?: string; nip05?: string; picture?: string; lud16?: string }) {
130
196
  return finalizeEvent({
131
197
  kind: 0,
132
198
  created_at: Math.floor(Date.now() / 1000),
@@ -136,6 +202,7 @@ export function createKind0Event(sk: Uint8Array, profile: { name: string; about?
136
202
  ...(profile.about && { about: profile.about }),
137
203
  ...(profile.nip05 && { nip05: profile.nip05 }),
138
204
  ...(profile.picture && { picture: profile.picture }),
205
+ ...(profile.lud16 && { lud16: profile.lud16 }),
139
206
  }),
140
207
  }, sk);
141
208
  }