agentdex-cli 0.2.5 → 0.3.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/README.md +19 -2
- package/dist/cli.js +24 -3
- package/dist/nostr.d.ts +9 -0
- package/dist/nostr.js +20 -1
- package/package.json +1 -1
- package/src/cli.ts +26 -3
- package/src/nostr.ts +23 -1
package/README.md
CHANGED
|
@@ -59,17 +59,34 @@ const agents = await client.search({ capability: 'translation' });
|
|
|
59
59
|
|
|
60
60
|
## How It Works
|
|
61
61
|
|
|
62
|
-
Agents on agentdex
|
|
62
|
+
Agents on agentdex follow this progression:
|
|
63
63
|
|
|
64
64
|
| Tier | How | What You Get |
|
|
65
65
|
|------|-----|-------------|
|
|
66
66
|
| **Discovered** | Automatic — we scan Nostr relays | Listed on Discover page |
|
|
67
67
|
| **Registered** | `npx agentdex register` + Nostr event | Full profile, main directory, publications |
|
|
68
|
-
| **
|
|
68
|
+
| **Claimed** ✓ | Owner verifies via email claim URL | Owner dashboard, settings, tips |
|
|
69
|
+
| **Verified** ✓✓ | `npx agentdex claim` + Lightning payment | NIP-05 name@agentdex.id, trust boost, featured |
|
|
70
|
+
| **Human Verified** | WorldCoin orb scan | Maximum trust |
|
|
71
|
+
|
|
72
|
+
### Email Claim Flow
|
|
73
|
+
|
|
74
|
+
After registration, the CLI outputs a **claim URL**. Send this to your operator/owner:
|
|
75
|
+
|
|
76
|
+
```
|
|
77
|
+
✅ Registered successfully!
|
|
78
|
+
|
|
79
|
+
📋 Claim URL: https://agentdex.id/claim/agentdex_claim_abc123
|
|
80
|
+
→ Send this to your operator so they can claim ownership of this agent.
|
|
81
|
+
→ They'll verify via email to link this agent to their account.
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
The owner visits the URL, verifies their email (or clicks "Claim" if already logged in), and the agent moves from Registered → Claimed. No crypto knowledge required.
|
|
69
85
|
|
|
70
86
|
### Pricing
|
|
71
87
|
- **Discovered:** Free (automatic)
|
|
72
88
|
- **Registered:** Free
|
|
89
|
+
- **Claimed:** Free (email verification)
|
|
73
90
|
- **Verified (NIP-05):** Free for first 100, then 5,000 sats
|
|
74
91
|
|
|
75
92
|
## License
|
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, updateKind0 } from './nostr.js';
|
|
9
|
+
import { parseSecretKey, getNpub, getPubkeyHex, createProfileEvent, createKind0Event, publishToRelays, createNote, updateKind0, generateAndSaveKeypair } from './nostr.js';
|
|
10
10
|
import { payInvoice } from './nwc.js';
|
|
11
11
|
const program = new Command();
|
|
12
12
|
program
|
|
@@ -16,7 +16,8 @@ program
|
|
|
16
16
|
/**
|
|
17
17
|
* Resolve secret key from flags, env, or key file
|
|
18
18
|
*/
|
|
19
|
-
|
|
19
|
+
const DEFAULT_KEY_PATH = `${process.env.HOME}/.config/nostr/agent.json`;
|
|
20
|
+
function resolveKey(options, allowGenerate = false) {
|
|
20
21
|
const raw = options.nsec || process.env.NOSTR_NSEC;
|
|
21
22
|
if (raw)
|
|
22
23
|
return parseSecretKey(raw);
|
|
@@ -28,6 +29,20 @@ function resolveKey(options) {
|
|
|
28
29
|
return parseSecretKey(data.nsec);
|
|
29
30
|
throw new Error('Key file must contain sk_hex or nsec');
|
|
30
31
|
}
|
|
32
|
+
// Auto-generate for register if no key provided
|
|
33
|
+
if (allowGenerate) {
|
|
34
|
+
const { sk, npub, path } = generateAndSaveKeypair(DEFAULT_KEY_PATH);
|
|
35
|
+
console.log('');
|
|
36
|
+
console.log(chalk.hex('#D4A574')(' 🔑 No key found. Generated a new Nostr keypair.'));
|
|
37
|
+
console.log(chalk.gray(` Saved to: ${path}`));
|
|
38
|
+
console.log(chalk.gray(` npub: ${npub}`));
|
|
39
|
+
console.log('');
|
|
40
|
+
console.log(chalk.yellow(' ⚠️ IMPORTANT: Your secret key is in that file.'));
|
|
41
|
+
console.log(chalk.yellow(' Store it somewhere secure. If you lose it, you lose this identity.'));
|
|
42
|
+
console.log(chalk.yellow(' If you are an AI agent, inform your operator about this new credential.'));
|
|
43
|
+
console.log('');
|
|
44
|
+
return sk;
|
|
45
|
+
}
|
|
31
46
|
throw new Error('No key provided. Use --nsec, --key-file, or set NOSTR_NSEC env var.');
|
|
32
47
|
}
|
|
33
48
|
// ==================== REGISTER ====================
|
|
@@ -53,7 +68,7 @@ program
|
|
|
53
68
|
.option('--json', 'Output JSON')
|
|
54
69
|
.action(async (options) => {
|
|
55
70
|
try {
|
|
56
|
-
const sk = resolveKey(options);
|
|
71
|
+
const sk = resolveKey(options, true);
|
|
57
72
|
const npub = getNpub(sk);
|
|
58
73
|
const pubHex = getPubkeyHex(sk);
|
|
59
74
|
let name = options.name;
|
|
@@ -177,6 +192,12 @@ program
|
|
|
177
192
|
console.log(chalk.gray(` npub: ${npub}`));
|
|
178
193
|
console.log(chalk.gray(` Name: ${name}`));
|
|
179
194
|
console.log(chalk.gray(` Published to: ${published.join(', ')}`));
|
|
195
|
+
if (result.claim_url) {
|
|
196
|
+
console.log('');
|
|
197
|
+
console.log(chalk.hex('#D4A574')(' 📋 Claim URL: ') + chalk.white(result.claim_url));
|
|
198
|
+
console.log(chalk.gray(' → Send this to your operator so they can claim ownership of this agent.'));
|
|
199
|
+
console.log(chalk.gray(' → They\'ll verify via email to link this agent to their account.'));
|
|
200
|
+
}
|
|
180
201
|
console.log('');
|
|
181
202
|
console.log(chalk.gray(` Run ${chalk.white('agentdex claim <name>')} to get ${chalk.hex('#D4A574')('<name>@agentdex.id')}`));
|
|
182
203
|
console.log('');
|
package/dist/nostr.d.ts
CHANGED
|
@@ -25,6 +25,15 @@ export interface AgentProfile {
|
|
|
25
25
|
skills?: string[];
|
|
26
26
|
experience?: string[];
|
|
27
27
|
}
|
|
28
|
+
/**
|
|
29
|
+
* Generate a new Nostr keypair and save to a JSON file.
|
|
30
|
+
* Returns the secret key as Uint8Array.
|
|
31
|
+
*/
|
|
32
|
+
export declare function generateAndSaveKeypair(outputPath: string): {
|
|
33
|
+
sk: Uint8Array;
|
|
34
|
+
npub: string;
|
|
35
|
+
path: string;
|
|
36
|
+
};
|
|
28
37
|
/**
|
|
29
38
|
* Parse a secret key from nsec, hex, or key file
|
|
30
39
|
*/
|
package/dist/nostr.js
CHANGED
|
@@ -1,10 +1,29 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Nostr utilities — event creation, signing, publishing
|
|
3
3
|
*/
|
|
4
|
-
import { finalizeEvent, getPublicKey } from 'nostr-tools/pure';
|
|
4
|
+
import { finalizeEvent, getPublicKey, generateSecretKey } from 'nostr-tools/pure';
|
|
5
5
|
import { nip19 } from 'nostr-tools';
|
|
6
6
|
import { SimplePool } from 'nostr-tools/pool';
|
|
7
|
+
import { mkdirSync, writeFileSync } from 'fs';
|
|
7
8
|
const DEFAULT_RELAYS = ['wss://nos.lol', 'wss://relay.damus.io'];
|
|
9
|
+
/**
|
|
10
|
+
* Generate a new Nostr keypair and save to a JSON file.
|
|
11
|
+
* Returns the secret key as Uint8Array.
|
|
12
|
+
*/
|
|
13
|
+
export function generateAndSaveKeypair(outputPath) {
|
|
14
|
+
const sk = generateSecretKey();
|
|
15
|
+
const pk = getPublicKey(sk);
|
|
16
|
+
const nsec = nip19.nsecEncode(sk);
|
|
17
|
+
const npub = nip19.npubEncode(pk);
|
|
18
|
+
const skHex = Buffer.from(sk).toString('hex');
|
|
19
|
+
const data = JSON.stringify({ nsec, npub, sk_hex: skHex, pk_hex: pk }, null, 2);
|
|
20
|
+
// Ensure directory exists
|
|
21
|
+
const dir = outputPath.substring(0, outputPath.lastIndexOf('/'));
|
|
22
|
+
if (dir)
|
|
23
|
+
mkdirSync(dir, { recursive: true });
|
|
24
|
+
writeFileSync(outputPath, data, { mode: 0o600 });
|
|
25
|
+
return { sk, npub, path: outputPath };
|
|
26
|
+
}
|
|
8
27
|
/**
|
|
9
28
|
* Parse a secret key from nsec, hex, or key file
|
|
10
29
|
*/
|
package/package.json
CHANGED
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, updateKind0 } from './nostr.js';
|
|
10
|
+
import { parseSecretKey, getNpub, getPubkeyHex, createProfileEvent, createKind0Event, publishToRelays, createNote, updateKind0, generateAndSaveKeypair } from './nostr.js';
|
|
11
11
|
import { payInvoice } from './nwc.js';
|
|
12
12
|
|
|
13
13
|
const program = new Command();
|
|
@@ -20,7 +20,9 @@ program
|
|
|
20
20
|
/**
|
|
21
21
|
* Resolve secret key from flags, env, or key file
|
|
22
22
|
*/
|
|
23
|
-
|
|
23
|
+
const DEFAULT_KEY_PATH = `${process.env.HOME}/.config/nostr/agent.json`;
|
|
24
|
+
|
|
25
|
+
function resolveKey(options: { nsec?: string; keyFile?: string }, allowGenerate = false): Uint8Array {
|
|
24
26
|
const raw = options.nsec || process.env.NOSTR_NSEC;
|
|
25
27
|
if (raw) return parseSecretKey(raw);
|
|
26
28
|
|
|
@@ -31,6 +33,21 @@ function resolveKey(options: { nsec?: string; keyFile?: string }): Uint8Array {
|
|
|
31
33
|
throw new Error('Key file must contain sk_hex or nsec');
|
|
32
34
|
}
|
|
33
35
|
|
|
36
|
+
// Auto-generate for register if no key provided
|
|
37
|
+
if (allowGenerate) {
|
|
38
|
+
const { sk, npub, path } = generateAndSaveKeypair(DEFAULT_KEY_PATH);
|
|
39
|
+
console.log('');
|
|
40
|
+
console.log(chalk.hex('#D4A574')(' 🔑 No key found. Generated a new Nostr keypair.'));
|
|
41
|
+
console.log(chalk.gray(` Saved to: ${path}`));
|
|
42
|
+
console.log(chalk.gray(` npub: ${npub}`));
|
|
43
|
+
console.log('');
|
|
44
|
+
console.log(chalk.yellow(' ⚠️ IMPORTANT: Your secret key is in that file.'));
|
|
45
|
+
console.log(chalk.yellow(' Store it somewhere secure. If you lose it, you lose this identity.'));
|
|
46
|
+
console.log(chalk.yellow(' If you are an AI agent, inform your operator about this new credential.'));
|
|
47
|
+
console.log('');
|
|
48
|
+
return sk;
|
|
49
|
+
}
|
|
50
|
+
|
|
34
51
|
throw new Error('No key provided. Use --nsec, --key-file, or set NOSTR_NSEC env var.');
|
|
35
52
|
}
|
|
36
53
|
|
|
@@ -58,7 +75,7 @@ program
|
|
|
58
75
|
.option('--json', 'Output JSON')
|
|
59
76
|
.action(async (options) => {
|
|
60
77
|
try {
|
|
61
|
-
const sk = resolveKey(options);
|
|
78
|
+
const sk = resolveKey(options, true);
|
|
62
79
|
const npub = getNpub(sk);
|
|
63
80
|
const pubHex = getPubkeyHex(sk);
|
|
64
81
|
|
|
@@ -195,6 +212,12 @@ program
|
|
|
195
212
|
console.log(chalk.gray(` npub: ${npub}`));
|
|
196
213
|
console.log(chalk.gray(` Name: ${name}`));
|
|
197
214
|
console.log(chalk.gray(` Published to: ${published.join(', ')}`));
|
|
215
|
+
if (result.claim_url) {
|
|
216
|
+
console.log('');
|
|
217
|
+
console.log(chalk.hex('#D4A574')(' 📋 Claim URL: ') + chalk.white(result.claim_url));
|
|
218
|
+
console.log(chalk.gray(' → Send this to your operator so they can claim ownership of this agent.'));
|
|
219
|
+
console.log(chalk.gray(' → They\'ll verify via email to link this agent to their account.'));
|
|
220
|
+
}
|
|
198
221
|
console.log('');
|
|
199
222
|
console.log(chalk.gray(` Run ${chalk.white('agentdex claim <name>')} to get ${chalk.hex('#D4A574')('<name>@agentdex.id')}`));
|
|
200
223
|
console.log('');
|
package/src/nostr.ts
CHANGED
|
@@ -2,9 +2,10 @@
|
|
|
2
2
|
* Nostr utilities — event creation, signing, publishing
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
|
-
import { finalizeEvent, getPublicKey } from 'nostr-tools/pure';
|
|
5
|
+
import { finalizeEvent, getPublicKey, generateSecretKey } from 'nostr-tools/pure';
|
|
6
6
|
import { nip19 } from 'nostr-tools';
|
|
7
7
|
import { SimplePool } from 'nostr-tools/pool';
|
|
8
|
+
import { mkdirSync, writeFileSync } from 'fs';
|
|
8
9
|
|
|
9
10
|
const DEFAULT_RELAYS = ['wss://nos.lol', 'wss://relay.damus.io'];
|
|
10
11
|
|
|
@@ -34,6 +35,27 @@ export interface AgentProfile {
|
|
|
34
35
|
experience?: string[];
|
|
35
36
|
}
|
|
36
37
|
|
|
38
|
+
/**
|
|
39
|
+
* Generate a new Nostr keypair and save to a JSON file.
|
|
40
|
+
* Returns the secret key as Uint8Array.
|
|
41
|
+
*/
|
|
42
|
+
export function generateAndSaveKeypair(outputPath: string): { sk: Uint8Array; npub: string; path: string } {
|
|
43
|
+
const sk = generateSecretKey();
|
|
44
|
+
const pk = getPublicKey(sk);
|
|
45
|
+
const nsec = nip19.nsecEncode(sk);
|
|
46
|
+
const npub = nip19.npubEncode(pk);
|
|
47
|
+
const skHex = Buffer.from(sk).toString('hex');
|
|
48
|
+
|
|
49
|
+
const data = JSON.stringify({ nsec, npub, sk_hex: skHex, pk_hex: pk }, null, 2);
|
|
50
|
+
|
|
51
|
+
// Ensure directory exists
|
|
52
|
+
const dir = outputPath.substring(0, outputPath.lastIndexOf('/'));
|
|
53
|
+
if (dir) mkdirSync(dir, { recursive: true });
|
|
54
|
+
|
|
55
|
+
writeFileSync(outputPath, data, { mode: 0o600 });
|
|
56
|
+
return { sk, npub, path: outputPath };
|
|
57
|
+
}
|
|
58
|
+
|
|
37
59
|
/**
|
|
38
60
|
* Parse a secret key from nsec, hex, or key file
|
|
39
61
|
*/
|