agentdex-cli 0.1.0 → 0.2.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
@@ -6,12 +6,13 @@ 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, publishToRelays, createNote } from './nostr.js';
9
+ import { parseSecretKey, getNpub, getPubkeyHex, createProfileEvent, createKind0Event, publishToRelays, createNote } from './nostr.js';
10
+ import { payInvoice } from './nwc.js';
10
11
  const program = new Command();
11
12
  program
12
13
  .name('agentdex')
13
14
  .description('CLI for the agentdex AI agent directory')
14
- .version('0.1.0');
15
+ .version('0.2.0');
15
16
  /**
16
17
  * Resolve secret key from flags, env, or key file
17
18
  */
@@ -43,6 +44,7 @@ program
43
44
  .option('--website <url>', 'Website URL')
44
45
  .option('--lightning <addr>', 'Lightning address')
45
46
  .option('--owner-x <handle>', 'Owner X/Twitter handle (e.g., @username)')
47
+ .option('--nwc <uri>', 'Nostr Wallet Connect URI for auto-pay')
46
48
  .option('--api-key <key>', 'Agentdex API key')
47
49
  .option('--relay <url>', 'Additional relay (repeatable)', (val, acc) => [...acc, val], [])
48
50
  .option('--json', 'Output JSON')
@@ -84,6 +86,65 @@ program
84
86
  const client = new AgentdexClient({ apiKey: options.apiKey });
85
87
  try {
86
88
  const result = await client.register(event);
89
+ // Payment required (402)
90
+ if (result.status === 'awaiting_payment' && result.invoice) {
91
+ spinner.stop();
92
+ console.log('');
93
+ console.log(chalk.hex('#D4A574')(` 💰 Registration fee: ${result.amount_sats?.toLocaleString()} sats`));
94
+ console.log('');
95
+ const nwcUri = options.nwc || process.env.NWC_URL;
96
+ if (nwcUri) {
97
+ const paySpinner = ora('Paying invoice via NWC...').start();
98
+ try {
99
+ await payInvoice(nwcUri, result.invoice);
100
+ paySpinner.succeed('Invoice paid!');
101
+ }
102
+ catch (payErr) {
103
+ paySpinner.fail(`NWC payment failed: ${payErr.message}`);
104
+ console.log('');
105
+ console.log(chalk.gray(' Pay manually:'));
106
+ qrcode.generate(result.invoice, { small: true }, (qr) => { console.log(qr); });
107
+ console.log(chalk.gray(` bolt11: ${result.invoice}`));
108
+ console.log('');
109
+ }
110
+ }
111
+ else {
112
+ qrcode.generate(result.invoice, { small: true }, (qr) => { console.log(qr); });
113
+ console.log(chalk.gray(` bolt11: ${result.invoice}`));
114
+ console.log('');
115
+ }
116
+ // Poll for payment
117
+ const pollSpinner = ora('Waiting for payment...').start();
118
+ const startTime = Date.now();
119
+ const timeout = 15 * 60 * 1000;
120
+ while (Date.now() - startTime < timeout) {
121
+ await new Promise((r) => setTimeout(r, 3000));
122
+ const status = await client.registerStatus(result.payment_hash);
123
+ if (status.paid) {
124
+ pollSpinner.succeed('Registered!');
125
+ spinner.text = 'Publishing to Nostr relays...';
126
+ const relays = ['wss://nos.lol', 'wss://relay.damus.io', ...options.relay];
127
+ const published = await publishToRelays(event, relays);
128
+ if (options.json) {
129
+ console.log(JSON.stringify({ ...result, relays: published }, null, 2));
130
+ }
131
+ else {
132
+ console.log('');
133
+ console.log(chalk.hex('#D4A574')(' ✅ Registered on agentdex'));
134
+ console.log(chalk.gray(` npub: ${npub}`));
135
+ console.log(chalk.gray(` Name: ${name}`));
136
+ console.log(chalk.gray(` Published to: ${published.join(', ')}`));
137
+ console.log('');
138
+ console.log(chalk.gray(` Run ${chalk.white('agentdex claim <name>')} to get ${chalk.hex('#D4A574')('<name>@agentdex.id')}`));
139
+ }
140
+ return;
141
+ }
142
+ }
143
+ pollSpinner.fail('Payment timeout (15 min). Invoice expired.');
144
+ process.exit(1);
145
+ return;
146
+ }
147
+ // Free registration — no payment needed
87
148
  spinner.text = 'Publishing to Nostr relays...';
88
149
  const relays = ['wss://nos.lol', 'wss://relay.damus.io', ...options.relay];
89
150
  const published = await publishToRelays(event, relays);
@@ -104,7 +165,13 @@ program
104
165
  }
