@silicaclaw/cli 2026.3.20-2 → 2026.3.20-21

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.
Files changed (145) hide show
  1. package/CHANGELOG.md +108 -0
  2. package/INSTALL.md +13 -7
  3. package/README.md +60 -12
  4. package/VERSION +1 -1
  5. package/apps/local-console/dist/apps/local-console/src/server.d.ts +139 -3
  6. package/apps/local-console/dist/apps/local-console/src/server.js +1029 -92
  7. package/apps/local-console/dist/packages/core/src/index.d.ts +2 -0
  8. package/apps/local-console/dist/packages/core/src/index.js +2 -0
  9. package/apps/local-console/dist/packages/core/src/privateCrypto.d.ts +17 -0
  10. package/apps/local-console/dist/packages/core/src/privateCrypto.js +40 -0
  11. package/apps/local-console/dist/packages/core/src/privateMessage.d.ts +23 -0
  12. package/apps/local-console/dist/packages/core/src/privateMessage.js +74 -0
  13. package/apps/local-console/dist/packages/core/src/profile.js +2 -0
  14. package/apps/local-console/dist/packages/core/src/publicProfileSummary.d.ts +4 -0
  15. package/apps/local-console/dist/packages/core/src/publicProfileSummary.js +3 -0
  16. package/apps/local-console/dist/packages/core/src/types.d.ts +40 -0
  17. package/apps/local-console/dist/packages/network/src/relayPreview.d.ts +12 -0
  18. package/apps/local-console/dist/packages/network/src/relayPreview.js +108 -8
  19. package/apps/local-console/dist/packages/network/src/types.d.ts +4 -0
  20. package/apps/local-console/dist/packages/storage/src/repos.d.ts +27 -1
  21. package/apps/local-console/dist/packages/storage/src/repos.js +35 -1
  22. package/apps/local-console/public/app/app.js +502 -11
  23. package/apps/local-console/public/app/events.js +21 -0
  24. package/apps/local-console/public/app/network.js +144 -32
  25. package/apps/local-console/public/app/overview.js +57 -27
  26. package/apps/local-console/public/app/social.js +342 -105
  27. package/apps/local-console/public/app/styles.css +149 -43
  28. package/apps/local-console/public/app/template.js +196 -100
  29. package/apps/local-console/public/app/translations.js +438 -316
  30. package/apps/local-console/src/server.ts +1177 -90
  31. package/apps/public-explorer/public/app/template.js +2 -2
  32. package/apps/public-explorer/public/app/translations.js +36 -36
  33. package/docs/NEW_USER_OPERATIONS.md +5 -5
  34. package/docs/OPENCLAW_BRIDGE.md +7 -7
  35. package/docs/OPENCLAW_BRIDGE_ZH.md +6 -6
  36. package/node_modules/@silicaclaw/core/dist/packages/core/src/index.d.ts +2 -0
  37. package/node_modules/@silicaclaw/core/dist/packages/core/src/index.js +2 -0
  38. package/node_modules/@silicaclaw/core/dist/packages/core/src/privateCrypto.d.ts +17 -0
  39. package/node_modules/@silicaclaw/core/dist/packages/core/src/privateCrypto.js +40 -0
  40. package/node_modules/@silicaclaw/core/dist/packages/core/src/privateMessage.d.ts +23 -0
  41. package/node_modules/@silicaclaw/core/dist/packages/core/src/privateMessage.js +74 -0
  42. package/node_modules/@silicaclaw/core/dist/packages/core/src/profile.js +2 -0
  43. package/node_modules/@silicaclaw/core/dist/packages/core/src/publicProfileSummary.d.ts +4 -0
  44. package/node_modules/@silicaclaw/core/dist/packages/core/src/publicProfileSummary.js +3 -0
  45. package/node_modules/@silicaclaw/core/dist/packages/core/src/types.d.ts +40 -0
  46. package/node_modules/@silicaclaw/core/package.json +2 -2
  47. package/node_modules/@silicaclaw/core/src/index.ts +2 -0
  48. package/node_modules/@silicaclaw/core/src/privateCrypto.ts +57 -0
  49. package/node_modules/@silicaclaw/core/src/privateMessage.ts +101 -0
  50. package/node_modules/@silicaclaw/core/src/profile.ts +2 -0
  51. package/node_modules/@silicaclaw/core/src/publicProfileSummary.ts +7 -0
  52. package/node_modules/@silicaclaw/core/src/types.ts +44 -0
  53. package/node_modules/@silicaclaw/network/dist/packages/network/src/relayPreview.d.ts +12 -0
  54. package/node_modules/@silicaclaw/network/dist/packages/network/src/relayPreview.js +108 -8
  55. package/node_modules/@silicaclaw/network/dist/packages/network/src/types.d.ts +4 -0
  56. package/node_modules/@silicaclaw/network/src/relayPreview.ts +120 -10
  57. package/node_modules/@silicaclaw/network/src/types.ts +2 -0
  58. package/node_modules/@silicaclaw/storage/dist/packages/core/src/index.d.ts +2 -0
  59. package/node_modules/@silicaclaw/storage/dist/packages/core/src/index.js +2 -0
  60. package/node_modules/@silicaclaw/storage/dist/packages/core/src/privateCrypto.d.ts +17 -0
  61. package/node_modules/@silicaclaw/storage/dist/packages/core/src/privateCrypto.js +40 -0
  62. package/node_modules/@silicaclaw/storage/dist/packages/core/src/privateMessage.d.ts +23 -0
  63. package/node_modules/@silicaclaw/storage/dist/packages/core/src/privateMessage.js +74 -0
  64. package/node_modules/@silicaclaw/storage/dist/packages/core/src/profile.js +2 -0
  65. package/node_modules/@silicaclaw/storage/dist/packages/core/src/publicProfileSummary.d.ts +4 -0
  66. package/node_modules/@silicaclaw/storage/dist/packages/core/src/publicProfileSummary.js +3 -0
  67. package/node_modules/@silicaclaw/storage/dist/packages/core/src/types.d.ts +40 -0
  68. package/node_modules/@silicaclaw/storage/dist/packages/storage/src/repos.d.ts +27 -1
  69. package/node_modules/@silicaclaw/storage/dist/packages/storage/src/repos.js +35 -1
  70. package/node_modules/@silicaclaw/storage/package.json +2 -2
  71. package/node_modules/@silicaclaw/storage/src/repos.ts +59 -1
  72. package/openclaw-skills/silicaclaw-bridge-setup/SKILL.md +18 -0
  73. package/openclaw-skills/silicaclaw-bridge-setup/VERSION +1 -1
  74. package/openclaw-skills/silicaclaw-bridge-setup/manifest.json +2 -2
  75. package/openclaw-skills/silicaclaw-broadcast/SKILL.md +18 -0
  76. package/openclaw-skills/silicaclaw-broadcast/VERSION +1 -1
  77. package/openclaw-skills/silicaclaw-broadcast/manifest.json +2 -2
  78. package/openclaw-skills/silicaclaw-network-config/SKILL.md +158 -0
  79. package/openclaw-skills/silicaclaw-network-config/VERSION +1 -0
  80. package/openclaw-skills/silicaclaw-network-config/agents/openai.yaml +6 -0
  81. package/openclaw-skills/silicaclaw-network-config/manifest.json +27 -0
  82. package/openclaw-skills/silicaclaw-network-config/references/network-modes.md +22 -0
  83. package/openclaw-skills/silicaclaw-network-config/references/owner-dialogue-cheatsheet-zh.md +47 -0
  84. package/openclaw-skills/silicaclaw-network-config/references/public-discovery.md +22 -0
  85. package/openclaw-skills/silicaclaw-owner-push/SKILL.md +18 -0
  86. package/openclaw-skills/silicaclaw-owner-push/VERSION +1 -1
  87. package/openclaw-skills/silicaclaw-owner-push/manifest.json +2 -2
  88. package/openclaw-skills/silicaclaw-owner-push/references/runtime-setup.md +3 -0
  89. package/openclaw-skills/silicaclaw-owner-push/scripts/owner-push-forwarder.mjs +151 -9
  90. package/package.json +1 -1
  91. package/packages/core/dist/packages/core/src/index.d.ts +2 -0
  92. package/packages/core/dist/packages/core/src/index.js +2 -0
  93. package/packages/core/dist/packages/core/src/privateCrypto.d.ts +17 -0
  94. package/packages/core/dist/packages/core/src/privateCrypto.js +40 -0
  95. package/packages/core/dist/packages/core/src/privateMessage.d.ts +23 -0
  96. package/packages/core/dist/packages/core/src/privateMessage.js +74 -0
  97. package/packages/core/dist/packages/core/src/profile.js +2 -0
  98. package/packages/core/dist/packages/core/src/publicProfileSummary.d.ts +4 -0
  99. package/packages/core/dist/packages/core/src/publicProfileSummary.js +3 -0
  100. package/packages/core/dist/packages/core/src/types.d.ts +40 -0
  101. package/packages/core/package.json +2 -2
  102. package/packages/core/src/index.ts +2 -0
  103. package/packages/core/src/privateCrypto.ts +57 -0
  104. package/packages/core/src/privateMessage.ts +101 -0
  105. package/packages/core/src/profile.ts +2 -0
  106. package/packages/core/src/publicProfileSummary.ts +7 -0
  107. package/packages/core/src/types.ts +44 -0
  108. package/packages/network/dist/packages/network/src/relayPreview.d.ts +12 -0
  109. package/packages/network/dist/packages/network/src/relayPreview.js +108 -8
  110. package/packages/network/dist/packages/network/src/types.d.ts +4 -0
  111. package/packages/network/src/relayPreview.ts +120 -10
  112. package/packages/network/src/types.ts +2 -0
  113. package/packages/storage/dist/packages/core/src/index.d.ts +2 -0
  114. package/packages/storage/dist/packages/core/src/index.js +2 -0
  115. package/packages/storage/dist/packages/core/src/privateCrypto.d.ts +17 -0
  116. package/packages/storage/dist/packages/core/src/privateCrypto.js +40 -0
  117. package/packages/storage/dist/packages/core/src/privateMessage.d.ts +23 -0
  118. package/packages/storage/dist/packages/core/src/privateMessage.js +74 -0
  119. package/packages/storage/dist/packages/core/src/profile.js +2 -0
  120. package/packages/storage/dist/packages/core/src/publicProfileSummary.d.ts +4 -0
  121. package/packages/storage/dist/packages/core/src/publicProfileSummary.js +3 -0
  122. package/packages/storage/dist/packages/core/src/types.d.ts +40 -0
  123. package/packages/storage/dist/packages/storage/src/repos.d.ts +27 -1
  124. package/packages/storage/dist/packages/storage/src/repos.js +35 -1
  125. package/packages/storage/package.json +2 -2
  126. package/packages/storage/src/repos.ts +59 -1
  127. package/scripts/silicaclaw-cli.mjs +4 -1
  128. package/scripts/silicaclaw-gateway.mjs +114 -2
  129. package/scripts/validate-openclaw-skill.mjs +19 -0
  130. package/node_modules/@silicaclaw/storage/dist/index.d.ts +0 -3
  131. package/node_modules/@silicaclaw/storage/dist/index.js +0 -19
  132. package/node_modules/@silicaclaw/storage/dist/jsonRepo.d.ts +0 -7
  133. package/node_modules/@silicaclaw/storage/dist/jsonRepo.js +0 -29
  134. package/node_modules/@silicaclaw/storage/dist/repos.d.ts +0 -61
  135. package/node_modules/@silicaclaw/storage/dist/repos.js +0 -67
  136. package/node_modules/@silicaclaw/storage/dist/socialRuntimeRepo.d.ts +0 -5
  137. package/node_modules/@silicaclaw/storage/dist/socialRuntimeRepo.js +0 -57
  138. package/packages/storage/dist/index.d.ts +0 -3
  139. package/packages/storage/dist/index.js +0 -19
  140. package/packages/storage/dist/jsonRepo.d.ts +0 -7
  141. package/packages/storage/dist/jsonRepo.js +0 -29
  142. package/packages/storage/dist/repos.d.ts +0 -61
  143. package/packages/storage/dist/repos.js +0 -67
  144. package/packages/storage/dist/socialRuntimeRepo.d.ts +0 -5
  145. package/packages/storage/dist/socialRuntimeRepo.js +0 -57
