@silicaclaw/cli 2026.3.20-2 → 2026.3.20-4
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 +13 -7
- package/README.md +60 -12
- package/VERSION +1 -1
- package/apps/local-console/dist/apps/local-console/src/server.d.ts +39 -0
- package/apps/local-console/dist/apps/local-console/src/server.js +220 -0
- package/apps/local-console/dist/packages/network/src/relayPreview.d.ts +1 -0
- package/apps/local-console/dist/packages/network/src/relayPreview.js +17 -0
- package/apps/local-console/public/app/app.js +274 -3
- package/apps/local-console/public/app/events.js +21 -0
- package/apps/local-console/public/app/network.js +111 -30
- package/apps/local-console/public/app/overview.js +49 -21
- package/apps/local-console/public/app/social.js +315 -93
- package/apps/local-console/public/app/styles.css +86 -0
- package/apps/local-console/public/app/template.js +56 -35
- package/apps/local-console/public/app/translations.js +394 -312
- package/apps/local-console/src/server.ts +251 -1
- 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/network/dist/packages/network/src/relayPreview.d.ts +1 -0
- package/node_modules/@silicaclaw/network/dist/packages/network/src/relayPreview.js +17 -0
- package/node_modules/@silicaclaw/network/src/relayPreview.ts +17 -0
- 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 +67 -8
- package/package.json +1 -1
- package/packages/network/dist/packages/network/src/relayPreview.d.ts +1 -0
- package/packages/network/dist/packages/network/src/relayPreview.js +17 -0
- package/packages/network/src/relayPreview.ts +17 -0
- package/scripts/silicaclaw-cli.mjs +4 -1
- package/scripts/silicaclaw-gateway.mjs +108 -0
- package/scripts/validate-openclaw-skill.mjs +19 -0
|
@@ -12,6 +12,7 @@ const OWNER_FORWARD_CMD = String(process.env.OPENCLAW_OWNER_FORWARD_CMD || "").t
|
|
|
12
12
|
const STATE_PATH = resolve(
|
|
13
13
|
String(process.env.OPENCLAW_OWNER_FORWARD_STATE_PATH || resolve(homedir(), ".openclaw", "workspace", "state", "silicaclaw-owner-push.json"))
|
|
14
14
|
);
|
|
15
|
+
const LATEST_ONLY = String(process.env.OPENCLAW_FORWARD_LATEST_ONLY || "true").trim().toLowerCase() !== "false";
|
|
15
16
|
const ONCE = process.argv.includes("--once");
|
|
16
17
|
const VERBOSE = process.argv.includes("--verbose");
|
|
17
18
|
|
|
@@ -61,14 +62,24 @@ function loadState() {
|
|
|
61
62
|
return {
|
|
62
63
|
seen_ids: [],
|
|
63
64
|
pushed_at: {},
|
|
65
|
+
last_pushed_created_at: 0,
|
|
66
|
+
last_pushed_message_id: "",
|
|
64
67
|
};
|
|
65
68
|
}
|
|
66
69
|
try {
|
|
67
|
-
|
|
70
|
+
const parsed = JSON.parse(readFileSync(STATE_PATH, "utf8"));
|
|
71
|
+
return {
|
|
72
|
+
seen_ids: Array.isArray(parsed?.seen_ids) ? parsed.seen_ids : [],
|
|
73
|
+
pushed_at: parsed?.pushed_at && typeof parsed.pushed_at === "object" ? parsed.pushed_at : {},
|
|
74
|
+
last_pushed_created_at: Number(parsed?.last_pushed_created_at || 0) || 0,
|
|
75
|
+
last_pushed_message_id: String(parsed?.last_pushed_message_id || ""),
|
|
76
|
+
};
|
|
68
77
|
} catch {
|
|
69
78
|
return {
|
|
70
79
|
seen_ids: [],
|
|
71
80
|
pushed_at: {},
|
|
81
|
+
last_pushed_created_at: 0,
|
|
82
|
+
last_pushed_message_id: "",
|
|
72
83
|
};
|
|
73
84
|
}
|
|
74
85
|
}
|
|
@@ -85,6 +96,22 @@ function trimState(state) {
|
|
|
85
96
|
state.pushed_at = Object.fromEntries(pushedEntries);
|
|
86
97
|
}
|
|
87
98
|
|
|
99
|
+
function messageCreatedAt(item) {
|
|
100
|
+
const createdAt = Number(item?.created_at || 0);
|
|
101
|
+
return Number.isFinite(createdAt) && createdAt > 0 ? createdAt : 0;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
function isNewerThanCursor(item, state) {
|
|
105
|
+
const createdAt = messageCreatedAt(item);
|
|
106
|
+
const lastCreatedAt = Number(state.last_pushed_created_at || 0) || 0;
|
|
107
|
+
const messageId = String(item?.message_id || "").trim();
|
|
108
|
+
const lastMessageId = String(state.last_pushed_message_id || "").trim();
|
|
109
|
+
if (createdAt > lastCreatedAt) return true;
|
|
110
|
+
if (createdAt < lastCreatedAt) return false;
|
|
111
|
+
if (!createdAt) return !state.seen_ids.includes(messageId);
|
|
112
|
+
return Boolean(messageId) && messageId !== lastMessageId && !state.seen_ids.includes(messageId);
|
|
113
|
+
}
|
|
114
|
+
|
|
88
115
|
function shouldWatchTopic(message) {
|
|
89
116
|
if (!TOPIC_FILTERS.length) return true;
|
|
90
117
|
return TOPIC_FILTERS.includes(String(message?.topic || "global").toLowerCase());
|
|
@@ -165,29 +192,60 @@ function dispatchToOwner(route, summary, message) {
|
|
|
165
192
|
async function pollOnce(state) {
|
|
166
193
|
const payload = await request(`/api/openclaw/bridge/messages?limit=${LIMIT}`);
|
|
167
194
|
const items = Array.isArray(payload?.items) ? payload.items.slice().reverse() : [];
|
|
195
|
+
const candidates = [];
|
|
168
196
|
|
|
169
197
|
for (const item of items) {
|
|
170
198
|
const messageId = String(item?.message_id || "").trim();
|
|
171
199
|
if (!messageId) continue;
|
|
172
|
-
if (state
|
|
173
|
-
|
|
174
|
-
|
|
200
|
+
if (!isNewerThanCursor(item, state)) {
|
|
201
|
+
if (!state.seen_ids.includes(messageId)) {
|
|
202
|
+
state.seen_ids.push(messageId);
|
|
203
|
+
}
|
|
204
|
+
continue;
|
|
205
|
+
}
|
|
175
206
|
|
|
176
207
|
if (!shouldWatchTopic(item)) {
|
|
208
|
+
state.seen_ids.push(messageId);
|
|
177
209
|
if (VERBOSE) console.log(`skip topic: ${messageId}`);
|
|
178
210
|
continue;
|
|
179
211
|
}
|
|
180
212
|
|
|
181
213
|
const route = scoreRoute(item);
|
|
182
214
|
if (route === "ignore") {
|
|
215
|
+
state.seen_ids.push(messageId);
|
|
183
216
|
if (VERBOSE) console.log(`ignore low-signal: ${messageId}`);
|
|
184
217
|
continue;
|
|
185
218
|
}
|
|
186
219
|
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
220
|
+
candidates.push({ item, messageId, route, createdAt: messageCreatedAt(item) });
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
const selected = LATEST_ONLY
|
|
224
|
+
? candidates.sort((left, right) => {
|
|
225
|
+
if (left.createdAt !== right.createdAt) return right.createdAt - left.createdAt;
|
|
226
|
+
return left.messageId.localeCompare(right.messageId);
|
|
227
|
+
})[0] || null
|
|
228
|
+
: null;
|
|
229
|
+
|
|
230
|
+
const toPush = LATEST_ONLY ? (selected ? [selected] : []) : candidates;
|
|
231
|
+
|
|
232
|
+
for (const candidate of toPush) {
|
|
233
|
+
const summary = summarizeForOwner(candidate.item);
|
|
234
|
+
await dispatchToOwner(candidate.route, summary, candidate.item);
|
|
235
|
+
state.pushed_at[candidate.messageId] = new Date().toISOString();
|
|
236
|
+
state.last_pushed_created_at = candidate.createdAt || Date.now();
|
|
237
|
+
state.last_pushed_message_id = candidate.messageId;
|
|
238
|
+
if (VERBOSE) console.log(`pushed to owner: ${candidate.messageId}`);
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
if (LATEST_ONLY && selected) {
|
|
242
|
+
for (const candidate of candidates) {
|
|
243
|
+
state.seen_ids.push(candidate.messageId);
|
|
244
|
+
}
|
|
245
|
+
} else {
|
|
246
|
+
for (const candidate of candidates) {
|
|
247
|
+
state.seen_ids.push(candidate.messageId);
|
|
248
|
+
}
|
|
191
249
|
}
|
|
192
250
|
|
|
193
251
|
trimState(state);
|
|
@@ -199,6 +257,7 @@ async function main() {
|
|
|
199
257
|
if (VERBOSE) {
|
|
200
258
|
console.log(`SilicaClaw owner push watching ${API_BASE}`);
|
|
201
259
|
console.log(`State file: ${STATE_PATH}`);
|
|
260
|
+
console.log(`Latest-only mode: ${LATEST_ONLY ? "on" : "off"}`);
|
|
202
261
|
}
|
|
203
262
|
|
|
204
263
|
do {
|
package/package.json
CHANGED
|
@@ -349,6 +349,7 @@ class RelayPreviewAdapter {
|
|
|
349
349
|
if (!this.lastJoinAt || Date.now() - this.lastJoinAt > Math.max(45_000, this.pollIntervalMs * 6)) {
|
|
350
350
|
await this.joinRoom(reason);
|
|
351
351
|
}
|
|
352
|
+
this.ensurePollingAlive(reason);
|
|
352
353
|
}
|
|
353
354
|
async get(path) {
|
|
354
355
|
return this.requestJson("GET", path);
|
|
@@ -444,5 +445,21 @@ class RelayPreviewAdapter {
|
|
|
444
445
|
this.pollOnce().catch(() => { });
|
|
445
446
|
}, Math.max(1000, delayMs + jitterMs));
|
|
446
447
|
}
|
|
448
|
+
ensurePollingAlive(reason) {
|
|
449
|
+
if (!this.started)
|
|
450
|
+
return;
|
|
451
|
+
const pollStaleMs = Math.max(45_000, this.pollIntervalMs * 6);
|
|
452
|
+
const pollMissing = !this.poller;
|
|
453
|
+
const pollStale = Boolean(this.lastPollAt) && Date.now() - this.lastPollAt > pollStaleMs;
|
|
454
|
+
if (!pollMissing && !pollStale) {
|
|
455
|
+
return;
|
|
456
|
+
}
|
|
457
|
+
this.recordDiscovery("poll_recover_scheduled", {
|
|
458
|
+
endpoint: this.activeEndpoint,
|
|
459
|
+
detail: `${reason}:${pollMissing ? "missing" : "stale"}`,
|
|
460
|
+
});
|
|
461
|
+
this.currentPollDelayMs = this.pollIntervalMs;
|
|
462
|
+
this.scheduleNextPoll(0);
|
|
463
|
+
}
|
|
447
464
|
}
|
|
448
465
|
exports.RelayPreviewAdapter = RelayPreviewAdapter;
|
|
@@ -467,6 +467,7 @@ export class RelayPreviewAdapter implements NetworkAdapter {
|
|
|
467
467
|
if (!this.lastJoinAt || Date.now() - this.lastJoinAt > Math.max(45_000, this.pollIntervalMs * 6)) {
|
|
468
468
|
await this.joinRoom(reason);
|
|
469
469
|
}
|
|
470
|
+
this.ensurePollingAlive(reason);
|
|
470
471
|
}
|
|
471
472
|
|
|
472
473
|
private async get(path: string): Promise<any> {
|
|
@@ -565,4 +566,20 @@ export class RelayPreviewAdapter implements NetworkAdapter {
|
|
|
565
566
|
this.pollOnce().catch(() => {});
|
|
566
567
|
}, Math.max(1000, delayMs + jitterMs));
|
|
567
568
|
}
|
|
569
|
+
|
|
570
|
+
private ensurePollingAlive(reason: string): void {
|
|
571
|
+
if (!this.started) return;
|
|
572
|
+
const pollStaleMs = Math.max(45_000, this.pollIntervalMs * 6);
|
|
573
|
+
const pollMissing = !this.poller;
|
|
574
|
+
const pollStale = Boolean(this.lastPollAt) && Date.now() - this.lastPollAt > pollStaleMs;
|
|
575
|
+
if (!pollMissing && !pollStale) {
|
|
576
|
+
return;
|
|
577
|
+
}
|
|
578
|
+
this.recordDiscovery("poll_recover_scheduled", {
|
|
579
|
+
endpoint: this.activeEndpoint,
|
|
580
|
+
detail: `${reason}:${pollMissing ? "missing" : "stale"}`,
|
|
581
|
+
});
|
|
582
|
+
this.currentPollDelayMs = this.pollIntervalMs;
|
|
583
|
+
this.scheduleNextPoll(0);
|
|
584
|
+
}
|
|
568
585
|
}
|
|
@@ -224,10 +224,12 @@ function shellInitTargets() {
|
|
|
224
224
|
shell.endsWith("/bash") ||
|
|
225
225
|
process.env.BASH_VERSION ||
|
|
226
226
|
existsSync(resolve(home, ".bashrc")) ||
|
|
227
|
-
existsSync(resolve(home, ".bash_profile"))
|
|
227
|
+
existsSync(resolve(home, ".bash_profile")) ||
|
|
228
|
+
existsSync(resolve(home, ".profile"))
|
|
228
229
|
) {
|
|
229
230
|
add(resolve(home, ".bashrc"));
|
|
230
231
|
add(resolve(home, ".bash_profile"));
|
|
232
|
+
add(resolve(home, ".profile"));
|
|
231
233
|
}
|
|
232
234
|
|
|
233
235
|
if (targets.length === 0) {
|
|
@@ -280,6 +282,7 @@ function installPersistentCommand(specifier = readPackageVersion()) {
|
|
|
280
282
|
kv("Command", "silicaclaw");
|
|
281
283
|
console.log("");
|
|
282
284
|
kv("Activate", `source "${envFile}"`);
|
|
285
|
+
kv("Current shell", "run Activate now if `silicaclaw` is not found yet");
|
|
283
286
|
if (configuredFiles.length > 0) {
|
|
284
287
|
kv("Startup", "configured");
|
|
285
288
|
} else {
|
|
@@ -74,6 +74,11 @@ function readJson(file) {
|
|
|
74
74
|
}
|
|
75
75
|
}
|
|
76
76
|
|
|
77
|
+
function readPackageVersionFrom(dir) {
|
|
78
|
+
const pkg = readJson(resolve(dir, "package.json"));
|
|
79
|
+
return String(pkg?.version || "latest").trim() || "latest";
|
|
80
|
+
}
|
|
81
|
+
|
|
77
82
|
function isSilicaClawDir(dir) {
|
|
78
83
|
const pkgPath = join(dir, "package.json");
|
|
79
84
|
if (!existsSync(pkgPath)) return false;
|
|
@@ -144,6 +149,107 @@ function ensureStateDir() {
|
|
|
144
149
|
mkdirSync(STATE_DIR, { recursive: true });
|
|
145
150
|
}
|
|
146
151
|
|
|
152
|
+
function userShimDir() {
|
|
153
|
+
return join(homedir(), ".silicaclaw", "bin");
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
function userShimPath() {
|
|
157
|
+
return join(userShimDir(), "silicaclaw");
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
function userEnvFile() {
|
|
161
|
+
return join(homedir(), ".silicaclaw", "env.sh");
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
function userNpmCacheDir() {
|
|
165
|
+
return join(homedir(), ".silicaclaw", "npm-cache");
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
function preferredShellRcFile() {
|
|
169
|
+
const shell = String(process.env.SHELL || "");
|
|
170
|
+
if (shell.endsWith("/zsh")) return resolve(homedir(), ".zshrc");
|
|
171
|
+
if (shell.endsWith("/bash")) return resolve(homedir(), ".bashrc");
|
|
172
|
+
if (process.env.ZSH_VERSION) return resolve(homedir(), ".zshrc");
|
|
173
|
+
return resolve(homedir(), ".bashrc");
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
function shellInitTargets() {
|
|
177
|
+
const home = homedir();
|
|
178
|
+
const shell = String(process.env.SHELL || "");
|
|
179
|
+
const targets = [];
|
|
180
|
+
const add = (filePath) => {
|
|
181
|
+
if (!targets.includes(filePath)) targets.push(filePath);
|
|
182
|
+
};
|
|
183
|
+
|
|
184
|
+
if (shell.endsWith("/zsh") || process.env.ZSH_VERSION || existsSync(resolve(home, ".zshrc"))) {
|
|
185
|
+
add(resolve(home, ".zshrc"));
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
if (
|
|
189
|
+
shell.endsWith("/bash") ||
|
|
190
|
+
process.env.BASH_VERSION ||
|
|
191
|
+
existsSync(resolve(home, ".bashrc")) ||
|
|
192
|
+
existsSync(resolve(home, ".bash_profile")) ||
|
|
193
|
+
existsSync(resolve(home, ".profile"))
|
|
194
|
+
) {
|
|
195
|
+
add(resolve(home, ".bashrc"));
|
|
196
|
+
add(resolve(home, ".bash_profile"));
|
|
197
|
+
add(resolve(home, ".profile"));
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
if (targets.length === 0) {
|
|
201
|
+
add(preferredShellRcFile());
|
|
202
|
+
}
|
|
203
|
+
return targets;
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
function ensureLineInFile(filePath, block) {
|
|
207
|
+
try {
|
|
208
|
+
const current = existsSync(filePath) ? readFileSync(filePath, "utf8") : "";
|
|
209
|
+
if (current.includes(block.trim())) return true;
|
|
210
|
+
const next = `${current.replace(/\s*$/, "")}\n\n${block}\n`;
|
|
211
|
+
mkdirSync(dirname(filePath), { recursive: true });
|
|
212
|
+
writeFileSync(filePath, next, "utf8");
|
|
213
|
+
return true;
|
|
214
|
+
} catch {
|
|
215
|
+
return false;
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
function shimScriptText(specifier = "latest") {
|
|
220
|
+
return [
|
|
221
|
+
"#!/usr/bin/env bash",
|
|
222
|
+
"set -euo pipefail",
|
|
223
|
+
'export npm_config_cache="${npm_config_cache:-$HOME/.silicaclaw/npm-cache}"',
|
|
224
|
+
`exec npx -y @silicaclaw/cli@${specifier} "$@"`,
|
|
225
|
+
"",
|
|
226
|
+
].join("\n");
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
function ensureUserCommandInstalled() {
|
|
230
|
+
const version = readPackageVersionFrom(APP_DIR);
|
|
231
|
+
const envBlock = [
|
|
232
|
+
"#!/usr/bin/env bash",
|
|
233
|
+
'export PATH="$HOME/.silicaclaw/bin:$PATH"',
|
|
234
|
+
'export npm_config_cache="$HOME/.silicaclaw/npm-cache"',
|
|
235
|
+
"",
|
|
236
|
+
].join("\n");
|
|
237
|
+
const rcBlock = [
|
|
238
|
+
"# >>> silicaclaw >>>",
|
|
239
|
+
'[ -f "$HOME/.silicaclaw/env.sh" ] && . "$HOME/.silicaclaw/env.sh"',
|
|
240
|
+
"# <<< silicaclaw <<<",
|
|
241
|
+
].join("\n");
|
|
242
|
+
|
|
243
|
+
mkdirSync(userShimDir(), { recursive: true });
|
|
244
|
+
mkdirSync(userNpmCacheDir(), { recursive: true });
|
|
245
|
+
writeFileSync(userEnvFile(), envBlock, { encoding: "utf8", mode: 0o755 });
|
|
246
|
+
writeFileSync(userShimPath(), shimScriptText(version), { encoding: "utf8", mode: 0o755 });
|
|
247
|
+
|
|
248
|
+
for (const filePath of shellInitTargets()) {
|
|
249
|
+
ensureLineInFile(filePath, rcBlock);
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
|
|
147
253
|
function ensureLaunchAgentsDir() {
|
|
148
254
|
mkdirSync(LAUNCH_AGENTS_DIR, { recursive: true });
|
|
149
255
|
}
|
|
@@ -797,6 +903,7 @@ async function stopAll() {
|
|
|
797
903
|
|
|
798
904
|
async function startAll() {
|
|
799
905
|
ensureStateDir();
|
|
906
|
+
ensureUserCommandInstalled();
|
|
800
907
|
|
|
801
908
|
const mode = parseMode(parseFlag("mode", process.env.NETWORK_MODE || DEFAULT_NETWORK_MODE));
|
|
802
909
|
const adapter = adapterForMode(mode);
|
|
@@ -923,6 +1030,7 @@ async function startAll() {
|
|
|
923
1030
|
}
|
|
924
1031
|
|
|
925
1032
|
async function restartAll() {
|
|
1033
|
+
ensureUserCommandInstalled();
|
|
926
1034
|
if (!isLaunchdPlatform()) {
|
|
927
1035
|
await stopAll();
|
|
928
1036
|
await startAll();
|
|
@@ -100,6 +100,25 @@ function main() {
|
|
|
100
100
|
assert(dialogueCheatsheetZh.includes("主人对话速查表"), "owner dialogue cheatsheet zh content mismatch");
|
|
101
101
|
},
|
|
102
102
|
},
|
|
103
|
+
"silicaclaw-network-config": {
|
|
104
|
+
requiredFiles: [
|
|
105
|
+
resolve(skillDir, "references", "network-modes.md"),
|
|
106
|
+
resolve(skillDir, "references", "public-discovery.md"),
|
|
107
|
+
resolve(skillDir, "references", "owner-dialogue-cheatsheet-zh.md"),
|
|
108
|
+
],
|
|
109
|
+
uiDisplayName: 'display_name: "SilicaClaw Network Config"',
|
|
110
|
+
checks(manifest, files) {
|
|
111
|
+
const networkModes = readFileSync(files[0], "utf8");
|
|
112
|
+
const publicDiscovery = readFileSync(files[1], "utf8");
|
|
113
|
+
const dialogueCheatsheetZh = readFileSync(files[2], "utf8");
|
|
114
|
+
assert(String(manifest.references?.network_modes || "") === "references/network-modes.md", "manifest network modes reference mismatch");
|
|
115
|
+
assert(String(manifest.references?.public_discovery || "") === "references/public-discovery.md", "manifest public discovery reference mismatch");
|
|
116
|
+
assert(String(manifest.references?.owner_dialogue_cheatsheet_zh || "") === "references/owner-dialogue-cheatsheet-zh.md", "manifest owner dialogue cheatsheet zh reference mismatch");
|
|
117
|
+
assert(networkModes.includes("## Modes"), "network modes content mismatch");
|
|
118
|
+
assert(publicDiscovery.includes("public_enabled"), "public discovery content mismatch");
|
|
119
|
+
assert(dialogueCheatsheetZh.includes("主人对话速查表"), "owner dialogue cheatsheet zh content mismatch");
|
|
120
|
+
},
|
|
121
|
+
},
|
|
103
122
|
}[skillName];
|
|
104
123
|
|
|
105
124
|
assert(profile, `Unsupported skill for validation: ${skillName}`);
|