105
166
  }
106
167
  catch (err) {
107
- spinner.fail(`Registration failed: ${err.message}`);
168
+ const apiErr = err;
169
+ if (apiErr.status === 503) {
170
+ spinner.fail('Registration is currently disabled.');
171
+ }
172
+ else {
173
+ spinner.fail(`Registration failed: ${err.message}`);
174
+ }
108
175
  process.exit(1);
109
176
  }
110
177
  }
@@ -121,6 +188,8 @@ program
121
188
  .option('--key-file <path>', 'Path to JSON key file')
122
189
  .option('--nwc <uri>', 'Nostr Wallet Connect URI for auto-pay')
123
190
  .option('--api-key <key>', 'Agentdex API key')
191
+ .option('--skip-kind0', 'Skip publishing kind 0 profile to relays')
192
+ .option('--relay <url>', 'Additional relay', (val, acc) => [...acc, val], [])
124
193
  .option('--json', 'Output JSON')
125
194
  .action(async (name, options) => {
126
195
  try {
@@ -136,16 +205,32 @@ program
136
205
  // Free/successful claim
137
206
  if (claim.claimed) {
138
207
  spinner.succeed(`${chalk.hex('#D4A574')(`${claim.nip05}`)} is now active!`);
139
- if (claim.next_steps) {
140
- console.log('');
141
- const ns = claim.next_steps;
142
- if (ns.publish_kind0) {
143
- console.log(chalk.gray(` Next: ${ns.publish_kind0.description}`));
144
- if (ns.publish_kind0.relays) {
145
- console.log(chalk.gray(` Relays: ${ns.publish_kind0.relays.join(', ')}`));
146
- }
208
+ // Auto-publish kind 0 to relays so Nostr clients verify the NIP-05
209
+ if (!options.skipKind0) {
210
+ const k0Spinner = ora('Publishing kind 0 profile to Nostr relays...').start();
211
+ try {
212
+ const kind0 = createKind0Event(sk, {
213
+ name: claim.agent?.name || name,
214
+ nip05: `${name}@agentdex.id`,
215
+ });
216
+ const relays = ['wss://nos.lol', 'wss://relay.damus.io', ...(options.relay || [])];
217
+ const published = await publishToRelays(kind0, relays);
218
+ k0Spinner.succeed(`Kind 0 published to ${published.join(', ')}`);
219
+ console.log(chalk.gray(' NIP-05 will appear on njump/Damus/Primal once relays propagate (~30s)'));
220
+ }
221
+ catch {
222
+ k0Spinner.warn('Kind 0 publish failed. Publish manually:');
223
+ console.log(chalk.gray(` kind 0 content: {"name":"...","nip05":"${name}@agentdex.id"}`));
147
224
  }
148
225
  }
226
+ else {
227
+ console.log('');
228
+ console.log(chalk.yellow(' ⚠ Skipped kind 0 publish. For NIP-05 to show on Nostr clients:'));
229
+ console.log(chalk.gray(` Publish kind 0 with: "nip05": "${name}@agentdex.id"`));
230
+ }
231
+ if (options.json) {
232
+ console.log(JSON.stringify(claim, null, 2));
233
+ }
149
234
  return;
150
235
  }
151
236
  // Payment required (402)
@@ -154,14 +239,26 @@ program
154
239
  console.log('');
155
240
  console.log(chalk.hex('#D4A574')(` 💰 Claim ${name}@agentdex.id for ${claim.amount_sats?.toLocaleString()} sats`));
156
241
  console.log('');
157
- qrcode.generate(claim.invoice, { small: true }, (qr) => {
158
- console.log(qr);
159
- });
160
- console.log(chalk.gray(` bolt11: ${claim.invoice}`));
161
- console.log('');
162
- if (options.nwc) {
163
- console.log(chalk.gray(' Auto-paying via NWC...'));
164
- console.log(chalk.yellow(' NWC auto-pay not yet implemented. Pay the invoice manually.'));
242
+ const nwcUri = options.nwc || process.env.NWC_URL;
243
+ if (nwcUri) {
244
+ const paySpinner = ora('Paying invoice via NWC...').start();
245
+ try {
246
+ await payInvoice(nwcUri, claim.invoice);
247
+ paySpinner.succeed('Invoice paid!');
248
+ }
249
+ catch (payErr) {
250
+ paySpinner.fail(`NWC payment failed: ${payErr.message}`);
251
+ console.log('');
252
+ console.log(chalk.gray(' Pay manually:'));
253
+ qrcode.generate(claim.invoice, { small: true }, (qr) => { console.log(qr); });
254
+ console.log(chalk.gray(` bolt11: ${claim.invoice}`));
255
+ console.log('');
256
+ }
257
+ }
258
+ else {
259
+ qrcode.generate(claim.invoice, { small: true }, (qr) => { console.log(qr); });
260
+ console.log(chalk.gray(` bolt11: ${claim.invoice}`));
261
+ console.log('');
165
262
  }
166
263
  // Poll for payment
167
264
  const pollSpinner = ora('Waiting for payment...').start();
@@ -172,6 +269,19 @@ program
172
269
  const status = await client.claimStatus(claim.payment_hash);
173
270
  if (status.paid) {
174
271
  pollSpinner.succeed(`${chalk.hex('#D4A574')(`${name}@agentdex.id`)} is now active!`);
272
+ // Auto-publish kind 0 after payment
273
+ if (!options.skipKind0) {
274
+ const k0Spinner = ora('Publishing kind 0 profile to Nostr relays...').start();
275
+ try {
276
+ const kind0 = createKind0Event(sk, { name, nip05: `${name}@agentdex.id` });
277
+ const relays = ['wss://nos.lol', 'wss://relay.damus.io', ...(options.relay || [])];
278
+ await publishToRelays(kind0, relays);
279
+ k0Spinner.succeed('Kind 0 published — NIP-05 active on all Nostr clients');
280
+ }
281
+ catch {
282
+ k0Spinner.warn('Kind 0 publish failed — publish manually');
283
+ }
284
+ }
175
285
  return;
176
286
  }
177
287
  }
package/dist/client.d.ts CHANGED
@@ -66,10 +66,10 @@ export declare class AgentdexClient {
66
66
  constructor(config?: AgentdexConfig);
67
67
  private fetch;
68
68
  verify(pubkeyOrNpub: string): Promise<VerifyResult>;
69
- register(event: object): Promise<{
70
- agent: object;
71
- registered: boolean;
72
- tier: string;
69
+ register(event: object): Promise<any>;
70
+ registerStatus(paymentHash: string): Promise<{
71
+ paid: boolean;
72
+ agent?: object;
73
73
  }>;
74
74
  claim(name: string, event: object): Promise<ClaimResult>;
75
75
  claimStatus(paymentHash: string): Promise<ClaimStatus>;
package/dist/client.js CHANGED
@@ -28,12 +28,16 @@ export class AgentdexClient {
28
28
  method: 'POST',
29
29
  body: JSON.stringify({ event }),
30
30
  });
31
- if (!res.ok) {
31
+ if (!res.ok && res.status !== 402) {
32
32
  const err = await res.json();
33
33
  throw new Error(err.error || 'Registration failed');
34
34
  }
35
35
  return res.json();
36
36
  }
37
+ async registerStatus(paymentHash) {
38
+ const res = await this.fetch(`/api/v1/agents/register/status?payment_hash=${encodeURIComponent(paymentHash)}`);
39
+ return res.json();
40
+ }
37
41
  async claim(name, event) {
38
42
  const res = await this.fetch('/api/v1/agents/claim', {
39
43
  method: 'POST',
package/dist/index.d.ts CHANGED
@@ -11,5 +11,5 @@
11
11
  */
12
12
  export { AgentdexClient } from './client.js';
13
13
  export type { AgentdexConfig, RegisterOptions, VerifyResult, ClaimResult, ClaimStatus, SearchOptions, } from './client.js';
14
- export { parseSecretKey, getNpub, getPubkeyHex, createProfileEvent, publishToRelays, createNote, } from './nostr.js';
14
+ export { parseSecretKey, getNpub, getPubkeyHex, createProfileEvent, createKind0Event, publishToRelays, createNote, } from './nostr.js';
15
15
  export type { AgentProfile } from './nostr.js';
package/dist/index.js CHANGED
@@ -10,4 +10,4 @@
10
10
  * ```
11
11
  */
12
12
  export { AgentdexClient } from './client.js';
13
- export { parseSecretKey, getNpub, getPubkeyHex, createProfileEvent, publishToRelays, createNote, } from './nostr.js';
13
+ export { parseSecretKey, getNpub, getPubkeyHex, createProfileEvent, createKind0Event, publishToRelays, createNote, } from './nostr.js';
package/dist/nostr.d.ts CHANGED
@@ -37,6 +37,17 @@ export declare function createProfileEvent(sk: Uint8Array, profile: AgentProfile
37
37
  * Publish an event to Nostr relays
38
38
  */
39
39
  export declare function publishToRelays(event: object, relays?: string[]): Promise<string[]>;
40
+ /**
41
+ * Build and sign a kind 0 profile metadata event (for NIP-05 verification).
42
+ * After claiming a NIP-05 name, publish this to relays so Nostr clients
43
+ * (njump, Damus, Primal) can verify the identity.
44
+ */
45
+ export declare function createKind0Event(sk: Uint8Array, profile: {
46
+ name: string;
47
+ about?: string;
48
+ nip05?: string;
49
+ picture?: string;
50
+ }): import("nostr-tools").VerifiedEvent;
40
51
  /**
41
52
  * Create and sign a kind 1 note tagged #agentdex
42
53
  */
package/dist/nostr.js CHANGED
@@ -102,6 +102,24 @@ export async function publishToRelays(event, relays = DEFAULT_RELAYS) {
102
102
  }
103
103
  return published;
104
104
  }
105
+ /**
106
+ * Build and sign a kind 0 profile metadata event (for NIP-05 verification).
107
+ * After claiming a NIP-05 name, publish this to relays so Nostr clients
108
+ * (njump, Damus, Primal) can verify the identity.
109
+ */
110
+ export function createKind0Event(sk, profile) {
111
+ return finalizeEvent({
112
+ kind: 0,
113
+ created_at: Math.floor(Date.now() / 1000),
114
+ tags: [],
115
+ content: JSON.stringify({
116
+ name: profile.name,
117
+ ...(profile.about && { about: profile.about }),
118
+ ...(profile.nip05 && { nip05: profile.nip05 }),
119
+ ...(profile.picture && { picture: profile.picture }),
120
+ }),
121
+ }, sk);
122
+ }
105
123
  /**
106
124
  * Create and sign a kind 1 note tagged #agentdex
107
125
  */
package/dist/nwc.d.ts ADDED
@@ -0,0 +1,11 @@
1
+ /**
2
+ * NWC (Nostr Wallet Connect) payment utility using Alby SDK
3
+ */
4
+ export interface PaymentResult {
5
+ preimage: string;
6
+ paid: boolean;
7
+ }
8
+ /**
9
+ * Pay a bolt11 invoice via NWC
10
+ */
11
+ export declare function payInvoice(nwcUri: string, bolt11: string): Promise<PaymentResult>;
package/dist/nwc.js ADDED
@@ -0,0 +1,17 @@
1
+ /**
2
+ * NWC (Nostr Wallet Connect) payment utility using Alby SDK
3
+ */
4
+ import { NWCClient } from '@getalby/sdk';
5
+ /**
6
+ * Pay a bolt11 invoice via NWC
7
+ */
8
+ export async function payInvoice(nwcUri, bolt11) {
9
+ const client = new NWCClient({ nostrWalletConnectUrl: nwcUri });
10
+ try {
11
+ const response = await client.payInvoice({ invoice: bolt11 });
12
+ return { preimage: response.preimage, paid: true };
13
+ }
14
+ finally {
15
+ client.close();
16
+ }
17
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "agentdex-cli",
3
- "version": "0.1.0",
3
+ "version": "0.2.0",
4
4
  "description": "CLI and SDK for the agentdex AI agent directory",
5
5
  "type": "module",
6
6
  "bin": {
@@ -19,7 +19,14 @@
19
19
  "dev": "tsc --watch",
20
20
  "prepublishOnly": "npm run build"
21
21
  },
22
- "keywords": ["agentdex", "nostr", "ai", "agent", "directory", "nip-05"],
22
+ "keywords": [
23
+ "agentdex",
24
+ "nostr",
25
+ "ai",
26
+ "agent",
27
+ "directory",
28
+ "nip-05"
29
+ ],
23
30
  "author": "Koda <kodabuilds@gmail.com>",
24
31
  "license": "MIT",
25
32
  "repository": {
@@ -27,17 +34,18 @@
27
34
  "url": "https://github.com/Koda-Builds/agentdex-cli"
28
35
  },
29
36
  "dependencies": {
30
- "nostr-tools": "^2.10.4",
31
- "commander": "^12.0.0",
37
+ "@getalby/sdk": "^7.0.0",
32
38
  "chalk": "^5.3.0",
33
- "ora": "^8.0.0",
39
+ "commander": "^12.0.0",
34
40
  "inquirer": "^9.2.0",
41
+ "nostr-tools": "^2.10.4",
42
+ "ora": "^8.0.0",
35
43
  "qrcode-terminal": "^0.12.0"
36
44
  },
37
45
  "devDependencies": {
38
- "typescript": "^5.4.0",
39
- "@types/node": "^22.0.0",
40
46
  "@types/inquirer": "^9.0.0",
41
- "@types/qrcode-terminal": "^0.12.0"
47
+ "@types/node": "^22.0.0",
48
+ "@types/qrcode-terminal": "^0.12.0",
49
+ "typescript": "^5.4.0"
42
50
  }
43
51
  }
package/src/cli.ts CHANGED
@@ -7,14 +7,15 @@ 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, publishToRelays, createNote } from './nostr.js';
10
+ import { parseSecretKey, getNpub, getPubkeyHex, createProfileEvent, createKind0Event, publishToRelays, createNote } from './nostr.js';
11
+ import { payInvoice } from './nwc.js';
11
12
 
12
13
  const program = new Command();
13
14
 
14
15
  program
15
16
  .name('agentdex')
16
17
  .description('CLI for the agentdex AI agent directory')
17
- .version('0.1.0');
18
+ .version('0.2.0');
18
19
 
19
20
  /**
20
21
  * Resolve secret key from flags, env, or key file
@@ -48,6 +49,7 @@ program
48
49
  .option('--website <url>', 'Website URL')
49
50
  .option('--lightning <addr>', 'Lightning address')
50
51
  .option('--owner-x <handle>', 'Owner X/Twitter handle (e.g., @username)')
52
+ .option('--nwc <uri>', 'Nostr Wallet Connect URI for auto-pay')
51
53
  .option('--api-key <key>', 'Agentdex API key')
52
54
  .option('--relay <url>', 'Additional relay (repeatable)', (val: string, acc: string[]) => [...acc, val], [])
53
55
  .option('--json', 'Output JSON')
@@ -96,6 +98,70 @@ program
96
98
  try {
97
99
  const result = await client.register(event);
98
100
 
101
+ // Payment required (402)
102
+ if (result.status === 'awaiting_payment' && result.invoice) {
103
+ spinner.stop();
104
+ console.log('');
105
+ console.log(chalk.hex('#D4A574')(` 💰 Registration fee: ${result.amount_sats?.toLocaleString()} sats`));
106
+ console.log('');
107
+
108
+ const nwcUri = options.nwc || process.env.NWC_URL;
109
+
110
+ if (nwcUri) {
111
+ const paySpinner = ora('Paying invoice via NWC...').start();
112
+ try {
113
+ await payInvoice(nwcUri, result.invoice);
114
+ paySpinner.succeed('Invoice paid!');
115
+ } catch (payErr) {
116
+ paySpinner.fail(`NWC payment failed: ${(payErr as Error).message}`);
117
+ console.log('');
118
+ console.log(chalk.gray(' Pay manually:'));
119
+ qrcode.generate(result.invoice, { small: true }, (qr: string) => { console.log(qr); });
120
+ console.log(chalk.gray(` bolt11: ${result.invoice}`));
121
+ console.log('');
122
+ }
123
+ } else {
124
+ qrcode.generate(result.invoice, { small: true }, (qr: string) => { console.log(qr); });
125
+ console.log(chalk.gray(` bolt11: ${result.invoice}`));
126
+ console.log('');
127
+ }
128
+
129
+ // Poll for payment
130
+ const pollSpinner = ora('Waiting for payment...').start();
131
+ const startTime = Date.now();
132
+ const timeout = 15 * 60 * 1000;
133
+
134
+ while (Date.now() - startTime < timeout) {
135
+ await new Promise((r) => setTimeout(r, 3000));
136
+ const status = await client.registerStatus(result.payment_hash!);
137
+ if (status.paid) {
138
+ pollSpinner.succeed('Registered!');
139
+
140
+ spinner.text = 'Publishing to Nostr relays...';
141
+ const relays = ['wss://nos.lol', 'wss://relay.damus.io', ...options.relay];
142
+ const published = await publishToRelays(event, relays);
143
+
144
+ if (options.json) {
145
+ console.log(JSON.stringify({ ...result, relays: published }, null, 2));
146
+ } else {
147
+ console.log('');
148
+ console.log(chalk.hex('#D4A574')(' ✅ Registered on agentdex'));
149
+ console.log(chalk.gray(` npub: ${npub}`));
150
+ console.log(chalk.gray(` Name: ${name}`));
151
+ console.log(chalk.gray(` Published to: ${published.join(', ')}`));
152
+ console.log('');
153
+ console.log(chalk.gray(` Run ${chalk.white('agentdex claim <name>')} to get ${chalk.hex('#D4A574')('<name>@agentdex.id')}`));
154
+ }
155
+ return;
156
+ }
157
+ }
158
+
159
+ pollSpinner.fail('Payment timeout (15 min). Invoice expired.');
160
+ process.exit(1);
161
+ return;
162
+ }
163
+
164
+ // Free registration — no payment needed
99
165
  spinner.text = 'Publishing to Nostr relays...';
100
166
  const relays = ['wss://nos.lol', 'wss://relay.damus.io', ...options.relay];
101
167
  const published = await publishToRelays(event, relays);
@@ -116,7 +182,12 @@ program
116
182
  console.log(chalk.gray(' Next: Claim a NIP-05 name to get verified (first 100 free, then 5000 sats).'));
117
183
  }
118
184
  } catch (err) {
119
- spinner.fail(`Registration failed: ${(err as Error).message}`);
185
+ const apiErr = err as any;
186
+ if (apiErr.status === 503) {
187
+ spinner.fail('Registration is currently disabled.');
188
+ } else {
189
+ spinner.fail(`Registration failed: ${(err as Error).message}`);
190
+ }
120
191
  process.exit(1);
121
192
  }
122
193
  } catch (err) {
@@ -134,6 +205,8 @@ program
134
205
  .option('--key-file <path>', 'Path to JSON key file')
135
206
  .option('--nwc <uri>', 'Nostr Wallet Connect URI for auto-pay')
136
207
  .option('--api-key <key>', 'Agentdex API key')
208
+ .option('--skip-kind0', 'Skip publishing kind 0 profile to relays')
209
+ .option('--relay <url>', 'Additional relay', (val: string, acc: string[]) => [...acc, val], [])
137
210
  .option('--json', 'Output JSON')
138
211
  .action(async (name: string, options) => {
139
212
  try {
@@ -153,15 +226,31 @@ program
153
226
  // Free/successful claim
154
227
  if (claim.claimed) {
155
228
  spinner.succeed(`${chalk.hex('#D4A574')(`${claim.nip05}`)} is now active!`);
156
- if (claim.next_steps) {
157
- console.log('');
158
- const ns = claim.next_steps as Record<string, { description?: string; relays?: string[] }>;
159
- if (ns.publish_kind0) {
160
- console.log(chalk.gray(` Next: ${ns.publish_kind0.description}`));
161
- if (ns.publish_kind0.relays) {
162
- console.log(chalk.gray(` Relays: ${ns.publish_kind0.relays.join(', ')}`));
163
- }
229
+
230
+ // Auto-publish kind 0 to relays so Nostr clients verify the NIP-05
231
+ if (!options.skipKind0) {
232
+ const k0Spinner = ora('Publishing kind 0 profile to Nostr relays...').start();
233
+ try {
234
+ const kind0 = createKind0Event(sk, {
235
+ name: claim.agent?.name || name,
236
+ nip05: `${name}@agentdex.id`,
237
+ });
238
+ const relays = ['wss://nos.lol', 'wss://relay.damus.io', ...(options.relay || [])];
239
+ const published = await publishToRelays(kind0, relays);
240
+ k0Spinner.succeed(`Kind 0 published to ${published.join(', ')}`);
241
+ console.log(chalk.gray(' NIP-05 will appear on njump/Damus/Primal once relays propagate (~30s)'));
242
+ } catch {
243
+ k0Spinner.warn('Kind 0 publish failed. Publish manually:');
244
+ console.log(chalk.gray(` kind 0 content: {"name":"...","nip05":"${name}@agentdex.id"}`));
164
245
  }
246
+ } else {
247
+ console.log('');
248
+ console.log(chalk.yellow(' ⚠ Skipped kind 0 publish. For NIP-05 to show on Nostr clients:'));
249
+ console.log(chalk.gray(` Publish kind 0 with: "nip05": "${name}@agentdex.id"`));
250
+ }
251
+
252
+ if (options.json) {
253
+ console.log(JSON.stringify(claim, null, 2));
165
254
  }
166
255
  return;
167
256
  }
@@ -173,15 +262,25 @@ program
173
262
  console.log(chalk.hex('#D4A574')(` 💰 Claim ${name}@agentdex.id for ${claim.amount_sats?.toLocaleString()} sats`));
174
263
  console.log('');
175
264
 
176
- qrcode.generate(claim.invoice, { small: true }, (qr: string) => {
177
- console.log(qr);
178
- });
179
- console.log(chalk.gray(` bolt11: ${claim.invoice}`));
180
- console.log('');
181
-
182
- if (options.nwc) {
183
- console.log(chalk.gray(' Auto-paying via NWC...'));
184
- console.log(chalk.yellow(' NWC auto-pay not yet implemented. Pay the invoice manually.'));
265
+ const nwcUri = options.nwc || process.env.NWC_URL;
266
+
267
+ if (nwcUri) {
268
+ const paySpinner = ora('Paying invoice via NWC...').start();
269
+ try {
270
+ await payInvoice(nwcUri, claim.invoice);
271
+ paySpinner.succeed('Invoice paid!');
272
+ } catch (payErr) {
273
+ paySpinner.fail(`NWC payment failed: ${(payErr as Error).message}`);
274
+ console.log('');
275
+ console.log(chalk.gray(' Pay manually:'));
276
+ qrcode.generate(claim.invoice, { small: true }, (qr: string) => { console.log(qr); });
277
+ console.log(chalk.gray(` bolt11: ${claim.invoice}`));
278
+ console.log('');
279
+ }
280
+ } else {
281
+ qrcode.generate(claim.invoice, { small: true }, (qr: string) => { console.log(qr); });
282
+ console.log(chalk.gray(` bolt11: ${claim.invoice}`));
283
+ console.log('');
185
284
  }
186
285
 
187
286
  // Poll for payment
@@ -194,6 +293,19 @@ program
194
293
  const status = await client.claimStatus(claim.payment_hash!);
195
294
  if (status.paid) {
196
295
  pollSpinner.succeed(`${chalk.hex('#D4A574')(`${name}@agentdex.id`)} is now active!`);
296
+
297
+ // Auto-publish kind 0 after payment
298
+ if (!options.skipKind0) {
299
+ const k0Spinner = ora('Publishing kind 0 profile to Nostr relays...').start();
300
+ try {
301
+ const kind0 = createKind0Event(sk, { name, nip05: `${name}@agentdex.id` });
302
+ const relays = ['wss://nos.lol', 'wss://relay.damus.io', ...(options.relay || [])];
303
+ await publishToRelays(kind0, relays);
304
+ k0Spinner.succeed('Kind 0 published — NIP-05 active on all Nostr clients');
305
+ } catch {
306
+ k0Spinner.warn('Kind 0 publish failed — publish manually');
307
+ }
308
+ }
197
309
  return;
198
310
  }
199
311
  }
package/src/client.ts CHANGED
@@ -90,18 +90,23 @@ export class AgentdexClient {
90
90
  return res.json();
91
91
  }
92
92
 
93
- async register(event: object): Promise<{ agent: object; registered: boolean; tier: string }> {
93
+ async register(event: object): Promise<any> {
94
94
  const res = await this.fetch('/api/v1/agents/register', {
95
95
  method: 'POST',
96
96
  body: JSON.stringify({ event }),
97
97
  });
98
- if (!res.ok) {
98
+ if (!res.ok && res.status !== 402) {
99
99
  const err = await res.json();
100
100
  throw new Error(err.error || 'Registration failed');
101
101
  }
102
102
  return res.json();
103
103
  }
104
104
 
105
+ async registerStatus(paymentHash: string): Promise<{ paid: boolean; agent?: object }> {
106
+ const res = await this.fetch(`/api/v1/agents/register/status?payment_hash=${encodeURIComponent(paymentHash)}`);
107
+ return res.json();
108
+ }
109
+
105
110
  async claim(name: string, event: object): Promise<ClaimResult> {
106
111
  const res = await this.fetch('/api/v1/agents/claim', {
107
112
  method: 'POST',
package/src/index.ts CHANGED
@@ -25,6 +25,7 @@ export {
25
25
  getNpub,
26
26
  getPubkeyHex,
27
27
  createProfileEvent,
28
+ createKind0Event,
28
29
  publishToRelays,
29
30
  createNote,
30
31
  } from './nostr.js';
package/src/nostr.ts CHANGED
@@ -121,6 +121,25 @@ export async function publishToRelays(event: object, relays: string[] = DEFAULT_
121
121
  return published;
122
122
  }
123
123
 
124
+ /**
125
+ * Build and sign a kind 0 profile metadata event (for NIP-05 verification).
126
+ * After claiming a NIP-05 name, publish this to relays so Nostr clients
127
+ * (njump, Damus, Primal) can verify the identity.
128
+ */
129
+ export function createKind0Event(sk: Uint8Array, profile: { name: string; about?: string; nip05?: string; picture?: string }) {
130
+ return finalizeEvent({
131
+ kind: 0,
132
+ created_at: Math.floor(Date.now() / 1000),
133
+ tags: [],
134
+ content: JSON.stringify({
135
+ name: profile.name,
136
+ ...(profile.about && { about: profile.about }),
137
+ ...(profile.nip05 && { nip05: profile.nip05 }),
138
+ ...(profile.picture && { picture: profile.picture }),
139
+ }),
140
+ }, sk);
141
+ }
142
+
124
143
  /**
125
144
  * Create and sign a kind 1 note tagged #agentdex
126
145
  */
package/src/nwc.ts ADDED
@@ -0,0 +1,24 @@
1
+ /**
2
+ * NWC (Nostr Wallet Connect) payment utility using Alby SDK
3
+ */
4
+
5
+ import { NWCClient } from '@getalby/sdk';
6
+
7
+ export interface PaymentResult {
8
+ preimage: string;
9
+ paid: boolean;
10
+ }
11
+
12
+ /**
13
+ * Pay a bolt11 invoice via NWC
14
+ */
15
+ export async function payInvoice(nwcUri: string, bolt11: string): Promise<PaymentResult> {
16
+ const client = new NWCClient({ nostrWalletConnectUrl: nwcUri });
17
+
18
+ try {
19
+ const response = await client.payInvoice({ invoice: bolt11 });
20
+ return { preimage: response.preimage, paid: true };
21
+ } finally {
22
+ client.close();
23
+ }
24
+ }