@silicaclaw/cli 2026.3.20-1 → 2026.3.20-11
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 +60 -0
- package/INSTALL.md +13 -7
- package/README.md +60 -12
- package/VERSION +1 -1
- package/apps/local-console/dist/apps/local-console/src/server.d.ts +129 -2
- package/apps/local-console/dist/apps/local-console/src/server.js +887 -91
- package/apps/local-console/dist/packages/core/src/index.d.ts +2 -0
- package/apps/local-console/dist/packages/core/src/index.js +2 -0
- package/apps/local-console/dist/packages/core/src/privateCrypto.d.ts +17 -0
- package/apps/local-console/dist/packages/core/src/privateCrypto.js +40 -0
- package/apps/local-console/dist/packages/core/src/privateMessage.d.ts +23 -0
- package/apps/local-console/dist/packages/core/src/privateMessage.js +74 -0
- package/apps/local-console/dist/packages/core/src/profile.js +2 -0
- package/apps/local-console/dist/packages/core/src/publicProfileSummary.d.ts +4 -0
- package/apps/local-console/dist/packages/core/src/publicProfileSummary.js +3 -0
- package/apps/local-console/dist/packages/core/src/types.d.ts +40 -0
- package/apps/local-console/dist/packages/network/src/relayPreview.d.ts +12 -0
- package/apps/local-console/dist/packages/network/src/relayPreview.js +108 -8
- package/apps/local-console/dist/packages/network/src/types.d.ts +4 -0
- package/apps/local-console/dist/packages/storage/src/repos.d.ts +13 -1
- package/apps/local-console/dist/packages/storage/src/repos.js +19 -1
- package/apps/local-console/public/app/app.js +465 -11
- package/apps/local-console/public/app/events.js +21 -0
- package/apps/local-console/public/app/network.js +144 -32
- package/apps/local-console/public/app/overview.js +60 -52
- package/apps/local-console/public/app/social.js +316 -93
- package/apps/local-console/public/app/styles.css +127 -1
- package/apps/local-console/public/app/template.js +121 -35
- package/apps/local-console/public/app/translations.js +430 -316
- package/apps/local-console/src/server.ts +1024 -89
- package/apps/public-explorer/public/app/template.js +2 -2
- package/apps/public-explorer/public/app/translations.js +36 -36
- package/docs/NEW_USER_OPERATIONS.md +5 -5
- package/docs/OPENCLAW_BRIDGE.md +7 -7
- package/docs/OPENCLAW_BRIDGE_ZH.md +6 -6
- package/node_modules/@silicaclaw/core/dist/packages/core/src/index.d.ts +2 -0
- package/node_modules/@silicaclaw/core/dist/packages/core/src/index.js +2 -0
- package/node_modules/@silicaclaw/core/dist/packages/core/src/privateCrypto.d.ts +17 -0
- package/node_modules/@silicaclaw/core/dist/packages/core/src/privateCrypto.js +40 -0
- package/node_modules/@silicaclaw/core/dist/packages/core/src/privateMessage.d.ts +23 -0
- package/node_modules/@silicaclaw/core/dist/packages/core/src/privateMessage.js +74 -0
- package/node_modules/@silicaclaw/core/dist/packages/core/src/profile.js +2 -0
- package/node_modules/@silicaclaw/core/dist/packages/core/src/publicProfileSummary.d.ts +4 -0
- package/node_modules/@silicaclaw/core/dist/packages/core/src/publicProfileSummary.js +3 -0
- package/node_modules/@silicaclaw/core/dist/packages/core/src/types.d.ts +40 -0
- package/node_modules/@silicaclaw/core/src/index.ts +2 -0
- package/node_modules/@silicaclaw/core/src/privateCrypto.ts +57 -0
- package/node_modules/@silicaclaw/core/src/privateMessage.ts +101 -0
- package/node_modules/@silicaclaw/core/src/profile.ts +2 -0
- package/node_modules/@silicaclaw/core/src/publicProfileSummary.ts +7 -0
- package/node_modules/@silicaclaw/core/src/types.ts +44 -0
- package/node_modules/@silicaclaw/network/dist/packages/network/src/relayPreview.d.ts +12 -0
- package/node_modules/@silicaclaw/network/dist/packages/network/src/relayPreview.js +108 -8
- package/node_modules/@silicaclaw/network/dist/packages/network/src/types.d.ts +4 -0
- package/node_modules/@silicaclaw/network/src/relayPreview.ts +120 -10
- package/node_modules/@silicaclaw/network/src/types.ts +2 -0
- package/node_modules/@silicaclaw/storage/dist/packages/core/src/index.d.ts +2 -0
- package/node_modules/@silicaclaw/storage/dist/packages/core/src/index.js +2 -0
- package/node_modules/@silicaclaw/storage/dist/packages/core/src/privateCrypto.d.ts +17 -0
- package/node_modules/@silicaclaw/storage/dist/packages/core/src/privateCrypto.js +40 -0
- package/node_modules/@silicaclaw/storage/dist/packages/core/src/privateMessage.d.ts +23 -0
- package/node_modules/@silicaclaw/storage/dist/packages/core/src/privateMessage.js +74 -0
- package/node_modules/@silicaclaw/storage/dist/packages/core/src/profile.js +2 -0
- package/node_modules/@silicaclaw/storage/dist/packages/core/src/publicProfileSummary.d.ts +4 -0
- package/node_modules/@silicaclaw/storage/dist/packages/core/src/publicProfileSummary.js +3 -0
- package/node_modules/@silicaclaw/storage/dist/packages/core/src/types.d.ts +40 -0
- package/node_modules/@silicaclaw/storage/dist/packages/storage/src/repos.d.ts +13 -1
- package/node_modules/@silicaclaw/storage/dist/packages/storage/src/repos.js +19 -1
- package/node_modules/@silicaclaw/storage/package.json +2 -2
- package/node_modules/@silicaclaw/storage/src/repos.ts +31 -1
- package/openclaw-skills/silicaclaw-bridge-setup/SKILL.md +18 -0
- package/openclaw-skills/silicaclaw-bridge-setup/VERSION +1 -1
- package/openclaw-skills/silicaclaw-bridge-setup/manifest.json +2 -2
- package/openclaw-skills/silicaclaw-broadcast/SKILL.md +18 -0
- package/openclaw-skills/silicaclaw-broadcast/VERSION +1 -1
- package/openclaw-skills/silicaclaw-broadcast/manifest.json +2 -2
- package/openclaw-skills/silicaclaw-network-config/SKILL.md +158 -0
- package/openclaw-skills/silicaclaw-network-config/VERSION +1 -0
- package/openclaw-skills/silicaclaw-network-config/agents/openai.yaml +6 -0
- package/openclaw-skills/silicaclaw-network-config/manifest.json +27 -0
- package/openclaw-skills/silicaclaw-network-config/references/network-modes.md +22 -0
- package/openclaw-skills/silicaclaw-network-config/references/owner-dialogue-cheatsheet-zh.md +47 -0
- package/openclaw-skills/silicaclaw-network-config/references/public-discovery.md +22 -0
- package/openclaw-skills/silicaclaw-owner-push/SKILL.md +18 -0
- package/openclaw-skills/silicaclaw-owner-push/VERSION +1 -1
- package/openclaw-skills/silicaclaw-owner-push/manifest.json +2 -2
- package/openclaw-skills/silicaclaw-owner-push/references/runtime-setup.md +3 -0
- package/openclaw-skills/silicaclaw-owner-push/scripts/owner-push-forwarder.mjs +151 -9
- package/package.json +1 -1
- package/packages/core/dist/packages/core/src/index.d.ts +2 -0
- package/packages/core/dist/packages/core/src/index.js +2 -0
- package/packages/core/dist/packages/core/src/privateCrypto.d.ts +17 -0
- package/packages/core/dist/packages/core/src/privateCrypto.js +40 -0
- package/packages/core/dist/packages/core/src/privateMessage.d.ts +23 -0
- package/packages/core/dist/packages/core/src/privateMessage.js +74 -0
- package/packages/core/dist/packages/core/src/profile.js +2 -0
- package/packages/core/dist/packages/core/src/publicProfileSummary.d.ts +4 -0
- package/packages/core/dist/packages/core/src/publicProfileSummary.js +3 -0
- package/packages/core/dist/packages/core/src/types.d.ts +40 -0
- package/packages/core/src/index.ts +2 -0
- package/packages/core/src/privateCrypto.ts +57 -0
- package/packages/core/src/privateMessage.ts +101 -0
- package/packages/core/src/profile.ts +2 -0
- package/packages/core/src/publicProfileSummary.ts +7 -0
- package/packages/core/src/types.ts +44 -0
- package/packages/network/dist/packages/network/src/relayPreview.d.ts +12 -0
- package/packages/network/dist/packages/network/src/relayPreview.js +108 -8
- package/packages/network/dist/packages/network/src/types.d.ts +4 -0
- package/packages/network/src/relayPreview.ts +120 -10
- package/packages/network/src/types.ts +2 -0
- package/packages/storage/dist/packages/core/src/index.d.ts +2 -0
- package/packages/storage/dist/packages/core/src/index.js +2 -0
- package/packages/storage/dist/packages/core/src/privateCrypto.d.ts +17 -0
- package/packages/storage/dist/packages/core/src/privateCrypto.js +40 -0
- package/packages/storage/dist/packages/core/src/privateMessage.d.ts +23 -0
- package/packages/storage/dist/packages/core/src/privateMessage.js +74 -0
- package/packages/storage/dist/packages/core/src/profile.js +2 -0
- package/packages/storage/dist/packages/core/src/publicProfileSummary.d.ts +4 -0
- package/packages/storage/dist/packages/core/src/publicProfileSummary.js +3 -0
- package/packages/storage/dist/packages/core/src/types.d.ts +40 -0
- package/packages/storage/dist/packages/storage/src/repos.d.ts +13 -1
- package/packages/storage/dist/packages/storage/src/repos.js +19 -1
- package/packages/storage/package.json +2 -2
- package/packages/storage/src/repos.ts +31 -1
- package/scripts/silicaclaw-cli.mjs +59 -6
- package/scripts/silicaclaw-gateway.mjs +108 -0
- package/scripts/validate-openclaw-skill.mjs +19 -0
- package/node_modules/@silicaclaw/storage/dist/index.d.ts +0 -3
- package/node_modules/@silicaclaw/storage/dist/index.js +0 -19
- package/node_modules/@silicaclaw/storage/dist/jsonRepo.d.ts +0 -7
- package/node_modules/@silicaclaw/storage/dist/jsonRepo.js +0 -29
- package/node_modules/@silicaclaw/storage/dist/repos.d.ts +0 -61
- package/node_modules/@silicaclaw/storage/dist/repos.js +0 -67
- package/node_modules/@silicaclaw/storage/dist/socialRuntimeRepo.d.ts +0 -5
- package/node_modules/@silicaclaw/storage/dist/socialRuntimeRepo.js +0 -57
- package/packages/storage/dist/index.d.ts +0 -3
- package/packages/storage/dist/index.js +0 -19
- package/packages/storage/dist/jsonRepo.d.ts +0 -7
- package/packages/storage/dist/jsonRepo.js +0 -29
- package/packages/storage/dist/repos.d.ts +0 -61
- package/packages/storage/dist/repos.js +0 -67
- package/packages/storage/dist/socialRuntimeRepo.d.ts +0 -5
- package/packages/storage/dist/socialRuntimeRepo.js +0 -57
package/package.json
CHANGED
|
@@ -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>;
|
|
@@ -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";
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import nacl from "tweetnacl";
|
|
2
|
+
import { fromBase64, toBase64 } from "./crypto";
|
|
3
|
+
import { PrivateEncryptionKeyPair } from "./types";
|
|
4
|
+
|
|
5
|
+
export function createPrivateEncryptionKeyPair(now = Date.now()): PrivateEncryptionKeyPair {
|
|
6
|
+
const pair = nacl.box.keyPair();
|
|
7
|
+
return {
|
|
8
|
+
public_key: toBase64(pair.publicKey),
|
|
9
|
+
private_key: toBase64(pair.secretKey),
|
|
10
|
+
created_at: now,
|
|
11
|
+
};
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export function encryptPrivatePayload(input: {
|
|
15
|
+
plaintext: string;
|
|
16
|
+
recipient_public_key: string;
|
|
17
|
+
sender_keypair?: PrivateEncryptionKeyPair | null;
|
|
18
|
+
}): {
|
|
19
|
+
ciphertext: string;
|
|
20
|
+
nonce: string;
|
|
21
|
+
sender_encryption_public_key: string;
|
|
22
|
+
} {
|
|
23
|
+
const sender = input.sender_keypair || createPrivateEncryptionKeyPair();
|
|
24
|
+
const nonce = nacl.randomBytes(nacl.box.nonceLength);
|
|
25
|
+
const message = Buffer.from(String(input.plaintext || ""), "utf8");
|
|
26
|
+
const ciphertext = nacl.box(
|
|
27
|
+
new Uint8Array(message),
|
|
28
|
+
nonce,
|
|
29
|
+
fromBase64(input.recipient_public_key),
|
|
30
|
+
fromBase64(sender.private_key),
|
|
31
|
+
);
|
|
32
|
+
return {
|
|
33
|
+
ciphertext: toBase64(ciphertext),
|
|
34
|
+
nonce: toBase64(nonce),
|
|
35
|
+
sender_encryption_public_key: sender.public_key,
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export function decryptPrivatePayload(input: {
|
|
40
|
+
ciphertext: string;
|
|
41
|
+
nonce: string;
|
|
42
|
+
sender_encryption_public_key: string;
|
|
43
|
+
recipient_private_key: string;
|
|
44
|
+
}): string | null {
|
|
45
|
+
try {
|
|
46
|
+
const opened = nacl.box.open(
|
|
47
|
+
fromBase64(input.ciphertext),
|
|
48
|
+
fromBase64(input.nonce),
|
|
49
|
+
fromBase64(input.sender_encryption_public_key),
|
|
50
|
+
fromBase64(input.recipient_private_key),
|
|
51
|
+
);
|
|
52
|
+
if (!opened) return null;
|
|
53
|
+
return Buffer.from(opened).toString("utf8");
|
|
54
|
+
} catch {
|
|
55
|
+
return null;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
import {
|
|
2
|
+
AgentIdentity,
|
|
3
|
+
PrivateMessageReceiptRecord,
|
|
4
|
+
PrivateMessageRecord,
|
|
5
|
+
} from "./types";
|
|
6
|
+
import { fromBase64, hashPublicKey, signPayload, verifyPayload } from "./crypto";
|
|
7
|
+
|
|
8
|
+
function unsignedPrivateMessage(
|
|
9
|
+
record: PrivateMessageRecord
|
|
10
|
+
): Omit<PrivateMessageRecord, "signature"> {
|
|
11
|
+
const { signature: _signature, ...rest } = record;
|
|
12
|
+
return rest;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
function unsignedPrivateMessageReceipt(
|
|
16
|
+
record: PrivateMessageReceiptRecord
|
|
17
|
+
): Omit<PrivateMessageReceiptRecord, "signature"> {
|
|
18
|
+
const { signature: _signature, ...rest } = record;
|
|
19
|
+
return rest;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export function signPrivateMessage(input: {
|
|
23
|
+
identity: AgentIdentity;
|
|
24
|
+
message_id: string;
|
|
25
|
+
conversation_id: string;
|
|
26
|
+
to_agent_id: string;
|
|
27
|
+
sender_encryption_public_key: string;
|
|
28
|
+
recipient_encryption_public_key: string;
|
|
29
|
+
ciphertext: string;
|
|
30
|
+
nonce: string;
|
|
31
|
+
created_at?: number;
|
|
32
|
+
}): PrivateMessageRecord {
|
|
33
|
+
const payload: Omit<PrivateMessageRecord, "signature"> = {
|
|
34
|
+
type: "private.message",
|
|
35
|
+
message_id: input.message_id,
|
|
36
|
+
conversation_id: input.conversation_id,
|
|
37
|
+
from_agent_id: input.identity.agent_id,
|
|
38
|
+
to_agent_id: input.to_agent_id,
|
|
39
|
+
sender_public_key: input.identity.public_key,
|
|
40
|
+
sender_encryption_public_key: input.sender_encryption_public_key,
|
|
41
|
+
recipient_encryption_public_key: input.recipient_encryption_public_key,
|
|
42
|
+
cipher_scheme: "nacl-box-v1",
|
|
43
|
+
ciphertext: input.ciphertext,
|
|
44
|
+
nonce: input.nonce,
|
|
45
|
+
created_at: input.created_at ?? Date.now(),
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
return {
|
|
49
|
+
...payload,
|
|
50
|
+
signature: signPayload(payload, input.identity.private_key),
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
export function verifyPrivateMessage(record: PrivateMessageRecord): boolean {
|
|
55
|
+
try {
|
|
56
|
+
if (hashPublicKey(fromBase64(record.sender_public_key)) !== record.from_agent_id) {
|
|
57
|
+
return false;
|
|
58
|
+
}
|
|
59
|
+
return verifyPayload(unsignedPrivateMessage(record), record.signature, record.sender_public_key);
|
|
60
|
+
} catch {
|
|
61
|
+
return false;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
export function signPrivateMessageReceipt(input: {
|
|
66
|
+
identity: AgentIdentity;
|
|
67
|
+
receipt_id: string;
|
|
68
|
+
message_id: string;
|
|
69
|
+
conversation_id: string;
|
|
70
|
+
to_agent_id: string;
|
|
71
|
+
status: "received" | "read";
|
|
72
|
+
created_at?: number;
|
|
73
|
+
}): PrivateMessageReceiptRecord {
|
|
74
|
+
const payload: Omit<PrivateMessageReceiptRecord, "signature"> = {
|
|
75
|
+
type: "private.message.receipt",
|
|
76
|
+
receipt_id: input.receipt_id,
|
|
77
|
+
message_id: input.message_id,
|
|
78
|
+
conversation_id: input.conversation_id,
|
|
79
|
+
from_agent_id: input.identity.agent_id,
|
|
80
|
+
to_agent_id: input.to_agent_id,
|
|
81
|
+
sender_public_key: input.identity.public_key,
|
|
82
|
+
status: input.status,
|
|
83
|
+
created_at: input.created_at ?? Date.now(),
|
|
84
|
+
};
|
|
85
|
+
|
|
86
|
+
return {
|
|
87
|
+
...payload,
|
|
88
|
+
signature: signPayload(payload, input.identity.private_key),
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
export function verifyPrivateMessageReceipt(record: PrivateMessageReceiptRecord): boolean {
|
|
93
|
+
try {
|
|
94
|
+
if (hashPublicKey(fromBase64(record.sender_public_key)) !== record.from_agent_id) {
|
|
95
|
+
return false;
|
|
96
|
+
}
|
|
97
|
+
return verifyPayload(unsignedPrivateMessageReceipt(record), record.signature, record.sender_public_key);
|
|
98
|
+
} catch {
|
|
99
|
+
return false;
|
|
100
|
+
}
|
|
101
|
+
}
|
|
@@ -13,6 +13,7 @@ export function signProfile(input: ProfileInput, identity: AgentIdentity): Publi
|
|
|
13
13
|
bio: input.bio,
|
|
14
14
|
tags: input.tags,
|
|
15
15
|
avatar_url: input.avatar_url,
|
|
16
|
+
private_encryption_public_key: input.private_encryption_public_key,
|
|
16
17
|
public_enabled: input.public_enabled,
|
|
17
18
|
updated_at: Date.now(),
|
|
18
19
|
};
|
|
@@ -34,6 +35,7 @@ export function createDefaultProfileInput(agentId: string): ProfileInput {
|
|
|
34
35
|
bio: "",
|
|
35
36
|
tags: [],
|
|
36
37
|
avatar_url: "",
|
|
38
|
+
private_encryption_public_key: "",
|
|
37
39
|
public_enabled: false,
|
|
38
40
|
};
|
|
39
41
|
}
|
|
@@ -10,9 +10,11 @@ export type ProfileVisibility = {
|
|
|
10
10
|
|
|
11
11
|
export type PublicProfileSummary = {
|
|
12
12
|
agent_id: string;
|
|
13
|
+
is_self: boolean;
|
|
13
14
|
display_name: string;
|
|
14
15
|
bio: string;
|
|
15
16
|
avatar_url?: string;
|
|
17
|
+
private_encryption_public_key?: string;
|
|
16
18
|
public_enabled: boolean;
|
|
17
19
|
updated_at: number;
|
|
18
20
|
online: boolean;
|
|
@@ -33,6 +35,7 @@ export type PublicProfileSummary = {
|
|
|
33
35
|
display_name: string;
|
|
34
36
|
bio: string;
|
|
35
37
|
avatar_url?: string;
|
|
38
|
+
private_encryption_public_key?: string;
|
|
36
39
|
tags: string[];
|
|
37
40
|
public_enabled: boolean;
|
|
38
41
|
profile_version: string;
|
|
@@ -73,6 +76,7 @@ export function deriveCapabilitiesSummary(tags: string[]): string[] {
|
|
|
73
76
|
|
|
74
77
|
export function buildPublicProfileSummary(args: {
|
|
75
78
|
profile: PublicProfile;
|
|
79
|
+
is_self?: boolean;
|
|
76
80
|
online: boolean;
|
|
77
81
|
last_seen_at: number | null;
|
|
78
82
|
network_mode?: string;
|
|
@@ -130,9 +134,11 @@ export function buildPublicProfileSummary(args: {
|
|
|
130
134
|
|
|
131
135
|
return {
|
|
132
136
|
agent_id: args.profile.agent_id,
|
|
137
|
+
is_self: Boolean(args.is_self),
|
|
133
138
|
display_name: args.profile.display_name,
|
|
134
139
|
bio: args.profile.bio,
|
|
135
140
|
avatar_url: args.profile.avatar_url,
|
|
141
|
+
private_encryption_public_key: args.profile.private_encryption_public_key,
|
|
136
142
|
public_enabled: args.profile.public_enabled,
|
|
137
143
|
updated_at: args.profile.updated_at,
|
|
138
144
|
online: args.online,
|
|
@@ -153,6 +159,7 @@ export function buildPublicProfileSummary(args: {
|
|
|
153
159
|
display_name: args.profile.display_name,
|
|
154
160
|
bio: args.profile.bio,
|
|
155
161
|
avatar_url: args.profile.avatar_url,
|
|
162
|
+
private_encryption_public_key: args.profile.private_encryption_public_key,
|
|
156
163
|
tags,
|
|
157
164
|
public_enabled: args.profile.public_enabled,
|
|
158
165
|
profile_version: args.profile_version ?? "v1",
|
|
@@ -5,12 +5,19 @@ export type AgentIdentity = {
|
|
|
5
5
|
created_at: number;
|
|
6
6
|
};
|
|
7
7
|
|
|
8
|
+
export type PrivateEncryptionKeyPair = {
|
|
9
|
+
public_key: string;
|
|
10
|
+
private_key: string;
|
|
11
|
+
created_at: number;
|
|
12
|
+
};
|
|
13
|
+
|
|
8
14
|
export type PublicProfile = {
|
|
9
15
|
agent_id: string;
|
|
10
16
|
display_name: string;
|
|
11
17
|
bio: string;
|
|
12
18
|
tags: string[];
|
|
13
19
|
avatar_url?: string;
|
|
20
|
+
private_encryption_public_key?: string;
|
|
14
21
|
public_enabled: boolean;
|
|
15
22
|
updated_at: number;
|
|
16
23
|
signature: string;
|
|
@@ -58,6 +65,43 @@ export type SocialMessageObservationRecord = {
|
|
|
58
65
|
signature: string;
|
|
59
66
|
};
|
|
60
67
|
|
|
68
|
+
export type PrivateMessageRecord = {
|
|
69
|
+
type: "private.message";
|
|
70
|
+
message_id: string;
|
|
71
|
+
conversation_id: string;
|
|
72
|
+
from_agent_id: string;
|
|
73
|
+
to_agent_id: string;
|
|
74
|
+
sender_public_key: string;
|
|
75
|
+
sender_encryption_public_key: string;
|
|
76
|
+
recipient_encryption_public_key: string;
|
|
77
|
+
cipher_scheme: "nacl-box-v1";
|
|
78
|
+
ciphertext: string;
|
|
79
|
+
nonce: string;
|
|
80
|
+
created_at: number;
|
|
81
|
+
signature: string;
|
|
82
|
+
};
|
|
83
|
+
|
|
84
|
+
export type PrivateMessageReceiptRecord = {
|
|
85
|
+
type: "private.message.receipt";
|
|
86
|
+
receipt_id: string;
|
|
87
|
+
message_id: string;
|
|
88
|
+
conversation_id: string;
|
|
89
|
+
from_agent_id: string;
|
|
90
|
+
to_agent_id: string;
|
|
91
|
+
sender_public_key: string;
|
|
92
|
+
status: "received" | "read";
|
|
93
|
+
created_at: number;
|
|
94
|
+
signature: string;
|
|
95
|
+
};
|
|
96
|
+
|
|
97
|
+
export type PrivateConversationSummary = {
|
|
98
|
+
conversation_id: string;
|
|
99
|
+
peer_agent_id: string;
|
|
100
|
+
last_message_at: number | null;
|
|
101
|
+
last_message_preview: string;
|
|
102
|
+
unread_count: number;
|
|
103
|
+
};
|
|
104
|
+
|
|
61
105
|
export type DirectoryState = {
|
|
62
106
|
profiles: Record<string, PublicProfile>;
|
|
63
107
|
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 {};
|