agent-relay 3.1.7 → 3.1.9

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.
Files changed (38) hide show
  1. package/bin/agent-relay-broker-darwin-arm64 +0 -0
  2. package/bin/agent-relay-broker-darwin-x64 +0 -0
  3. package/bin/agent-relay-broker-linux-arm64 +0 -0
  4. package/bin/agent-relay-broker-linux-x64 +0 -0
  5. package/package.json +8 -8
  6. package/packages/acp-bridge/package.json +2 -2
  7. package/packages/config/package.json +1 -1
  8. package/packages/hooks/package.json +4 -4
  9. package/packages/memory/package.json +2 -2
  10. package/packages/openclaw/dist/__tests__/ws-client.test.js +69 -0
  11. package/packages/openclaw/dist/__tests__/ws-client.test.js.map +1 -1
  12. package/packages/openclaw/dist/cli.js +8 -1
  13. package/packages/openclaw/dist/cli.js.map +1 -1
  14. package/packages/openclaw/dist/config.d.ts +6 -2
  15. package/packages/openclaw/dist/config.d.ts.map +1 -1
  16. package/packages/openclaw/dist/config.js +95 -7
  17. package/packages/openclaw/dist/config.js.map +1 -1
  18. package/packages/openclaw/dist/gateway.d.ts +8 -0
  19. package/packages/openclaw/dist/gateway.d.ts.map +1 -1
  20. package/packages/openclaw/dist/gateway.js +269 -34
  21. package/packages/openclaw/dist/gateway.js.map +1 -1
  22. package/packages/openclaw/dist/setup.d.ts.map +1 -1
  23. package/packages/openclaw/dist/setup.js +117 -15
  24. package/packages/openclaw/dist/setup.js.map +1 -1
  25. package/packages/openclaw/package.json +2 -2
  26. package/packages/openclaw/skill/SKILL.md +103 -0
  27. package/packages/openclaw/src/__tests__/ws-client.test.ts +72 -0
  28. package/packages/openclaw/src/cli.ts +7 -1
  29. package/packages/openclaw/src/config.ts +94 -8
  30. package/packages/openclaw/src/gateway.ts +328 -36
  31. package/packages/openclaw/src/setup.ts +120 -13
  32. package/packages/policy/package.json +2 -2
  33. package/packages/sdk/package.json +2 -2
  34. package/packages/sdk-py/pyproject.toml +1 -1
  35. package/packages/telemetry/package.json +1 -1
  36. package/packages/trajectory/package.json +2 -2
  37. package/packages/user-directory/package.json +2 -2
  38. package/packages/utils/package.json +2 -2
@@ -5,6 +5,7 @@ import { existsSync } from 'node:fs';
5
5
  import { hostname } from 'node:os';
6
6
  import { fileURLToPath } from 'node:url';
7
7
  import { spawn as spawnProcess, execFileSync } from 'node:child_process';
8
+ import { randomBytes } from 'node:crypto';
8
9
 
9
10
  import { RelayCast } from '@relaycast/sdk';
10
11
 
@@ -25,6 +26,30 @@ function extractNestedValue(obj: unknown, path: string): unknown {
25
26
  return current;
26
27
  }
27
28
 
29
+ /**
30
+ * Set a deeply nested value in an object by dot-separated path, creating
31
+ * intermediate objects as needed.
32
+ */
33
+ const DANGEROUS_KEYS = new Set(['__proto__', 'prototype', 'constructor']);
34
+
35
+ function setNestedValue(obj: Record<string, unknown>, path: string, value: unknown): void {
36
+ const keys = path.split('.');
37
+ for (const key of keys) {
38
+ if (DANGEROUS_KEYS.has(key)) {
39
+ throw new Error(`Refusing to set dangerous key "${key}" in path "${path}"`);
40
+ }
41
+ }
42
+ let current: Record<string, unknown> = obj;
43
+ for (let i = 0; i < keys.length - 1; i++) {
44
+ const key = keys[i];
45
+ if (current[key] == null || typeof current[key] !== 'object') {
46
+ current[key] = {};
47
+ }
48
+ current = current[key] as Record<string, unknown>;
49
+ }
50
+ current[keys[keys.length - 1]] = value;
51
+ }
52
+
28
53
  /**
29
54
  * Resolve how to invoke mcporter. Prefers a global binary, falls back to npx.
30
55
  */
