@silicaclaw/cli 1.0.0-beta.0
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/ARCHITECTURE.md +137 -0
- package/CHANGELOG.md +411 -0
- package/DEMO_GUIDE.md +89 -0
- package/INSTALL.md +156 -0
- package/README.md +244 -0
- package/RELEASE_NOTES_v1.0.md +65 -0
- package/ROADMAP.md +48 -0
- package/SOCIAL_MD_SPEC.md +122 -0
- package/VERSION +1 -0
- package/apps/local-console/package.json +23 -0
- package/apps/local-console/public/assets/README.md +5 -0
- package/apps/local-console/public/assets/silicaclaw-logo.png +0 -0
- package/apps/local-console/public/index.html +1602 -0
- package/apps/local-console/src/server.ts +1656 -0
- package/apps/local-console/src/socialRoutes.ts +90 -0
- package/apps/local-console/tsconfig.json +7 -0
- package/apps/public-explorer/package.json +20 -0
- package/apps/public-explorer/public/assets/README.md +5 -0
- package/apps/public-explorer/public/assets/silicaclaw-logo.png +0 -0
- package/apps/public-explorer/public/index.html +483 -0
- package/apps/public-explorer/src/server.ts +32 -0
- package/apps/public-explorer/tsconfig.json +7 -0
- package/docs/QUICK_START.md +48 -0
- package/docs/assets/README.md +8 -0
- package/docs/assets/banner.svg +25 -0
- package/docs/assets/silicaclaw-logo.png +0 -0
- package/docs/assets/silicaclaw-og.png +0 -0
- package/docs/release/GITHUB_RELEASE_v1.0-beta.md +143 -0
- package/docs/screenshots/README.md +8 -0
- package/docs/screenshots/v0.3.1-explorer-search.svg +9 -0
- package/docs/screenshots/v0.3.1-machine-a-network.svg +9 -0
- package/docs/screenshots/v0.3.1-machine-b-peers.svg +9 -0
- package/docs/screenshots/v0.3.1-stale-transition.svg +9 -0
- package/openclaw.social.md.example +28 -0
- package/package.json +64 -0
- package/packages/core/package.json +13 -0
- package/packages/core/src/crypto.ts +55 -0
- package/packages/core/src/directory.ts +171 -0
- package/packages/core/src/identity.ts +14 -0
- package/packages/core/src/index.ts +11 -0
- package/packages/core/src/indexing.ts +42 -0
- package/packages/core/src/presence.ts +24 -0
- package/packages/core/src/profile.ts +39 -0
- package/packages/core/src/publicProfileSummary.ts +180 -0
- package/packages/core/src/socialConfig.ts +440 -0
- package/packages/core/src/socialResolver.ts +281 -0
- package/packages/core/src/socialTemplate.ts +97 -0
- package/packages/core/src/types.ts +43 -0
- package/packages/core/tsconfig.json +7 -0
- package/packages/network/package.json +10 -0
- package/packages/network/src/abstractions/messageEnvelope.ts +80 -0
- package/packages/network/src/abstractions/peerDiscovery.ts +49 -0
- package/packages/network/src/abstractions/topicCodec.ts +4 -0
- package/packages/network/src/abstractions/transport.ts +40 -0
- package/packages/network/src/codec/jsonMessageEnvelopeCodec.ts +22 -0
- package/packages/network/src/codec/jsonTopicCodec.ts +11 -0
- package/packages/network/src/discovery/heartbeatPeerDiscovery.ts +173 -0
- package/packages/network/src/index.ts +16 -0
- package/packages/network/src/localEventBus.ts +61 -0
- package/packages/network/src/mock.ts +27 -0
- package/packages/network/src/realPreview.ts +436 -0
- package/packages/network/src/transport/udpLanBroadcastTransport.ts +173 -0
- package/packages/network/src/types.ts +6 -0
- package/packages/network/src/webrtcPreview.ts +1052 -0
- package/packages/network/tsconfig.json +7 -0
- package/packages/storage/package.json +13 -0
- package/packages/storage/src/index.ts +3 -0
- package/packages/storage/src/jsonRepo.ts +25 -0
- package/packages/storage/src/repos.ts +46 -0
- package/packages/storage/src/socialRuntimeRepo.ts +51 -0
- package/packages/storage/tsconfig.json +7 -0
- package/scripts/functional-check.mjs +165 -0
- package/scripts/install-logo.sh +53 -0
- package/scripts/quickstart.sh +144 -0
- package/scripts/silicaclaw-cli.mjs +88 -0
- package/scripts/webrtc-signaling-server.mjs +249 -0
- package/social.md.example +30 -0
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { IndexRefRecord, PublicProfile } from "./types";
|
|
2
|
+
|
|
3
|
+
export function normalizeTag(tag: string): string {
|
|
4
|
+
return tag.trim().toLowerCase();
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
export function buildTagIndexKeys(tags: string[]): string[] {
|
|
8
|
+
return tags
|
|
9
|
+
.map(normalizeTag)
|
|
10
|
+
.filter(Boolean)
|
|
11
|
+
.map((tag) => `tag:${tag}`);
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export function buildNamePrefixKeys(displayName: string): string[] {
|
|
15
|
+
const normalized = displayName.trim().toLowerCase().replace(/\s+/g, " ");
|
|
16
|
+
const collapsed = normalized.replace(/[^a-z0-9]+/g, "");
|
|
17
|
+
const source = collapsed || normalized.replace(/\s+/g, "");
|
|
18
|
+
const keys: string[] = [];
|
|
19
|
+
for (let i = 1; i <= source.length; i += 1) {
|
|
20
|
+
keys.push(`name:${source.slice(0, i)}`);
|
|
21
|
+
}
|
|
22
|
+
return keys;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export function buildIndexKeys(profile: PublicProfile): string[] {
|
|
26
|
+
const keys = new Set<string>();
|
|
27
|
+
for (const key of buildTagIndexKeys(profile.tags)) {
|
|
28
|
+
keys.add(key);
|
|
29
|
+
}
|
|
30
|
+
for (const key of buildNamePrefixKeys(profile.display_name)) {
|
|
31
|
+
keys.add(key);
|
|
32
|
+
}
|
|
33
|
+
return Array.from(keys);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export function buildIndexRecords(profile: PublicProfile): IndexRefRecord[] {
|
|
37
|
+
return buildIndexKeys(profile).map((key) => ({
|
|
38
|
+
type: "index",
|
|
39
|
+
key,
|
|
40
|
+
agent_id: profile.agent_id,
|
|
41
|
+
}));
|
|
42
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { AgentIdentity } from "./types";
|
|
2
|
+
import { signPayload, verifyPayload } from "./crypto";
|
|
3
|
+
import { PresenceRecord } from "./types";
|
|
4
|
+
|
|
5
|
+
function unsignedPresence(record: PresenceRecord): Omit<PresenceRecord, "signature"> {
|
|
6
|
+
const { signature: _signature, ...rest } = record;
|
|
7
|
+
return rest;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export function signPresence(identity: AgentIdentity, timestamp = Date.now()): PresenceRecord {
|
|
11
|
+
const payload = {
|
|
12
|
+
type: "presence" as const,
|
|
13
|
+
agent_id: identity.agent_id,
|
|
14
|
+
timestamp,
|
|
15
|
+
};
|
|
16
|
+
return {
|
|
17
|
+
...payload,
|
|
18
|
+
signature: signPayload(payload, identity.private_key),
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export function verifyPresence(record: PresenceRecord, publicKey: string): boolean {
|
|
23
|
+
return verifyPayload(unsignedPresence(record), record.signature, publicKey);
|
|
24
|
+
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { signPayload, verifyPayload } from "./crypto";
|
|
2
|
+
import { AgentIdentity, ProfileInput, PublicProfile } from "./types";
|
|
3
|
+
|
|
4
|
+
function payloadWithoutSignature(profile: PublicProfile): Omit<PublicProfile, "signature"> {
|
|
5
|
+
const { signature: _signature, ...payload } = profile;
|
|
6
|
+
return payload;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export function signProfile(input: ProfileInput, identity: AgentIdentity): PublicProfile {
|
|
10
|
+
const unsigned: Omit<PublicProfile, "signature"> = {
|
|
11
|
+
agent_id: input.agent_id,
|
|
12
|
+
display_name: input.display_name,
|
|
13
|
+
bio: input.bio,
|
|
14
|
+
tags: input.tags,
|
|
15
|
+
avatar_url: input.avatar_url,
|
|
16
|
+
public_enabled: input.public_enabled,
|
|
17
|
+
updated_at: Date.now(),
|
|
18
|
+
};
|
|
19
|
+
const signature = signPayload(unsigned, identity.private_key);
|
|
20
|
+
return {
|
|
21
|
+
...unsigned,
|
|
22
|
+
signature,
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export function verifyProfile(profile: PublicProfile, publicKey: string): boolean {
|
|
27
|
+
return verifyPayload(payloadWithoutSignature(profile), profile.signature, publicKey);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export function createDefaultProfileInput(agentId: string): ProfileInput {
|
|
31
|
+
return {
|
|
32
|
+
agent_id: agentId,
|
|
33
|
+
display_name: "",
|
|
34
|
+
bio: "",
|
|
35
|
+
tags: [],
|
|
36
|
+
avatar_url: "",
|
|
37
|
+
public_enabled: false,
|
|
38
|
+
};
|
|
39
|
+
}
|
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
import { PublicProfile } from "./types";
|
|
2
|
+
|
|
3
|
+
export type CapabilityKey = "browser" | "computer" | "research" | "openclaw";
|
|
4
|
+
|
|
5
|
+
export type ProfileVisibility = {
|
|
6
|
+
show_tags: boolean;
|
|
7
|
+
show_last_seen: boolean;
|
|
8
|
+
show_capabilities_summary: boolean;
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
export type PublicProfileSummary = {
|
|
12
|
+
agent_id: string;
|
|
13
|
+
display_name: string;
|
|
14
|
+
bio: string;
|
|
15
|
+
avatar_url?: string;
|
|
16
|
+
public_enabled: boolean;
|
|
17
|
+
updated_at: number;
|
|
18
|
+
online: boolean;
|
|
19
|
+
last_seen_at: number | null;
|
|
20
|
+
tags: string[];
|
|
21
|
+
network_mode: string;
|
|
22
|
+
openclaw_bound: boolean;
|
|
23
|
+
capabilities_summary: string[];
|
|
24
|
+
profile_version: string;
|
|
25
|
+
public_key_fingerprint: string | null;
|
|
26
|
+
profile_updated_at: number;
|
|
27
|
+
presence_seen_at: number | null;
|
|
28
|
+
freshness_status: "live" | "recently_seen" | "stale";
|
|
29
|
+
verified_profile: boolean;
|
|
30
|
+
verified_presence_recent: boolean;
|
|
31
|
+
verification_status: "verified" | "stale" | "unverified";
|
|
32
|
+
signed_claims: {
|
|
33
|
+
display_name: string;
|
|
34
|
+
bio: string;
|
|
35
|
+
avatar_url?: string;
|
|
36
|
+
tags: string[];
|
|
37
|
+
public_enabled: boolean;
|
|
38
|
+
profile_version: string;
|
|
39
|
+
profile_updated_at: number;
|
|
40
|
+
public_key_fingerprint: string | null;
|
|
41
|
+
verified_profile: boolean;
|
|
42
|
+
};
|
|
43
|
+
observed_state: {
|
|
44
|
+
online: boolean;
|
|
45
|
+
freshness_status: "live" | "recently_seen" | "stale";
|
|
46
|
+
presence_seen_at: number | null;
|
|
47
|
+
verified_presence_recent: boolean;
|
|
48
|
+
};
|
|
49
|
+
integration_metadata: {
|
|
50
|
+
network_mode: string;
|
|
51
|
+
openclaw_bound: boolean;
|
|
52
|
+
verification_status: "verified" | "stale" | "unverified";
|
|
53
|
+
};
|
|
54
|
+
public_visibility: {
|
|
55
|
+
visible_fields: string[];
|
|
56
|
+
hidden_fields: string[];
|
|
57
|
+
};
|
|
58
|
+
visibility: ProfileVisibility;
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
const DEFAULT_VISIBILITY: ProfileVisibility = {
|
|
62
|
+
show_tags: true,
|
|
63
|
+
show_last_seen: true,
|
|
64
|
+
show_capabilities_summary: true,
|
|
65
|
+
};
|
|
66
|
+
|
|
67
|
+
const CAPABILITY_KEYS: CapabilityKey[] = ["browser", "computer", "research", "openclaw"];
|
|
68
|
+
|
|
69
|
+
export function deriveCapabilitiesSummary(tags: string[]): string[] {
|
|
70
|
+
const normalized = new Set(tags.map((tag) => String(tag).trim().toLowerCase()).filter(Boolean));
|
|
71
|
+
return CAPABILITY_KEYS.filter((key) => normalized.has(key));
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
export function buildPublicProfileSummary(args: {
|
|
75
|
+
profile: PublicProfile;
|
|
76
|
+
online: boolean;
|
|
77
|
+
last_seen_at: number | null;
|
|
78
|
+
network_mode?: string;
|
|
79
|
+
openclaw_bound?: boolean;
|
|
80
|
+
visibility?: Partial<ProfileVisibility>;
|
|
81
|
+
profile_version?: string;
|
|
82
|
+
public_key_fingerprint?: string | null;
|
|
83
|
+
verified_profile?: boolean;
|
|
84
|
+
now?: number;
|
|
85
|
+
presence_ttl_ms?: number;
|
|
86
|
+
}): PublicProfileSummary {
|
|
87
|
+
const visibility: ProfileVisibility = {
|
|
88
|
+
show_tags:
|
|
89
|
+
typeof args.visibility?.show_tags === "boolean"
|
|
90
|
+
? args.visibility.show_tags
|
|
91
|
+
: DEFAULT_VISIBILITY.show_tags,
|
|
92
|
+
show_last_seen:
|
|
93
|
+
typeof args.visibility?.show_last_seen === "boolean"
|
|
94
|
+
? args.visibility.show_last_seen
|
|
95
|
+
: DEFAULT_VISIBILITY.show_last_seen,
|
|
96
|
+
show_capabilities_summary:
|
|
97
|
+
typeof args.visibility?.show_capabilities_summary === "boolean"
|
|
98
|
+
? args.visibility.show_capabilities_summary
|
|
99
|
+
: DEFAULT_VISIBILITY.show_capabilities_summary,
|
|
100
|
+
};
|
|
101
|
+
|
|
102
|
+
const tags = visibility.show_tags ? args.profile.tags : [];
|
|
103
|
+
const capabilities = visibility.show_capabilities_summary ? deriveCapabilitiesSummary(args.profile.tags) : [];
|
|
104
|
+
const now = Number.isFinite(args.now) ? Number(args.now) : Date.now();
|
|
105
|
+
const ttl = Number.isFinite(args.presence_ttl_ms) ? Number(args.presence_ttl_ms) : 30_000;
|
|
106
|
+
const age = args.last_seen_at ? Math.max(0, now - args.last_seen_at) : Number.POSITIVE_INFINITY;
|
|
107
|
+
const freshness_status: "live" | "recently_seen" | "stale" =
|
|
108
|
+
age <= ttl ? "live" : age <= ttl * 3 ? "recently_seen" : "stale";
|
|
109
|
+
const verified_profile = Boolean(args.verified_profile);
|
|
110
|
+
const verified_presence_recent = freshness_status !== "stale" && Boolean(args.last_seen_at);
|
|
111
|
+
const verification_status: "verified" | "stale" | "unverified" = !verified_profile
|
|
112
|
+
? "unverified"
|
|
113
|
+
: verified_presence_recent
|
|
114
|
+
? "verified"
|
|
115
|
+
: "stale";
|
|
116
|
+
const visible_fields = [
|
|
117
|
+
"display_name",
|
|
118
|
+
"bio",
|
|
119
|
+
"public_enabled",
|
|
120
|
+
"profile_updated_at",
|
|
121
|
+
visibility.show_tags ? "tags" : "",
|
|
122
|
+
visibility.show_last_seen ? "presence_seen_at" : "",
|
|
123
|
+
visibility.show_capabilities_summary ? "capabilities_summary" : "",
|
|
124
|
+
].filter((field): field is string => Boolean(field));
|
|
125
|
+
const hidden_fields = [
|
|
126
|
+
visibility.show_tags ? "" : "tags",
|
|
127
|
+
visibility.show_last_seen ? "" : "presence_seen_at",
|
|
128
|
+
visibility.show_capabilities_summary ? "" : "capabilities_summary",
|
|
129
|
+
].filter((field): field is string => Boolean(field));
|
|
130
|
+
|
|
131
|
+
return {
|
|
132
|
+
agent_id: args.profile.agent_id,
|
|
133
|
+
display_name: args.profile.display_name,
|
|
134
|
+
bio: args.profile.bio,
|
|
135
|
+
avatar_url: args.profile.avatar_url,
|
|
136
|
+
public_enabled: args.profile.public_enabled,
|
|
137
|
+
updated_at: args.profile.updated_at,
|
|
138
|
+
online: args.online,
|
|
139
|
+
last_seen_at: visibility.show_last_seen ? args.last_seen_at : null,
|
|
140
|
+
tags,
|
|
141
|
+
network_mode: args.network_mode ?? "unknown",
|
|
142
|
+
openclaw_bound: Boolean(args.openclaw_bound),
|
|
143
|
+
capabilities_summary: capabilities,
|
|
144
|
+
profile_version: args.profile_version ?? "v1",
|
|
145
|
+
public_key_fingerprint: args.public_key_fingerprint ?? null,
|
|
146
|
+
profile_updated_at: args.profile.updated_at,
|
|
147
|
+
presence_seen_at: visibility.show_last_seen ? args.last_seen_at : null,
|
|
148
|
+
freshness_status,
|
|
149
|
+
verified_profile,
|
|
150
|
+
verified_presence_recent,
|
|
151
|
+
verification_status,
|
|
152
|
+
signed_claims: {
|
|
153
|
+
display_name: args.profile.display_name,
|
|
154
|
+
bio: args.profile.bio,
|
|
155
|
+
avatar_url: args.profile.avatar_url,
|
|
156
|
+
tags,
|
|
157
|
+
public_enabled: args.profile.public_enabled,
|
|
158
|
+
profile_version: args.profile_version ?? "v1",
|
|
159
|
+
profile_updated_at: args.profile.updated_at,
|
|
160
|
+
public_key_fingerprint: args.public_key_fingerprint ?? null,
|
|
161
|
+
verified_profile,
|
|
162
|
+
},
|
|
163
|
+
observed_state: {
|
|
164
|
+
online: args.online,
|
|
165
|
+
freshness_status,
|
|
166
|
+
presence_seen_at: visibility.show_last_seen ? args.last_seen_at : null,
|
|
167
|
+
verified_presence_recent,
|
|
168
|
+
},
|
|
169
|
+
integration_metadata: {
|
|
170
|
+
network_mode: args.network_mode ?? "unknown",
|
|
171
|
+
openclaw_bound: Boolean(args.openclaw_bound),
|
|
172
|
+
verification_status,
|
|
173
|
+
},
|
|
174
|
+
public_visibility: {
|
|
175
|
+
visible_fields,
|
|
176
|
+
hidden_fields,
|
|
177
|
+
},
|
|
178
|
+
visibility,
|
|
179
|
+
};
|
|
180
|
+
}
|