@unicitylabs/openclaw-unicity 0.5.4 → 0.5.6-dev.1
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/package.json +2 -2
- package/src/channel.ts +16 -5
- package/src/sphere.ts +29 -6
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@unicitylabs/openclaw-unicity",
|
|
3
|
-
"version": "0.5.
|
|
3
|
+
"version": "0.5.6-dev.1",
|
|
4
4
|
"description": "Unicity wallet identity and encrypted DMs for OpenClaw agents — powered by Sphere SDK",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "src/index.ts",
|
|
@@ -44,7 +44,7 @@
|
|
|
44
44
|
"dependencies": {
|
|
45
45
|
"@clack/prompts": "^0.10.0",
|
|
46
46
|
"@sinclair/typebox": "^0.34.48",
|
|
47
|
-
"@unicitylabs/sphere-sdk": "
|
|
47
|
+
"@unicitylabs/sphere-sdk": "0.6.8-dev.2"
|
|
48
48
|
},
|
|
49
49
|
"peerDependencies": {
|
|
50
50
|
"openclaw": "*"
|
package/src/channel.ts
CHANGED
|
@@ -244,16 +244,27 @@ export const unicityChannelPlugin = {
|
|
|
244
244
|
|
|
245
245
|
// Track DM start time and seen IDs to skip historical replays from the relay.
|
|
246
246
|
// The SDK fires onDirectMessage for every cached/replayed DM on connect.
|
|
247
|
-
|
|
247
|
+
// msg.timestamp is milliseconds, so dmStartTime must be ms too.
|
|
248
|
+
const dmStartTime = Date.now();
|
|
248
249
|
const seenDmIds = new Set<string>();
|
|
249
250
|
const DM_SEEN_MAX = 1000;
|
|
250
251
|
|
|
251
252
|
// Collect all known representations of "self" so we can detect echoed-back
|
|
252
|
-
// messages.
|
|
253
|
-
//
|
|
254
|
-
//
|
|
253
|
+
// messages. We must track BOTH the 33-byte compressed chainPubkey (02/03…)
|
|
254
|
+
// and the 32-byte x-only Nostr transport key (chainPubkey without prefix).
|
|
255
|
+
// The SDK's own self-check in CommunicationsModule has a bug where it
|
|
256
|
+
// compares transport pubkey (32-byte) against chainPubkey (33-byte), which
|
|
257
|
+
// never matches — so self-messages can leak through to dmHandlers.
|
|
255
258
|
const selfPubkeys = new Set<string>();
|
|
256
|
-
if (sphere.identity?.chainPubkey)
|
|
259
|
+
if (sphere.identity?.chainPubkey) {
|
|
260
|
+
const cpk = sphere.identity.chainPubkey;
|
|
261
|
+
selfPubkeys.add(cpk);
|
|
262
|
+
// x-only transport key = compressed pubkey without the 02/03 prefix
|
|
263
|
+
if (cpk.length === 66 && (cpk.startsWith("02") || cpk.startsWith("03"))) {
|
|
264
|
+
selfPubkeys.add(cpk.slice(2));
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
// Also add the groupChat key (same value but grabbed independently for safety)
|
|
257
268
|
const myNostrPubkey = sphere.groupChat?.getMyPublicKey?.() ?? null;
|
|
258
269
|
if (myNostrPubkey) selfPubkeys.add(myNostrPubkey);
|
|
259
270
|
|
package/src/sphere.ts
CHANGED
|
@@ -116,6 +116,7 @@ async function doInitSphere(
|
|
|
116
116
|
...(existingMnemonic ? { mnemonic: existingMnemonic } : { autoGenerate: true }),
|
|
117
117
|
...(cfg.nametag ? { nametag: cfg.nametag } : {}),
|
|
118
118
|
...(groupChat ? { groupChat: groupChatRelays ? { relays: groupChatRelays } : true } : {}),
|
|
119
|
+
dmSince: Math.floor(Date.now() / 1000) - 86400,
|
|
119
120
|
});
|
|
120
121
|
|
|
121
122
|
sphereInstance = result.sphere;
|
|
@@ -133,8 +134,10 @@ async function doInitSphere(
|
|
|
133
134
|
}
|
|
134
135
|
|
|
135
136
|
// Register nametag if configured and wallet doesn't have one yet
|
|
136
|
-
|
|
137
|
-
|
|
137
|
+
// Normalize: strip leading '@' for consistent comparison
|
|
138
|
+
const walletNametag = result.sphere.identity?.nametag?.replace(/^@/, "");
|
|
139
|
+
const cfgNametag = cfg.nametag?.replace(/^@/, "");
|
|
140
|
+
if (cfgNametag && !walletNametag) {
|
|
138
141
|
try {
|
|
139
142
|
await result.sphere.registerNametag(cfg.nametag);
|
|
140
143
|
const log = logger ?? console;
|
|
@@ -148,11 +151,31 @@ async function doInitSphere(
|
|
|
148
151
|
console.warn(msg);
|
|
149
152
|
}
|
|
150
153
|
}
|
|
151
|
-
} else if (
|
|
154
|
+
} else if (cfgNametag && walletNametag && cfgNametag !== walletNametag) {
|
|
155
|
+
// Nametag changed — check if another address in this wallet already owns it,
|
|
156
|
+
// otherwise derive a new HD address and mint the nametag there.
|
|
152
157
|
const log = logger ?? console;
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
158
|
+
try {
|
|
159
|
+
const activeAddresses = result.sphere.getActiveAddresses() as
|
|
160
|
+
{ index: number; nametag?: string }[];
|
|
161
|
+
const existing = activeAddresses.find(
|
|
162
|
+
(a) => a.nametag?.replace(/^@/, "") === cfgNametag,
|
|
163
|
+
);
|
|
164
|
+
if (existing) {
|
|
165
|
+
log.info(`[unicity] Switching to existing address ${existing.index} for nametag '${cfg.nametag}'...`);
|
|
166
|
+
await result.sphere.switchToAddress(existing.index);
|
|
167
|
+
log.info(`[unicity] Switched to address ${existing.index} with nametag '${cfg.nametag}'.`);
|
|
168
|
+
} else {
|
|
169
|
+
const nextIndex = activeAddresses.length > 0
|
|
170
|
+
? Math.max(...activeAddresses.map((a) => a.index)) + 1
|
|
171
|
+
: 1;
|
|
172
|
+
log.info(`[unicity] Minting nametag '${cfg.nametag}' on new address ${nextIndex}...`);
|
|
173
|
+
await result.sphere.switchToAddress(nextIndex, { nametag: cfg.nametag });
|
|
174
|
+
log.info(`[unicity] Switched to address ${nextIndex} with nametag '${cfg.nametag}'.`);
|
|
175
|
+
}
|
|
176
|
+
} catch (err) {
|
|
177
|
+
log.warn(`[unicity] Failed to switch address for nametag '${cfg.nametag}': ${err}`);
|
|
178
|
+
}
|
|
156
179
|
}
|
|
157
180
|
|
|
158
181
|
// Send greeting DM to owner on first wallet creation
|