@silicaclaw/cli 2026.3.20-12 → 2026.3.20-13

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/CHANGELOG.md CHANGED
@@ -2,6 +2,12 @@
2
2
 
3
3
  ## v1.0 beta - 2026-03-20
4
4
 
5
+ ### 2026.3.20-13
6
+
7
+ - release build:
8
+ - prepared another fresh latest-channel package build without publishing
9
+ - regenerated the npm tarball through the verified release packing workflow
10
+
5
11
  ### 2026.3.20-12
6
12
 
7
13
  - release build:
package/VERSION CHANGED
@@ -1 +1 @@
1
- v2026.3.20-12
1
+ v2026.3.20-13
@@ -38,7 +38,7 @@ type PrivateMessageView = {
38
38
  body: string;
39
39
  created_at: number;
40
40
  is_self: boolean;
41
- delivery_status: "sent" | "received" | "read";
41
+ delivery_status: "sent" | "direct-sent" | "fallback-sent" | "received" | "read";
42
42
  };
43
43
  type RuntimeMessageGovernance = SocialMessageGovernanceConfig;
44
44
  type OpenClawBridgeStatus = {
@@ -181,6 +181,7 @@ export declare class LocalNodeService {
181
181
  private privateEncryptionKeyPair;
182
182
  private privatePeerRoutes;
183
183
  private privateMessageBodyCache;
184
+ private privateMessageDeliveryStatusCache;
184
185
  private messageGovernance;
185
186
  private privateMessagesPersistDirty;
186
187
  private privateMessageReceiptsPersistDirty;
@@ -787,6 +787,7 @@ class LocalNodeService {
787
787
  privateEncryptionKeyPair = null;
788
788
  privatePeerRoutes = {};
789
789
  privateMessageBodyCache = new Map();
790
+ privateMessageDeliveryStatusCache = new Map();
790
791
  messageGovernance;
791
792
  privateMessagesPersistDirty = false;
792
793
  privateMessageReceiptsPersistDirty = false;
@@ -1674,7 +1675,9 @@ class LocalNodeService {
1674
1675
  body: this.decryptPrivateMessageBody(message),
1675
1676
  created_at: message.created_at,
1676
1677
  is_self: message.from_agent_id === this.identity?.agent_id,
1677
- delivery_status: receiptsByMessageId.get(message.message_id) || "sent",
1678
+ delivery_status: receiptsByMessageId.get(message.message_id) ||
1679
+ this.privateMessageDeliveryStatusCache.get(message.message_id) ||
1680
+ (message.from_agent_id === this.identity?.agent_id ? "fallback-sent" : "sent"),
1678
1681
  }));
1679
1682
  }
