agentdex-cli 0.3.3 → 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 +29 -2
- package/dist/nostr.d.ts +3 -1
- package/dist/nostr.js +11 -5
- package/package.json +1 -1
- package/src/cli.ts +28 -2
- package/src/nostr.ts +11 -6
package/dist/cli.js
CHANGED
|
@@ -7,6 +7,7 @@ import qrcode from 'qrcode-terminal';
|
|
|
7
7
|
import { readFileSync } from 'fs';
|
|
8
8
|
import { fileURLToPath } from 'url';
|
|
9
9
|
import { dirname, join } from 'path';
|
|
10
|
+
import { nip19 } from 'nostr-tools';
|
|
10
11
|
import { AgentdexClient } from './client.js';
|
|
11
12
|
import { parseSecretKey, getNpub, getPubkeyHex, createProfileEvent, createKind0Event, publishToRelays, createNote, generateAndSaveKeypair } from './nostr.js';
|
|
12
13
|
import { payInvoice } from './nwc.js';
|
|
@@ -65,6 +66,8 @@ program
|
|
|
65
66
|
.option('--avatar <url>', 'Avatar image URL (sets picture in kind 0 profile)')
|
|
66
67
|
.option('--lightning <addr>', 'Lightning address (sets lud16 in kind 0 profile)')
|
|
67
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)')
|
|
68
71
|
.option('--portfolio <entry>', 'Portfolio URL (format: "url,name,description") — repeatable', (val, acc) => [...acc, val], [])
|
|
69
72
|
.option('--skill <skill>', 'Skill tag (repeatable)', (val, acc) => [...acc, val], [])
|
|
70
73
|
.option('--experience <exp>', 'Experience tag (repeatable)', (val, acc) => [...acc, val], [])
|
|
@@ -100,6 +103,25 @@ program
|
|
|
100
103
|
const parts = entry.split(',').map((s) => s.trim());
|
|
101
104
|
return { url: parts[0], name: parts[1], description: parts[2] };
|
|
102
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
|
+
}
|
|
103
125
|
const event = createProfileEvent(sk, {
|
|
104
126
|
name,
|
|
105
127
|
description,
|
|
@@ -108,6 +130,7 @@ program
|
|
|
108
130
|
model: options.model,
|
|
109
131
|
website: options.website,
|
|
110
132
|
lightning: options.lightning,
|
|
133
|
+
human: humanNpub,
|
|
111
134
|
ownerX: options.ownerX,
|
|
112
135
|
status: 'active',
|
|
113
136
|
portfolio: portfolio.length > 0 ? portfolio : undefined,
|
|
@@ -176,6 +199,8 @@ program
|
|
|
176
199
|
about: description || undefined,
|
|
177
200
|
picture: options.avatar || undefined,
|
|
178
201
|
lud16: options.lightning || undefined,
|
|
202
|
+
ownerPubkeyHex,
|
|
203
|
+
bot: !!options.bot,
|
|
179
204
|
});
|
|
180
205
|
await publishToRelays(kind0, relays);
|
|
181
206
|
k0Spinner.succeed('Kind 0 published — visible on all Nostr clients');
|
|
@@ -215,7 +240,7 @@ program
|
|
|
215
240
|
console.log(chalk.gray(` Run ${chalk.white('agentdex claim <name>')} to get ${chalk.hex('#D4A574')('<name>@agentdex.id')}`));
|
|
216
241
|
console.log('');
|
|
217
242
|
// Publish kind 0 profile (name, about, avatar, website, lud16)
|
|
218
|
-
// Kind 0 is canonical for basic profile; kind
|
|
243
|
+
// Kind 0 is canonical for basic profile; kind 31339 is agent-specific metadata
|
|
219
244
|
const k0Spinner = ora('Publishing kind 0 profile to Nostr relays...').start();
|
|
220
245
|
try {
|
|
221
246
|
const kind0 = createKind0Event(sk, {
|
|
@@ -223,6 +248,8 @@ program
|
|
|
223
248
|
about: description || undefined,
|
|
224
249
|
picture: options.avatar || undefined,
|
|
225
250
|
lud16: options.lightning || undefined,
|
|
251
|
+
ownerPubkeyHex,
|
|
252
|
+
bot: !!options.bot,
|
|
226
253
|
});
|
|
227
254
|
await publishToRelays(kind0, relays);
|
|
228
255
|
k0Spinner.succeed('Kind 0 published — visible on all Nostr clients');
|
|
@@ -267,7 +294,7 @@ program
|
|
|
267
294
|
const sk = resolveKey(options);
|
|
268
295
|
const client = new AgentdexClient({ apiKey: options.apiKey });
|
|
269
296
|
const spinner = ora(`Claiming ${name}@agentdex.id...`).start();
|
|
270
|
-
// Sign a kind
|
|
297
|
+
// Sign a kind 31339 event for claim authentication
|
|
271
298
|
const event = createProfileEvent(sk, {
|
|
272
299
|
name,
|
|
273
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
|
|
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
|
|
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
|
|
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
|
|
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:
|
|
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
package/src/cli.ts
CHANGED
|
@@ -8,6 +8,7 @@ import qrcode from 'qrcode-terminal';
|
|
|
8
8
|
import { readFileSync } from 'fs';
|
|
9
9
|
import { fileURLToPath } from 'url';
|
|
10
10
|
import { dirname, join } from 'path';
|
|
11
|
+
import { nip19 } from 'nostr-tools';
|
|
11
12
|
import { AgentdexClient } from './client.js';
|
|
12
13
|
import { parseSecretKey, getNpub, getPubkeyHex, createProfileEvent, createKind0Event, publishToRelays, createNote, updateKind0, generateAndSaveKeypair } from './nostr.js';
|
|
13
14
|
import { payInvoice } from './nwc.js';
|
|
@@ -73,6 +74,8 @@ program
|
|
|
73
74
|
.option('--avatar <url>', 'Avatar image URL (sets picture in kind 0 profile)')
|
|
74
75
|
.option('--lightning <addr>', 'Lightning address (sets lud16 in kind 0 profile)')
|
|
75
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)')
|
|
76
79
|
.option('--portfolio <entry>', 'Portfolio URL (format: "url,name,description") — repeatable', (val: string, acc: string[]) => [...acc, val], [])
|
|
77
80
|
.option('--skill <skill>', 'Skill tag (repeatable)', (val: string, acc: string[]) => [...acc, val], [])
|
|
78
81
|
.option('--experience <exp>', 'Experience tag (repeatable)', (val: string, acc: string[]) => [...acc, val], [])
|
|
@@ -113,6 +116,24 @@ program
|
|
|
113
116
|
return { url: parts[0], name: parts[1], description: parts[2] };
|
|
114
117
|
});
|
|
115
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
|
+
|
|
116
137
|
const event = createProfileEvent(sk, {
|
|
117
138
|
name,
|
|
118
139
|
description,
|
|
@@ -121,6 +142,7 @@ program
|
|
|
121
142
|
model: options.model,
|
|
122
143
|
website: options.website,
|
|
123
144
|
lightning: options.lightning,
|
|
145
|
+
human: humanNpub,
|
|
124
146
|
ownerX: options.ownerX,
|
|
125
147
|
status: 'active',
|
|
126
148
|
portfolio: portfolio.length > 0 ? portfolio : undefined,
|
|
@@ -196,6 +218,8 @@ program
|
|
|
196
218
|
about: description || undefined,
|
|
197
219
|
picture: options.avatar || undefined,
|
|
198
220
|
lud16: options.lightning || undefined,
|
|
221
|
+
ownerPubkeyHex,
|
|
222
|
+
bot: !!options.bot,
|
|
199
223
|
});
|
|
200
224
|
await publishToRelays(kind0, relays);
|
|
201
225
|
k0Spinner.succeed('Kind 0 published — visible on all Nostr clients');
|
|
@@ -237,7 +261,7 @@ program
|
|
|
237
261
|
console.log(chalk.gray(` Run ${chalk.white('agentdex claim <name>')} to get ${chalk.hex('#D4A574')('<name>@agentdex.id')}`));
|
|
238
262
|
console.log('');
|
|
239
263
|
// Publish kind 0 profile (name, about, avatar, website, lud16)
|
|
240
|
-
// Kind 0 is canonical for basic profile; kind
|
|
264
|
+
// Kind 0 is canonical for basic profile; kind 31339 is agent-specific metadata
|
|
241
265
|
const k0Spinner = ora('Publishing kind 0 profile to Nostr relays...').start();
|
|
242
266
|
try {
|
|
243
267
|
const kind0 = createKind0Event(sk, {
|
|
@@ -245,6 +269,8 @@ program
|
|
|
245
269
|
about: description || undefined,
|
|
246
270
|
picture: options.avatar || undefined,
|
|
247
271
|
lud16: options.lightning || undefined,
|
|
272
|
+
ownerPubkeyHex,
|
|
273
|
+
bot: !!options.bot,
|
|
248
274
|
});
|
|
249
275
|
await publishToRelays(kind0, relays);
|
|
250
276
|
k0Spinner.succeed('Kind 0 published — visible on all Nostr clients');
|
|
@@ -290,7 +316,7 @@ program
|
|
|
290
316
|
|
|
291
317
|
const spinner = ora(`Claiming ${name}@agentdex.id...`).start();
|
|
292
318
|
|
|
293
|
-
// Sign a kind
|
|
319
|
+
// Sign a kind 31339 event for claim authentication
|
|
294
320
|
const event = createProfileEvent(sk, {
|
|
295
321
|
name,
|
|
296
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
|
|
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
|
|
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
|
|
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:
|
|
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 }),
|