rol-websocket-channel 1.0.6 → 1.0.8

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "rol-websocket-channel",
3
- "version": "1.0.6",
3
+ "version": "1.0.8",
4
4
  "description": "Unified OpenClaw plugin: MQTT Channel + Admin Bridge for remote management",
5
5
  "license": "MIT",
6
6
  "author": "nixgnehc",
@@ -1,11 +1,16 @@
1
+ import { execFile } from 'node:child_process';
1
2
  import path from 'node:path';
3
+ import { promisify } from 'node:util';
2
4
 
3
5
  import { pathExists, readJsonFile, writeJsonFile } from '../lib/fs.ts';
4
6
  import { JsonRpcException, JSON_RPC_ERRORS } from '../jsonrpc.ts';
5
7
  import type { JsonValue, MethodContext } from '../types.ts';
6
8
 
9
+ const execFileAsync = promisify(execFile);
10
+
7
11
  const DEFAULT_PLUGIN_ID = 'rol-websocket-channel';
8
- const DEFAULT_PAIR_ENDPOINT = 'http://api.deotaland.local/api-core-bot/front/agent/agent/key/query';
12
+ const DEFAULT_PRODUCTION_BASE_URL = 'https://api.deotaland.ai';
13
+ const GATEWAY_SERVICE = 'openclaw-gateway.service';
9
14
 
10
15
  interface PairingCommandOptions {
11
16
  key: string;
@@ -57,6 +62,7 @@ export async function pairWithKey(
57
62
  const payload = await exchangePairKey(key, options.endpoint, options.auth, existingMqttUrl);
58
63
  applyPairingConfig(config, key, payload);
59
64
  await writeJsonFile(configPath, config);
65
+ const restart = await restartGateway(context.projectRoot);
60
66
 
61
67
  return {
62
68
  ok: true,
@@ -69,7 +75,7 @@ export async function pairWithKey(
69
75
  `channels.${payload.pluginId}`
70
76
  ],
71
77
  channel: payload.channel,
72
- next: 'restart-openclaw-gateway'
78
+ restart
73
79
  };
74
80
  }
75
81
 
@@ -100,8 +106,7 @@ async function exchangePairKey(
100
106
  authOverride?: string,
101
107
  existingMqttUrl?: string | null
102
108
  ): Promise<PairingPayload> {
103
- const endpoint = pickString(endpointOverride)
104
- ?? DEFAULT_PAIR_ENDPOINT;
109
+ const endpoint = buildPairEndpoint(endpointOverride);
105
110
  const auth = pickString(authOverride);
106
111
 
107
112
  const headers: Record<string, string> = {
@@ -145,8 +150,6 @@ function normalizePairingPayload(
145
150
  const apiCoreBotValue = isRecord(root.apiCoreBot) ? root.apiCoreBot : {};
146
151
  const channelValue = isRecord(root.channel) ? root.channel : {};
147
152
 
148
- const apiCoreBotBaseUrl = pickString(apiCoreBotValue.baseUrl)
149
- ?? deriveBaseUrl(endpoint);
150
153
  const apiCoreBotAuthToken = pickString(apiCoreBotValue.authToken)
151
154
  ?? pickString(root.authToken)
152
155
  ?? pickString(root.token);
@@ -179,7 +182,6 @@ function normalizePairingPayload(
179
182
  ...(rawValue ? { rawValue } : {})
180
183
  },
181
184
  apiCoreBot: {
182
- baseUrl: apiCoreBotBaseUrl,
183
185
  ...(apiCoreBotAuthToken ? { authToken: apiCoreBotAuthToken } : {})
184
186
  },
185
187
  channel: {
@@ -219,7 +221,7 @@ function applyPairingConfig(config: OpenClawConfig, key: string, payload: Pairin
219
221
  },
220
222
  apiCoreBot: {
221
223
  ...(isRecord(existingPluginConfig.apiCoreBot) ? existingPluginConfig.apiCoreBot : {}),
222
- ...payload.apiCoreBot
224
+ ...(payload.apiCoreBot.authToken ? { authToken: payload.apiCoreBot.authToken } : {})
223
225
  }
224
226
  }
225
227
  };
@@ -270,10 +272,14 @@ function tryParseJson(raw: string): unknown {
270
272
  }
271
273
  }
272
274
 
273
- function deriveBaseUrl(endpoint: string): string {
274
- const marker = '/front/';
275
- const markerIndex = endpoint.indexOf(marker);
276
- return markerIndex >= 0 ? endpoint.slice(0, markerIndex) : endpoint.replace(/\/+$/, '');
275
+ function buildPairEndpoint(endpointOverride?: string): string {
276
+ const override = pickString(endpointOverride);
277
+ if (override) {
278
+ return override;
279
+ }
280
+
281
+ const baseUrl = getDeotalandApiBaseUrl();
282
+ return `${baseUrl}/api-core-bot/front/agent/agent/key/query`;
277
283
  }
278
284
 
279
285
  function resolveExistingMqttUrl(config: OpenClawConfig): string | null {
@@ -285,6 +291,23 @@ function resolveExistingMqttUrl(config: OpenClawConfig): string | null {
285
291
  return pickString(channelConfig.mqttUrl);
286
292
  }
287
293
 
294
+ async function restartGateway(cwd: string): Promise<JsonValue> {
295
+ try {
296
+ await execFileAsync('systemctl', ['--user', 'restart', GATEWAY_SERVICE], { cwd });
297
+ return {
298
+ attempted: true,
299
+ success: true
300
+ };
301
+ } catch (error: any) {
302
+ return {
303
+ attempted: true,
304
+ success: false,
305
+ message: error instanceof Error ? error.message : String(error),
306
+ stderr: typeof error?.stderr === 'string' ? error.stderr : ''
307
+ };
308
+ }
309
+ }
310
+
288
311
  function normalizeGroupPolicy(value: string): 'pairing' | 'allowlist' | 'open' | 'disabled' {
289
312
  if (value === 'pairing' || value === 'allowlist' || value === 'open' || value === 'disabled') {
290
313
  return value;
@@ -302,6 +325,11 @@ function pickString(value: unknown): string | null {
302
325
  return trimmed.length > 0 ? trimmed : null;
303
326
  }
304
327
 
328
+ function getDeotalandApiBaseUrl(): string {
329
+ const configured = pickString(process.env.DEOTALAND_API_BASE_URL);
330
+ return (configured ?? DEFAULT_PRODUCTION_BASE_URL).replace(/\/+$/, '');
331
+ }
332
+
305
333
  function isRecord(value: unknown): value is Record<string, any> {
306
334
  return Boolean(value) && typeof value === 'object' && !Array.isArray(value);
307
335
  }
@@ -63,12 +63,11 @@ export function parseUsernameFromTopic(topic: string): string {
63
63
  */
64
64
  export function getSubscribeTopic(topic: string): string {
65
65
  const username = parseUsernameFromTopic(topic);
66
- if (username !== "default_name") {
67
- return `announcement/${username}/#`;
68
- }
69
- if (topic.endsWith("#")) return topic;
70
- if (topic.endsWith("/")) return `${topic}#`;
71
- return `${topic}/#`;
66
+ // if (username !== "default_name") {
67
+ // return `announcement/${username}/#`;
68
+ // }
69
+ // if (topic.endsWith("#")) return topic;
70
+ return topic;
72
71
  }
73
72
 
74
73
  /**