@silicaclaw/cli 2026.3.19-2 → 2026.3.19-3
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
CHANGED
package/VERSION
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
v2026.3.19-
|
|
1
|
+
v2026.3.19-3
|
|
@@ -3357,6 +3357,8 @@
|
|
|
3357
3357
|
bootstrapHints: 'bootstrap hints',
|
|
3358
3358
|
restartRequired: 'restart required',
|
|
3359
3359
|
openclawInstalled: 'OpenClaw detected',
|
|
3360
|
+
openclawDetectionMode: 'Detection mode',
|
|
3361
|
+
openclawGateway: 'Gateway',
|
|
3360
3362
|
running: 'running',
|
|
3361
3363
|
skillInstalled: 'Skill installed',
|
|
3362
3364
|
installMode: 'Install mode',
|
|
@@ -3844,6 +3846,8 @@
|
|
|
3844
3846
|
bootstrapHints: 'Bootstrap 提示',
|
|
3845
3847
|
restartRequired: '需要重启',
|
|
3846
3848
|
openclawInstalled: '已检测到 OpenClaw',
|
|
3849
|
+
openclawDetectionMode: '检测方式',
|
|
3850
|
+
openclawGateway: '网关地址',
|
|
3847
3851
|
running: '运行中',
|
|
3848
3852
|
skillInstalled: '技能已安装',
|
|
3849
3853
|
installMode: '安装方式',
|
|
@@ -4610,7 +4614,7 @@
|
|
|
4610
4614
|
document.getElementById('pillBroadcast').className = pillBroadcastClassName;
|
|
4611
4615
|
|
|
4612
4616
|
const openclawRunning = !!bridge.openclaw_runtime?.running;
|
|
4613
|
-
const openclawDetected = !!bridge.openclaw_installation?.detected;
|
|
4617
|
+
const openclawDetected = !!bridge.openclaw_installation?.detected || openclawRunning || !!bridge.openclaw_runtime?.gateway_reachable;
|
|
4614
4618
|
const skillInstalled = !!bridge.skill_learning?.installed;
|
|
4615
4619
|
const globalMode = heroModeText === 'global-preview';
|
|
4616
4620
|
const networkDiag = networkStats.adapter_diagnostics_summary || {};
|
|
@@ -5235,8 +5239,8 @@
|
|
|
5235
5239
|
const skillLearning = bridge.skill_learning || {};
|
|
5236
5240
|
const ownerDelivery = bridge.owner_delivery || {};
|
|
5237
5241
|
const installAction = skillLearning.install_action || {};
|
|
5238
|
-
const openclawDetected = !!bridge.openclaw_installation?.detected;
|
|
5239
5242
|
const openclawRunning = !!bridge.openclaw_runtime?.running;
|
|
5243
|
+
const openclawDetected = !!bridge.openclaw_installation?.detected || openclawRunning || !!bridge.openclaw_runtime?.gateway_reachable;
|
|
5240
5244
|
const skillInstalled = !!skillLearning.installed;
|
|
5241
5245
|
const installedSkillPath = skillLearning.installed_skill_path || '-';
|
|
5242
5246
|
const ownerDeliveryStatusEl = document.getElementById('socialOwnerDeliveryStatus');
|
|
@@ -5278,6 +5282,8 @@
|
|
|
5278
5282
|
[t('social.broadcastReadable'), ownerDelivery.bridge_messages_readable ? t('common.yes') : t('common.no')],
|
|
5279
5283
|
[t('social.ownerForwardReady'), ownerDelivery.ready ? t('common.yes') : t('common.no')],
|
|
5280
5284
|
[t('social.ownerForwardCommand'), ownerDelivery.forward_command_configured ? t('common.yes') : t('common.no')],
|
|
5285
|
+
[t('social.openclawDetectionMode'), bridge.openclaw_runtime?.detection_mode || '-'],
|
|
5286
|
+
[t('social.openclawGateway'), bridge.openclaw_runtime?.gateway_url || '-'],
|
|
5281
5287
|
[t('social.installMode'), skillLearning.install_mode || '-'],
|
|
5282
5288
|
[t('social.installedPath'), skillInstalled ? installedSkillPath : '-'],
|
|
5283
5289
|
].map(([k,v]) => `<div class="card"><div class="label">${k}</div><div class="value" style="font-size:17px;">${escapeHtml(v)}</div></div>`).join('');
|
|
@@ -5285,7 +5291,7 @@
|
|
|
5285
5291
|
? `${ownerDelivery.forward_command}${ownerDelivery.owner_channel ? ` · ${ownerDelivery.owner_channel}` : ''}${ownerDelivery.owner_target ? ` · ${ownerDelivery.owner_target}` : ''}`
|
|
5286
5292
|
: skillInstalled
|
|
5287
5293
|
? installedSkillPath
|
|
5288
|
-
:
|
|
5294
|
+
: `${installAction.recommended_command || '-'}${bridge.openclaw_runtime?.gateway_url ? ` · detect ${bridge.openclaw_runtime.gateway_url}` : ''}`;
|
|
5289
5295
|
document.getElementById('openclawSkillHint').textContent = !openclawDetected
|
|
5290
5296
|
? t('feedback.openclawRoleBroadcasterOnly')
|
|
5291
5297
|
: !openclawRunning
|
|
@@ -78,6 +78,9 @@ const NETWORK_MAX_FUTURE_DRIFT_MS = Number(process.env.NETWORK_MAX_FUTURE_DRIFT_
|
|
|
78
78
|
const NETWORK_MAX_PAST_DRIFT_MS = Number(process.env.NETWORK_MAX_PAST_DRIFT_MS || 120_000);
|
|
79
79
|
const NETWORK_HEARTBEAT_INTERVAL_MS = Number(process.env.NETWORK_HEARTBEAT_INTERVAL_MS || 12_000);
|
|
80
80
|
const NETWORK_PEER_STALE_AFTER_MS = Number(process.env.NETWORK_PEER_STALE_AFTER_MS || 45_000);
|
|
81
|
+
const OPENCLAW_GATEWAY_HOST = "127.0.0.1";
|
|
82
|
+
const OPENCLAW_GATEWAY_PORT = 18_789;
|
|
83
|
+
const OPENCLAW_GATEWAY_URL = `http://${OPENCLAW_GATEWAY_HOST}:${OPENCLAW_GATEWAY_PORT}/`;
|
|
81
84
|
const NETWORK_PEER_REMOVE_AFTER_MS = Number(process.env.NETWORK_PEER_REMOVE_AFTER_MS || 180_000);
|
|
82
85
|
const NETWORK_UDP_BIND_ADDRESS = process.env.NETWORK_UDP_BIND_ADDRESS || "0.0.0.0";
|
|
83
86
|
const NETWORK_UDP_BROADCAST_ADDRESS = process.env.NETWORK_UDP_BROADCAST_ADDRESS || "255.255.255.255";
|
|
@@ -219,7 +222,52 @@ function detectOpenClawInstallation(workspaceRoot: string) {
|
|
|
219
222
|
} as const;
|
|
220
223
|
}
|
|
221
224
|
|
|
222
|
-
function
|
|
225
|
+
function readOpenClawConfiguredGateway(workspaceRoot: string) {
|
|
226
|
+
const configuredSourceDir = String(process.env.OPENCLAW_SOURCE_DIR || "").trim();
|
|
227
|
+
const defaultSourceDir = resolve(workspaceRoot, "..", "openclaw");
|
|
228
|
+
const sourceDir = configuredSourceDir || defaultSourceDir;
|
|
229
|
+
const homeDir = resolve(process.env.HOME || "", ".openclaw");
|
|
230
|
+
const explicitConfigPath = String(process.env.OPENCLAW_CONFIG_PATH || "").trim();
|
|
231
|
+
const explicitStateDir = String(process.env.OPENCLAW_STATE_DIR || "").trim();
|
|
232
|
+
const candidates = dedupeStrings([
|
|
233
|
+
explicitConfigPath,
|
|
234
|
+
explicitStateDir ? resolve(explicitStateDir, "openclaw.json") : "",
|
|
235
|
+
resolve(homeDir, "openclaw.json"),
|
|
236
|
+
resolve(homeDir, "clawdbot.json"),
|
|
237
|
+
resolve(sourceDir, ".openclaw", "openclaw.json"),
|
|
238
|
+
]);
|
|
239
|
+
|
|
240
|
+
for (const candidate of candidates) {
|
|
241
|
+
if (!candidate || !existsSync(candidate)) continue;
|
|
242
|
+
try {
|
|
243
|
+
const raw = readFileSync(candidate, "utf8");
|
|
244
|
+
const portMatch = raw.match(/["']?port["']?\s*:\s*(\d{2,5})/);
|
|
245
|
+
const bindMatch = raw.match(/["']?bind["']?\s*:\s*["']([^"']+)["']/);
|
|
246
|
+
const port = portMatch ? Number(portMatch[1]) : OPENCLAW_GATEWAY_PORT;
|
|
247
|
+
if (!Number.isFinite(port) || port <= 0) continue;
|
|
248
|
+
return {
|
|
249
|
+
config_path: candidate,
|
|
250
|
+
gateway_port: port,
|
|
251
|
+
gateway_host: OPENCLAW_GATEWAY_HOST,
|
|
252
|
+
gateway_bind: bindMatch?.[1] || null,
|
|
253
|
+
gateway_url: `http://${OPENCLAW_GATEWAY_HOST}:${port}/`,
|
|
254
|
+
} as const;
|
|
255
|
+
} catch {
|
|
256
|
+
continue;
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
return {
|
|
261
|
+
config_path: null,
|
|
262
|
+
gateway_port: OPENCLAW_GATEWAY_PORT,
|
|
263
|
+
gateway_host: OPENCLAW_GATEWAY_HOST,
|
|
264
|
+
gateway_bind: null,
|
|
265
|
+
gateway_url: OPENCLAW_GATEWAY_URL,
|
|
266
|
+
} as const;
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
function detectOpenClawRuntime(workspaceRoot: string) {
|
|
270
|
+
const configuredGateway = readOpenClawConfiguredGateway(workspaceRoot);
|
|
223
271
|
const result = spawnSync("ps", ["-Ao", "pid=,ppid=,command="], {
|
|
224
272
|
encoding: "utf8",
|
|
225
273
|
});
|
|
@@ -252,11 +300,84 @@ function detectOpenClawRuntime() {
|
|
|
252
300
|
})
|
|
253
301
|
.filter((item): item is { pid: number; ppid: number; command: string } => Boolean(item));
|
|
254
302
|
|
|
303
|
+
const openclawPids = new Set(processes.map((item) => item.pid));
|
|
304
|
+
const gatewayProbe = spawnSync("lsof", ["-nP", "-iTCP", "-sTCP:LISTEN"], {
|
|
305
|
+
encoding: "utf8",
|
|
306
|
+
});
|
|
307
|
+
const gatewayLines = String(gatewayProbe.stdout || "")
|
|
308
|
+
.split("\n")
|
|
309
|
+
.map((line) => line.trim())
|
|
310
|
+
.filter(Boolean);
|
|
311
|
+
const gatewayListeners = gatewayLines
|
|
312
|
+
.slice(1)
|
|
313
|
+
.map((line) => {
|
|
314
|
+
const parts = line.split(/\s+/);
|
|
315
|
+
const pid = Number(parts[1] || 0);
|
|
316
|
+
const command = parts[0] || "";
|
|
317
|
+
const lowerCommand = command.toLowerCase();
|
|
318
|
+
const endpoint = parts[8] || parts[parts.length - 1] || "";
|
|
319
|
+
const portMatch = endpoint.match(/:(\d+)(?:\s*\(|$)/);
|
|
320
|
+
if (!pid || !command || !portMatch) return null;
|
|
321
|
+
const isOpenClawListener =
|
|
322
|
+
openclawPids.has(pid) ||
|
|
323
|
+
lowerCommand.includes("openclaw");
|
|
324
|
+
if (!isOpenClawListener) return null;
|
|
325
|
+
const port = Number(portMatch[1]);
|
|
326
|
+
if (!Number.isFinite(port) || port <= 0) return null;
|
|
327
|
+
return {
|
|
328
|
+
pid,
|
|
329
|
+
ppid: 0,
|
|
330
|
+
port,
|
|
331
|
+
command: `${command} listening on ${OPENCLAW_GATEWAY_HOST}:${port}`,
|
|
332
|
+
};
|
|
333
|
+
})
|
|
334
|
+
.filter((item): item is { pid: number; ppid: number; port: number; command: string } => Boolean(item));
|
|
335
|
+
const preferredListener =
|
|
336
|
+
gatewayListeners.find((item) => item.port === configuredGateway.gateway_port) ||
|
|
337
|
+
gatewayListeners[0] ||
|
|
338
|
+
null;
|
|
339
|
+
|
|
340
|
+
const combinedProcesses = new Map<number, { pid: number; ppid: number; command: string }>();
|
|
341
|
+
for (const process of [...processes, ...gatewayListeners]) {
|
|
342
|
+
if (!combinedProcesses.has(process.pid)) {
|
|
343
|
+
combinedProcesses.set(process.pid, process);
|
|
344
|
+
continue;
|
|
345
|
+
}
|
|
346
|
+
const current = combinedProcesses.get(process.pid);
|
|
347
|
+
if (current && current.command.length < process.command.length) {
|
|
348
|
+
combinedProcesses.set(process.pid, process);
|
|
349
|
+
}
|
|
350
|
+
}
|
|
351
|
+
const allProcesses = Array.from(combinedProcesses.values());
|
|
352
|
+
const gatewayReachable = gatewayListeners.length > 0;
|
|
353
|
+
const detectionNotes = [];
|
|
354
|
+
if (result.status !== 0) detectionNotes.push(String(result.stderr || "ps failed").trim());
|
|
355
|
+
if (gatewayProbe.status !== 0 && gatewayLines.length === 0) {
|
|
356
|
+
detectionNotes.push(String(gatewayProbe.stderr || "lsof failed").trim());
|
|
357
|
+
}
|
|
358
|
+
const gatewayPort = preferredListener?.port || configuredGateway.gateway_port;
|
|
359
|
+
const gatewayUrl = `http://${OPENCLAW_GATEWAY_HOST}:${gatewayPort}/`;
|
|
360
|
+
|
|
255
361
|
return {
|
|
256
|
-
running:
|
|
257
|
-
process_count:
|
|
258
|
-
processes:
|
|
259
|
-
detection_error:
|
|
362
|
+
running: allProcesses.length > 0 || gatewayReachable,
|
|
363
|
+
process_count: allProcesses.length,
|
|
364
|
+
processes: allProcesses.slice(0, 10),
|
|
365
|
+
detection_error: detectionNotes.filter(Boolean).join(" | ") || null,
|
|
366
|
+
gateway_url: gatewayUrl,
|
|
367
|
+
gateway_port: gatewayPort,
|
|
368
|
+
gateway_reachable: gatewayReachable,
|
|
369
|
+
configured_gateway_url: configuredGateway.gateway_url,
|
|
370
|
+
configured_gateway_port: configuredGateway.gateway_port,
|
|
371
|
+
configured_gateway_bind: configuredGateway.gateway_bind,
|
|
372
|
+
configured_gateway_config_path: configuredGateway.config_path,
|
|
373
|
+
detection_mode:
|
|
374
|
+
processes.length > 0 && gatewayReachable
|
|
375
|
+
? "process+gateway"
|
|
376
|
+
: gatewayReachable
|
|
377
|
+
? "gateway"
|
|
378
|
+
: processes.length > 0
|
|
379
|
+
? "process"
|
|
380
|
+
: "not_running",
|
|
260
381
|
} as const;
|
|
261
382
|
}
|
|
262
383
|
|
|
@@ -462,6 +583,14 @@ type OpenClawBridgeStatus = {
|
|
|
462
583
|
command: string;
|
|
463
584
|
}>;
|
|
464
585
|
detection_error: string | null;
|
|
586
|
+
gateway_url: string;
|
|
587
|
+
gateway_port: number;
|
|
588
|
+
gateway_reachable: boolean;
|
|
589
|
+
configured_gateway_url: string;
|
|
590
|
+
configured_gateway_port: number;
|
|
591
|
+
configured_gateway_bind: string | null;
|
|
592
|
+
configured_gateway_config_path: string | null;
|
|
593
|
+
detection_mode: "process" | "gateway" | "process+gateway" | "not_running";
|
|
465
594
|
};
|
|
466
595
|
skill_learning: {
|
|
467
596
|
available: boolean;
|
|
@@ -507,6 +636,10 @@ type OpenClawBridgeConfigView = {
|
|
|
507
636
|
bridge_api_base: string;
|
|
508
637
|
openclaw_detected: boolean;
|
|
509
638
|
openclaw_running: boolean;
|
|
639
|
+
openclaw_gateway_host: string;
|
|
640
|
+
openclaw_gateway_port: number;
|
|
641
|
+
openclaw_gateway_url: string;
|
|
642
|
+
openclaw_gateway_config_path: string | null;
|
|
510
643
|
openclaw_workspace_skill_dir: string;
|
|
511
644
|
openclaw_legacy_skill_dir: string;
|
|
512
645
|
silicaclaw_env_template_path: string;
|
|
@@ -1260,7 +1393,7 @@ export class LocalNodeService {
|
|
|
1260
1393
|
getOpenClawBridgeStatus(): OpenClawBridgeStatus {
|
|
1261
1394
|
const integration = this.getIntegrationStatus();
|
|
1262
1395
|
const openclawInstallation = detectOpenClawInstallation(this.workspaceRoot);
|
|
1263
|
-
const openclawRuntime = detectOpenClawRuntime();
|
|
1396
|
+
const openclawRuntime = detectOpenClawRuntime(this.workspaceRoot);
|
|
1264
1397
|
const skillInstallation = detectOpenClawSkillInstallation();
|
|
1265
1398
|
const ownerDelivery = detectOwnerDeliveryStatus({
|
|
1266
1399
|
workspaceRoot: this.workspaceRoot,
|
|
@@ -1355,11 +1488,16 @@ export class LocalNodeService {
|
|
|
1355
1488
|
const workspaceSkillDir = resolve(homeDir, "workspace", "skills");
|
|
1356
1489
|
const legacySkillDir = resolve(homeDir, "skills");
|
|
1357
1490
|
const openclawSourceDir = resolve(this.workspaceRoot, "..", "openclaw");
|
|
1491
|
+
const openclawRuntime = detectOpenClawRuntime(this.workspaceRoot);
|
|
1358
1492
|
|
|
1359
1493
|
return {
|
|
1360
1494
|
bridge_api_base: "http://localhost:4310",
|
|
1361
1495
|
openclaw_detected: detectOpenClawInstallation(this.workspaceRoot).detected,
|
|
1362
|
-
openclaw_running:
|
|
1496
|
+
openclaw_running: openclawRuntime.running,
|
|
1497
|
+
openclaw_gateway_host: OPENCLAW_GATEWAY_HOST,
|
|
1498
|
+
openclaw_gateway_port: openclawRuntime.configured_gateway_port,
|
|
1499
|
+
openclaw_gateway_url: openclawRuntime.configured_gateway_url,
|
|
1500
|
+
openclaw_gateway_config_path: openclawRuntime.configured_gateway_config_path,
|
|
1363
1501
|
openclaw_workspace_skill_dir: workspaceSkillDir,
|
|
1364
1502
|
openclaw_legacy_skill_dir: legacySkillDir,
|
|
1365
1503
|
silicaclaw_env_template_path: resolve(this.workspaceRoot, "openclaw-owner-forward.env.example"),
|
|
@@ -1382,6 +1520,7 @@ export class LocalNodeService {
|
|
|
1382
1520
|
notes: [
|
|
1383
1521
|
"Install and maintain the skill from SilicaClaw; do not edit OpenClaw core source for this integration.",
|
|
1384
1522
|
"OpenClaw learns broadcasts via the installed skill under ~/.openclaw/workspace/skills/.",
|
|
1523
|
+
"Runtime detection prefers the actual OpenClaw gateway listener port, then falls back to OpenClaw's own openclaw.json gateway.port.",
|
|
1385
1524
|
"Owner delivery runs through OpenClaw's own message channel stack after the skill forwards a summary.",
|
|
1386
1525
|
"Sensitive computer control still requires OpenClaw's own owner approval and node permission flow.",
|
|
1387
1526
|
],
|
|
@@ -1 +1 @@
|
|
|
1
|
-
2026.3.19-
|
|
1
|
+
2026.3.19-3
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "silicaclaw-broadcast",
|
|
3
|
-
"version": "2026.3.19-
|
|
3
|
+
"version": "2026.3.19-3",
|
|
4
4
|
"display_name": "SilicaClaw Broadcast",
|
|
5
5
|
"description": "OpenClaw skill for reading SilicaClaw public broadcasts, publishing public broadcasts, and forwarding relevant updates to the owner through OpenClaw's native social channel.",
|
|
6
6
|
"entrypoints": {
|