@matelink/cli 2026.4.21 → 2026.4.23

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/README.md CHANGED
@@ -178,3 +178,31 @@ API:
178
178
  - `GET /v1/gateways/{gatewayId}/requests/next` gateway bridge polls pending chat requests
179
179
  - `POST /v1/gateways/{gatewayId}/requests/{requestId}/events` gateway bridge streams relay events
180
180
  - `POST /v1/openclaw/responses` app chat endpoint (supports `gatewayId + clientToken`)
181
+
182
+ ## 9) CLI Bridge Logging
183
+
184
+ Bridge runs as a systemd user service on server 80, logs are written to files.
185
+
186
+ ### Viewing logs (server 80)
187
+
188
+ ```bash
189
+ tail -f /root/.openclaw/matecli/logs/bridge.stdout.log # normal logs (requests, relay status)
190
+ tail -f /root/.openclaw/matecli/logs/bridge.stderr.log # error logs (poll failures, retries)
191
+
192
+ # last 100 lines
193
+ tail -100 /root/.openclaw/matecli/logs/bridge.stderr.log
194
+
195
+ # search for specific request
196
+ grep "Bridge request" /root/.openclaw/matecli/logs/bridge.stdout.log | tail -20
197
+ ```
198
+
199
+ ### Service management
200
+
201
+ ```bash
202
+ systemctl --user status matelink-matecli-bridge # check status
203
+ systemctl --user restart matelink-matecli-bridge # restart
204
+ systemctl --user stop matelink-matecli-bridge # stop
205
+ journalctl --user -u matelink-matecli-bridge -f # systemd journal (if enabled)
206
+ ```
207
+
208
+ Service config: `~/.config/systemd/user/matelink-matecli-bridge.service`
package/bin/matecli.mjs CHANGED
@@ -18,7 +18,7 @@ import { fileURLToPath, pathToFileURL } from "node:url";
18
18
 
19
19
  const NUMERIC_CODE_LENGTH = 4;
20
20
  const GROUP_SIZE = 4;
21
- const DEFAULT_RELAY_WORKER_WAIT_SECONDS = 600;
21
+ const DEFAULT_RELAY_WORKER_WAIT_SECONDS = 90;
22
22
  const DEFAULT_NETWORK_TIMEOUT_MS = 600000;
23
23
  const BRIDGE_RETRY_DELAY_MS = 2000;
24
24
  const DEFAULT_RELAY_URL = "https://test-mate.clipzap.ai";
