@unicitylabs/openclaw-unicity 0.3.2 → 0.3.4

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 CHANGED
@@ -7,6 +7,7 @@
7
7
  <p align="center">
8
8
  <a href="https://www.npmjs.com/package/@unicitylabs/openclaw-unicity"><img src="https://img.shields.io/npm/v/@unicitylabs/openclaw-unicity" alt="npm version" /></a>
9
9
  <a href="https://github.com/unicitynetwork/openclaw-unicity/blob/main/LICENSE"><img src="https://img.shields.io/github/license/unicitynetwork/openclaw-unicity" alt="license" /></a>
10
+ <a href="https://deepwiki.com/unicitynetwork/openclaw-unicity"><img src="https://deepwiki.com/badge.svg" alt="Ask DeepWiki"></a>
10
11
  </p>
11
12
 
12
13
  ---
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@unicitylabs/openclaw-unicity",
3
- "version": "0.3.2",
3
+ "version": "0.3.4",
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",
package/src/channel.ts CHANGED
@@ -453,6 +453,25 @@ export const unicityChannelPlugin = {
453
453
  replyToId?: string;
454
454
  };
455
455
 
456
+ // Nostr pubkey for self-message detection and reply-to-self detection.
457
+ // Group messages use the 32-byte x-only Nostr pubkey (event.pubkey),
458
+ // NOT the 33-byte compressed chainPubkey.
459
+ const myNostrPubkey = sphere.groupChat?.getMyPublicKey?.() ?? null;
460
+
461
+ // Detect if a group message is a reply to one of the agent's own messages.
462
+ // Used to set WasMentioned so the mention gate treats replies-to-self as
463
+ // implicit mentions (same pattern Discord uses for thread replies).
464
+ function isReplyToSelf(msg: GroupMsg): boolean {
465
+ if (!msg.replyToId || !myNostrPubkey) return false;
466
+ try {
467
+ const messages = sphere.groupChat?.getMessages?.(msg.groupId) ?? [];
468
+ const repliedTo = messages.find((m: { id: string }) => m.id === msg.replyToId);
469
+ return repliedTo?.senderPubkey === myNostrPubkey;
470
+ } catch {
471
+ return false;
472
+ }
473
+ }
474
+
456
475
  function dispatchGroupMessage(msg: GroupMsg): void {
457
476
  const senderName = msg.senderNametag ?? msg.senderPubkey.slice(0, 12);
458
477
  const groupData = sphere.groupChat?.getGroup?.(msg.groupId);
@@ -461,6 +480,15 @@ export const unicityChannelPlugin = {
461
480
  const metadataHeader = `[SenderName: ${senderName} | SenderId: ${msg.senderPubkey} | GroupId: ${msg.groupId} | GroupName: ${groupName} | IsOwner: ${isOwner} | CommandAuthorized: ${isOwner}]`;
462
481
  const sanitizedContent = msg.content.replace(/\[(?:SenderName|SenderId|IsOwner|CommandAuthorized|GroupId|GroupName)\s*:/gi, "[BLOCKED:");
463
482
 
483
+ // Detect if the agent was mentioned — either by @nametag in the text
484
+ // or by replying to the agent's own message (implicit mention, mirrors
485
+ // Discord's behavior). Without this, the mention gate skips the message.
486
+ const agentTag = sphere.identity?.nametag?.replace(/^@/, "");
487
+ const wasTextMentioned = agentTag
488
+ ? msg.content.toLowerCase().includes(`@${agentTag.toLowerCase()}`)
489
+ : false;
490
+ const wasMentioned = wasTextMentioned || isReplyToSelf(msg) || undefined;
491
+
464
492
  ctx.log?.info(`[${ctx.account.accountId}] Group message from ${senderName} in ${groupName}: ${msg.content.slice(0, 80)}`);
465
493
 
466
494
  const inboundCtx = runtime.channel.reply.finalizeInboundContext({
@@ -479,6 +507,7 @@ export const unicityChannelPlugin = {
479
507
  SenderId: msg.senderPubkey,
480
508
  IsOwner: isOwner,
481
509
  CommandAuthorized: isOwner,
510
+ WasMentioned: wasMentioned,
482
511
  });
483
512
 
484
513
  runtime.channel.reply
@@ -490,7 +519,7 @@ export const unicityChannelPlugin = {
490
519
  const text = payload.text;
491
520
  if (!text) return;
492
521
  try {
493
- await sphere.groupChat.sendMessage(msg.groupId, text);
522
+ await sphere.groupChat.sendMessage(msg.groupId, text, msg.id);
494
523
  ctx.log?.info(`[${ctx.account.accountId}] Group message sent to ${groupName}: ${text.slice(0, 80)}`);
495
524
  } catch (err) {
496
525
  ctx.log?.error(`[${ctx.account.accountId}] Failed to send group message to ${groupName}: ${err}`);
@@ -509,11 +538,6 @@ export const unicityChannelPlugin = {
509
538
  });
510
539
  }
511
540
 
512
- // Nostr pubkey for self-message detection. Group messages use the 32-byte
513
- // x-only Nostr pubkey (event.pubkey), NOT the 33-byte compressed chainPubkey.
514
- // sphere.groupChat.getMyPublicKey() returns the correct Nostr-format key.
515
- const myNostrPubkey = sphere.groupChat?.getMyPublicKey?.() ?? null;
516
-
517
541
  // Per-group backfill state: buffer messages during the initial burst, then
518
542
  // switch to live dispatch once the burst settles.
519
543
  const groupBackfillStates = new Map<string, GroupBackfillState>();