libp2p-mesh 2026.5.24 → 2026.5.25

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.
@@ -50,6 +50,38 @@ export function registerLibp2pMesh(api) {
50
50
  api.logger.error?.(`[libp2p-mesh] Identity exchange error: ${String(err)}`);
51
51
  });
52
52
  }
53
+ else if (msg.type === "direct") {
54
+ // sendToPeer 包装了一层 direct 外壳,原始 identity 消息藏在 payload 里。
55
+ // 检测并处理:注册对方 + 发送自己的身份回复。
56
+ let handled = false;
57
+ try {
58
+ const raw = JSON.parse(msg.payload);
59
+ if (raw && raw.type === "identity") {
60
+ const localIdentity = peerIdentityMap.getLocalIdentity();
61
+ handleIdentityMessage(msg, {
62
+ peerIdentityMap,
63
+ localPeerId: localIdentity?.sessionKey ?? "",
64
+ localAgentId: api.name,
65
+ localChannel: relayChannel ?? "",
66
+ localAccountId: relayAccountId ?? "",
67
+ localInstanceId: localIdentity?.instanceId,
68
+ send: async (targetPeerId, replyMsg) => {
69
+ mesh.sendToPeer(targetPeerId, JSON.stringify(replyMsg)).catch(() => { });
70
+ },
71
+ logger: api.logger,
72
+ }).catch((err) => {
73
+ api.logger.error?.(`[libp2p-mesh] Identity exchange error: ${String(err)}`);
74
+ });
75
+ handled = true;
76
+ }
77
+ }
78
+ catch {
79
+ // payload 不是 JSON,正常走 direct 消息逻辑
80
+ }
81
+ if (!handled) {
82
+ handleP2PInbound(msg, buildInboundDeps());
83
+ }
84
+ }
53
85
  else {
54
86
  handleP2PInbound(msg, buildInboundDeps());
55
87
  }
@@ -132,6 +164,22 @@ export function registerLibp2pMesh(api) {
132
164
  peerIdentityMap.unregister(peerId);
133
165
  peerIdentityMap.saveNow().catch(() => { });
134
166
  });
167
+ // Actively announce identity to all currently-connected peers.
168
+ // This covers the race where mDNS discovery fires peer:connect during
169
+ // node.start() before onPeerConnect was registered — those peers are
170
+ // already connected but never received our identity.
171
+ if (relayChannel && relayAccountId) {
172
+ const identityMsg = buildIdentityMessage(localPeerId ?? "", api.name, relayChannel, relayAccountId, localInstanceId);
173
+ const connectedNow = mesh.getConnectedPeers();
174
+ if (connectedNow.length > 0) {
175
+ api.logger.info?.(`[libp2p-mesh] Sending initial identity to ${connectedNow.length} connected peer(s)`);
176
+ for (const peerId of connectedNow) {
177
+ mesh.sendToPeer(peerId, JSON.stringify(identityMsg)).catch((err) => {
178
+ api.logger.debug?.(`[libp2p-mesh] Initial identity send to ${peerId} failed: ${String(err)}`);
179
+ });
180
+ }
181
+ }
182
+ }
135
183
  const identity = mesh.getInstanceIdentity();
136
184
  api.logger.info?.(`[libp2p-mesh] Service started. Peer ID: ${localPeerId}`);
137
185
  if (identity) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "libp2p-mesh",
3
- "version": "2026.5.24",
3
+ "version": "2026.5.25",
4
4
  "description": "OpenClaw libp2p P2P mesh network plugin for cross-instance agent communication",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
package/src/plugin.ts CHANGED
@@ -58,6 +58,36 @@ export function registerLibp2pMesh(api: OpenClawPluginApi) {
58
58
  }).catch((err) => {
59
59
  api.logger.error?.(`[libp2p-mesh] Identity exchange error: ${String(err)}`);
60
60
  });
61
+ } else if (msg.type === "direct") {
62
+ // sendToPeer 包装了一层 direct 外壳,原始 identity 消息藏在 payload 里。
63
+ // 检测并处理:注册对方 + 发送自己的身份回复。
64
+ let handled = false;
65
+ try {
66
+ const raw = JSON.parse(msg.payload);
67
+ if (raw && raw.type === "identity") {
68
+ const localIdentity = peerIdentityMap.getLocalIdentity();
69
+ handleIdentityMessage(msg, {
70
+ peerIdentityMap,
71
+ localPeerId: localIdentity?.sessionKey ?? "",
72
+ localAgentId: api.name,
73
+ localChannel: relayChannel ?? "",
74
+ localAccountId: relayAccountId ?? "",
75
+ localInstanceId: localIdentity?.instanceId,
76
+ send: async (targetPeerId: string, replyMsg: any) => {
77
+ mesh.sendToPeer(targetPeerId, JSON.stringify(replyMsg)).catch(() => {});
78
+ },
79
+ logger: api.logger,
80
+ }).catch((err) => {
81
+ api.logger.error?.(`[libp2p-mesh] Identity exchange error: ${String(err)}`);
82
+ });
83
+ handled = true;
84
+ }
85
+ } catch {
86
+ // payload 不是 JSON,正常走 direct 消息逻辑
87
+ }
88
+ if (!handled) {
89
+ handleP2PInbound(msg, buildInboundDeps());
90
+ }
61
91
  } else {
62
92
  handleP2PInbound(msg, buildInboundDeps());
63
93
  }
@@ -165,6 +195,33 @@ export function registerLibp2pMesh(api: OpenClawPluginApi) {
165
195
  peerIdentityMap.saveNow().catch(() => {});
166
196
  });
167
197
 
198
+ // Actively announce identity to all currently-connected peers.
199
+ // This covers the race where mDNS discovery fires peer:connect during
200
+ // node.start() before onPeerConnect was registered — those peers are
201
+ // already connected but never received our identity.
202
+ if (relayChannel && relayAccountId) {
203
+ const identityMsg = buildIdentityMessage(
204
+ localPeerId ?? "",
205
+ api.name,
206
+ relayChannel,
207
+ relayAccountId,
208
+ localInstanceId,
209
+ );
210
+ const connectedNow = mesh.getConnectedPeers();
211
+ if (connectedNow.length > 0) {
212
+ api.logger.info?.(
213
+ `[libp2p-mesh] Sending initial identity to ${connectedNow.length} connected peer(s)`,
214
+ );
215
+ for (const peerId of connectedNow) {
216
+ mesh.sendToPeer(peerId, JSON.stringify(identityMsg)).catch((err) => {
217
+ api.logger.debug?.(
218
+ `[libp2p-mesh] Initial identity send to ${peerId} failed: ${String(err)}`,
219
+ );
220
+ });
221
+ }
222
+ }
223
+ }
224
+
168
225
  const identity = mesh.getInstanceIdentity();
169
226
  api.logger.info?.(`[libp2p-mesh] Service started. Peer ID: ${localPeerId}`);
170
227
  if (identity) {