@@ -4,6 +4,8 @@ export * from "./identity";
4
4
  export * from "./profile";
5
5
  export * from "./presence";
6
6
  export * from "./socialMessage";
7
+ export * from "./privateCrypto";
8
+ export * from "./privateMessage";
7
9
  export * from "./indexing";
8
10
  export * from "./directory";
9
11
  export * from "./publicProfileSummary";
@@ -20,6 +20,8 @@ __exportStar(require("./identity"), exports);
20
20
  __exportStar(require("./profile"), exports);
21
21
  __exportStar(require("./presence"), exports);
22
22
  __exportStar(require("./socialMessage"), exports);
23
+ __exportStar(require("./privateCrypto"), exports);
24
+ __exportStar(require("./privateMessage"), exports);
23
25
  __exportStar(require("./indexing"), exports);
24
26
  __exportStar(require("./directory"), exports);
25
27
  __exportStar(require("./publicProfileSummary"), exports);
@@ -0,0 +1,17 @@
1
+ import { PrivateEncryptionKeyPair } from "./types";
2
+ export declare function createPrivateEncryptionKeyPair(now?: number): PrivateEncryptionKeyPair;
3
+ export declare function encryptPrivatePayload(input: {
4
+ plaintext: string;
5
+ recipient_public_key: string;
6
+ sender_keypair?: PrivateEncryptionKeyPair | null;
7
+ }): {
8
+ ciphertext: string;
9
+ nonce: string;
10
+ sender_encryption_public_key: string;
11
+ };
12
+ export declare function decryptPrivatePayload(input: {
13
+ ciphertext: string;
14
+ nonce: string;
15
+ sender_encryption_public_key: string;
16
+ recipient_private_key: string;
17
+ }): string | null;
@@ -0,0 +1,40 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.createPrivateEncryptionKeyPair = createPrivateEncryptionKeyPair;
7
+ exports.encryptPrivatePayload = encryptPrivatePayload;
8
+ exports.decryptPrivatePayload = decryptPrivatePayload;
9
+ const tweetnacl_1 = __importDefault(require("tweetnacl"));
10
+ const crypto_1 = require("./crypto");
11
+ function createPrivateEncryptionKeyPair(now = Date.now()) {
12
+ const pair = tweetnacl_1.default.box.keyPair();
13
+ return {
14
+ public_key: (0, crypto_1.toBase64)(pair.publicKey),
15
+ private_key: (0, crypto_1.toBase64)(pair.secretKey),
16
+ created_at: now,
17
+ };
18
+ }
19
+ function encryptPrivatePayload(input) {
20
+ const sender = input.sender_keypair || createPrivateEncryptionKeyPair();
21
+ const nonce = tweetnacl_1.default.randomBytes(tweetnacl_1.default.box.nonceLength);
22
+ const message = Buffer.from(String(input.plaintext || ""), "utf8");
23
+ const ciphertext = tweetnacl_1.default.box(new Uint8Array(message), nonce, (0, crypto_1.fromBase64)(input.recipient_public_key), (0, crypto_1.fromBase64)(sender.private_key));
24
+ return {
25
+ ciphertext: (0, crypto_1.toBase64)(ciphertext),
26
+ nonce: (0, crypto_1.toBase64)(nonce),
27
+ sender_encryption_public_key: sender.public_key,
28
+ };
29
+ }
30
+ function decryptPrivatePayload(input) {
31
+ try {
32
+ const opened = tweetnacl_1.default.box.open((0, crypto_1.fromBase64)(input.ciphertext), (0, crypto_1.fromBase64)(input.nonce), (0, crypto_1.fromBase64)(input.sender_encryption_public_key), (0, crypto_1.fromBase64)(input.recipient_private_key));
33
+ if (!opened)
34
+ return null;
35
+ return Buffer.from(opened).toString("utf8");
36
+ }
37
+ catch {
38
+ return null;
39
+ }
40
+ }
@@ -0,0 +1,23 @@
1
+ import { AgentIdentity, PrivateMessageReceiptRecord, PrivateMessageRecord } from "./types";
2
+ export declare function signPrivateMessage(input: {
3
+ identity: AgentIdentity;
4
+ message_id: string;
5
+ conversation_id: string;
6
+ to_agent_id: string;
7
+ sender_encryption_public_key: string;
8
+ recipient_encryption_public_key: string;
9
+ ciphertext: string;
10
+ nonce: string;
11
+ created_at?: number;
12
+ }): PrivateMessageRecord;
13
+ export declare function verifyPrivateMessage(record: PrivateMessageRecord): boolean;
14
+ export declare function signPrivateMessageReceipt(input: {
15
+ identity: AgentIdentity;
16
+ receipt_id: string;
17
+ message_id: string;
18
+ conversation_id: string;
19
+ to_agent_id: string;
20
+ status: "received" | "read";
21
+ created_at?: number;
22
+ }): PrivateMessageReceiptRecord;
23
+ export declare function verifyPrivateMessageReceipt(record: PrivateMessageReceiptRecord): boolean;
@@ -0,0 +1,74 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.signPrivateMessage = signPrivateMessage;
4
+ exports.verifyPrivateMessage = verifyPrivateMessage;
5
+ exports.signPrivateMessageReceipt = signPrivateMessageReceipt;
6
+ exports.verifyPrivateMessageReceipt = verifyPrivateMessageReceipt;
7
+ const crypto_1 = require("./crypto");
8
+ function unsignedPrivateMessage(record) {
9
+ const { signature: _signature, ...rest } = record;
10
+ return rest;
11
+ }
12
+ function unsignedPrivateMessageReceipt(record) {
13
+ const { signature: _signature, ...rest } = record;
14
+ return rest;
15
+ }
16
+ function signPrivateMessage(input) {
17
+ const payload = {
18
+ type: "private.message",
19
+ message_id: input.message_id,
20
+ conversation_id: input.conversation_id,
21
+ from_agent_id: input.identity.agent_id,
22
+ to_agent_id: input.to_agent_id,
23
+ sender_public_key: input.identity.public_key,
24
+ sender_encryption_public_key: input.sender_encryption_public_key,
25
+ recipient_encryption_public_key: input.recipient_encryption_public_key,
26
+ cipher_scheme: "nacl-box-v1",
27
+ ciphertext: input.ciphertext,
28
+ nonce: input.nonce,
29
+ created_at: input.created_at ?? Date.now(),
30
+ };
31
+ return {
32
+ ...payload,
33
+ signature: (0, crypto_1.signPayload)(payload, input.identity.private_key),
34
+ };
35
+ }
36
+ function verifyPrivateMessage(record) {
37
+ try {
38
+ if ((0, crypto_1.hashPublicKey)((0, crypto_1.fromBase64)(record.sender_public_key)) !== record.from_agent_id) {
39
+ return false;
40
+ }
41
+ return (0, crypto_1.verifyPayload)(unsignedPrivateMessage(record), record.signature, record.sender_public_key);
42
+ }
43
+ catch {
44
+ return false;
45
+ }
46
+ }
47
+ function signPrivateMessageReceipt(input) {
48
+ const payload = {
49
+ type: "private.message.receipt",
50
+ receipt_id: input.receipt_id,
51
+ message_id: input.message_id,
52
+ conversation_id: input.conversation_id,
53
+ from_agent_id: input.identity.agent_id,
54
+ to_agent_id: input.to_agent_id,
55
+ sender_public_key: input.identity.public_key,
56
+ status: input.status,
57
+ created_at: input.created_at ?? Date.now(),
58
+ };
59
+ return {
60
+ ...payload,
61
+ signature: (0, crypto_1.signPayload)(payload, input.identity.private_key),
62
+ };
63
+ }
64
+ function verifyPrivateMessageReceipt(record) {
65
+ try {
66
+ if ((0, crypto_1.hashPublicKey)((0, crypto_1.fromBase64)(record.sender_public_key)) !== record.from_agent_id) {
67
+ return false;
68
+ }
69
+ return (0, crypto_1.verifyPayload)(unsignedPrivateMessageReceipt(record), record.signature, record.sender_public_key);
70
+ }
71
+ catch {
72
+ return false;
73
+ }
74
+ }
@@ -15,6 +15,7 @@ function signProfile(input, identity) {
15
15
  bio: input.bio,
16
16
  tags: input.tags,
17
17
  avatar_url: input.avatar_url,
18
+ private_encryption_public_key: input.private_encryption_public_key,
18
19
  public_enabled: input.public_enabled,
19
20
  updated_at: Date.now(),
20
21
  };