@@ -98,14 +123,18 @@ export async function setup(options: SetupOptions): Promise<SetupResult> {
98
123
  const baseUrl = options.baseUrl ?? 'https://api.relaycast.dev';
99
124
  const channels = options.channels ?? ['general'];
100
125
 
126
+ // CLI name for restart reminder messages (based on detected variant)
127
+ const cliName = detection.variant === 'clawdbot' ? 'clawdbot' : 'openclaw';
128
+ const serviceName = detection.variant === 'clawdbot' ? 'clawdbot' : 'openclaw';
129
+
101
130
  if (!detection.installed) {
102
131
  // Auto-create ~/.openclaw/ if OpenClaw binary is available but the config dir
103
132
  // doesn't exist yet (common in Docker images before onboarding).
104
133
  try {
105
134
  await mkdir(detection.homeDir, { recursive: true });
106
135
  await mkdir(join(detection.homeDir, 'workspace'), { recursive: true });
107
- // Write a minimal openclaw.json so MCP servers can be registered
108
- const configPath = join(detection.homeDir, 'openclaw.json');
136
+ // Write a minimal config file so MCP servers can be registered
137
+ const configPath = join(detection.homeDir, detection.configFilename);
109
138
  if (!existsSync(configPath)) {
110
139
  await writeFile(configPath, JSON.stringify({ mcpServers: {} }, null, 2) + '\n', 'utf-8');
111
140
  }
@@ -126,14 +155,48 @@ export async function setup(options: SetupOptions): Promise<SetupResult> {
126
155
 
127
156
  // Enable the OpenResponses HTTP API so the inbound gateway can inject
128
157
  // messages via POST /v1/responses on the local OpenClaw gateway.
129
- try {
130
- execFileSync('openclaw', [
158
+ // Try CLI names in order: openclaw, clawdbot, clawdbot-cli.sh.
159
+ // If all CLI calls fail, mutate the config JSON directly.
160
+ let configMutated = false;
161
+ {
162
+ const httpEndpointArgs = [
131
163
  'config', 'set',
132
164
  'gateway.http.endpoints.responses.enabled', 'true',
133
- ], { stdio: 'pipe' });
134
- } catch {
135
- console.warn('Could not enable OpenResponses API (non-fatal). Enable manually:');
136
- console.warn(' openclaw config set gateway.http.endpoints.responses.enabled true');
165
+ ];
166
+ const cliCandidates = ['openclaw', 'clawdbot', 'clawdbot-cli.sh'];
167
+ let cliSuccess = false;
168
+
169
+ for (const cli of cliCandidates) {
170
+ try {
171
+ execFileSync(cli, httpEndpointArgs, { stdio: 'pipe' });
172
+ cliSuccess = true;
173
+ break;
174
+ } catch {
175
+ // Try next candidate
176
+ }
177
+ }
178
+
179
+ if (!cliSuccess) {
180
+ // Fall back to direct JSON config file mutation
181
+ if (detection.configFile) {
182
+ try {
183
+ const raw = await readFile(detection.configFile, 'utf-8');
184
+ const cfg = JSON.parse(raw) as Record<string, unknown>;
185
+ setNestedValue(cfg, 'gateway.http.endpoints.responses.enabled', true);
186
+ await writeFile(detection.configFile, JSON.stringify(cfg, null, 2) + '\n', 'utf-8');
187
+ // Reload config in detection
188
+ detection.config = cfg;
189
+ configMutated = true;
190
+ console.log('[setup] Enabled gateway.http.endpoints.responses.enabled via config file.');
191
+ } catch (writeErr) {
192
+ console.warn('Could not enable OpenResponses API (non-fatal). Enable manually:');
193
+ console.warn(` ${cliName} config set gateway.http.endpoints.responses.enabled true`);
194
+ }
195
+ } else {
196
+ console.warn('Could not enable OpenResponses API (non-fatal). Enable manually:');
197
+ console.warn(` ${cliName} config set gateway.http.endpoints.responses.enabled true`);
198
+ }
199
+ }
137
200
  }
138
201
 
139
202
  // Resolve API key: use provided key or create a new workspace
@@ -220,19 +283,63 @@ export async function setup(options: SetupOptions): Promise<SetupResult> {
220
283
  );
221
284
  }
222
285
 
223
- // Extract gateway auth from openclaw.json (if available)
224
- const openclawGatewayToken =
286
+ // Extract gateway auth from config (if available). Auto-generate if missing.
287
+ let openclawGatewayToken: string | undefined =
225
288
  process.env.OPENCLAW_GATEWAY_TOKEN ??
226
289
  (extractNestedValue(detection.config, 'gateway.auth.token') as string | undefined);
290
+
227
291
  const openclawGatewayPortRaw =
228
292
  process.env.OPENCLAW_GATEWAY_PORT ??
229
293
  (extractNestedValue(detection.config, 'gateway.port') as number | string | undefined);
230
294
  const openclawGatewayPort = openclawGatewayPortRaw ? Number(openclawGatewayPortRaw) : undefined;
231
295
 
232
296
  if (!openclawGatewayToken) {
233
- console.warn('[setup] No gateway token found in openclaw.json or OPENCLAW_GATEWAY_TOKEN env.');
234
- console.warn('[setup] Inbound gateway may fail to pair. Set it manually:');
235
- console.warn('[setup] export OPENCLAW_GATEWAY_TOKEN=$(cat ~/.openclaw/openclaw.json | jq -r .gateway.auth.token)');
297
+ // Generate a random token and persist it to the config file
298
+ const generated = randomBytes(16).toString('hex');
299
+ openclawGatewayToken = generated;
300
+ console.log('[setup] No gateway token found — generating one and writing to config file.');
301
+
302
+ if (detection.configFile) {
303
+ try {
304
+ const raw = await readFile(detection.configFile, 'utf-8');
305
+ const cfg = JSON.parse(raw) as Record<string, unknown>;
306
+ setNestedValue(cfg, 'gateway.auth.token', generated);
307
+ await writeFile(detection.configFile, JSON.stringify(cfg, null, 2) + '\n', 'utf-8');
308
+ detection.config = cfg;
309
+ configMutated = true;
310
+ } catch (writeErr) {
311
+ console.warn(`[setup] Could not write generated token to config file: ${writeErr instanceof Error ? writeErr.message : String(writeErr)}`);
312
+ }
313
+ } else {
314
+ console.warn('[setup] No config file available to persist generated token. Set manually:');
315
+ console.warn(`[setup] export OPENCLAW_GATEWAY_TOKEN=${generated}`);
316
+ }
317
+ }
318
+
319
+ // Print restart reminder if any config mutations were made
320
+ if (configMutated) {
321
+ console.log('');
322
+ console.log('Config changes detected. Restart the gateway to apply:');
323
+ console.log(` systemctl restart ${serviceName}`);
324
+ if (serviceName !== 'openclaw') {
325
+ console.log(` # or: systemctl restart openclaw`);
326
+ }
327
+ console.log(` # or restart manually if not using systemd`);
328
+ console.log('');
329
+ }
330
+
331
+ // Exec policy preflight warning — warn when security is missing OR not 'full'
332
+ {
333
+ const execSecurity = extractNestedValue(detection.config, 'tools.exec.security') as string | undefined;
334
+ if (execSecurity !== 'full') {
335
+ console.warn('');
336
+ console.warn('Warning: Execution policies may be locked down. If the agent can only chat:');
337
+ console.warn(` ${cliName} config set tools.exec.host gateway`);
338
+ console.warn(` ${cliName} config set tools.exec.ask off`);
339
+ console.warn(` ${cliName} config set tools.exec.security full`);
340
+ console.warn(` systemctl restart ${serviceName}`);
341
+ console.warn('');
342
+ }
236
343
  }
237
344
 
238
345
  // Save gateway config (.env)
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agent-relay/policy",
3
- "version": "3.1.7",
3
+ "version": "3.1.9",
4
4
  "description": "Agent policy management with multi-level fallback (repo, local PRPM, cloud workspace)",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -22,7 +22,7 @@
22
22
  "test:watch": "vitest"
23
23
  },
24
24
  "dependencies": {
25
- "@agent-relay/config": "3.1.7"
25
+ "@agent-relay/config": "3.1.9"
26
26
  },
27
27
  "devDependencies": {
28
28
  "@types/node": "^22.19.3",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agent-relay/sdk",
3
- "version": "3.1.7",
3
+ "version": "3.1.9",
4
4
  "type": "module",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -81,7 +81,7 @@
81
81
  "typescript": "^5.7.3"
82
82
  },
83
83
  "dependencies": {
84
- "@agent-relay/config": "3.1.7",
84
+ "@agent-relay/config": "3.1.9",
85
85
  "@relaycast/sdk": "^0.4.0",
86
86
  "yaml": "^2.7.0"
87
87
  }
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "agent-relay-sdk"
7
- version = "3.1.7"
7
+ version = "3.1.9"
8
8
  description = "Python SDK for Agent Relay workflows"
9
9
  readme = "README.md"
10
10
  license = "Apache-2.0"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agent-relay/telemetry",
3
- "version": "3.1.7",
3
+ "version": "3.1.9",
4
4
  "description": "Anonymous telemetry for Agent Relay usage analytics",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agent-relay/trajectory",
3
- "version": "3.1.7",
3
+ "version": "3.1.9",
4
4
  "description": "Trajectory integration utilities (trail/PDERO) for Relay",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -22,7 +22,7 @@
22
22
  "test:watch": "vitest"
23
23
  },
24
24
  "dependencies": {
25
- "@agent-relay/config": "3.1.7"
25
+ "@agent-relay/config": "3.1.9"
26
26
  },
27
27
  "devDependencies": {
28
28
  "@types/node": "^22.19.3",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agent-relay/user-directory",
3
- "version": "3.1.7",
3
+ "version": "3.1.9",
4
4
  "description": "User directory service for agent-relay (per-user credential storage)",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -22,7 +22,7 @@
22
22
  "test:watch": "vitest"
23
23
  },
24
24
  "dependencies": {
25
- "@agent-relay/utils": "3.1.7"
25
+ "@agent-relay/utils": "3.1.9"
26
26
  },
27
27
  "devDependencies": {
28
28
  "@types/node": "^22.19.3",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agent-relay/utils",
3
- "version": "3.1.7",
3
+ "version": "3.1.9",
4
4
  "description": "Shared utilities for agent-relay: logging, name generation, command resolution, update checking",
5
5
  "type": "module",
6
6
  "main": "dist/cjs/index.js",
@@ -112,7 +112,7 @@
112
112
  "vitest": "^3.2.4"
113
113
  },
114
114
  "dependencies": {
115
- "@agent-relay/config": "3.1.7",
115
+ "@agent-relay/config": "3.1.9",
116
116
  "compare-versions": "^6.1.1"
117
117
  },
118
118
  "publishConfig": {