agentdex-cli 0.3.2 → 0.4.0

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
@@ -5,14 +5,20 @@ import ora from 'ora';
5
5
  import inquirer from 'inquirer';
6
6
  import qrcode from 'qrcode-terminal';
7
7
  import { readFileSync } from 'fs';
8
+ import { fileURLToPath } from 'url';
9
+ import { dirname, join } from 'path';
10
+ import { nip19 } from 'nostr-tools';
8
11
  import { AgentdexClient } from './client.js';
9
12
  import { parseSecretKey, getNpub, getPubkeyHex, createProfileEvent, createKind0Event, publishToRelays, createNote, generateAndSaveKeypair } from './nostr.js';
10
13
  import { payInvoice } from './nwc.js';
14
+ const __filename = fileURLToPath(import.meta.url);
15
+ const __dirname = dirname(__filename);
16
+ const pkg = JSON.parse(readFileSync(join(__dirname, '..', 'package.json'), 'utf-8'));
11
17
  const program = new Command();
12
18
  program
13
19
  .name('agentdex')
14
20
  .description('CLI for the agentdex AI agent directory')
15
- .version('0.2.0');
21
+ .version(pkg.version);
16
22
  /**
17
23
  * Resolve secret key from flags, env, or key file
18
24
  */
@@ -60,6 +66,8 @@ program
60
66
  .option('--avatar <url>', 'Avatar image URL (sets picture in kind 0 profile)')
61
67
  .option('--lightning <addr>', 'Lightning address (sets lud16 in kind 0 profile)')
62
68
  .option('--owner-x <handle>', 'Owner X/Twitter handle (e.g., @username)')
69
+ .option('--human <npub-or-hex>', 'Owner/operator Nostr pubkey (npub or hex) — enables bidirectional verification')
70
+ .option('--bot', 'Add ["bot"] tag to kind 0 profile (declares this pubkey as automated)')
63
71
  .option('--portfolio <entry>', 'Portfolio URL (format: "url,name,description") — repeatable', (val, acc) => [...acc, val], [])
64
72
  .option('--skill <skill>', 'Skill tag (repeatable)', (val, acc) => [...acc, val], [])
65
73
  .option('--experience <exp>', 'Experience tag (repeatable)', (val, acc) => [...acc, val], [])
@@ -95,6 +103,25 @@ program
95
103
  const parts = entry.split(',').map((s) => s.trim());
96
104
  return { url: parts[0], name: parts[1], description: parts[2] };
97
105
  });
106
+ // Resolve owner pubkey hex from --human flag (npub or hex)
107
+ let humanNpub = options.human;
108
+ let ownerPubkeyHex;
109
+ if (humanNpub) {
110
+ if (humanNpub.startsWith('npub')) {
111
+ try {
112
+ const decoded = nip19.decode(humanNpub);
113
+ ownerPubkeyHex = decoded.data;
114
+ }
115
+ catch {
116
+ console.error(chalk.red('Invalid --human npub'));
117
+ process.exit(1);
118
+ }
119
+ }
120
+ else {
121
+ ownerPubkeyHex = humanNpub;
122
+ humanNpub = nip19.npubEncode(humanNpub);
123
+ }
124
+ }
98
125
  const event = createProfileEvent(sk, {
99
126
  name,
100
127
  description,
@@ -103,6 +130,7 @@ program
103
130
  model: options.model,
104
131
  website: options.website,
105
132
  lightning: options.lightning,
133
+ human: humanNpub,
106
134
  ownerX: options.ownerX,
107
135
  status: 'active',
108
136
  portfolio: portfolio.length > 0 ? portfolio : undefined,
@@ -171,6 +199,8 @@ program
171
199
  about: description || undefined,
172
200
  picture: options.avatar || undefined,
173
201
  lud16: options.lightning || undefined,
202
+ ownerPubkeyHex,
203
+ bot: !!options.bot,
174
204
  });
175
205
  await publishToRelays(kind0, relays);
176
206
  k0Spinner.succeed('Kind 0 published — visible on all Nostr clients');
@@ -210,7 +240,7 @@ program
210
240
  console.log(chalk.gray(` Run ${chalk.white('agentdex claim <name>')} to get ${chalk.hex('#D4A574')('<name>@agentdex.id')}`));
211
241
  console.log('');
212
242
  // Publish kind 0 profile (name, about, avatar, website, lud16)
213
- // Kind 0 is canonical for basic profile; kind 31337 is agent-specific metadata
243
+ // Kind 0 is canonical for basic profile; kind 31339 is agent-specific metadata
214
244
  const k0Spinner = ora('Publishing kind 0 profile to Nostr relays...').start();
