nostr-bray 1.1.0 → 1.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 +118 -40
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -83,6 +83,10 @@ Safety:
|
|
|
83
83
|
safety-configure [persona-name] Configure alternative identity
|
|
84
84
|
safety-activate [persona-name] Switch to alternative identity
|
|
85
85
|
|
|
86
|
+
Modes:
|
|
87
|
+
(no command) Start MCP server (stdio)
|
|
88
|
+
shell Interactive REPL (persistent relay connection)
|
|
89
|
+
|
|
86
90
|
Environment:
|
|
87
91
|
NOSTR_SECRET_KEY nsec, hex, or BIP-39 mnemonic
|
|
88
92
|
NOSTR_SECRET_KEY_FILE Path to secret key file
|
|
@@ -109,26 +113,56 @@ const masterRelays = await nip65.loadForIdentity(ctx.activeNpub);
|
|
|
109
113
|
pool.reconfigure(ctx.activeNpub, masterRelays);
|
|
110
114
|
/** Helper: print JSON result */
|
|
111
115
|
function out(data) { console.log(JSON.stringify(data, null, 2)); }
|
|
112
|
-
/**
|
|
113
|
-
function
|
|
114
|
-
const
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
116
|
+
/** Parse a shell line into args, respecting quotes */
|
|
117
|
+
function parseShellLine(line) {
|
|
118
|
+
const result = [];
|
|
119
|
+
let current = '';
|
|
120
|
+
let inQuote = null;
|
|
121
|
+
for (const ch of line) {
|
|
122
|
+
if (inQuote) {
|
|
123
|
+
if (ch === inQuote) {
|
|
124
|
+
inQuote = null;
|
|
125
|
+
}
|
|
126
|
+
else {
|
|
127
|
+
current += ch;
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
else if (ch === '"' || ch === "'") {
|
|
131
|
+
inQuote = ch;
|
|
132
|
+
}
|
|
133
|
+
else if (ch === ' ' || ch === '\t') {
|
|
134
|
+
if (current) {
|
|
135
|
+
result.push(current);
|
|
136
|
+
current = '';
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
else {
|
|
140
|
+
current += ch;
|
|
141
|
+
}
|
|
118
142
|
}
|
|
119
|
-
|
|
143
|
+
if (current)
|
|
144
|
+
result.push(current);
|
|
145
|
+
return result;
|
|
120
146
|
}
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
}
|
|
131
|
-
|
|
147
|
+
async function run(cmdArgs) {
|
|
148
|
+
const command = cmdArgs[0];
|
|
149
|
+
/** Require arg or throw */
|
|
150
|
+
function req(index, usage) {
|
|
151
|
+
const val = cmdArgs[index];
|
|
152
|
+
if (!val) {
|
|
153
|
+
throw new Error(`Usage: ${usage}`);
|
|
154
|
+
}
|
|
155
|
+
return val;
|
|
156
|
+
}
|
|
157
|
+
function flag(name, fallback) {
|
|
158
|
+
const i = cmdArgs.indexOf(`--${name}`);
|
|
159
|
+
if (i === -1)
|
|
160
|
+
return fallback;
|
|
161
|
+
return cmdArgs[i + 1] ?? fallback;
|
|
162
|
+
}
|
|
163
|
+
function hasFlag(name) {
|
|
164
|
+
return cmdArgs.includes(`--${name}`);
|
|
165
|
+
}
|
|
132
166
|
switch (command) {
|
|
133
167
|
// === Identity ===
|
|
134
168
|
case 'whoami':
|
|
@@ -141,21 +175,21 @@ async function run() {
|
|
|
141
175
|
out(handleIdentityList(ctx));
|
|
142
176
|
break;
|
|
143
177
|
case 'derive':
|
|
144
|
-
out(ctx.derive(req(1, 'derive <purpose> [index]'), parseInt(
|
|
178
|
+
out(ctx.derive(req(1, 'derive <purpose> [index]'), parseInt(cmdArgs[2] ?? '0', 10)));
|
|
145
179
|
break;
|
|
146
180
|
case 'persona':
|
|
147
|
-
out(ctx.derivePersona(req(1, 'persona <name> [index]'), parseInt(
|
|
181
|
+
out(ctx.derivePersona(req(1, 'persona <name> [index]'), parseInt(cmdArgs[2] ?? '0', 10)));
|
|
148
182
|
break;
|
|
149
183
|
case 'switch':
|
|
150
|
-
ctx.switch(req(1, 'switch <target> [index]'),
|
|
184
|
+
ctx.switch(req(1, 'switch <target> [index]'), cmdArgs[2] ? parseInt(cmdArgs[2], 10) : undefined);
|
|
151
185
|
console.log(ctx.activeNpub);
|
|
152
186
|
break;
|
|
153
187
|
case 'prove':
|
|
154
|
-
out(handleIdentityProve(ctx, { mode: (
|
|
188
|
+
out(handleIdentityProve(ctx, { mode: (cmdArgs[1] === 'full' ? 'full' : 'blind') }));
|
|
155
189
|
break;
|
|
156
190
|
case 'proof-publish': {
|
|
157
191
|
const r = await handleTrustProofPublish(ctx, pool, {
|
|
158
|
-
mode: (
|
|
192
|
+
mode: (cmdArgs[1] === 'full' ? 'full' : 'blind'),
|
|
159
193
|
confirm: hasFlag('confirm'),
|
|
160
194
|
});
|
|
161
195
|
out(r);
|
|
@@ -164,8 +198,8 @@ async function run() {
|
|
|
164
198
|
case 'backup':
|
|
165
199
|
out(handleBackupShamir({
|
|
166
200
|
secret: new Uint8Array(ctx.activePrivateKey),
|
|
167
|
-
threshold: parseInt(
|
|
168
|
-
shares: parseInt(
|
|
201
|
+
threshold: parseInt(cmdArgs[2] ?? '3', 10),
|
|
202
|
+
shares: parseInt(cmdArgs[3] ?? '5', 10),
|
|
169
203
|
outputDir: req(1, 'backup <dir> [threshold] [shares]'),
|
|
170
204
|
}));
|
|
171
205
|
break;
|
|
@@ -203,7 +237,7 @@ async function run() {
|
|
|
203
237
|
out(await handleSocialReact(ctx, pool, {
|
|
204
238
|
eventId: req(1, 'react <event-id> <pubkey> [emoji]'),
|
|
205
239
|
eventPubkey: req(2, 'react <event-id> <pubkey> [emoji]'),
|
|
206
|
-
reaction:
|
|
240
|
+
reaction: cmdArgs[3] ?? '+',
|
|
207
241
|
}));
|
|
208
242
|
break;
|
|
209
243
|
case 'profile':
|
|
@@ -235,8 +269,8 @@ async function run() {
|
|
|
235
269
|
case 'attest':
|
|
236
270
|
out(await handleTrustAttest(ctx, pool, {
|
|
237
271
|
type: req(1, 'attest <type> <identifier> [subject]'),
|
|
238
|
-
identifier:
|
|
239
|
-
subject:
|
|
272
|
+
identifier: cmdArgs[2],
|
|
273
|
+
subject: cmdArgs[3],
|
|
240
274
|
}));
|
|
241
275
|
break;
|
|
242
276
|
case 'trust-read':
|
|
@@ -306,7 +340,7 @@ async function run() {
|
|
|
306
340
|
case 'relay-add':
|
|
307
341
|
out(handleRelayAdd(ctx, pool, {
|
|
308
342
|
url: req(1, 'relay-add <url> [read|write]'),
|
|
309
|
-
mode:
|
|
343
|
+
mode: cmdArgs[2],
|
|
310
344
|
}));
|
|
311
345
|
break;
|
|
312
346
|
case 'relay-info':
|
|
@@ -322,7 +356,7 @@ async function run() {
|
|
|
322
356
|
case 'zap-invoice':
|
|
323
357
|
out(await handleZapMakeInvoice(ctx, pool, {
|
|
324
358
|
amountMsats: parseInt(req(1, 'zap-invoice <msats> [description]'), 10),
|
|
325
|
-
description:
|
|
359
|
+
description: cmdArgs[2],
|
|
326
360
|
nwcUri,
|
|
327
361
|
}));
|
|
328
362
|
break;
|
|
@@ -343,21 +377,65 @@ async function run() {
|
|
|
343
377
|
break;
|
|
344
378
|
// === Safety ===
|
|
345
379
|
case 'safety-configure':
|
|
346
|
-
out(handleDuressConfigure(ctx, pool, { personaName:
|
|
380
|
+
out(handleDuressConfigure(ctx, pool, { personaName: cmdArgs[1] }));
|
|
347
381
|
break;
|
|
348
382
|
case 'safety-activate':
|
|
349
|
-
out(handleDuressActivate(ctx, { personaName:
|
|
383
|
+
out(handleDuressActivate(ctx, { personaName: cmdArgs[1] }));
|
|
350
384
|
break;
|
|
351
385
|
default:
|
|
352
|
-
|
|
353
|
-
console.error(HELP);
|
|
354
|
-
process.exit(1);
|
|
386
|
+
throw new Error(`Unknown command: ${command}. Run --help for usage.`);
|
|
355
387
|
}
|
|
356
388
|
}
|
|
357
|
-
|
|
358
|
-
|
|
389
|
+
// === Shell mode ===
|
|
390
|
+
async function shell() {
|
|
391
|
+
const { createInterface } = await import('node:readline');
|
|
392
|
+
const rl = createInterface({ input: process.stdin, output: process.stdout });
|
|
393
|
+
console.log(`nostr-bray shell — ${ctx.activeNpub}`);
|
|
394
|
+
console.log('Type a command, or "help" / "exit".\n');
|
|
395
|
+
const prompt = () => new Promise(resolve => {
|
|
396
|
+
rl.question('bray> ', resolve);
|
|
397
|
+
});
|
|
398
|
+
while (true) {
|
|
399
|
+
const line = await prompt();
|
|
400
|
+
const trimmed = line.trim();
|
|
401
|
+
if (!trimmed)
|
|
402
|
+
continue;
|
|
403
|
+
if (trimmed === 'exit' || trimmed === 'quit')
|
|
404
|
+
break;
|
|
405
|
+
if (trimmed === 'help') {
|
|
406
|
+
console.log(HELP);
|
|
407
|
+
continue;
|
|
408
|
+
}
|
|
409
|
+
const shellArgs = parseShellLine(trimmed);
|
|
410
|
+
try {
|
|
411
|
+
await run(shellArgs);
|
|
412
|
+
}
|
|
413
|
+
catch (e) {
|
|
414
|
+
console.error(e.message);
|
|
415
|
+
}
|
|
416
|
+
}
|
|
417
|
+
rl.close();
|
|
359
418
|
}
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
419
|
+
// === Entry point ===
|
|
420
|
+
if (command === 'shell') {
|
|
421
|
+
try {
|
|
422
|
+
await shell();
|
|
423
|
+
}
|
|
424
|
+
finally {
|
|
425
|
+
ctx.destroy();
|
|
426
|
+
pool.close();
|
|
427
|
+
}
|
|
428
|
+
}
|
|
429
|
+
else {
|
|
430
|
+
try {
|
|
431
|
+
await run(args);
|
|
432
|
+
}
|
|
433
|
+
catch (e) {
|
|
434
|
+
console.error(e.message);
|
|
435
|
+
process.exit(1);
|
|
436
|
+
}
|
|
437
|
+
finally {
|
|
438
|
+
ctx.destroy();
|
|
439
|
+
pool.close();
|
|
440
|
+
}
|
|
363
441
|
}
|
package/package.json
CHANGED