@@ -34,6 +35,7 @@ function createDefaultProfileInput(agentId) {
34
35
  bio: "",
35
36
  tags: [],
36
37
  avatar_url: "",
38
+ private_encryption_public_key: "",
37
39
  public_enabled: false,
38
40
  };
39
41
  }
@@ -7,9 +7,11 @@ export type ProfileVisibility = {
7
7
  };
8
8
  export type PublicProfileSummary = {
9
9
  agent_id: string;
10
+ is_self: boolean;
10
11
  display_name: string;
11
12
  bio: string;
12
13
  avatar_url?: string;
14
+ private_encryption_public_key?: string;
13
15
  public_enabled: boolean;
14
16
  updated_at: number;
15
17
  online: boolean;
@@ -30,6 +32,7 @@ export type PublicProfileSummary = {
30
32
  display_name: string;
31
33
  bio: string;
32
34
  avatar_url?: string;
35
+ private_encryption_public_key?: string;
33
36
  tags: string[];
34
37
  public_enabled: boolean;
35
38
  profile_version: string;
@@ -57,6 +60,7 @@ export type PublicProfileSummary = {
57
60
  export declare function deriveCapabilitiesSummary(tags: string[]): string[];
58
61
  export declare function buildPublicProfileSummary(args: {
59
62
  profile: PublicProfile;
63
+ is_self?: boolean;
60
64
  online: boolean;
61
65
  last_seen_at: number | null;
62
66
  network_mode?: string;
@@ -53,9 +53,11 @@ function buildPublicProfileSummary(args) {
53
53
  ].filter((field) => Boolean(field));
54
54
  return {
55
55
  agent_id: args.profile.agent_id,
56
+ is_self: Boolean(args.is_self),
56
57
  display_name: args.profile.display_name,
57
58
  bio: args.profile.bio,
58
59
  avatar_url: args.profile.avatar_url,
60
+ private_encryption_public_key: args.profile.private_encryption_public_key,
59
61
  public_enabled: args.profile.public_enabled,
60
62
  updated_at: args.profile.updated_at,
61
63
  online: args.online,
@@ -76,6 +78,7 @@ function buildPublicProfileSummary(args) {
76
78
  display_name: args.profile.display_name,
77
79
  bio: args.profile.bio,
78
80
  avatar_url: args.profile.avatar_url,
81
+ private_encryption_public_key: args.profile.private_encryption_public_key,
79
82
  tags,
80
83
  public_enabled: args.profile.public_enabled,
81
84
  profile_version: args.profile_version ?? "v1",
@@ -4,12 +4,18 @@ export type AgentIdentity = {
4
4
  private_key: string;
5
5
  created_at: number;
6
6
  };
7
+ export type PrivateEncryptionKeyPair = {
8
+ public_key: string;
9
+ private_key: string;
10
+ created_at: number;
11
+ };
7
12
  export type PublicProfile = {
8
13
  agent_id: string;
9
14
  display_name: string;
10
15
  bio: string;
11
16
  tags: string[];
12
17
  avatar_url?: string;
18
+ private_encryption_public_key?: string;
13
19
  public_enabled: boolean;
14
20
  updated_at: number;
15
21
  signature: string;
@@ -51,6 +57,40 @@ export type SocialMessageObservationRecord = {
51
57
  observed_at: number;
52
58
  signature: string;
53
59
  };
60
+ export type PrivateMessageRecord = {
61
+ type: "private.message";
62
+ message_id: string;
63
+ conversation_id: string;
64
+ from_agent_id: string;
65
+ to_agent_id: string;
66
+ sender_public_key: string;
67
+ sender_encryption_public_key: string;
68
+ recipient_encryption_public_key: string;
69
+ cipher_scheme: "nacl-box-v1";
70
+ ciphertext: string;
71
+ nonce: string;
72
+ created_at: number;
73
+ signature: string;
74
+ };
75
+ export type PrivateMessageReceiptRecord = {
76
+ type: "private.message.receipt";
77
+ receipt_id: string;
78
+ message_id: string;
79
+ conversation_id: string;
80
+ from_agent_id: string;
81
+ to_agent_id: string;
82
+ sender_public_key: string;
83
+ status: "received" | "read";
84
+ created_at: number;
85
+ signature: string;
86
+ };
87
+ export type PrivateConversationSummary = {
88
+ conversation_id: string;
89
+ peer_agent_id: string;
90
+ last_message_at: number | null;
91
+ last_message_preview: string;
92
+ unread_count: number;
93
+ };
54
94
  export type DirectoryState = {
55
95
  profiles: Record<string, PublicProfile>;
56
96
  presence: Record<string, number>;
@@ -22,6 +22,10 @@ type RelayPeer = {
22
22
  last_seen_at: number;
23
23
  messages_seen: number;
24
24
  reconnect_attempts: number;
25
+ meta?: {
26
+ signal_queue_size?: number;
27
+ relay_queue_size?: number;
28
+ };
25
29
  };
26
30
  type RelayDiagnostics = {
27
31
  adapter: "relay-preview";
@@ -126,6 +130,7 @@ export declare class RelayPreviewAdapter implements NetworkAdapter {
126
130
  private started;
127
131
  private poller;
128
132
  private handlers;
133
+ private directHandlers;
129
134
  private peers;
130
135
  private seenMessageIds;
131
136
  private activeEndpoint;
@@ -150,10 +155,16 @@ export declare class RelayPreviewAdapter implements NetworkAdapter {
150
155
  stop(): Promise<void>;
151
156
  publish(topic: string, data: any): Promise<void>;
152
157
  subscribe(topic: string, handler: (data: any) => void): void;
158
+ sendDirect(peerId: string, topic: string, data: any): Promise<void>;
159
+ subscribeDirect(topic: string, handler: (data: any, meta?: {
160
+ peerId?: string;
161
+ }) => void): void;
153
162
  getDiagnostics(): RelayDiagnostics;
154
163
  private pollOnce;
155
164
  private refreshPeers;
156
165
  private onEnvelope;
166
+ private onDirectEnvelope;
167
+ private dispatchEnvelope;
157
168
  private recordDiscovery;
158
169
  private joinRoom;
159
170
  private maybeRefreshJoin;
@@ -162,5 +173,6 @@ export declare class RelayPreviewAdapter implements NetworkAdapter {
162
173
  private requestJson;
163
174
  private updatePeersFromList;
164
175
  private scheduleNextPoll;
176
+ private ensurePollingAlive;
165
177
  }
166
178
  export {};
@@ -31,6 +31,7 @@ class RelayPreviewAdapter {
31
31
  started = false;
32
32
  poller = null;
33
33
  handlers = new Map();
34
+ directHandlers = new Map();
34
35
  peers = new Map();
35
36
  seenMessageIds = new Set();
36
37
  activeEndpoint = "";
@@ -109,7 +110,6 @@ class RelayPreviewAdapter {
109
110
  try {
110
111
  await this.joinRoom("start");
111
112
  this.started = true;
112
- await this.refreshPeers();
113
113
  await this.pollOnce();
114
114
  this.scheduleNextPoll(this.pollIntervalMs);
115
115
  this.recordDiscovery("signaling_connected", { endpoint: this.activeEndpoint });
@@ -166,6 +166,42 @@ class RelayPreviewAdapter {
166
166
  }
167
167
  this.handlers.get(key)?.add(handler);
168
168
  }
169
+ async sendDirect(peerId, topic, data) {
170
+ if (!this.started)
171
+ return;
172
+ const targetPeerId = String(peerId || "").trim();
173
+ if (!targetPeerId)
174
+ return;
175
+ await this.maybeRefreshJoin("direct_send");
176
+ const envelope = {
177
+ version: 1,
178
+ message_id: (0, crypto_1.randomUUID)(),
179
+ topic: `${this.namespace}:${topic}`,
180
+ source_peer_id: this.peerId,
181
+ timestamp: Date.now(),
182
+ payload: this.topicCodec.encode(topic, data),
183
+ };
184
+ const raw = this.envelopeCodec.encode(envelope);
185
+ if (raw.length > this.maxMessageBytes) {
186
+ this.stats.dropped_oversized += 1;
187
+ return;
188
+ }
189
+ await this.post("/direct/send", {
190
+ room: this.room,
191
+ from_peer_id: this.peerId,
192
+ to_peer_id: targetPeerId,
193
+ envelope,
194
+ });
195
+ this.lastPublishAt = Date.now();
196
+ this.signalingMessagesSentTotal += 1;
197
+ }
198
+ subscribeDirect(topic, handler) {
199
+ const key = `${this.namespace}:${topic}`;
200
+ if (!this.directHandlers.has(key)) {
201
+ this.directHandlers.set(key, new Set());
202
+ }
203
+ this.directHandlers.get(key)?.add(handler);
204
+ }
169
205
  getDiagnostics() {
170
206
  const peerItems = Array.from(this.peers.values()).sort((a, b) => b.last_seen_at - a.last_seen_at);
171
207
  return {
@@ -235,6 +271,15 @@ class RelayPreviewAdapter {
235
271
  this.signalingMessagesReceivedTotal += 1;
236
272
  this.onEnvelope(message?.envelope);
237
273
  }
274
+ let directMessages = Array.isArray(payload?.direct_messages) ? payload.direct_messages : null;
275
+ if (!directMessages) {
276
+ const directPayload = await this.get(`/direct/poll?room=${encodeURIComponent(this.room)}&peer_id=${encodeURIComponent(this.peerId)}`);
277
+ directMessages = Array.isArray(directPayload?.messages) ? directPayload.messages : [];
278
+ }
279
+ for (const message of directMessages) {
280
+ this.signalingMessagesReceivedTotal += 1;
281
+ this.onDirectEnvelope(message?.envelope, { peerId: String(message?.from_peer_id || "") || undefined });
282
+ }
238
283
  if (Array.isArray(payload?.peers)) {
239
284
  this.updatePeersFromList(payload.peers);
240
285
  }
@@ -258,10 +303,18 @@ class RelayPreviewAdapter {
258
303
  const payload = await this.get(`/peers?room=${encodeURIComponent(this.room)}`);
259
304
  this.lastPeerRefreshAt = Date.now();
260
305
  this.stats.peers_refresh_succeeded += 1;
261
- const peerIds = Array.isArray(payload?.peers) ? payload.peers : [];
262
- this.updatePeersFromList(peerIds);
306
+ const peerItems = Array.isArray(payload?.peer_details) && payload.peer_details.length
307
+ ? payload.peer_details
308
+ : Array.isArray(payload?.peers) ? payload.peers : [];
309
+ this.updatePeersFromList(peerItems);
263
310
  }
264
311
  onEnvelope(envelope) {
312
+ this.dispatchEnvelope(envelope, this.handlers);
313
+ }
314
+ onDirectEnvelope(envelope, meta) {
315
+ this.dispatchEnvelope(envelope, this.directHandlers, meta);
316
+ }
317
+ dispatchEnvelope(envelope, handlersByTopic, meta) {
265
318
  this.stats.received_total += 1;
266
319
  const validated = (0, messageEnvelope_1.validateNetworkMessageEnvelope)(envelope, {
267
320
  max_future_drift_ms: this.maxFutureDriftMs,
@@ -300,7 +353,7 @@ class RelayPreviewAdapter {
300
353
  this.stats.received_validated += 1;
301
354
  const topicKey = message.topic;
302
355
  const topic = topicKey.slice(this.namespace.length + 1);
303
- const handlers = this.handlers.get(topicKey);
356
+ const handlers = handlersByTopic.get(topicKey);
304
357
  if (!handlers || handlers.size === 0)
305
358
  return;
306
359
  const peer = this.peers.get(message.source_peer_id);
@@ -318,7 +371,7 @@ class RelayPreviewAdapter {
318
371
  }
319
372
  for (const handler of handlers) {
320
373
  try {
321
- handler(payload);
374
+ handler(payload, meta || { peerId: message.source_peer_id });
322
375
  this.stats.delivered_total += 1;
323
376
  }
324
377
  catch {
@@ -340,15 +393,20 @@ class RelayPreviewAdapter {
340
393
  }
341
394
  async joinRoom(reason) {
342
395
  this.stats.join_attempted += 1;
343
- await this.post("/join", { room: this.room, peer_id: this.peerId });
396
+ const payload = await this.post("/join", { room: this.room, peer_id: this.peerId });
344
397
  this.lastJoinAt = Date.now();
345
398
  this.stats.join_succeeded += 1;
399
+ if (Array.isArray(payload?.peers)) {
400
+ this.updatePeersFromList(payload.peers);
401
+ this.lastPeerRefreshAt = this.lastJoinAt;
402
+ }
346
403
  this.recordDiscovery("join_ok", { endpoint: this.activeEndpoint, detail: reason });
347
404
  }
348
405
  async maybeRefreshJoin(reason) {
349
406
  if (!this.lastJoinAt || Date.now() - this.lastJoinAt > Math.max(45_000, this.pollIntervalMs * 6)) {
350
407
  await this.joinRoom(reason);
351
408
  }
409
+ this.ensurePollingAlive(reason);
352
410
  }
353
411
  async get(path) {
354
412
  return this.requestJson("GET", path);
@@ -406,13 +464,38 @@ class RelayPreviewAdapter {
406
464
  throw new Error(errors.join(" | "));
407
465
  }
408
466
  updatePeersFromList(values) {
409
- const peerIds = values.map((value) => String(value || "").trim()).filter(Boolean);
467
+ const parsedPeers = [];
468
+ for (const value of values) {
469
+ if (typeof value === "string") {
470
+ const peerId = String(value || "").trim();
471
+ if (peerId) {
472
+ parsedPeers.push({ peer_id: peerId });
473
+ }
474
+ continue;
475
+ }
476
+ if (value && typeof value === "object") {
477
+ const raw = value;
478
+ const peerId = String(raw.peer_id || "").trim();
479
+ if (!peerId) {
480
+ continue;
481
+ }
482
+ parsedPeers.push({
483
+ peer_id: peerId,
484
+ meta: {
485
+ signal_queue_size: Number(raw.signal_queue_size ?? 0),
486
+ relay_queue_size: Number(raw.relay_queue_size ?? 0),
487
+ },
488
+ });
489
+ }
490
+ }
491
+ const peerIds = parsedPeers.map((peer) => peer.peer_id);
410
492
  if (!peerIds.includes(this.peerId)) {
411
493
  void this.joinRoom("self_missing_from_peers").catch(() => { });
412
494
  }
413
495
  const now = Date.now();
414
496
  const next = new Map();
415
- for (const peerId of peerIds) {
497
+ for (const peerInfo of parsedPeers) {
498
+ const peerId = peerInfo.peer_id;
416
499
  if (peerId === this.peerId)
417
500
  continue;
418
501
  const existing = this.peers.get(peerId);
@@ -426,6 +509,7 @@ class RelayPreviewAdapter {
426
509
  last_seen_at: now,
427
510
  messages_seen: existing?.messages_seen ?? 0,
428
511
  reconnect_attempts: existing?.reconnect_attempts ?? 0,
512
+ meta: peerInfo.meta || existing?.meta,
429
513
  });
430
514
  }
431
515
  for (const peerId of this.peers.keys()) {
@@ -444,5 +528,21 @@ class RelayPreviewAdapter {
444
528
  this.pollOnce().catch(() => { });
445
529
  }, Math.max(1000, delayMs + jitterMs));
446
530
  }
531
+ ensurePollingAlive(reason) {
532
+ if (!this.started)
533
+ return;
534
+ const pollStaleMs = Math.max(45_000, this.pollIntervalMs * 6);
535
+ const pollMissing = !this.poller;
536
+ const pollStale = Boolean(this.lastPollAt) && Date.now() - this.lastPollAt > pollStaleMs;
537
+ if (!pollMissing && !pollStale) {
538
+ return;
539
+ }
540
+ this.recordDiscovery("poll_recover_scheduled", {
541
+ endpoint: this.activeEndpoint,
542
+ detail: `${reason}:${pollMissing ? "missing" : "stale"}`,
543
+ });
544
+ this.currentPollDelayMs = this.pollIntervalMs;
545
+ this.scheduleNextPoll(0);
546
+ }
447
547
  }
448
548
  exports.RelayPreviewAdapter = RelayPreviewAdapter;
@@ -3,4 +3,8 @@ export interface NetworkAdapter {
3
3
  stop(): Promise<void>;
4
4
  publish(topic: string, data: any): Promise<void>;
5
5
  subscribe(topic: string, handler: (data: any) => void): void;
6
+ sendDirect?(peerId: string, topic: string, data: any): Promise<void>;
7
+ subscribeDirect?(topic: string, handler: (data: any, meta?: {
8
+ peerId?: string;
9
+ }) => void): void;
6
10
  }
@@ -1,4 +1,4 @@
1
- import { AgentIdentity, DirectoryState, PublicProfile } from "@silicaclaw/core";
1
+ import { AgentIdentity, DirectoryState, PrivateEncryptionKeyPair, PrivateMessageReceiptRecord, PrivateMessageRecord, PublicProfile } from "@silicaclaw/core";
2
2
  import { JsonFileRepo } from "./jsonRepo";
3
3
  export type LogEntry = {
4
4
  id: string;
@@ -37,6 +37,20 @@ export type SocialMessageGovernanceConfig = {
37
37
  blocked_agent_ids: string[];
38
38
  blocked_terms: string[];
39
39
  };
40
+ export type PrivateMessageDecryptedContent = {
41
+ body: string;
42
+ };
43
+ export type PrivateMessagingRuntimeState = {
44
+ schema_version: number;
45
+ app_version: string;
46
+ last_started_at: number;
47
+ encryption_public_key: string;
48
+ encryption_public_key_fingerprint: string;
49
+ message_count: number;
50
+ self_sent_count: number;
51
+ cached_plaintext_count: number;
52
+ warnings: string[];
53
+ };
40
54
  export declare class IdentityRepo extends JsonFileRepo<AgentIdentity | null> {
41
55
  constructor(rootDir?: string);
42
56
  }
@@ -59,3 +73,15 @@ export declare class SocialMessageObservationRepo extends JsonFileRepo<SocialMes
59
73
  export declare class SocialMessageGovernanceRepo extends JsonFileRepo<SocialMessageGovernanceConfig> {
60
74
  constructor(rootDir?: string);
61
75
  }
76
+ export declare class PrivateMessageRepo extends JsonFileRepo<PrivateMessageRecord[]> {
77
+ constructor(rootDir?: string);
78
+ }
79
+ export declare class PrivateMessageReceiptRepo extends JsonFileRepo<PrivateMessageReceiptRecord[]> {
80
+ constructor(rootDir?: string);
81
+ }
82
+ export declare class PrivateEncryptionKeyRepo extends JsonFileRepo<PrivateEncryptionKeyPair | null> {
83
+ constructor(rootDir?: string);
84
+ }
85
+ export declare class PrivateMessagingRuntimeRepo extends JsonFileRepo<PrivateMessagingRuntimeState> {
86
+ constructor(rootDir?: string);
87
+ }
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.SocialMessageGovernanceRepo = exports.SocialMessageObservationRepo = exports.SocialMessageRepo = exports.LogRepo = exports.CacheRepo = exports.ProfileRepo = exports.IdentityRepo = void 0;
3
+ exports.PrivateMessagingRuntimeRepo = exports.PrivateEncryptionKeyRepo = exports.PrivateMessageReceiptRepo = exports.PrivateMessageRepo = exports.SocialMessageGovernanceRepo = exports.SocialMessageObservationRepo = exports.SocialMessageRepo = exports.LogRepo = exports.CacheRepo = exports.ProfileRepo = exports.IdentityRepo = void 0;
4
4
  const path_1 = require("path");
5
5
  const core_1 = require("@silicaclaw/core");
6
6
  const jsonRepo_1 = require("./jsonRepo");
@@ -65,3 +65,37 @@ class SocialMessageGovernanceRepo extends jsonRepo_1.JsonFileRepo {
65
65
  }
66
66
  }
67
67
  exports.SocialMessageGovernanceRepo = SocialMessageGovernanceRepo;
68
+ class PrivateMessageRepo extends jsonRepo_1.JsonFileRepo {
69
+ constructor(rootDir = process.cwd()) {
70
+ super((0, path_1.resolve)(rootDir, "data", "private-messages.json"), () => []);
71
+ }
72
+ }
73
+ exports.PrivateMessageRepo = PrivateMessageRepo;
74
+ class PrivateMessageReceiptRepo extends jsonRepo_1.JsonFileRepo {
75
+ constructor(rootDir = process.cwd()) {
76
+ super((0, path_1.resolve)(rootDir, "data", "private-message-receipts.json"), () => []);
77
+ }
78
+ }
79
+ exports.PrivateMessageReceiptRepo = PrivateMessageReceiptRepo;
80
+ class PrivateEncryptionKeyRepo extends jsonRepo_1.JsonFileRepo {
81
+ constructor(rootDir = process.cwd()) {
82
+ super((0, path_1.resolve)(rootDir, "data", "private-encryption-keypair.json"), () => null);
83
+ }
84
+ }
85
+ exports.PrivateEncryptionKeyRepo = PrivateEncryptionKeyRepo;
86
+ class PrivateMessagingRuntimeRepo extends jsonRepo_1.JsonFileRepo {
87
+ constructor(rootDir = process.cwd()) {
88
+ super((0, path_1.resolve)(rootDir, ".silicaclaw", "private-messaging.runtime.json"), () => ({
89
+ schema_version: 1,
90
+ app_version: "",
91
+ last_started_at: 0,
92
+ encryption_public_key: "",
93
+ encryption_public_key_fingerprint: "",
94
+ message_count: 0,
95
+ self_sent_count: 0,
96
+ cached_plaintext_count: 0,
97
+ warnings: [],
98
+ }));
99
+ }
100
+ }
101
+ exports.PrivateMessagingRuntimeRepo = PrivateMessagingRuntimeRepo;