1680
1683
  async sendPrivateMessage(input) {
@@ -1688,12 +1691,9 @@ class LocalNodeService {
1688
1691
  return { sent: false, reason: "self_private_message_not_allowed" };
1689
1692
  }
1690
1693
  const toPeerId = this.privatePeerRoutes[toAgentId] || "";
1691
- if (!toAgentId || !toPeerId || !recipientKey || !body) {
1694
+ if (!toAgentId || !recipientKey || !body) {
1692
1695
  return { sent: false, reason: "invalid_private_message_input" };
1693
1696
  }
1694
- if (typeof this.network.sendDirect !== "function") {
1695
- return { sent: false, reason: "direct_delivery_not_supported" };
1696
- }
1697
1697
  const encrypted = (0, core_1.encryptPrivatePayload)({
1698
1698
  plaintext: body,
1699
1699
  recipient_public_key: recipientKey,
@@ -1710,11 +1710,28 @@ class LocalNodeService {
1710
1710
  nonce: encrypted.nonce,
1711
1711
  created_at: Date.now(),
1712
1712
  });
1713
+ this.privateMessageBodyCache.set(message.message_id, body);
1713
1714
  this.ingestPrivateMessage(message);
1714
1715
  await this.persistPrivateMessages();
1715
- await this.network.sendDirect(toPeerId, PRIVATE_MESSAGE_TOPIC, message);
1716
+ let reason = "fallback-sent";
1717
+ if (toPeerId && typeof this.network.sendDirect === "function") {
1718
+ try {
1719
+ await this.network.sendDirect(toPeerId, PRIVATE_MESSAGE_TOPIC, message);
1720
+ reason = "direct-sent";
1721
+ }
1722
+ catch {
1723
+ await this.publish(PRIVATE_MESSAGE_TOPIC, message);
1724
+ }
1725
+ }
1726
+ else {
1727
+ await this.publish(PRIVATE_MESSAGE_TOPIC, message);
1728
+ }
1729
+ this.privateMessageDeliveryStatusCache.set(message.message_id, reason);
1716
1730
  const view = this.getPrivateMessages(message.conversation_id).find((item) => item.message_id === message.message_id);
1717
- return { sent: true, reason: "sent", message: view };
1731
+ if (view) {
1732
+ view.delivery_status = reason;
1733
+ }
1734
+ return { sent: true, reason, message: view };
1718
1735
  }
1719
1736
  getOpenClawBridgeStatus() {
1720
1737
  const now = Date.now();
@@ -2555,6 +2572,12 @@ class LocalNodeService {
2555
2572
  this.network.subscribe(SOCIAL_MESSAGE_OBSERVATION_TOPIC, (data, meta) => {
2556
2573
  this.onMessage(SOCIAL_MESSAGE_OBSERVATION_TOPIC, data, meta);
2557
2574
  });
2575
+ this.network.subscribe(PRIVATE_MESSAGE_TOPIC, (data, meta) => {
2576
+ this.onDirectMessage(PRIVATE_MESSAGE_TOPIC, data, meta);
2577
+ });
2578
+ this.network.subscribe(PRIVATE_MESSAGE_RECEIPT_TOPIC, (data, meta) => {
2579
+ this.onDirectMessage(PRIVATE_MESSAGE_RECEIPT_TOPIC, data, meta);
2580
+ });
2558
2581
  if (typeof this.network.subscribeDirect === "function") {
2559
2582
  this.network.subscribeDirect(PRIVATE_MESSAGE_TOPIC, (data, meta) => {
2560
2583
  this.onDirectMessage(PRIVATE_MESSAGE_TOPIC, data, meta);
@@ -3257,7 +3280,12 @@ class LocalNodeService {
3257
3280
  created_at: Date.now(),
3258
3281
  });
3259
3282
  this.ingestPrivateMessageReceipt(receipt);
3260
- await this.network.sendDirect(replyPeerId, PRIVATE_MESSAGE_RECEIPT_TOPIC, receipt);
3283
+ try {
3284
+ await this.network.sendDirect(replyPeerId, PRIVATE_MESSAGE_RECEIPT_TOPIC, receipt);
3285
+ }
3286
+ catch {
3287
+ await this.publish(PRIVATE_MESSAGE_RECEIPT_TOPIC, receipt);
3288
+ }
3261
3289
  await this.persistPrivateMessageReceipts();
3262
3290
  }
3263
3291
  normalizeIncomingPrivateMessage(value) {
@@ -3387,12 +3415,19 @@ class LocalNodeService {
3387
3415
  }
3388
3416
  this.privateMessages = this.normalizePrivateMessages(this.privateMessages);
3389
3417
  const validIds = new Set(this.privateMessages.map((item) => item.message_id));
3390
- this.privateMessageBodyCache.delete(message.message_id);
3418
+ if (message.from_agent_id !== this.identity?.agent_id) {
3419
+ this.privateMessageBodyCache.delete(message.message_id);
3420
+ }
3391
3421
  for (const key of Array.from(this.privateMessageBodyCache.keys())) {
3392
3422
  if (!validIds.has(key)) {
3393
3423
  this.privateMessageBodyCache.delete(key);
3394
3424
  }
3395
3425
  }
3426
+ for (const key of Array.from(this.privateMessageDeliveryStatusCache.keys())) {
3427
+ if (!validIds.has(key)) {
3428
+ this.privateMessageDeliveryStatusCache.delete(key);
3429
+ }
3430
+ }
3396
3431
  }
3397
3432
  ingestPrivateMessageReceipt(receipt) {
3398
3433
  const existing = this.privateMessageReceipts.findIndex((item) => item.receipt_id === receipt.receipt_id);
@@ -3403,6 +3438,7 @@ class LocalNodeService {
3403
3438
  this.privateMessageReceipts.push(receipt);
3404
3439
  }
3405
3440
  this.privateMessageReceipts = this.normalizePrivateMessageReceipts(this.privateMessageReceipts);
3441
+ this.privateMessageDeliveryStatusCache.set(receipt.message_id, receipt.status);
3406
3442
  }
3407
3443
  normalizeIncomingSocialMessage(value) {
3408
3444
  if (typeof value !== "object" || value === null) {
@@ -3796,7 +3832,11 @@ async function main() {
3796
3832
  body: String(req.body?.body || ""),
3797
3833
  });
3798
3834
  sendOk(res, result, {
3799
- message: result.sent ? "Private message sent" : `Private message skipped: ${result.reason}`,
3835
+ message: result.sent
3836
+ ? (result.reason === "direct-sent"
3837
+ ? "Private message sent directly"
3838
+ : "Private message sent via encrypted fallback")
3839
+ : `Private message skipped: ${result.reason}`,
3800
3840
  });
3801
3841
  }));
3802
3842
  app.get("/api/openclaw/bridge", (_req, res) => {
@@ -692,6 +692,13 @@ const APP_UPDATE_SESSION_KEY = 'silicaclaw_pending_updated_version';
692
692
  }
693
693
 
694
694
  function renderPrivate() {
695
+ const privateDeliveryLabel = (status) => {
696
+ if (status === 'direct-sent') return 'Direct';
697
+ if (status === 'fallback-sent') return 'Fallback';
698
+ if (status === 'received') return 'Received';
699
+ if (status === 'read') return 'Read';
700
+ return 'Sent';
701
+ };
695
702
  document.getElementById('privateStateMeta').textContent = privateState?.enabled
696
703
  ? `${privateConversations.length} conversation(s)`
697
704
  : 'Private messaging unavailable';
@@ -716,7 +723,7 @@ const APP_UPDATE_SESSION_KEY = 'silicaclaw_pending_updated_version';
716
723
  <div style="display:flex; align-items:center; justify-content:space-between; gap:12px;">
717
724
  <div>
718
725
  <strong>${item.is_self ? 'Me' : escapeHtml(privateTarget?.display_name || item.from_agent_id || 'Unknown')}</strong>
719
- <span class="tag-chip" style="margin-left:8px;">${escapeHtml(item.delivery_status)}</span>
726
+ <span class="tag-chip" style="margin-left:8px;">${escapeHtml(privateDeliveryLabel(item.delivery_status))}</span>
720
727
  </div>
721
728
  <div class="mono" style="color:#90a2c3;">${new Date(item.created_at).toLocaleString()}</div>
722
729
  </div>
@@ -899,7 +899,7 @@ type PrivateMessageView = {
899
899
  body: string;
900
900
  created_at: number;
901
901
  is_self: boolean;
902
- delivery_status: "sent" | "received" | "read";
902
+ delivery_status: "sent" | "direct-sent" | "fallback-sent" | "received" | "read";
903
903
  };
904
904
 
905
905
  type RuntimeMessageGovernance = SocialMessageGovernanceConfig;
@@ -1047,6 +1047,7 @@ export class LocalNodeService {
1047
1047
  private privateEncryptionKeyPair: PrivateEncryptionKeyPair | null = null;
1048
1048
  private privatePeerRoutes: Record<string, string> = {};
1049
1049
  private privateMessageBodyCache = new Map<string, string>();
1050
+ private privateMessageDeliveryStatusCache = new Map<string, PrivateMessageView["delivery_status"]>();
1050
1051
  private messageGovernance: RuntimeMessageGovernance;
1051
1052
  private privateMessagesPersistDirty = false;
1052
1053
  private privateMessageReceiptsPersistDirty = false;
@@ -2026,7 +2027,10 @@ export class LocalNodeService {
2026
2027
  body: this.decryptPrivateMessageBody(message),
2027
2028
  created_at: message.created_at,
2028
2029
  is_self: message.from_agent_id === this.identity?.agent_id,
2029
- delivery_status: receiptsByMessageId.get(message.message_id) || "sent",
2030
+ delivery_status:
2031
+ receiptsByMessageId.get(message.message_id) ||
2032
+ this.privateMessageDeliveryStatusCache.get(message.message_id) ||
2033
+ (message.from_agent_id === this.identity?.agent_id ? "fallback-sent" : "sent"),
2030
2034
  }));
2031
2035
  }
2032
2036
 
@@ -2045,12 +2049,9 @@ export class LocalNodeService {
2045
2049
  return { sent: false, reason: "self_private_message_not_allowed" };
2046
2050
  }
2047
2051
  const toPeerId = this.privatePeerRoutes[toAgentId] || "";
2048
- if (!toAgentId || !toPeerId || !recipientKey || !body) {
2052
+ if (!toAgentId || !recipientKey || !body) {
2049
2053
  return { sent: false, reason: "invalid_private_message_input" };
2050
2054
  }
2051
- if (typeof this.network.sendDirect !== "function") {
2052
- return { sent: false, reason: "direct_delivery_not_supported" };
2053
- }
2054
2055
  const encrypted = encryptPrivatePayload({
2055
2056
  plaintext: body,
2056
2057
  recipient_public_key: recipientKey,
@@ -2067,11 +2068,26 @@ export class LocalNodeService {
2067
2068
  nonce: encrypted.nonce,
2068
2069
  created_at: Date.now(),
2069
2070
  });
2071
+ this.privateMessageBodyCache.set(message.message_id, body);
2070
2072
  this.ingestPrivateMessage(message);
2071
2073
  await this.persistPrivateMessages();
2072
- await this.network.sendDirect(toPeerId, PRIVATE_MESSAGE_TOPIC, message);
2074
+ let reason = "fallback-sent";
2075
+ if (toPeerId && typeof this.network.sendDirect === "function") {
2076
+ try {
2077
+ await this.network.sendDirect(toPeerId, PRIVATE_MESSAGE_TOPIC, message);
2078
+ reason = "direct-sent";
2079
+ } catch {
2080
+ await this.publish(PRIVATE_MESSAGE_TOPIC, message);
2081
+ }
2082
+ } else {
2083
+ await this.publish(PRIVATE_MESSAGE_TOPIC, message);
2084
+ }
2085
+ this.privateMessageDeliveryStatusCache.set(message.message_id, reason as PrivateMessageView["delivery_status"]);
2073
2086
  const view = this.getPrivateMessages(message.conversation_id).find((item) => item.message_id === message.message_id);
2074
- return { sent: true, reason: "sent", message: view };
2087
+ if (view) {
2088
+ view.delivery_status = reason as PrivateMessageView["delivery_status"];
2089
+ }
2090
+ return { sent: true, reason, message: view };
2075
2091
  }
2076
2092
 
2077
2093
  getOpenClawBridgeStatus(): OpenClawBridgeStatus {
@@ -3006,6 +3022,12 @@ export class LocalNodeService {
3006
3022
  this.network.subscribe(SOCIAL_MESSAGE_OBSERVATION_TOPIC, (data: SocialMessageObservationRecord, meta?: { peerId?: string }) => {
3007
3023
  this.onMessage(SOCIAL_MESSAGE_OBSERVATION_TOPIC, data, meta);
3008
3024
  });
3025
+ this.network.subscribe(PRIVATE_MESSAGE_TOPIC, (data: PrivateMessageRecord, meta?: { peerId?: string }) => {
3026
+ this.onDirectMessage(PRIVATE_MESSAGE_TOPIC, data, meta);
3027
+ });
3028
+ this.network.subscribe(PRIVATE_MESSAGE_RECEIPT_TOPIC, (data: PrivateMessageReceiptRecord, meta?: { peerId?: string }) => {
3029
+ this.onDirectMessage(PRIVATE_MESSAGE_RECEIPT_TOPIC, data, meta);
3030
+ });
3009
3031
  if (typeof this.network.subscribeDirect === "function") {
3010
3032
  this.network.subscribeDirect(PRIVATE_MESSAGE_TOPIC, (data: PrivateMessageRecord, meta?: { peerId?: string }) => {
3011
3033
  this.onDirectMessage(PRIVATE_MESSAGE_TOPIC, data, meta);
@@ -3799,7 +3821,11 @@ export class LocalNodeService {
3799
3821
  created_at: Date.now(),
3800
3822
  });
3801
3823
  this.ingestPrivateMessageReceipt(receipt);
3802
- await this.network.sendDirect(replyPeerId, PRIVATE_MESSAGE_RECEIPT_TOPIC, receipt);
3824
+ try {
3825
+ await this.network.sendDirect(replyPeerId, PRIVATE_MESSAGE_RECEIPT_TOPIC, receipt);
3826
+ } catch {
3827
+ await this.publish(PRIVATE_MESSAGE_RECEIPT_TOPIC, receipt);
3828
+ }
3803
3829
  await this.persistPrivateMessageReceipts();
3804
3830
  }
3805
3831
 
@@ -3938,12 +3964,19 @@ export class LocalNodeService {
3938
3964
  }
3939
3965
  this.privateMessages = this.normalizePrivateMessages(this.privateMessages);
3940
3966
  const validIds = new Set(this.privateMessages.map((item) => item.message_id));
3941
- this.privateMessageBodyCache.delete(message.message_id);
3967
+ if (message.from_agent_id !== this.identity?.agent_id) {
3968
+ this.privateMessageBodyCache.delete(message.message_id);
3969
+ }
3942
3970
  for (const key of Array.from(this.privateMessageBodyCache.keys())) {
3943
3971
  if (!validIds.has(key)) {
3944
3972
  this.privateMessageBodyCache.delete(key);
3945
3973
  }
3946
3974
  }
3975
+ for (const key of Array.from(this.privateMessageDeliveryStatusCache.keys())) {
3976
+ if (!validIds.has(key)) {
3977
+ this.privateMessageDeliveryStatusCache.delete(key);
3978
+ }
3979
+ }
3947
3980
  }
3948
3981
 
3949
3982
  private ingestPrivateMessageReceipt(receipt: PrivateMessageReceiptRecord): void {
@@ -3954,6 +3987,7 @@ export class LocalNodeService {
3954
3987
  this.privateMessageReceipts.push(receipt);
3955
3988
  }
3956
3989
  this.privateMessageReceipts = this.normalizePrivateMessageReceipts(this.privateMessageReceipts);
3990
+ this.privateMessageDeliveryStatusCache.set(receipt.message_id, receipt.status);
3957
3991
  }
3958
3992
 
3959
3993
  private normalizeIncomingSocialMessage(value: unknown): SocialMessageRecord | null {
@@ -4441,7 +4475,11 @@ export async function main() {
4441
4475
  body: String(req.body?.body || ""),
4442
4476
  });
4443
4477
  sendOk(res, result, {
4444
- message: result.sent ? "Private message sent" : `Private message skipped: ${result.reason}`,
4478
+ message: result.sent
4479
+ ? (result.reason === "direct-sent"
4480
+ ? "Private message sent directly"
4481
+ : "Private message sent via encrypted fallback")
4482
+ : `Private message skipped: ${result.reason}`,
4445
4483
  });
4446
4484
  })
4447
4485
  );
@@ -1 +1 @@
1
- 2026.3.20-beta.12
1
+ 2026.3.20-beta.13
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "silicaclaw-broadcast",
3
- "version": "2026.3.20-beta.12",
3
+ "version": "2026.3.20-beta.13",
4
4
  "display_name": "SilicaClaw Broadcast",
5
5
  "description": "Official OpenClaw skill for a bounded local SilicaClaw broadcast workflow: read public broadcasts, publish public broadcasts, and optionally forward owner-relevant summaries through OpenClaw's native channel.",
6
6
  "entrypoints": {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@silicaclaw/cli",
3
- "version": "2026.3.20-12",
3
+ "version": "2026.3.20-13",
4
4
  "private": false,
5
5
  "publishConfig": {
6
6
  "access": "public"