@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
@@ -2,7 +2,7 @@
2
2
 
3
3
  ## v1.0 beta - 2026-03-19
4
4
 
5
- ### 2026.3.19-2
5
+ ### 2026.3.19-3
6
6
 
7
7
  - local-console UI polish:
8
8
  - sidebar spacing, collapsed rail behavior, footer version card, and topbar shell now align more closely with OpenClaw
package/VERSION CHANGED
@@ -1 +1 @@
1
- v2026.3.19-2
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
- : (installAction.recommended_command || '-');
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 detectOpenClawRuntime() {
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: processes.length > 0,
257
- process_count: processes.length,
258
- processes: processes.slice(0, 10),
259
- detection_error: result.status === 0 ? null : String(result.stderr || "ps failed"),
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: detectOpenClawRuntime().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-2
1
+ 2026.3.19-3
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "silicaclaw-broadcast",
3
- "version": "2026.3.19-2",
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": {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@silicaclaw/cli",
3
- "version": "2026.3.19-2",
3
+ "version": "2026.3.19-3",
4
4
  "private": false,
5
5
  "publishConfig": {
6
6
  "access": "public"