@@ -54,6 +54,15 @@ const DEFAULT_GATEWAY_SCOPES = [
54
54
  const SESSION_CONTEXT_MIN_TOKENS = 1024;
55
55
  const CLI_ENTRY = fileURLToPath(import.meta.url);
56
56
 
57
+ function readCliVersion() {
58
+ try {
59
+ const pkgPath = path.resolve(path.dirname(CLI_ENTRY), "..", "package.json");
60
+ const pkg = JSON.parse(fs.readFileSync(pkgPath, "utf8"));
61
+ return pkg.version || "unknown";
62
+ } catch {
63
+ return "unknown";
64
+ }
65
+ }
57
66
 
58
67
  function buildPathString(values) {
59
68
  const entries = [];
@@ -2744,6 +2753,13 @@ async function readRelayNextGatewayRequest({
2744
2753
  method: "GET",
2745
2754
  headers: {
2746
2755
  ...relayGatewayHeaders(gatewayToken),
2756
+ "x-bridge-version": CLI_PACKAGE_NAME + "/" + readCliVersion(),
2757
+ "x-bridge-os": os.platform() + "/" + os.release(),
2758
+ "x-bridge-arch": os.arch(),
2759
+ "x-bridge-hostname": os.hostname(),
2760
+ "x-bridge-node": process.version,
2761
+ "x-bridge-pid": String(process.pid),
2762
+ "x-bridge-gateway-id": gatewayId ?? "",
2747
2763
  },
2748
2764
  }, (Math.max(waitSeconds, 1) + 15) * 1000);
2749
2765
  } catch (error) {
@@ -3673,6 +3689,22 @@ async function proxyGatewayRequestLocal({
3673
3689
  }
3674
3690
  }
3675
3691
 
3692
+ async function reportBridgeMetaToRelay({ relayUrl, gatewayId, gatewayToken, meta }) {
3693
+ const url = `${relayUrl}/v1/gateways/${encodeURIComponent(gatewayId)}/meta`;
3694
+ try {
3695
+ await fetchWithTimeout(url, {
3696
+ method: "POST",
3697
+ headers: {
3698
+ "content-type": "application/json",
3699
+ ...relayGatewayHeaders(gatewayToken),
3700
+ },
3701
+ body: JSON.stringify(meta),
3702
+ }, 15000);
3703
+ } catch {
3704
+ // best-effort, don't fail bridge startup
3705
+ }
3706
+ }
3707
+
3676
3708
  async function runRelayBridge({
3677
3709
  relayUrl,
3678
3710
  gatewayId,
@@ -3680,6 +3712,7 @@ async function runRelayBridge({
3680
3712
  gatewayBaseUrl,
3681
3713
  gatewayAuthToken,
3682
3714
  json,
3715
+ bridgeMeta,
3683
3716
  }) {
3684
3717
  if (!relayUrl) {
3685
3718
  fail("relay URL is required for bridge mode");
@@ -3692,6 +3725,18 @@ async function runRelayBridge({
3692
3725
  console.log(`Relay bridge online. gatewayId=${gatewayId}`);
3693
3726
  console.log(`Relay URL: ${relayUrl}`);
3694
3727
  console.log(`Local Gateway: ${gatewayBaseUrl}`);
3728
+ console.log(`Bridge version: ${bridgeMeta.bridgeVersion}`);
3729
+ console.log(`OS: ${bridgeMeta.osType} ${bridgeMeta.osRelease} (${bridgeMeta.arch})`);
3730
+ console.log(`Hostname: ${bridgeMeta.hostname} | User: ${bridgeMeta.username}`);
3731
+ console.log(`Node: ${bridgeMeta.nodeVersion} | PID: ${bridgeMeta.pid}`);
3732
+ console.log(`CPU: ${bridgeMeta.cpus}x ${bridgeMeta.cpuModel ?? "unknown"}`);
3733
+ console.log(`Memory: ${Math.round(bridgeMeta.freeMemory / 1024 / 1024)}MB free / ${Math.round(bridgeMeta.totalMemory / 1024 / 1024)}MB total`);
3734
+ if (bridgeMeta.linkedUserId) console.log(`Linked user: ${bridgeMeta.linkedUserId}`);
3735
+ if (bridgeMeta.accountId) console.log(`Account: ${bridgeMeta.accountId}`);
3736
+ if (bridgeMeta.deviceId) console.log(`Device: ${bridgeMeta.deviceId}`);
3737
+ if (bridgeMeta.pairCode) console.log(`Last pair code: ${bridgeMeta.pairCode}`);
3738
+ console.log(`Workspace: ${bridgeMeta.workspacePath ?? "default"}`);
3739
+ console.log(`Transport: ${bridgeMeta.transportMode}`);
3695
3740
  }
3696
3741
 
3697
3742
  setGatewayWsBridgePublisher(async (event, payload) => {
@@ -3708,6 +3753,8 @@ async function runRelayBridge({
3708
3753
  });
3709
3754
  });
3710
3755
 
3756
+ await reportBridgeMetaToRelay({ relayUrl, gatewayId, gatewayToken, meta: bridgeMeta });
3757
+
3711
3758
  const activeRequests = new Set();
3712
3759
 
3713
3760
  while (true) {
@@ -4506,6 +4553,88 @@ async function runBridge({ json, relay, noRelay, gateway }) {
4506
4553
  process.exit(0);
4507
4554
  });
4508
4555
 
4556
+ const linkedUserId = typeof section?.linkedUserId === "string" && section.linkedUserId.trim()
4557
+ ? section.linkedUserId.trim()
4558
+ : null;
4559
+ const pairCode = typeof section?.lastPairCode === "string" ? section.lastPairCode.trim() : null;
4560
+
4561
+ // Collect OpenClaw config (sanitized — strip sensitive tokens).
4562
+ const openclawConfig = (() => {
4563
+ try {
4564
+ const raw = readOptionalJsonFile(configPath);
4565
+ // Redact secrets but keep structure.
4566
+ const sanitized = JSON.parse(JSON.stringify(raw));
4567
+ if (sanitized?.gateway?.auth?.token) sanitized.gateway.auth.token = "***";
4568
+ if (sanitized?.channels?.testnextim?.appSecret) sanitized.channels.testnextim.appSecret = "***";
4569
+ if (sanitized?.channels?.["custom-im"]?.appSecret) sanitized.channels["custom-im"].appSecret = "***";
4570
+ return sanitized;
4571
+ } catch {
4572
+ return null;
4573
+ }
4574
+ })();
4575
+
4576
+ // Resolve workspace path.
4577
+ const workspacePath = (() => {
4578
+ try { return resolveConfiguredWorkspaceRoot(); } catch { return null; }
4579
+ })();
4580
+
4581
+ // Read device identity id (if available).
4582
+ const deviceId = (() => {
4583
+ try {
4584
+ const identity = readJsonFileIfExists(GATEWAY_CLIENT_IDENTITY_PATH);
4585
+ return identity?.deviceId ?? null;
4586
+ } catch { return null; }
4587
+ })();
4588
+
4589
+
4590
+ const bridgeMeta = {
4591
+ gatewayId: creds.gatewayId,
4592
+ relayUrl,
4593
+ gatewayBaseUrl,
4594
+ bridgeVersion: readCliVersion(),
4595
+ // System info
4596
+ os: os.platform() + "/" + os.release(),
4597
+ osPlatform: os.platform(),
4598
+ osRelease: os.release(),
4599
+ osType: os.type(),
4600
+ arch: os.arch(),
4601
+ hostname: os.hostname(),
4602
+ nodeVersion: process.version,
4603
+ pid: process.pid,
4604
+ uptime: os.uptime(),
4605
+ totalMemory: os.totalmem(),
4606
+ freeMemory: os.freemem(),
4607
+ cpus: os.cpus().length,
4608
+ cpuModel: os.cpus()[0]?.model ?? null,
4609
+ username: os.userInfo().username,
4610
+ homeDir: os.homedir(),
4611
+ shell: os.userInfo().shell ?? null,
4612
+ // Pairing & user info
4613
+ linkedUserId: linkedUserId,
4614
+ pairCode: pairCode,
4615
+ accountId: section?.accountId ?? null,
4616
+ clientUserId: section?.clientUserId ?? null,
4617
+ deviceId: deviceId,
4618
+ // Config paths
4619
+ configPath,
4620
+ statePath: resolveTestNextIMStatePath(),
4621
+ openclawHome: resolveOpenClawHome(),
4622
+ workspacePath: workspacePath,
4623
+ // OpenClaw config (sanitized)
4624
+ openclawConfig: openclawConfig,
4625
+ // Gateway details
4626
+ gatewayPort: resolveGatewayPort(config) ?? null,
4627
+ gatewayHost: resolveGatewayHost(config),
4628
+ hasGatewayAuthToken: Boolean(gatewayAuthToken),
4629
+ // Channel/transport
4630
+ transportMode: normalizeChatTransportMode(section?.chatTransportMode, "relay"),
4631
+ channelEnabled: section?.enabled !== false,
4632
+ channelName: section?.name ?? "TestNextIM",
4633
+ bindPublicBaseUrl: typeof section?.bindPublicBaseUrl === "string" ? section.bindPublicBaseUrl : null,
4634
+ // Timestamps
4635
+ startedAt: new Date().toISOString(),
4636
+ };
4637
+
4509
4638
  try {
4510
4639
  if (json) {
4511
4640
  console.log(
@@ -4513,9 +4642,7 @@ async function runBridge({ json, relay, noRelay, gateway }) {
4513
4642
  {
4514
4643
  command: "bridge",
4515
4644
  status: "running",
4516
- relayUrl,
4517
- gatewayId: creds.gatewayId,
4518
- gatewayBaseUrl,
4645
+ ...bridgeMeta,
4519
4646
  lockPath: bridgeLock.lockPath,
4520
4647
  },
4521
4648
  null,
@@ -4531,6 +4658,7 @@ async function runBridge({ json, relay, noRelay, gateway }) {
4531
4658
  gatewayBaseUrl,
4532
4659
  gatewayAuthToken,
4533
4660
  json,
4661
+ bridgeMeta,
4534
4662
  });
4535
4663
  } finally {
4536
4664
  cleanupBridgeLock();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@matelink/cli",
3
- "version": "2026.4.21",
3
+ "version": "2026.4.23",
4
4
  "private": false,
5
5
  "description": "Relay-first CLI for pairing and bridging OpenClaw gateway traffic",
6
6
  "type": "module",