215
245
  try {
216
246
  const kind0 = createKind0Event(sk, {
@@ -218,6 +248,8 @@ program
218
248
  about: description || undefined,
219
249
  picture: options.avatar || undefined,
220
250
  lud16: options.lightning || undefined,
251
+ ownerPubkeyHex,
252
+ bot: !!options.bot,
221
253
  });
222
254
  await publishToRelays(kind0, relays);
223
255
  k0Spinner.succeed('Kind 0 published — visible on all Nostr clients');
@@ -262,7 +294,7 @@ program
262
294
  const sk = resolveKey(options);
263
295
  const client = new AgentdexClient({ apiKey: options.apiKey });
264
296
  const spinner = ora(`Claiming ${name}@agentdex.id...`).start();
265
- // Sign a kind 31337 event for claim authentication
297
+ // Sign a kind 31339 event for claim authentication
266
298
  const event = createProfileEvent(sk, {
267
299
  name,
268
300
  status: 'active',
package/dist/nostr.d.ts CHANGED
@@ -47,7 +47,7 @@ export declare function getNpub(sk: Uint8Array): string;
47
47
  */
48
48
  export declare function getPubkeyHex(sk: Uint8Array): string;
49
49
  /**
50
- * Build and sign a kind 31337 agent profile event
50
+ * Build and sign a kind 31339 agent profile event
51
51
  */
52
52
  export declare function createProfileEvent(sk: Uint8Array, profile: AgentProfile): import("nostr-tools").VerifiedEvent;
53
53
  /**
@@ -72,6 +72,8 @@ export declare function createKind0Event(sk: Uint8Array, profile: {
72
72
  nip05?: string;
73
73
  picture?: string;
74
74
  lud16?: string;
75
+ ownerPubkeyHex?: string;
76
+ bot?: boolean;
75
77
  }): import("nostr-tools").VerifiedEvent;
76
78
  /**
77
79
  * Create and sign a kind 1 note tagged #agentdex
package/dist/nostr.js CHANGED
@@ -55,13 +55,13 @@ export function getPubkeyHex(sk) {
55
55
  return getPublicKey(sk);
56
56
  }
57
57
  /**
58
- * Build and sign a kind 31337 agent profile event
58
+ * Build and sign a kind 31339 agent profile event
59
59
  */
60
60
  export function createProfileEvent(sk, profile) {
61
61
  const tags = [
62
62
  ['d', 'agentdex-profile'],
63
63
  ];
64
- // name is optional in kind 31337 (canonical source is kind 0)
64
+ // name is optional in kind 31339 (canonical source is kind 0)
65
65
  // included for backward compatibility and standalone profiles
66
66
  if (profile.name)
67
67
  tags.push(['name', profile.name]);
@@ -80,7 +80,7 @@ export function createProfileEvent(sk, profile) {
80
80
  tags.push(['website', profile.website]);
81
81
  if (profile.avatar)
82
82
  tags.push(['avatar', profile.avatar]);
83
- // Lightning address belongs in kind 0 (lud16), not kind 31337
83
+ // Lightning address belongs in kind 0 (lud16), not kind 31339
84
84
  // Use --lightning flag to set lud16 in kind 0 during claim
85
85
  if (profile.human)
86
86
  tags.push(['human', profile.human]);
@@ -115,7 +115,7 @@ export function createProfileEvent(sk, profile) {
115
115
  }
116
116
  }
117
117
  const event = finalizeEvent({
118
- kind: 31337,
118
+ kind: 31339,
119
119
  created_at: Math.floor(Date.now() / 1000),
120
120
  tags,
121
121
  content: '',
@@ -189,10 +189,16 @@ export async function updateKind0(sk, updates, relays = DEFAULT_RELAYS) {
189
189
  * (njump, Damus, Primal) can verify the identity.
190
190
  */
191
191
  export function createKind0Event(sk, profile) {
192
+ const tags = [];
193
+ if (profile.bot)
194
+ tags.push(["bot"]);
195
+ if (profile.ownerPubkeyHex) {
196
+ tags.push(["p", profile.ownerPubkeyHex, "", "owner"]);
197
+ }
192
198
  return finalizeEvent({
193
199
  kind: 0,
194
200
  created_at: Math.floor(Date.now() / 1000),
195
- tags: [],
201
+ tags,
196
202
  content: JSON.stringify({
197
203
  name: profile.name,
198
204
  ...(profile.about && { about: profile.about }),
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "agentdex-cli",
3
- "version": "0.3.2",
3
+ "version": "0.4.0",
4
4
  "description": "CLI and SDK for the agentdex AI agent directory",
5
5
  "type": "module",
6
6
  "bin": {
package/src/cli.ts CHANGED
@@ -6,16 +6,23 @@ import ora from 'ora';
6
6
  import inquirer from 'inquirer';
7
7
  import qrcode from 'qrcode-terminal';
8
8
  import { readFileSync } from 'fs';
9
+ import { fileURLToPath } from 'url';
10
+ import { dirname, join } from 'path';
11
+ import { nip19 } from 'nostr-tools';
9
12
  import { AgentdexClient } from './client.js';
10
13
  import { parseSecretKey, getNpub, getPubkeyHex, createProfileEvent, createKind0Event, publishToRelays, createNote, updateKind0, generateAndSaveKeypair } from './nostr.js';
11
14
  import { payInvoice } from './nwc.js';
12
15
 
16
+ const __filename = fileURLToPath(import.meta.url);
17
+ const __dirname = dirname(__filename);
18
+ const pkg = JSON.parse(readFileSync(join(__dirname, '..', 'package.json'), 'utf-8'));
19
+
13
20
  const program = new Command();
14
21
 
15
22
  program
16
23
  .name('agentdex')
17
24
  .description('CLI for the agentdex AI agent directory')
18
- .version('0.2.0');
25
+ .version(pkg.version);
19
26
 
20
27
  /**
21
28
  * Resolve secret key from flags, env, or key file
@@ -67,6 +74,8 @@ program
67
74
  .option('--avatar <url>', 'Avatar image URL (sets picture in kind 0 profile)')
68
75
  .option('--lightning <addr>', 'Lightning address (sets lud16 in kind 0 profile)')
69
76
  .option('--owner-x <handle>', 'Owner X/Twitter handle (e.g., @username)')
77
+ .option('--human <npub-or-hex>', 'Owner/operator Nostr pubkey (npub or hex) — enables bidirectional verification')
78
+ .option('--bot', 'Add ["bot"] tag to kind 0 profile (declares this pubkey as automated)')
70
79
  .option('--portfolio <entry>', 'Portfolio URL (format: "url,name,description") — repeatable', (val: string, acc: string[]) => [...acc, val], [])
71
80
  .option('--skill <skill>', 'Skill tag (repeatable)', (val: string, acc: string[]) => [...acc, val], [])
72
81
  .option('--experience <exp>', 'Experience tag (repeatable)', (val: string, acc: string[]) => [...acc, val], [])
@@ -107,6 +116,24 @@ program
107
116
  return { url: parts[0], name: parts[1], description: parts[2] };
108
117
  });
109
118
 
119
+ // Resolve owner pubkey hex from --human flag (npub or hex)
120
+ let humanNpub = options.human;
121
+ let ownerPubkeyHex: string | undefined;
122
+ if (humanNpub) {
123
+ if (humanNpub.startsWith('npub')) {
124
+ try {
125
+ const decoded = nip19.decode(humanNpub);
126
+ ownerPubkeyHex = decoded.data as unknown as string;
127
+ } catch {
128
+ console.error(chalk.red('Invalid --human npub'));
129
+ process.exit(1);
130
+ }
131
+ } else {
132
+ ownerPubkeyHex = humanNpub;
133
+ humanNpub = nip19.npubEncode(humanNpub);
134
+ }
135
+ }
136
+
110
137
  const event = createProfileEvent(sk, {
111
138
  name,
112
139
  description,
@@ -115,6 +142,7 @@ program
115
142
  model: options.model,
116
143
  website: options.website,
117
144
  lightning: options.lightning,
145
+ human: humanNpub,
118
146
  ownerX: options.ownerX,
119
147
  status: 'active',
120
148
  portfolio: portfolio.length > 0 ? portfolio : undefined,
@@ -190,6 +218,8 @@ program
190
218
  about: description || undefined,
191
219
  picture: options.avatar || undefined,
192
220
  lud16: options.lightning || undefined,
221
+ ownerPubkeyHex,
222
+ bot: !!options.bot,
193
223
  });
194
224
  await publishToRelays(kind0, relays);
195
225
  k0Spinner.succeed('Kind 0 published — visible on all Nostr clients');
@@ -231,7 +261,7 @@ program
231
261
  console.log(chalk.gray(` Run ${chalk.white('agentdex claim <name>')} to get ${chalk.hex('#D4A574')('<name>@agentdex.id')}`));
232
262
  console.log('');
233
263
  // Publish kind 0 profile (name, about, avatar, website, lud16)
234
- // Kind 0 is canonical for basic profile; kind 31337 is agent-specific metadata
264
+ // Kind 0 is canonical for basic profile; kind 31339 is agent-specific metadata
235
265
  const k0Spinner = ora('Publishing kind 0 profile to Nostr relays...').start();
236
266
  try {
237
267
  const kind0 = createKind0Event(sk, {
@@ -239,6 +269,8 @@ program
239
269
  about: description || undefined,
240
270
  picture: options.avatar || undefined,
241
271
  lud16: options.lightning || undefined,
272
+ ownerPubkeyHex,
273
+ bot: !!options.bot,
242
274
  });
243
275
  await publishToRelays(kind0, relays);
244
276
  k0Spinner.succeed('Kind 0 published — visible on all Nostr clients');
@@ -284,7 +316,7 @@ program
284
316
 
285
317
  const spinner = ora(`Claiming ${name}@agentdex.id...`).start();
286
318
 
287
- // Sign a kind 31337 event for claim authentication
319
+ // Sign a kind 31339 event for claim authentication
288
320
  const event = createProfileEvent(sk, {
289
321
  name,
290
322
  status: 'active',
package/src/nostr.ts CHANGED
@@ -89,14 +89,14 @@ export function getPubkeyHex(sk: Uint8Array): string {
89
89
  }
90
90
 
91
91
  /**
92
- * Build and sign a kind 31337 agent profile event
92
+ * Build and sign a kind 31339 agent profile event
93
93
  */
94
94
  export function createProfileEvent(sk: Uint8Array, profile: AgentProfile) {
95
95
  const tags: string[][] = [
96
96
  ['d', 'agentdex-profile'],
97
97
  ];
98
98
 
99
- // name is optional in kind 31337 (canonical source is kind 0)
99
+ // name is optional in kind 31339 (canonical source is kind 0)
100
100
  // included for backward compatibility and standalone profiles
101
101
  if (profile.name) tags.push(['name', profile.name]);
102
102
  if (profile.description) tags.push(['description', profile.description]);
@@ -109,7 +109,7 @@ export function createProfileEvent(sk: Uint8Array, profile: AgentProfile) {
109
109
  if (profile.model) tags.push(['model', profile.model]);
110
110
  if (profile.website) tags.push(['website', profile.website]);
111
111
  if (profile.avatar) tags.push(['avatar', profile.avatar]);
112
- // Lightning address belongs in kind 0 (lud16), not kind 31337
112
+ // Lightning address belongs in kind 0 (lud16), not kind 31339
113
113
  // Use --lightning flag to set lud16 in kind 0 during claim
114
114
  if (profile.human) tags.push(['human', profile.human]);
115
115
  if (profile.ownerX) tags.push(['owner_x', profile.ownerX]);
@@ -137,7 +137,7 @@ export function createProfileEvent(sk: Uint8Array, profile: AgentProfile) {
137
137
  }
138
138
 
139
139
  const event = finalizeEvent({
140
- kind: 31337,
140
+ kind: 31339,
141
141
  created_at: Math.floor(Date.now() / 1000),
142
142
  tags,
143
143
  content: '',
@@ -219,11 +219,16 @@ export async function updateKind0(sk: Uint8Array, updates: { lud16?: string }, r
219
219
  * After claiming a NIP-05 name, publish this to relays so Nostr clients
220
220
  * (njump, Damus, Primal) can verify the identity.
221
221
  */
222
- export function createKind0Event(sk: Uint8Array, profile: { name: string; about?: string; nip05?: string; picture?: string; lud16?: string }) {
222
+ export function createKind0Event(sk: Uint8Array, profile: { name: string; about?: string; nip05?: string; picture?: string; lud16?: string; ownerPubkeyHex?: string; bot?: boolean }) {
223
+ const tags: string[][] = [];
224
+ if (profile.bot) tags.push(["bot"]);
225
+ if (profile.ownerPubkeyHex) {
226
+ tags.push(["p", profile.ownerPubkeyHex, "", "owner"]);
227
+ }
223
228
  return finalizeEvent({
224
229
  kind: 0,
225
230
  created_at: Math.floor(Date.now() / 1000),
226
- tags: [],
231
+ tags,
227
232
  content: JSON.stringify({
228
233
  name: profile.name,
229
234
  ...(profile.about && { about: profile.about }),