nostr-bray 1.28.1 → 1.29.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 +16 -0
- package/dist/context.js +18 -3
- package/dist/widgets/dm-thread.html +2 -2
- package/dist/widgets/identity-picker-handler.d.ts +1 -0
- package/dist/widgets/identity-picker-handler.js +1 -0
- package/dist/widgets/identity-picker.html +19 -8
- package/dist/widgets/social-feed.html +1 -1
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -221,6 +221,8 @@ Quick examples:
|
|
|
221
221
|
nostr-bray shell # interactive mode
|
|
222
222
|
|
|
223
223
|
Flags:
|
|
224
|
+
--bunker <uri> Use bunker:// URI (overrides env/config)
|
|
225
|
+
--key <nsec|hex|mnemonic> Use this secret key (overrides env/config)
|
|
224
226
|
--json Output raw JSON (for piping/scripts)
|
|
225
227
|
--human Force human-readable output
|
|
226
228
|
--help Show help for a command
|
|
@@ -235,6 +237,20 @@ if (command === 'help' || command === '--help' || command === '-h') {
|
|
|
235
237
|
console.log(HELP);
|
|
236
238
|
process.exit(0);
|
|
237
239
|
}
|
|
240
|
+
// Allow key/bunker overrides on the command line
|
|
241
|
+
// These are injected into env before loadConfig() so all loading logic stays centralised.
|
|
242
|
+
// Note: loadConfig() deletes BUNKER_URI / NOSTR_SECRET_KEY from env after reading them.
|
|
243
|
+
if (args.includes('--bunker')) {
|
|
244
|
+
process.env.BUNKER_URI = args[args.indexOf('--bunker') + 1];
|
|
245
|
+
// Remove from args so commands don't see it as a positional argument
|
|
246
|
+
const i = args.indexOf('--bunker');
|
|
247
|
+
args.splice(i, 2);
|
|
248
|
+
}
|
|
249
|
+
if (args.includes('--key')) {
|
|
250
|
+
process.env.NOSTR_SECRET_KEY = args[args.indexOf('--key') + 1];
|
|
251
|
+
const i = args.indexOf('--key');
|
|
252
|
+
args.splice(i, 2);
|
|
253
|
+
}
|
|
238
254
|
// Commands that work purely offline — no relay connection needed
|
|
239
255
|
const OFFLINE_COMMANDS = new Set([
|
|
240
256
|
'whoami', 'create', 'list', 'derive', 'persona', 'switch', 'prove',
|
package/dist/context.js
CHANGED
|
@@ -121,12 +121,27 @@ export class IdentityContext {
|
|
|
121
121
|
return;
|
|
122
122
|
}
|
|
123
123
|
}
|
|
124
|
-
// Not in cache — derive on the fly
|
|
125
|
-
|
|
124
|
+
// Not in cache — derive on the fly.
|
|
125
|
+
// If no colon, treat as a persona name (nostr:persona:{name}); otherwise raw purpose.
|
|
126
|
+
const isPersonaName = !purposeOrName.includes(':');
|
|
127
|
+
let identity;
|
|
128
|
+
let purpose;
|
|
129
|
+
let personaName;
|
|
130
|
+
if (isPersonaName) {
|
|
131
|
+
const persona = derivePersona(this.root, purposeOrName, index ?? 0);
|
|
132
|
+
identity = persona.identity;
|
|
133
|
+
purpose = persona.identity.purpose;
|
|
134
|
+
personaName = purposeOrName;
|
|
135
|
+
}
|
|
136
|
+
else {
|
|
137
|
+
identity = derive(this.root, purposeOrName, index ?? 0);
|
|
138
|
+
purpose = purposeOrName;
|
|
139
|
+
}
|
|
126
140
|
const entry = {
|
|
127
141
|
identity,
|
|
128
|
-
purpose
|
|
142
|
+
purpose,
|
|
129
143
|
index: index ?? 0,
|
|
144
|
+
personaName,
|
|
130
145
|
lastUsed: Date.now(),
|
|
131
146
|
};
|
|
132
147
|
this.putCache(identity.npub, entry);
|
|
@@ -240,11 +240,11 @@ const { App } = globalThis.ExtApps;
|
|
|
240
240
|
function sendReply() {
|
|
241
241
|
const message = replyInput.value.trim();
|
|
242
242
|
if (!message || !partnerPubkeyHex) return;
|
|
243
|
-
app.callServerTool("dm-send", { recipientPubkeyHex: partnerPubkeyHex, message
|
|
243
|
+
app.callServerTool({ name: "dm-send", arguments: { recipientPubkeyHex: partnerPubkeyHex, message } });
|
|
244
244
|
replyInput.value = "";
|
|
245
245
|
// Refresh conversation after short delay
|
|
246
246
|
setTimeout(() => {
|
|
247
|
-
app.callServerTool("dm-thread-widget", { withPubkeyHex: partnerPubkeyHex });
|
|
247
|
+
app.callServerTool({ name: "dm-thread-widget", arguments: { withPubkeyHex: partnerPubkeyHex } });
|
|
248
248
|
}, 1500);
|
|
249
249
|
}
|
|
250
250
|
|
|
@@ -25,6 +25,7 @@ export async function handleIdentityPickerWidget(ctx, pool) {
|
|
|
25
25
|
catch { /* profile lookup may fail for new identities */ }
|
|
26
26
|
entries.push({
|
|
27
27
|
npub: id.npub,
|
|
28
|
+
purpose: id.purpose ?? 'master',
|
|
28
29
|
personaName: id.personaName,
|
|
29
30
|
displayName,
|
|
30
31
|
pictureDataUri,
|
|
@@ -110,7 +110,7 @@ const { App } = globalThis.ExtApps;
|
|
|
110
110
|
app.ontoolresult = ({ content }) => {
|
|
111
111
|
try {
|
|
112
112
|
const data = JSON.parse(content[0].text);
|
|
113
|
-
render(data);
|
|
113
|
+
if (data.identities) render(data);
|
|
114
114
|
} catch (e) {
|
|
115
115
|
clearAndShowMessage("Failed to parse identity data.");
|
|
116
116
|
}
|
|
@@ -119,6 +119,10 @@ const { App } = globalThis.ExtApps;
|
|
|
119
119
|
await app.connect();
|
|
120
120
|
const hostCtx = app.getHostContext();
|
|
121
121
|
if (hostCtx) applyTheme(hostCtx.theme);
|
|
122
|
+
const caps = app.getHostCapabilities();
|
|
123
|
+
const canCallTools = !!caps?.serverTools;
|
|
124
|
+
console.debug("[identity-picker] hostCapabilities:", JSON.stringify(caps));
|
|
125
|
+
console.debug("[identity-picker] canCallTools:", canCallTools);
|
|
122
126
|
|
|
123
127
|
function clearAndShowMessage(msg) {
|
|
124
128
|
while (root.firstChild) root.removeChild(root.firstChild);
|
|
@@ -179,14 +183,21 @@ const { App } = globalThis.ExtApps;
|
|
|
179
183
|
card.appendChild(badge);
|
|
180
184
|
}
|
|
181
185
|
|
|
182
|
-
card.addEventListener("click", () => {
|
|
186
|
+
card.addEventListener("click", async () => {
|
|
183
187
|
if (id.isActive) return;
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
188
|
+
if (!canCallTools) {
|
|
189
|
+
clearAndShowMessage(`Host doesn't support widget tool calls. Ask the AI to switch to "${id.personaName || id.purpose}".`);
|
|
190
|
+
return;
|
|
191
|
+
}
|
|
192
|
+
const target = id.personaName || id.purpose;
|
|
193
|
+
try {
|
|
194
|
+
await app.callServerTool({ name: "identity-switch", arguments: { target } });
|
|
195
|
+
const result = await app.callServerTool({ name: "identity-picker-widget", arguments: {} });
|
|
196
|
+
const data = JSON.parse(result.content[0].text);
|
|
197
|
+
render(data);
|
|
198
|
+
} catch (e) {
|
|
199
|
+
clearAndShowMessage("Switch failed: " + (e?.message ?? e));
|
|
200
|
+
}
|
|
190
201
|
});
|
|
191
202
|
|
|
192
203
|
grid.appendChild(card);
|
|
@@ -210,7 +210,7 @@ const { App } = globalThis.ExtApps;
|
|
|
210
210
|
loadMore.className = "load-more";
|
|
211
211
|
loadMore.textContent = "Load more";
|
|
212
212
|
loadMore.addEventListener("click", () => {
|
|
213
|
-
app.callServerTool("social-feed-widget", { since: lastSince });
|
|
213
|
+
app.callServerTool({ name: "social-feed-widget", arguments: { since: lastSince } });
|
|
214
214
|
});
|
|
215
215
|
root.appendChild(loadMore);
|
|
216
216
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "nostr-bray",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.29.0",
|
|
4
4
|
"mcpName": "dev.forgesworn/bray",
|
|
5
5
|
"description": "Trust-aware Nostr for AI and humans. Three dimensions of trust -- verification, proximity, and access -- woven into every interaction.",
|
|
6
6
|
"type": "module",
|