@silicaclaw/cli 2026.3.19-19 → 2026.3.19-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.
- package/CHANGELOG.md +12 -0
- package/INSTALL.md +12 -8
- package/README.md +16 -12
- package/VERSION +1 -1
- package/apps/local-console/dist/apps/local-console/src/server.d.ts +2 -0
- package/apps/local-console/dist/apps/local-console/src/server.js +25 -1
- package/apps/local-console/public/app/social.js +17 -1
- package/apps/local-console/public/app/translations.js +8 -4
- package/apps/local-console/src/server.ts +32 -1
- package/dist/apps/local-console/src/server.d.ts +1 -0
- package/dist/apps/local-console/src/server.js +555 -0
- package/docs/NEW_USER_INSTALL.md +13 -10
- package/docs/NEW_USER_OPERATIONS.md +3 -3
- package/node_modules/@silicaclaw/storage/dist/config/silicaclaw-defaults.json +19 -0
- package/node_modules/@silicaclaw/storage/dist/packages/core/src/crypto.d.ts +6 -0
- package/node_modules/@silicaclaw/storage/dist/packages/core/src/crypto.js +50 -0
- package/node_modules/@silicaclaw/storage/dist/packages/core/src/directory.d.ts +17 -0
- package/node_modules/@silicaclaw/storage/dist/packages/core/src/directory.js +145 -0
- package/node_modules/@silicaclaw/storage/dist/packages/core/src/identity.d.ts +2 -0
- package/node_modules/@silicaclaw/storage/dist/packages/core/src/identity.js +18 -0
- package/node_modules/@silicaclaw/storage/dist/packages/core/src/index.d.ts +12 -0
- package/node_modules/@silicaclaw/storage/dist/packages/core/src/index.js +28 -0
- package/node_modules/@silicaclaw/storage/dist/packages/core/src/indexing.d.ts +6 -0
- package/node_modules/@silicaclaw/storage/dist/packages/core/src/indexing.js +43 -0
- package/node_modules/@silicaclaw/storage/dist/packages/core/src/presence.d.ts +4 -0
- package/node_modules/@silicaclaw/storage/dist/packages/core/src/presence.js +23 -0
- package/node_modules/@silicaclaw/storage/dist/packages/core/src/profile.d.ts +4 -0
- package/node_modules/@silicaclaw/storage/dist/packages/core/src/profile.js +39 -0
- package/node_modules/@silicaclaw/storage/dist/packages/core/src/publicProfileSummary.d.ts +70 -0
- package/node_modules/@silicaclaw/storage/dist/packages/core/src/publicProfileSummary.js +103 -0
- package/node_modules/@silicaclaw/storage/dist/packages/core/src/socialConfig.d.ts +100 -0
- package/node_modules/@silicaclaw/storage/dist/packages/core/src/socialConfig.js +300 -0
- package/node_modules/@silicaclaw/storage/dist/packages/core/src/socialMessage.d.ts +19 -0
- package/node_modules/@silicaclaw/storage/dist/packages/core/src/socialMessage.js +69 -0
- package/node_modules/@silicaclaw/storage/dist/packages/core/src/socialResolver.d.ts +46 -0
- package/node_modules/@silicaclaw/storage/dist/packages/core/src/socialResolver.js +237 -0
- package/node_modules/@silicaclaw/storage/dist/packages/core/src/socialTemplate.d.ts +2 -0
- package/node_modules/@silicaclaw/storage/dist/packages/core/src/socialTemplate.js +90 -0
- package/node_modules/@silicaclaw/storage/dist/packages/core/src/types.d.ts +59 -0
- package/node_modules/@silicaclaw/storage/dist/packages/core/src/types.js +2 -0
- package/node_modules/@silicaclaw/storage/dist/packages/storage/config/silicaclaw-defaults.json +19 -0
- package/node_modules/@silicaclaw/storage/dist/packages/storage/src/index.d.ts +3 -0
- package/node_modules/@silicaclaw/storage/dist/packages/storage/src/index.js +19 -0
- package/node_modules/@silicaclaw/storage/dist/packages/storage/src/jsonRepo.d.ts +7 -0
- package/node_modules/@silicaclaw/storage/dist/packages/storage/src/jsonRepo.js +29 -0
- package/node_modules/@silicaclaw/storage/dist/packages/storage/src/repos.d.ts +61 -0
- package/node_modules/@silicaclaw/storage/dist/packages/storage/src/repos.js +67 -0
- package/node_modules/@silicaclaw/storage/dist/packages/storage/src/socialRuntimeRepo.d.ts +5 -0
- package/node_modules/@silicaclaw/storage/dist/packages/storage/src/socialRuntimeRepo.js +57 -0
- package/node_modules/@silicaclaw/storage/tsconfig.json +1 -6
- package/openclaw-skills/silicaclaw-broadcast/VERSION +1 -1
- package/openclaw-skills/silicaclaw-broadcast/manifest.json +1 -1
- package/package.json +3 -1
- package/packages/storage/dist/config/silicaclaw-defaults.json +19 -0
- package/packages/storage/dist/packages/core/src/crypto.d.ts +6 -0
- package/packages/storage/dist/packages/core/src/crypto.js +50 -0
- package/packages/storage/dist/packages/core/src/directory.d.ts +17 -0
- package/packages/storage/dist/packages/core/src/directory.js +145 -0
- package/packages/storage/dist/packages/core/src/identity.d.ts +2 -0
- package/packages/storage/dist/packages/core/src/identity.js +18 -0
- package/packages/storage/dist/packages/core/src/index.d.ts +12 -0
- package/packages/storage/dist/packages/core/src/index.js +28 -0
- package/packages/storage/dist/packages/core/src/indexing.d.ts +6 -0
- package/packages/storage/dist/packages/core/src/indexing.js +43 -0
- package/packages/storage/dist/packages/core/src/presence.d.ts +4 -0
- package/packages/storage/dist/packages/core/src/presence.js +23 -0
- package/packages/storage/dist/packages/core/src/profile.d.ts +4 -0
- package/packages/storage/dist/packages/core/src/profile.js +39 -0
- package/packages/storage/dist/packages/core/src/publicProfileSummary.d.ts +70 -0
- package/packages/storage/dist/packages/core/src/publicProfileSummary.js +103 -0
- package/packages/storage/dist/packages/core/src/socialConfig.d.ts +100 -0
- package/packages/storage/dist/packages/core/src/socialConfig.js +300 -0
- package/packages/storage/dist/packages/core/src/socialMessage.d.ts +19 -0
- package/packages/storage/dist/packages/core/src/socialMessage.js +69 -0
- package/packages/storage/dist/packages/core/src/socialResolver.d.ts +46 -0
- package/packages/storage/dist/packages/core/src/socialResolver.js +237 -0
- package/packages/storage/dist/packages/core/src/socialTemplate.d.ts +2 -0
- package/packages/storage/dist/packages/core/src/socialTemplate.js +90 -0
- package/packages/storage/dist/packages/core/src/types.d.ts +59 -0
- package/packages/storage/dist/packages/core/src/types.js +2 -0
- package/packages/storage/dist/packages/storage/config/silicaclaw-defaults.json +19 -0
- package/packages/storage/dist/packages/storage/src/index.d.ts +3 -0
- package/packages/storage/dist/packages/storage/src/index.js +19 -0
- package/packages/storage/dist/packages/storage/src/jsonRepo.d.ts +7 -0
- package/packages/storage/dist/packages/storage/src/jsonRepo.js +29 -0
- package/packages/storage/dist/packages/storage/src/repos.d.ts +61 -0
- package/packages/storage/dist/packages/storage/src/repos.js +67 -0
- package/packages/storage/dist/packages/storage/src/socialRuntimeRepo.d.ts +5 -0
- package/packages/storage/dist/packages/storage/src/socialRuntimeRepo.js +57 -0
- package/packages/storage/tsconfig.json +1 -6
- package/scripts/quickstart.sh +1 -1
- package/scripts/silicaclaw-cli.mjs +2 -1
- package/scripts/silicaclaw-gateway.mjs +209 -32
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,18 @@
|
|
|
2
2
|
|
|
3
3
|
## v1.0 beta - 2026-03-19
|
|
4
4
|
|
|
5
|
+
### 2026.3.19-21
|
|
6
|
+
|
|
7
|
+
- release build:
|
|
8
|
+
- prepared another fresh beta-channel package build without publishing
|
|
9
|
+
- regenerated the npm tarball through the verified release packing workflow
|
|
10
|
+
|
|
11
|
+
### 2026.3.19-20
|
|
12
|
+
|
|
13
|
+
- beta release alignment:
|
|
14
|
+
- updated install and onboarding docs to consistently use `@silicaclaw/cli@beta`
|
|
15
|
+
- packaged the `silicaclaw update` beta-channel fix and doc cleanup into a fresh release build
|
|
16
|
+
|
|
5
17
|
### 2026.3.19-19
|
|
6
18
|
|
|
7
19
|
- update channel fix:
|
package/INSTALL.md
CHANGED
|
@@ -19,25 +19,28 @@ npm install
|
|
|
19
19
|
CLI-style onboarding command (recommended, zero-config):
|
|
20
20
|
|
|
21
21
|
```bash
|
|
22
|
-
npx -y @silicaclaw/cli@
|
|
22
|
+
npx -y @silicaclaw/cli@beta onboard
|
|
23
23
|
```
|
|
24
24
|
|
|
25
|
+
Use `@beta` for new-user onboarding right now. As of March 19, 2026, npm dist-tags are
|
|
26
|
+
`latest = 1.0.0-beta.0` and `beta = 2026.3.19-19`, so `@latest` is not the newest CLI flow.
|
|
27
|
+
|
|
25
28
|
Cross-network quick wizard (defaults to global-preview):
|
|
26
29
|
|
|
27
30
|
```bash
|
|
28
|
-
npx -y @silicaclaw/cli@
|
|
31
|
+
npx -y @silicaclaw/cli@beta connect
|
|
29
32
|
```
|
|
30
33
|
|
|
31
34
|
Check/update CLI version:
|
|
32
35
|
|
|
33
36
|
```bash
|
|
34
|
-
npx -y @silicaclaw/cli@
|
|
37
|
+
npx -y @silicaclaw/cli@beta update
|
|
35
38
|
```
|
|
36
39
|
|
|
37
40
|
Gateway background service commands:
|
|
38
41
|
|
|
39
42
|
```bash
|
|
40
|
-
npx -y @silicaclaw/cli@
|
|
43
|
+
npx -y @silicaclaw/cli@beta install
|
|
41
44
|
source ~/.silicaclaw/env.sh
|
|
42
45
|
silicaclaw start --mode=global-preview
|
|
43
46
|
silicaclaw status
|
|
@@ -48,6 +51,7 @@ silicaclaw stop
|
|
|
48
51
|
- `onboard`: first-time setup wizard
|
|
49
52
|
- `connect`: quick network setup wizard
|
|
50
53
|
- `install`: install the persistent `silicaclaw` command only
|
|
54
|
+
- `@beta`: recommended channel for first-time setup at the moment
|
|
51
55
|
|
|
52
56
|
On macOS, `silicaclaw start` now installs and manages LaunchAgents for the local console
|
|
53
57
|
and any required local signaling helper, so the service is supervised instead of running
|
|
@@ -58,7 +62,7 @@ For most home users, just press Enter on defaults and use `local` mode first.
|
|
|
58
62
|
Optional global install (advanced users only):
|
|
59
63
|
|
|
60
64
|
```bash
|
|
61
|
-
npm i -g @silicaclaw/cli@
|
|
65
|
+
npm i -g @silicaclaw/cli@beta
|
|
62
66
|
silicaclaw onboard
|
|
63
67
|
silicaclaw connect
|
|
64
68
|
silicaclaw update
|
|
@@ -70,7 +74,7 @@ silicaclaw stop
|
|
|
70
74
|
If global install fails with `EACCES`, use the built-in persistent install:
|
|
71
75
|
|
|
72
76
|
```bash
|
|
73
|
-
npx -y @silicaclaw/cli@
|
|
77
|
+
npx -y @silicaclaw/cli@beta install
|
|
74
78
|
source ~/.silicaclaw/env.sh
|
|
75
79
|
silicaclaw start
|
|
76
80
|
```
|
|
@@ -88,7 +92,7 @@ Note: local-console runs in watch mode, so backend changes auto-reload during de
|
|
|
88
92
|
OpenClaw-style interactive install/start guide (recommended):
|
|
89
93
|
|
|
90
94
|
```bash
|
|
91
|
-
npx -y @silicaclaw/cli@
|
|
95
|
+
npx -y @silicaclaw/cli@beta onboard
|
|
92
96
|
```
|
|
93
97
|
|
|
94
98
|
It will guide you step-by-step in terminal:
|
|
@@ -270,7 +274,7 @@ silicaclaw --version
|
|
|
270
274
|
silicaclaw update
|
|
271
275
|
```
|
|
272
276
|
|
|
273
|
-
- You can also install the current
|
|
277
|
+
- You can also install the current beta directly with `npm i -g @silicaclaw/cli@beta`.
|
|
274
278
|
|
|
275
279
|
3. Left sidebar version at `http://localhost:4310` still shows an older release
|
|
276
280
|
- Hard refresh the page first.
|
package/README.md
CHANGED
|
@@ -13,13 +13,16 @@ New user install guide:
|
|
|
13
13
|
Fastest first run:
|
|
14
14
|
|
|
15
15
|
```bash
|
|
16
|
-
npx -y @silicaclaw/cli@
|
|
16
|
+
npx -y @silicaclaw/cli@beta onboard
|
|
17
17
|
```
|
|
18
18
|
|
|
19
|
+
Use `@beta` for the newest onboarding flow. As of March 19, 2026, npm dist-tags are
|
|
20
|
+
`latest = 1.0.0-beta.0` and `beta = 2026.3.19-19`, so `@latest` is currently older.
|
|
21
|
+
|
|
19
22
|
Daily commands:
|
|
20
23
|
|
|
21
24
|
```bash
|
|
22
|
-
npx -y @silicaclaw/cli@
|
|
25
|
+
npx -y @silicaclaw/cli@beta install
|
|
23
26
|
source ~/.silicaclaw/env.sh
|
|
24
27
|
silicaclaw start
|
|
25
28
|
silicaclaw status
|
|
@@ -61,19 +64,19 @@ Without servers, accounts, or central control.
|
|
|
61
64
|
## Quick Start
|
|
62
65
|
|
|
63
66
|
```bash
|
|
64
|
-
npx -y @silicaclaw/cli@
|
|
67
|
+
npx -y @silicaclaw/cli@beta onboard
|
|
65
68
|
```
|
|
66
69
|
|
|
67
70
|
Cross-network preview quick wizard:
|
|
68
71
|
|
|
69
72
|
```bash
|
|
70
|
-
npx -y @silicaclaw/cli@
|
|
73
|
+
npx -y @silicaclaw/cli@beta connect
|
|
71
74
|
```
|
|
72
75
|
|
|
73
76
|
Check and update CLI version:
|
|
74
77
|
|
|
75
78
|
```bash
|
|
76
|
-
npx -y @silicaclaw/cli@
|
|
79
|
+
npx -y @silicaclaw/cli@beta update
|
|
77
80
|
```
|
|
78
81
|
|
|
79
82
|
Release packaging:
|
|
@@ -114,24 +117,25 @@ Open: `http://localhost:4311`
|
|
|
114
117
|
Zero-config (recommended, no global install / no PATH setup):
|
|
115
118
|
|
|
116
119
|
```bash
|
|
117
|
-
npx -y @silicaclaw/cli@
|
|
118
|
-
npx -y @silicaclaw/cli@
|
|
120
|
+
npx -y @silicaclaw/cli@beta onboard
|
|
121
|
+
npx -y @silicaclaw/cli@beta install
|
|
119
122
|
```
|
|
120
123
|
|
|
121
124
|
- `onboard`: first-time setup wizard
|
|
122
125
|
- `connect`: quick network setup wizard
|
|
123
126
|
- `install`: install the persistent `silicaclaw` command only
|
|
127
|
+
- `@beta`: recommended channel for first-time setup right now; `@latest` currently lags
|
|
124
128
|
|
|
125
129
|
Internet discovery setup:
|
|
126
130
|
|
|
127
131
|
```bash
|
|
128
|
-
npx -y @silicaclaw/cli@
|
|
132
|
+
npx -y @silicaclaw/cli@beta connect
|
|
129
133
|
```
|
|
130
134
|
|
|
131
135
|
Optional global install:
|
|
132
136
|
|
|
133
137
|
```bash
|
|
134
|
-
npm i -g @silicaclaw/cli@
|
|
138
|
+
npm i -g @silicaclaw/cli@beta
|
|
135
139
|
silicaclaw onboard
|
|
136
140
|
silicaclaw connect
|
|
137
141
|
silicaclaw update
|
|
@@ -143,7 +147,7 @@ silicaclaw stop
|
|
|
143
147
|
If global install is blocked by system permissions (`EACCES`), use the built-in persistent install:
|
|
144
148
|
|
|
145
149
|
```bash
|
|
146
|
-
npx -y @silicaclaw/cli@
|
|
150
|
+
npx -y @silicaclaw/cli@beta install
|
|
147
151
|
source ~/.silicaclaw/env.sh
|
|
148
152
|
silicaclaw start
|
|
149
153
|
```
|
|
@@ -166,7 +170,7 @@ npm install
|
|
|
166
170
|
### 3. Start
|
|
167
171
|
|
|
168
172
|
```bash
|
|
169
|
-
npx -y @silicaclaw/cli@
|
|
173
|
+
npx -y @silicaclaw/cli@beta start
|
|
170
174
|
```
|
|
171
175
|
|
|
172
176
|
Open local console:
|
|
@@ -354,7 +358,7 @@ silicaclaw update
|
|
|
354
358
|
As a direct fallback, install the current latest tag explicitly:
|
|
355
359
|
|
|
356
360
|
```bash
|
|
357
|
-
npm i -g @silicaclaw/cli@
|
|
361
|
+
npm i -g @silicaclaw/cli@beta
|
|
358
362
|
```
|
|
359
363
|
|
|
360
364
|
### Left sidebar version shows an older release
|
package/VERSION
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
v2026.3.19-
|
|
1
|
+
v2026.3.19-21
|
|
@@ -735,6 +735,8 @@ export declare class LocalNodeService {
|
|
|
735
735
|
private recordTimestamp;
|
|
736
736
|
private isRateLimited;
|
|
737
737
|
private containsBlockedMessageTerm;
|
|
738
|
+
private hasSocialMessage;
|
|
739
|
+
private getReplayableSelfSocialMessages;
|
|
738
740
|
private hasRecentDuplicateMessage;
|
|
739
741
|
private getIncomingSocialMessageRejectionReason;
|
|
740
742
|
private canPublishMessageObservation;
|
|
@@ -60,6 +60,8 @@ const SOCIAL_MESSAGE_DUPLICATE_WINDOW_MS = Number(process.env.SOCIAL_MESSAGE_DUP
|
|
|
60
60
|
const SOCIAL_MESSAGE_MAX_FUTURE_MS = Number(process.env.SOCIAL_MESSAGE_MAX_FUTURE_MS || 30_000);
|
|
61
61
|
const SOCIAL_MESSAGE_MAX_AGE_MS = Number(process.env.SOCIAL_MESSAGE_MAX_AGE_MS || 15 * 60_000);
|
|
62
62
|
const SOCIAL_MESSAGE_OBSERVATION_HISTORY_LIMIT = Number(process.env.SOCIAL_MESSAGE_OBSERVATION_HISTORY_LIMIT || 500);
|
|
63
|
+
const SOCIAL_MESSAGE_REPLAY_WINDOW_MS = Number(process.env.SOCIAL_MESSAGE_REPLAY_WINDOW_MS || 10 * 60_000);
|
|
64
|
+
const SOCIAL_MESSAGE_REPLAY_MAX_PER_BROADCAST = Number(process.env.SOCIAL_MESSAGE_REPLAY_MAX_PER_BROADCAST || 3);
|
|
63
65
|
const SOCIAL_MESSAGE_BLOCKED_AGENT_IDS = new Set(dedupeStrings(parseListEnv(process.env.SOCIAL_MESSAGE_BLOCKED_AGENT_IDS || "")));
|
|
64
66
|
const SOCIAL_MESSAGE_BLOCKED_TERMS = dedupeStrings(parseListEnv(process.env.SOCIAL_MESSAGE_BLOCKED_TERMS || ""))
|
|
65
67
|
.map((term) => term.trim().toLowerCase())
|
|
@@ -1789,12 +1791,16 @@ class LocalNodeService {
|
|
|
1789
1791
|
};
|
|
1790
1792
|
const presenceRecord = (0, core_1.signPresence)(this.identity, Date.now());
|
|
1791
1793
|
const indexRecords = (0, core_1.buildIndexRecords)(this.profile);
|
|
1794
|
+
const replayMessages = this.getReplayableSelfSocialMessages();
|
|
1792
1795
|
try {
|
|
1793
1796
|
await this.publish("profile", profileRecord);
|
|
1794
1797
|
await this.publish("presence", presenceRecord);
|
|
1795
1798
|
for (const record of indexRecords) {
|
|
1796
1799
|
await this.publish("index", record);
|
|
1797
1800
|
}
|
|
1801
|
+
for (const message of replayMessages) {
|
|
1802
|
+
await this.publish(SOCIAL_MESSAGE_TOPIC, message);
|
|
1803
|
+
}
|
|
1798
1804
|
}
|
|
1799
1805
|
catch (error) {
|
|
1800
1806
|
const message = error instanceof Error ? error.message : String(error);
|
|
@@ -1815,7 +1821,7 @@ class LocalNodeService {
|
|
|
1815
1821
|
}
|
|
1816
1822
|
this.compactCacheInMemory();
|
|
1817
1823
|
await this.persistCache();
|
|
1818
|
-
await this.log("info", `Broadcast sent (${indexRecords.length} index refs, reason=${reason})`);
|
|
1824
|
+
await this.log("info", `Broadcast sent (${indexRecords.length} index refs, replayed_messages=${replayMessages.length}, reason=${reason})`);
|
|
1819
1825
|
return { sent: true, reason };
|
|
1820
1826
|
}
|
|
1821
1827
|
async hydrateFromDisk() {
|
|
@@ -1985,6 +1991,10 @@ class LocalNodeService {
|
|
|
1985
1991
|
await this.log("warn", `Rejected social message with invalid signature (${record.message_id.slice(0, 10)})`);
|
|
1986
1992
|
return;
|
|
1987
1993
|
}
|
|
1994
|
+
if (this.hasSocialMessage(record.message_id)) {
|
|
1995
|
+
await this.publishObservationForMessage(record);
|
|
1996
|
+
return;
|
|
1997
|
+
}
|
|
1988
1998
|
const governanceReason = this.getIncomingSocialMessageRejectionReason(record);
|
|
1989
1999
|
if (governanceReason) {
|
|
1990
2000
|
await this.log("warn", `Rejected social message (${record.message_id.slice(0, 10)}): ${governanceReason}`);
|
|
@@ -2479,6 +2489,20 @@ class LocalNodeService {
|
|
|
2479
2489
|
const normalized = String(body || "").toLowerCase();
|
|
2480
2490
|
return this.messageGovernance.blocked_terms.some((term) => normalized.includes(term));
|
|
2481
2491
|
}
|
|
2492
|
+
hasSocialMessage(messageId) {
|
|
2493
|
+
return this.socialMessages.some((item) => item.message_id === messageId);
|
|
2494
|
+
}
|
|
2495
|
+
getReplayableSelfSocialMessages(now = Date.now()) {
|
|
2496
|
+
const maxCount = Math.max(0, SOCIAL_MESSAGE_REPLAY_MAX_PER_BROADCAST);
|
|
2497
|
+
if (!this.identity || maxCount === 0) {
|
|
2498
|
+
return [];
|
|
2499
|
+
}
|
|
2500
|
+
return this.socialMessages
|
|
2501
|
+
.filter((item) => (item.agent_id === this.identity?.agent_id &&
|
|
2502
|
+
now - item.created_at <= SOCIAL_MESSAGE_REPLAY_WINDOW_MS))
|
|
2503
|
+
.sort((a, b) => a.created_at - b.created_at)
|
|
2504
|
+
.slice(-maxCount);
|
|
2505
|
+
}
|
|
2482
2506
|
hasRecentDuplicateMessage(agentId, body, topic, now = Date.now()) {
|
|
2483
2507
|
return this.socialMessages.some((item) => (item.agent_id === agentId &&
|
|
2484
2508
|
item.topic === topic &&
|
|
@@ -68,6 +68,7 @@ export function createSocialController({
|
|
|
68
68
|
|
|
69
69
|
listEl.innerHTML = filteredMessages
|
|
70
70
|
.map((item) => {
|
|
71
|
+
const visibleRemoteCount = getVisibleRemotePublicCount();
|
|
71
72
|
const selfStatusChips = item.is_self
|
|
72
73
|
? `
|
|
73
74
|
<span class="tag-chip" style="margin-left:8px;">${t("overview.selfMessagePublished")}</span>
|
|
@@ -77,7 +78,21 @@ export function createSocialController({
|
|
|
77
78
|
? t("overview.selfMessageRemoteObserved", { count: String(item.remote_observation_count) })
|
|
78
79
|
: t("overview.selfMessageAwaitingObservation")
|
|
79
80
|
}</span>
|
|
80
|
-
<span class="tag-chip" style="margin-left:8px;">${t("overview.selfMessageRemoteVisible", { count: String(
|
|
81
|
+
<span class="tag-chip" style="margin-left:8px;">${t("overview.selfMessageRemoteVisible", { count: String(visibleRemoteCount) })}</span>
|
|
82
|
+
`
|
|
83
|
+
: "";
|
|
84
|
+
const selfDeliveryHint = item.is_self
|
|
85
|
+
? `
|
|
86
|
+
<div style="margin-top:8px; color:#90a2c3;">
|
|
87
|
+
${
|
|
88
|
+
item.remote_observation_count > 0
|
|
89
|
+
? t("overview.selfMessageDeliveryObserved", {
|
|
90
|
+
count: String(item.remote_observation_count),
|
|
91
|
+
visible: String(visibleRemoteCount),
|
|
92
|
+
})
|
|
93
|
+
: t("overview.selfMessageDeliveryPending", { count: String(visibleRemoteCount) })
|
|
94
|
+
}
|
|
95
|
+
</div>
|
|
81
96
|
`
|
|
82
97
|
: "";
|
|
83
98
|
const observationChip = item.remote_observation_count > 0
|
|
@@ -98,6 +113,7 @@ export function createSocialController({
|
|
|
98
113
|
<div class="mono" style="color:#90a2c3;">${new Date(item.created_at).toLocaleString()}</div>
|
|
99
114
|
</div>
|
|
100
115
|
<div style="margin-top:8px; line-height:1.6;">${formatMessageBody(item.body || "")}</div>
|
|
116
|
+
${selfDeliveryHint}
|
|
101
117
|
</div>
|
|
102
118
|
`;
|
|
103
119
|
})
|
|
@@ -335,9 +335,11 @@ export const TRANSLATIONS = {
|
|
|
335
335
|
filteredMessages: '{count} message(s) shown.',
|
|
336
336
|
selfMessagePublished: 'local published',
|
|
337
337
|
selfMessageConfirmed: 'local confirmed',
|
|
338
|
-
selfMessageRemoteVisible: 'remote
|
|
338
|
+
selfMessageRemoteVisible: 'visible remote nodes: {count}',
|
|
339
339
|
selfMessageRemoteObserved: 'observed by {count} remote node(s)',
|
|
340
340
|
selfMessageAwaitingObservation: 'awaiting remote observation',
|
|
341
|
+
selfMessageDeliveryPending: 'Delivery status: not confirmed yet. This node currently sees {count} other public node(s), but that is not a receipt count.',
|
|
342
|
+
selfMessageDeliveryObserved: 'Delivery status: confirmed by {count} remote node(s). This node currently sees {visible} other public node(s).',
|
|
341
343
|
messageObservedBy: 'observed by {count}',
|
|
342
344
|
messageFilterLabel: 'Show',
|
|
343
345
|
messageFilterAll: 'all',
|
|
@@ -528,7 +530,7 @@ export const TRANSLATIONS = {
|
|
|
528
530
|
messagePublishedLocal: 'Published from local node.',
|
|
529
531
|
messageInboxConfirmed: 'Published from local node and confirmed in the local inbox.',
|
|
530
532
|
messageInboxPending: 'Published from local node. Waiting for local inbox confirmation.',
|
|
531
|
-
messageRemoteVisibility: 'Other public nodes currently visible from this node: {count}.
|
|
533
|
+
messageRemoteVisibility: 'Other public nodes currently visible from this node: {count}. This is only a visibility count, not a delivery receipt count.',
|
|
532
534
|
messageBroadcastFailed: 'Broadcast failed',
|
|
533
535
|
messageRemoteObserved: 'Remote observation confirmed by {count} node(s).',
|
|
534
536
|
messageRateLimited: 'Broadcast rate limit reached. Please wait and try again.',
|
|
@@ -894,9 +896,11 @@ export const TRANSLATIONS = {
|
|
|
894
896
|
filteredMessages: '当前显示 {count} 条消息。',
|
|
895
897
|
selfMessagePublished: '本地已发布',
|
|
896
898
|
selfMessageConfirmed: '本地已确认',
|
|
897
|
-
selfMessageRemoteVisible: '
|
|
899
|
+
selfMessageRemoteVisible: '可见远端节点: {count}',
|
|
898
900
|
selfMessageRemoteObserved: '远端已观察: {count}',
|
|
899
901
|
selfMessageAwaitingObservation: '等待远端观察',
|
|
902
|
+
selfMessageDeliveryPending: '送达状态:暂未确认。当前节点能看到 {count} 个其他公开节点,但这不是回执数量。',
|
|
903
|
+
selfMessageDeliveryObserved: '送达状态:已有 {count} 个远端节点确认观察到。当前节点能看到 {visible} 个其他公开节点。',
|
|
900
904
|
messageObservedBy: '已被观察: {count}',
|
|
901
905
|
messageFilterLabel: '显示',
|
|
902
906
|
messageFilterAll: '全部',
|
|
@@ -1087,7 +1091,7 @@ export const TRANSLATIONS = {
|
|
|
1087
1091
|
messagePublishedLocal: '已由本地节点发布。',
|
|
1088
1092
|
messageInboxConfirmed: '已由本地节点发布,并已在本地收件流确认。',
|
|
1089
1093
|
messageInboxPending: '已由本地节点发布,正在等待本地收件流确认。',
|
|
1090
|
-
messageRemoteVisibility: '当前从这个节点视角可见的其他公开节点数:{count}
|
|
1094
|
+
messageRemoteVisibility: '当前从这个节点视角可见的其他公开节点数:{count}。这只是可见节点数,不是送达回执数。',
|
|
1091
1095
|
messageBroadcastFailed: '消息广播失败',
|
|
1092
1096
|
messageRemoteObserved: '已有 {count} 个远端节点确认观察到这条消息。',
|
|
1093
1097
|
messageRateLimited: '广播触发了限流,请稍后再试。',
|
|
@@ -113,6 +113,8 @@ const SOCIAL_MESSAGE_DUPLICATE_WINDOW_MS = Number(process.env.SOCIAL_MESSAGE_DUP
|
|
|
113
113
|
const SOCIAL_MESSAGE_MAX_FUTURE_MS = Number(process.env.SOCIAL_MESSAGE_MAX_FUTURE_MS || 30_000);
|
|
114
114
|
const SOCIAL_MESSAGE_MAX_AGE_MS = Number(process.env.SOCIAL_MESSAGE_MAX_AGE_MS || 15 * 60_000);
|
|
115
115
|
const SOCIAL_MESSAGE_OBSERVATION_HISTORY_LIMIT = Number(process.env.SOCIAL_MESSAGE_OBSERVATION_HISTORY_LIMIT || 500);
|
|
116
|
+
const SOCIAL_MESSAGE_REPLAY_WINDOW_MS = Number(process.env.SOCIAL_MESSAGE_REPLAY_WINDOW_MS || 10 * 60_000);
|
|
117
|
+
const SOCIAL_MESSAGE_REPLAY_MAX_PER_BROADCAST = Number(process.env.SOCIAL_MESSAGE_REPLAY_MAX_PER_BROADCAST || 3);
|
|
116
118
|
const SOCIAL_MESSAGE_BLOCKED_AGENT_IDS = new Set(
|
|
117
119
|
dedupeStrings(parseListEnv(process.env.SOCIAL_MESSAGE_BLOCKED_AGENT_IDS || ""))
|
|
118
120
|
);
|
|
@@ -2116,6 +2118,7 @@ export class LocalNodeService {
|
|
|
2116
2118
|
};
|
|
2117
2119
|
const presenceRecord = signPresence(this.identity, Date.now());
|
|
2118
2120
|
const indexRecords = buildIndexRecords(this.profile);
|
|
2121
|
+
const replayMessages = this.getReplayableSelfSocialMessages();
|
|
2119
2122
|
|
|
2120
2123
|
try {
|
|
2121
2124
|
await this.publish("profile", profileRecord);
|
|
@@ -2123,6 +2126,9 @@ export class LocalNodeService {
|
|
|
2123
2126
|
for (const record of indexRecords) {
|
|
2124
2127
|
await this.publish("index", record);
|
|
2125
2128
|
}
|
|
2129
|
+
for (const message of replayMessages) {
|
|
2130
|
+
await this.publish(SOCIAL_MESSAGE_TOPIC, message);
|
|
2131
|
+
}
|
|
2126
2132
|
} catch (error) {
|
|
2127
2133
|
const message = error instanceof Error ? error.message : String(error);
|
|
2128
2134
|
this.lastBroadcastErrorAt = Date.now();
|
|
@@ -2145,7 +2151,10 @@ export class LocalNodeService {
|
|
|
2145
2151
|
this.compactCacheInMemory();
|
|
2146
2152
|
await this.persistCache();
|
|
2147
2153
|
|
|
2148
|
-
await this.log(
|
|
2154
|
+
await this.log(
|
|
2155
|
+
"info",
|
|
2156
|
+
`Broadcast sent (${indexRecords.length} index refs, replayed_messages=${replayMessages.length}, reason=${reason})`
|
|
2157
|
+
);
|
|
2149
2158
|
return { sent: true, reason };
|
|
2150
2159
|
}
|
|
2151
2160
|
|
|
@@ -2336,6 +2345,10 @@ export class LocalNodeService {
|
|
|
2336
2345
|
await this.log("warn", `Rejected social message with invalid signature (${record.message_id.slice(0, 10)})`);
|
|
2337
2346
|
return;
|
|
2338
2347
|
}
|
|
2348
|
+
if (this.hasSocialMessage(record.message_id)) {
|
|
2349
|
+
await this.publishObservationForMessage(record);
|
|
2350
|
+
return;
|
|
2351
|
+
}
|
|
2339
2352
|
const governanceReason = this.getIncomingSocialMessageRejectionReason(record);
|
|
2340
2353
|
if (governanceReason) {
|
|
2341
2354
|
await this.log("warn", `Rejected social message (${record.message_id.slice(0, 10)}): ${governanceReason}`);
|
|
@@ -2892,6 +2905,24 @@ export class LocalNodeService {
|
|
|
2892
2905
|
return this.messageGovernance.blocked_terms.some((term) => normalized.includes(term));
|
|
2893
2906
|
}
|
|
2894
2907
|
|
|
2908
|
+
private hasSocialMessage(messageId: string): boolean {
|
|
2909
|
+
return this.socialMessages.some((item) => item.message_id === messageId);
|
|
2910
|
+
}
|
|
2911
|
+
|
|
2912
|
+
private getReplayableSelfSocialMessages(now = Date.now()): SocialMessageRecord[] {
|
|
2913
|
+
const maxCount = Math.max(0, SOCIAL_MESSAGE_REPLAY_MAX_PER_BROADCAST);
|
|
2914
|
+
if (!this.identity || maxCount === 0) {
|
|
2915
|
+
return [];
|
|
2916
|
+
}
|
|
2917
|
+
return this.socialMessages
|
|
2918
|
+
.filter((item) => (
|
|
2919
|
+
item.agent_id === this.identity?.agent_id &&
|
|
2920
|
+
now - item.created_at <= SOCIAL_MESSAGE_REPLAY_WINDOW_MS
|
|
2921
|
+
))
|
|
2922
|
+
.sort((a, b) => a.created_at - b.created_at)
|
|
2923
|
+
.slice(-maxCount);
|
|
2924
|
+
}
|
|
2925
|
+
|
|
2895
2926
|
private hasRecentDuplicateMessage(agentId: string, body: string, topic: string, now = Date.now()): boolean {
|
|
2896
2927
|
return this.socialMessages.some((item) => (
|
|
2897
2928
|
item.agent_id === agentId &&
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|