agent-relay 3.1.0 → 3.1.1

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 (148) hide show
  1. package/bin/agent-relay-broker-linux-x64 +0 -0
  2. package/package.json +9 -9
  3. package/packages/acp-bridge/package.json +2 -2
  4. package/packages/config/package.json +1 -1
  5. package/packages/hooks/package.json +4 -4
  6. package/packages/memory/package.json +2 -2
  7. package/packages/openclaw/README.md +78 -0
  8. package/packages/openclaw/bin/relay-openclaw.mjs +2 -0
  9. package/packages/openclaw/bridge/bridge.mjs +305 -0
  10. package/packages/openclaw/dist/__tests__/gateway-threads.test.d.ts +2 -0
  11. package/packages/openclaw/dist/__tests__/gateway-threads.test.d.ts.map +1 -0
  12. package/packages/openclaw/dist/__tests__/gateway-threads.test.js +320 -0
  13. package/packages/openclaw/dist/__tests__/gateway-threads.test.js.map +1 -0
  14. package/packages/openclaw/dist/__tests__/naming.test.d.ts +2 -0
  15. package/packages/openclaw/dist/__tests__/naming.test.d.ts.map +1 -0
  16. package/packages/openclaw/dist/__tests__/naming.test.js +21 -0
  17. package/packages/openclaw/dist/__tests__/naming.test.js.map +1 -0
  18. package/packages/openclaw/dist/__tests__/spawn-manager.test.d.ts +2 -0
  19. package/packages/openclaw/dist/__tests__/spawn-manager.test.d.ts.map +1 -0
  20. package/packages/openclaw/dist/__tests__/spawn-manager.test.js +126 -0
  21. package/packages/openclaw/dist/__tests__/spawn-manager.test.js.map +1 -0
  22. package/packages/openclaw/dist/auth/converter.d.ts +28 -0
  23. package/packages/openclaw/dist/auth/converter.d.ts.map +1 -0
  24. package/packages/openclaw/dist/auth/converter.js +64 -0
  25. package/packages/openclaw/dist/auth/converter.js.map +1 -0
  26. package/packages/openclaw/dist/cli.d.ts +2 -0
  27. package/packages/openclaw/dist/cli.d.ts.map +1 -0
  28. package/packages/openclaw/dist/cli.js +230 -0
  29. package/packages/openclaw/dist/cli.js.map +1 -0
  30. package/packages/openclaw/dist/config.d.ts +27 -0
  31. package/packages/openclaw/dist/config.d.ts.map +1 -0
  32. package/packages/openclaw/dist/config.js +97 -0
  33. package/packages/openclaw/dist/config.js.map +1 -0
  34. package/packages/openclaw/dist/control.d.ts +22 -0
  35. package/packages/openclaw/dist/control.d.ts.map +1 -0
  36. package/packages/openclaw/dist/control.js +58 -0
  37. package/packages/openclaw/dist/control.js.map +1 -0
  38. package/packages/openclaw/dist/gateway.d.ts +71 -0
  39. package/packages/openclaw/dist/gateway.d.ts.map +1 -0
  40. package/packages/openclaw/dist/gateway.js +785 -0
  41. package/packages/openclaw/dist/gateway.js.map +1 -0
  42. package/packages/openclaw/dist/identity/contract.d.ts +11 -0
  43. package/packages/openclaw/dist/identity/contract.d.ts.map +1 -0
  44. package/packages/openclaw/dist/identity/contract.js +40 -0
  45. package/packages/openclaw/dist/identity/contract.js.map +1 -0
  46. package/packages/openclaw/dist/identity/files.d.ts +33 -0
  47. package/packages/openclaw/dist/identity/files.d.ts.map +1 -0
  48. package/packages/openclaw/dist/identity/files.js +145 -0
  49. package/packages/openclaw/dist/identity/files.js.map +1 -0
  50. package/packages/openclaw/dist/identity/model.d.ts +11 -0
  51. package/packages/openclaw/dist/identity/model.d.ts.map +1 -0
  52. package/packages/openclaw/dist/identity/model.js +28 -0
  53. package/packages/openclaw/dist/identity/model.js.map +1 -0
  54. package/packages/openclaw/dist/identity/naming.d.ts +5 -0
  55. package/packages/openclaw/dist/identity/naming.d.ts.map +1 -0
  56. package/packages/openclaw/dist/identity/naming.js +7 -0
  57. package/packages/openclaw/dist/identity/naming.js.map +1 -0
  58. package/packages/openclaw/dist/index.d.ts +20 -0
  59. package/packages/openclaw/dist/index.d.ts.map +1 -0
  60. package/packages/openclaw/dist/index.js +27 -0
  61. package/packages/openclaw/dist/index.js.map +1 -0
  62. package/packages/openclaw/dist/inject.d.ts +14 -0
  63. package/packages/openclaw/dist/inject.d.ts.map +1 -0
  64. package/packages/openclaw/dist/inject.js +66 -0
  65. package/packages/openclaw/dist/inject.js.map +1 -0
  66. package/packages/openclaw/dist/mcp/server.d.ts +8 -0
  67. package/packages/openclaw/dist/mcp/server.d.ts.map +1 -0
  68. package/packages/openclaw/dist/mcp/server.js +105 -0
  69. package/packages/openclaw/dist/mcp/server.js.map +1 -0
  70. package/packages/openclaw/dist/mcp/tools.d.ts +17 -0
  71. package/packages/openclaw/dist/mcp/tools.d.ts.map +1 -0
  72. package/packages/openclaw/dist/mcp/tools.js +145 -0
  73. package/packages/openclaw/dist/mcp/tools.js.map +1 -0
  74. package/packages/openclaw/dist/runtime/openclaw-config.d.ts +20 -0
  75. package/packages/openclaw/dist/runtime/openclaw-config.d.ts.map +1 -0
  76. package/packages/openclaw/dist/runtime/openclaw-config.js +50 -0
  77. package/packages/openclaw/dist/runtime/openclaw-config.js.map +1 -0
  78. package/packages/openclaw/dist/runtime/patch.d.ts +24 -0
  79. package/packages/openclaw/dist/runtime/patch.d.ts.map +1 -0
  80. package/packages/openclaw/dist/runtime/patch.js +92 -0
  81. package/packages/openclaw/dist/runtime/patch.js.map +1 -0
  82. package/packages/openclaw/dist/runtime/setup.d.ts +26 -0
  83. package/packages/openclaw/dist/runtime/setup.d.ts.map +1 -0
  84. package/packages/openclaw/dist/runtime/setup.js +58 -0
  85. package/packages/openclaw/dist/runtime/setup.js.map +1 -0
  86. package/packages/openclaw/dist/setup.d.ts +29 -0
  87. package/packages/openclaw/dist/setup.d.ts.map +1 -0
  88. package/packages/openclaw/dist/setup.js +300 -0
  89. package/packages/openclaw/dist/setup.js.map +1 -0
  90. package/packages/openclaw/dist/spawn/docker.d.ts +58 -0
  91. package/packages/openclaw/dist/spawn/docker.d.ts.map +1 -0
  92. package/packages/openclaw/dist/spawn/docker.js +222 -0
  93. package/packages/openclaw/dist/spawn/docker.js.map +1 -0
  94. package/packages/openclaw/dist/spawn/manager.d.ts +45 -0
  95. package/packages/openclaw/dist/spawn/manager.d.ts.map +1 -0
  96. package/packages/openclaw/dist/spawn/manager.js +140 -0
  97. package/packages/openclaw/dist/spawn/manager.js.map +1 -0
  98. package/packages/openclaw/dist/spawn/process.d.ts +16 -0
  99. package/packages/openclaw/dist/spawn/process.d.ts.map +1 -0
  100. package/packages/openclaw/dist/spawn/process.js +241 -0
  101. package/packages/openclaw/dist/spawn/process.js.map +1 -0
  102. package/packages/openclaw/dist/spawn/types.d.ts +42 -0
  103. package/packages/openclaw/dist/spawn/types.d.ts.map +1 -0
  104. package/packages/openclaw/dist/spawn/types.js +2 -0
  105. package/packages/openclaw/dist/spawn/types.js.map +1 -0
  106. package/packages/openclaw/dist/types.d.ts +37 -0
  107. package/packages/openclaw/dist/types.d.ts.map +1 -0
  108. package/packages/openclaw/dist/types.js +2 -0
  109. package/packages/openclaw/dist/types.js.map +1 -0
  110. package/packages/openclaw/package.json +63 -0
  111. package/packages/openclaw/skill/SKILL.md +194 -0
  112. package/packages/openclaw/src/__tests__/gateway-threads.test.ts +384 -0
  113. package/packages/openclaw/src/__tests__/naming.test.ts +24 -0
  114. package/packages/openclaw/src/__tests__/spawn-manager.test.ts +152 -0
  115. package/packages/openclaw/src/auth/converter.ts +90 -0
  116. package/packages/openclaw/src/cli.ts +269 -0
  117. package/packages/openclaw/src/config.ts +124 -0
  118. package/packages/openclaw/src/control.ts +100 -0
  119. package/packages/openclaw/src/gateway.ts +941 -0
  120. package/packages/openclaw/src/identity/contract.ts +44 -0
  121. package/packages/openclaw/src/identity/files.ts +198 -0
  122. package/packages/openclaw/src/identity/model.ts +27 -0
  123. package/packages/openclaw/src/identity/naming.ts +6 -0
  124. package/packages/openclaw/src/index.ts +59 -0
  125. package/packages/openclaw/src/inject.ts +77 -0
  126. package/packages/openclaw/src/mcp/server.ts +121 -0
  127. package/packages/openclaw/src/mcp/tools.ts +174 -0
  128. package/packages/openclaw/src/runtime/openclaw-config.ts +64 -0
  129. package/packages/openclaw/src/runtime/patch.ts +103 -0
  130. package/packages/openclaw/src/runtime/setup.ts +89 -0
  131. package/packages/openclaw/src/setup.ts +336 -0
  132. package/packages/openclaw/src/spawn/docker.ts +261 -0
  133. package/packages/openclaw/src/spawn/manager.ts +181 -0
  134. package/packages/openclaw/src/spawn/process.ts +272 -0
  135. package/packages/openclaw/src/spawn/types.ts +43 -0
  136. package/packages/openclaw/src/types.ts +38 -0
  137. package/packages/openclaw/templates/SOUL.md.template +34 -0
  138. package/packages/openclaw/tsconfig.json +12 -0
  139. package/packages/policy/package.json +2 -2
  140. package/packages/sdk/package.json +2 -2
  141. package/packages/sdk-py/pyproject.toml +1 -1
  142. package/packages/telemetry/package.json +1 -1
  143. package/packages/trajectory/package.json +2 -2
  144. package/packages/user-directory/package.json +2 -2
  145. package/packages/utils/package.json +2 -2
  146. package/bin/agent-relay-broker-darwin-arm64 +0 -0
  147. package/bin/agent-relay-broker-darwin-x64 +0 -0
  148. package/bin/agent-relay-broker-linux-arm64 +0 -0
@@ -0,0 +1,140 @@
1
+ import { readFile, writeFile, mkdir } from 'node:fs/promises';
2
+ import { join } from 'node:path';
3
+ import { homedir } from 'node:os';
4
+ import { existsSync } from 'node:fs';
5
+ import { DockerSpawnProvider } from './docker.js';
6
+ import { ProcessSpawnProvider } from './process.js';
7
+ /** Default maximum number of concurrent spawns per manager. */
8
+ const DEFAULT_MAX_SPAWNS = 10;
9
+ /** Default maximum spawn depth (prevents recursive spawn chains). */
10
+ const DEFAULT_MAX_SPAWN_DEPTH = 3;
11
+ /**
12
+ * Detect whether Docker is available by checking if the socket exists.
13
+ * Used to auto-select spawn mode when not explicitly configured.
14
+ */
15
+ function isDockerAvailable() {
16
+ const socketPath = process.env.DOCKER_SOCKET ?? '/var/run/docker.sock';
17
+ return existsSync(socketPath);
18
+ }
19
+ /**
20
+ * SpawnManager — tracks active spawns and provides a unified interface
21
+ * for spawning, listing, and releasing OpenClaw instances.
22
+ *
23
+ * Security controls:
24
+ * - maxSpawns: Maximum concurrent spawns (default: 10)
25
+ * - maxDepth: Maximum spawn depth to prevent recursive chains (default: 3)
26
+ * - Persistent state in spawns.json for recovery on restart
27
+ */
28
+ export class SpawnManager {
29
+ provider;
30
+ handles = new Map();
31
+ maxSpawns;
32
+ maxDepth;
33
+ stateFile;
34
+ currentDepth;
35
+ constructor(options) {
36
+ // Mode resolution: explicit > env > auto-detect (docker if available, else process)
37
+ const explicitMode = options?.mode ?? process.env.OPENCLAW_SPAWN_MODE;
38
+ const resolvedMode = explicitMode ?? (isDockerAvailable() ? 'docker' : 'process');
39
+ this.provider = resolvedMode === 'docker'
40
+ ? new DockerSpawnProvider()
41
+ : new ProcessSpawnProvider();
42
+ this.maxSpawns = options?.maxSpawns
43
+ ?? Number(process.env.OPENCLAW_MAX_SPAWNS || DEFAULT_MAX_SPAWNS);
44
+ this.maxDepth = options?.maxDepth
45
+ ?? Number(process.env.OPENCLAW_MAX_SPAWN_DEPTH || DEFAULT_MAX_SPAWN_DEPTH);
46
+ this.currentDepth = options?.spawnDepth
47
+ ?? Number(process.env.OPENCLAW_SPAWN_DEPTH || 0);
48
+ this.stateFile = join(homedir(), '.openclaw', 'workspace', 'relaycast', 'spawns.json');
49
+ }
50
+ async spawn(options) {
51
+ // Enforce spawn depth limit — prevents recursive spawn chains
52
+ if (this.currentDepth >= this.maxDepth) {
53
+ throw new Error(`Spawn depth limit reached (${this.maxDepth}). ` +
54
+ 'Cannot spawn from a spawn chain this deep. Set OPENCLAW_MAX_SPAWN_DEPTH to increase.');
55
+ }
56
+ // Enforce concurrent spawn limit
57
+ if (this.handles.size >= this.maxSpawns) {
58
+ throw new Error(`Maximum concurrent spawns reached (${this.maxSpawns}). ` +
59
+ 'Release an existing OpenClaw before spawning a new one. Set OPENCLAW_MAX_SPAWNS to increase.');
60
+ }
61
+ // Check for duplicate by display name (the user-provided name)
62
+ for (const handle of this.handles.values()) {
63
+ if (handle.displayName === options.name) {
64
+ throw new Error(`OpenClaw "${options.name}" is already running (id: ${handle.id})`);
65
+ }
66
+ }
67
+ const handle = await this.provider.spawn(options);
68
+ this.handles.set(handle.id, handle);
69
+ await this.persistState();
70
+ return handle;
71
+ }
72
+ async release(id) {
73
+ const handle = this.handles.get(id);
74
+ if (!handle)
75
+ return false;
76
+ await handle.destroy();
77
+ this.handles.delete(id);
78
+ await this.persistState();
79
+ return true;
80
+ }
81
+ async releaseByName(name) {
82
+ for (const [id, handle] of this.handles) {
83
+ // Match by display name (user-provided) or normalized agent name
84
+ if (handle.displayName === name || handle.agentName === name) {
85
+ await handle.destroy();
86
+ this.handles.delete(id);
87
+ await this.persistState();
88
+ return true;
89
+ }
90
+ }
91
+ return false;
92
+ }
93
+ async releaseAll() {
94
+ const ids = Array.from(this.handles.keys());
95
+ await Promise.allSettled(ids.map((id) => this.release(id)));
96
+ }
97
+ list() {
98
+ return Array.from(this.handles.values());
99
+ }
100
+ get(id) {
101
+ return this.handles.get(id);
102
+ }
103
+ get size() {
104
+ return this.handles.size;
105
+ }
106
+ /** Persist spawn state to disk for recovery. */
107
+ async persistState() {
108
+ try {
109
+ const dir = join(homedir(), '.openclaw', 'workspace', 'relaycast');
110
+ await mkdir(dir, { recursive: true });
111
+ const state = {
112
+ spawns: Array.from(this.handles.values()).map((h) => ({
113
+ id: h.id,
114
+ displayName: h.displayName,
115
+ agentName: h.agentName,
116
+ gatewayPort: h.gatewayPort,
117
+ spawnedAt: new Date().toISOString(),
118
+ })),
119
+ };
120
+ await writeFile(this.stateFile, JSON.stringify(state, null, 2) + '\n', 'utf8');
121
+ }
122
+ catch {
123
+ // Best-effort persistence — don't crash if we can't write
124
+ }
125
+ }
126
+ /** Load persisted state (for display/diagnostics only — processes can't be recovered). */
127
+ async loadPersistedState() {
128
+ try {
129
+ if (!existsSync(this.stateFile))
130
+ return [];
131
+ const raw = await readFile(this.stateFile, 'utf8');
132
+ const state = JSON.parse(raw);
133
+ return state.spawns ?? [];
134
+ }
135
+ catch {
136
+ return [];
137
+ }
138
+ }
139
+ }
140
+ //# sourceMappingURL=manager.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"manager.js","sourceRoot":"","sources":["../../src/spawn/manager.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,16 @@
1
+ import type { SpawnProvider, SpawnOptions, SpawnHandle } from './types.js';
2
+ /**
3
+ * Spawn OpenClaw instances as local child processes.
4
+ * No Docker required — simplest local mode.
5
+ *
6
+ * Each spawn:
7
+ * 1. Starts `openclaw gateway` on an OS-assigned free port
8
+ * 2. Uses AgentRelay SDK to spawn a broker + bridge agent connected to the gateway
9
+ */
10
+ export declare class ProcessSpawnProvider implements SpawnProvider {
11
+ private readonly handles;
12
+ spawn(options: SpawnOptions): Promise<SpawnHandle>;
13
+ destroy(id: string): Promise<void>;
14
+ list(): Promise<SpawnHandle[]>;
15
+ }
16
+ //# sourceMappingURL=process.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"process.d.ts","sourceRoot":"","sources":["../../src/spawn/process.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAE,aAAa,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAqC3E;;;;;;;GAOG;AACH,qBAAa,oBAAqB,YAAW,aAAa;IACxD,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAoC;IAEtD,KAAK,CAAC,OAAO,EAAE,YAAY,GAAG,OAAO,CAAC,WAAW,CAAC;IAoKlD,OAAO,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAOlC,IAAI,IAAI,OAAO,CAAC,WAAW,EAAE,CAAC;CASrC"}
@@ -0,0 +1,241 @@
1
+ import { spawn as cpSpawn } from 'node:child_process';
2
+ import { join, dirname } from 'node:path';
3
+ import { homedir } from 'node:os';
4
+ import { mkdir } from 'node:fs/promises';
5
+ import { randomUUID } from 'node:crypto';
6
+ import { createServer } from 'node:net';
7
+ import { fileURLToPath } from 'node:url';
8
+ import { AgentRelay } from '@agent-relay/sdk';
9
+ import { normalizeModelRef } from '../identity/model.js';
10
+ import { buildIdentityTask } from '../identity/contract.js';
11
+ import { buildAgentName } from '../identity/naming.js';
12
+ import { ensureWorkspace } from '../identity/files.js';
13
+ import { convertCodexAuth } from '../auth/converter.js';
14
+ import { writeOpenClawConfig } from '../runtime/openclaw-config.js';
15
+ import { patchOpenClawDist, clearJitCache } from '../runtime/patch.js';
16
+ /**
17
+ * Find a free port by briefly binding to port 0 and reading the OS-assigned port.
18
+ */
19
+ async function findFreePort() {
20
+ return new Promise((resolve, reject) => {
21
+ const server = createServer();
22
+ server.listen(0, '127.0.0.1', () => {
23
+ const addr = server.address();
24
+ if (!addr || typeof addr === 'string') {
25
+ server.close();
26
+ reject(new Error('Failed to get ephemeral port'));
27
+ return;
28
+ }
29
+ const port = addr.port;
30
+ server.close(() => resolve(port));
31
+ });
32
+ server.on('error', reject);
33
+ });
34
+ }
35
+ /**
36
+ * Spawn OpenClaw instances as local child processes.
37
+ * No Docker required — simplest local mode.
38
+ *
39
+ * Each spawn:
40
+ * 1. Starts `openclaw gateway` on an OS-assigned free port
41
+ * 2. Uses AgentRelay SDK to spawn a broker + bridge agent connected to the gateway
42
+ */
43
+ export class ProcessSpawnProvider {
44
+ handles = new Map();
45
+ async spawn(options) {
46
+ const workspaceId = options.workspaceId ?? `local-${Date.now().toString(36)}`;
47
+ const agentName = buildAgentName(workspaceId, options.name);
48
+ const channels = options.channels?.length ? options.channels : ['general'];
49
+ const gatewayToken = randomUUID().replace(/-/g, '').slice(0, 32);
50
+ // Find a free port via OS allocation
51
+ const port = await findFreePort();
52
+ // Convert auth + write config
53
+ const { preferredProvider } = await convertCodexAuth();
54
+ const resolvedModel = normalizeModelRef(options.model, preferredProvider);
55
+ const identityTask = buildIdentityTask(agentName, workspaceId, resolvedModel);
56
+ // Ensure workspace — each spawn gets its own isolated directory
57
+ const workspacePath = options.workspacePath ?? join(homedir(), '.openclaw', 'spawns', options.name);
58
+ await mkdir(workspacePath, { recursive: true });
59
+ // Write config to a per-spawn isolated directory (not shared ~/.openclaw/)
60
+ // This prevents concurrent spawns from overwriting each other's model/workspace config.
61
+ const spawnHome = join(homedir(), '.openclaw', 'spawns', options.name, '.openclaw');
62
+ await writeOpenClawConfig({
63
+ modelRef: resolvedModel,
64
+ openclawHome: spawnHome,
65
+ });
66
+ await ensureWorkspace({
67
+ workspacePath,
68
+ workspaceId,
69
+ clawName: options.name,
70
+ role: options.role,
71
+ modelRef: resolvedModel,
72
+ });
73
+ // Copy parent auth profiles to spawned agent so it can call the model.
74
+ // OpenClaw stores auth in ~/.openclaw/agents/main/agent/auth-profiles.json
75
+ const parentAuthDir = join(homedir(), '.openclaw', 'agents', 'main', 'agent');
76
+ const spawnAuthDir = join(spawnHome, 'agents', 'main', 'agent');
77
+ try {
78
+ const parentAuthFile = join(parentAuthDir, 'auth-profiles.json');
79
+ const { existsSync: exists } = await import('node:fs');
80
+ if (exists(parentAuthFile)) {
81
+ await mkdir(spawnAuthDir, { recursive: true });
82
+ const { copyFile: cp } = await import('node:fs/promises');
83
+ await cp(parentAuthFile, join(spawnAuthDir, 'auth-profiles.json'));
84
+ }
85
+ }
86
+ catch {
87
+ // Non-fatal — spawned agent may not be able to call model
88
+ }
89
+ // Patch dist if available (best-effort)
90
+ // Try known dist locations
91
+ const distCandidates = [
92
+ '/usr/lib/node_modules/openclaw/dist',
93
+ '/app/dist',
94
+ '/usr/local/lib/node_modules/openclaw/dist',
95
+ ];
96
+ for (const candidate of distCandidates) {
97
+ await patchOpenClawDist(candidate, resolvedModel);
98
+ }
99
+ await clearJitCache();
100
+ // Start openclaw gateway
101
+ const gatewayProcess = cpSpawn('openclaw', ['gateway', '--port', String(port), '--bind', 'loopback', '--allow-unconfigured', '--auth', 'token'], {
102
+ env: {
103
+ ...process.env,
104
+ OPENCLAW_GATEWAY_TOKEN: gatewayToken,
105
+ OPENCLAW_MODEL: resolvedModel,
106
+ OPENCLAW_NAME: options.name,
107
+ OPENCLAW_WORKSPACE_ID: workspaceId,
108
+ OPENCLAW_HOME: spawnHome,
109
+ },
110
+ cwd: workspacePath,
111
+ stdio: ['pipe', 'pipe', 'pipe'],
112
+ });
113
+ gatewayProcess.stderr?.on('data', (data) => {
114
+ process.stderr.write(`[spawn:${options.name}:gateway] ${data}`);
115
+ });
116
+ // Wait for gateway to be healthy. If it fails, kill the gateway.
117
+ try {
118
+ await waitForGateway(port, 30);
119
+ }
120
+ catch (err) {
121
+ gatewayProcess.kill('SIGTERM');
122
+ throw err;
123
+ }
124
+ // Use AgentRelay SDK to spawn the broker + bridge agent.
125
+ // This replaces shelling out to `agent-relay broker-spawn --from-env`.
126
+ const bridgePath = resolvePackageBridgePath();
127
+ let relay = null;
128
+ try {
129
+ relay = new AgentRelay({
130
+ brokerName: agentName,
131
+ channels,
132
+ cwd: workspacePath,
133
+ env: {
134
+ ...process.env,
135
+ GATEWAY_PORT: String(port),
136
+ OPENCLAW_GATEWAY_TOKEN: gatewayToken,
137
+ OPENCLAW_WORKSPACE_ID: workspaceId,
138
+ OPENCLAW_NAME: options.name,
139
+ OPENCLAW_ROLE: options.role ?? 'general',
140
+ OPENCLAW_MODEL: resolvedModel,
141
+ RELAY_API_KEY: options.relayApiKey,
142
+ RELAY_BASE_URL: options.relayBaseUrl || 'https://api.relaycast.dev',
143
+ BROKER_NO_REMOTE_SPAWN: '1',
144
+ },
145
+ });
146
+ await relay.spawnPty({
147
+ name: agentName,
148
+ cli: 'node',
149
+ args: [bridgePath],
150
+ channels,
151
+ task: options.systemPrompt
152
+ ? `${options.systemPrompt}\n\n${identityTask}`
153
+ : identityTask,
154
+ });
155
+ relay.onAgentExited = (agent) => {
156
+ process.stderr.write(`[spawn:${options.name}] Agent exited: ${agent.name} code=${agent.exitCode ?? 'none'}\n`);
157
+ };
158
+ }
159
+ catch (err) {
160
+ // If SDK broker spawn fails, clean up gateway and propagate
161
+ gatewayProcess.kill('SIGTERM');
162
+ if (relay) {
163
+ await relay.shutdown().catch(() => { });
164
+ }
165
+ throw new Error(`Failed to start broker for "${options.name}": ${err instanceof Error ? err.message : String(err)}`);
166
+ }
167
+ const handle = {
168
+ id: `proc-${options.name}-${port}`,
169
+ displayName: options.name,
170
+ agentName,
171
+ gatewayPort: port,
172
+ gatewayProcess,
173
+ relay,
174
+ destroy: async () => {
175
+ this.handles.delete(handle.id);
176
+ // Shutdown relay (broker + agent) first via SDK
177
+ if (relay) {
178
+ await relay.shutdown().catch(() => { });
179
+ }
180
+ // Then kill gateway
181
+ gatewayProcess.kill('SIGTERM');
182
+ await new Promise((r) => setTimeout(r, 2000));
183
+ if (!gatewayProcess.killed)
184
+ gatewayProcess.kill('SIGKILL');
185
+ },
186
+ };
187
+ this.handles.set(handle.id, handle);
188
+ return handle;
189
+ }
190
+ async destroy(id) {
191
+ const handle = this.handles.get(id);
192
+ if (handle) {
193
+ await handle.destroy();
194
+ }
195
+ }
196
+ async list() {
197
+ return Array.from(this.handles.values()).map(({ id, displayName, agentName, gatewayPort, destroy }) => ({
198
+ id,
199
+ displayName,
200
+ agentName,
201
+ gatewayPort,
202
+ destroy,
203
+ }));
204
+ }
205
+ }
206
+ /**
207
+ * Wait for the OpenClaw gateway to become healthy via the CLI health check.
208
+ */
209
+ async function waitForGateway(port, timeoutSeconds) {
210
+ for (let i = 0; i < timeoutSeconds; i++) {
211
+ try {
212
+ const result = cpSpawn('openclaw', ['health', '--port', String(port)], {
213
+ stdio: ['pipe', 'pipe', 'pipe'],
214
+ });
215
+ const code = await new Promise((resolve) => {
216
+ result.on('close', resolve);
217
+ result.on('error', () => resolve(1));
218
+ });
219
+ if (code === 0)
220
+ return;
221
+ }
222
+ catch {
223
+ // Not ready yet
224
+ }
225
+ await new Promise((r) => setTimeout(r, 1000));
226
+ }
227
+ throw new Error(`OpenClaw gateway on port ${port} failed to start after ${timeoutSeconds}s`);
228
+ }
229
+ /**
230
+ * Resolve the path to bridge.mjs bundled with this package.
231
+ */
232
+ function resolvePackageBridgePath() {
233
+ try {
234
+ const thisFile = fileURLToPath(import.meta.url);
235
+ return join(dirname(thisFile), '..', '..', 'bridge', 'bridge.mjs');
236
+ }
237
+ catch {
238
+ return join(process.cwd(), 'node_modules', '@agent-relay', 'openclaw', 'bridge', 'bridge.mjs');
239
+ }
240
+ }
241
+ //# sourceMappingURL=process.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"process.js","sourceRoot":"","sources":["../../src/spawn/process.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,42 @@
1
+ export interface SpawnOptions {
2
+ /** Display name for the new OpenClaw (e.g. "researcher"). */
3
+ name: string;
4
+ /** Relay API key for Relaycast messaging. */
5
+ relayApiKey: string;
6
+ /** Channels to auto-join. */
7
+ channels?: string[];
8
+ /** Agent role description. */
9
+ role?: string;
10
+ /** Model reference (e.g. "openai-codex/gpt-5.3-codex"). */
11
+ model?: string;
12
+ /** System prompt / task description. */
13
+ systemPrompt?: string;
14
+ /** Path to an existing workspace directory (for bind-mounting). */
15
+ workspacePath?: string;
16
+ /** Relay base URL (default: https://api.relaycast.dev). */
17
+ relayBaseUrl?: string;
18
+ /** Workspace ID for identity. */
19
+ workspaceId?: string;
20
+ }
21
+ export interface SpawnHandle {
22
+ /** Unique identifier for this spawn (container ID, process PID, etc). */
23
+ id: string;
24
+ /** The user-provided display name (e.g. "researcher"). Used for lookups. */
25
+ displayName: string;
26
+ /** Relay agent name assigned to this spawn (normalized: claw-<workspace>-<name>). */
27
+ agentName: string;
28
+ /** Gateway port this spawn is listening on. */
29
+ gatewayPort: number;
30
+ /** Destroy (stop + clean up) this spawn. */
31
+ destroy: () => Promise<void>;
32
+ }
33
+ /**
34
+ * Provider interface for spawning OpenClaw instances.
35
+ * Implementations handle the details of container vs process spawning.
36
+ */
37
+ export interface SpawnProvider {
38
+ spawn(options: SpawnOptions): Promise<SpawnHandle>;
39
+ destroy(id: string): Promise<void>;
40
+ list(): Promise<SpawnHandle[]>;
41
+ }
42
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/spawn/types.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,YAAY;IAC3B,6DAA6D;IAC7D,IAAI,EAAE,MAAM,CAAC;IACb,6CAA6C;IAC7C,WAAW,EAAE,MAAM,CAAC;IACpB,6BAA6B;IAC7B,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;IACpB,8BAA8B;IAC9B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,2DAA2D;IAC3D,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,wCAAwC;IACxC,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,mEAAmE;IACnE,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,2DAA2D;IAC3D,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,iCAAiC;IACjC,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,WAAW;IAC1B,yEAAyE;IACzE,EAAE,EAAE,MAAM,CAAC;IACX,4EAA4E;IAC5E,WAAW,EAAE,MAAM,CAAC;IACpB,qFAAqF;IACrF,SAAS,EAAE,MAAM,CAAC;IAClB,+CAA+C;IAC/C,WAAW,EAAE,MAAM,CAAC;IACpB,4CAA4C;IAC5C,OAAO,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;CAC9B;AAED;;;GAGG;AACH,MAAM,WAAW,aAAa;IAC5B,KAAK,CAAC,OAAO,EAAE,YAAY,GAAG,OAAO,CAAC,WAAW,CAAC,CAAC;IACnD,OAAO,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACnC,IAAI,IAAI,OAAO,CAAC,WAAW,EAAE,CAAC,CAAC;CAChC"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/spawn/types.ts"],"names":[],"mappings":""}
@@ -0,0 +1,37 @@
1
+ export interface GatewayConfig {
2
+ /** Relaycast workspace API key (rk_live_*). */
3
+ apiKey: string;
4
+ /** Name for this claw in the Relaycast workspace. */
5
+ clawName: string;
6
+ /** Relaycast API base URL (default: https://api.relaycast.dev). */
7
+ baseUrl: string;
8
+ /** Channels to auto-join on connect. */
9
+ channels: string[];
10
+ /** OpenClaw gateway token for authenticating with the local gateway API. */
11
+ openclawGatewayToken?: string;
12
+ /** OpenClaw gateway port (default: 18789). */
13
+ openclawGatewayPort?: number;
14
+ }
15
+ export interface InboundMessage {
16
+ /** Relaycast message ID. */
17
+ id: string;
18
+ /** Channel the message was posted to. */
19
+ channel: string;
20
+ /** Agent name of the sender. */
21
+ from: string;
22
+ /** Message body text. */
23
+ text: string;
24
+ /** ISO timestamp. */
25
+ timestamp: string;
26
+ /** Parent message ID when this is a thread reply. */
27
+ threadParentId?: string;
28
+ }
29
+ export interface DeliveryResult {
30
+ /** Whether delivery succeeded. */
31
+ ok: boolean;
32
+ /** Which method delivered: 'relay_sdk' | 'gateway_ws' | 'failed'. */
33
+ method: 'relay_sdk' | 'gateway_ws' | 'failed';
34
+ /** Error message if failed. */
35
+ error?: string;
36
+ }
37
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,aAAa;IAC5B,+CAA+C;IAC/C,MAAM,EAAE,MAAM,CAAC;IACf,qDAAqD;IACrD,QAAQ,EAAE,MAAM,CAAC;IACjB,mEAAmE;IACnE,OAAO,EAAE,MAAM,CAAC;IAChB,wCAAwC;IACxC,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,4EAA4E;IAC5E,oBAAoB,CAAC,EAAE,MAAM,CAAC;IAC9B,8CAA8C;IAC9C,mBAAmB,CAAC,EAAE,MAAM,CAAC;CAC9B;AAED,MAAM,WAAW,cAAc;IAC7B,4BAA4B;IAC5B,EAAE,EAAE,MAAM,CAAC;IACX,yCAAyC;IACzC,OAAO,EAAE,MAAM,CAAC;IAChB,gCAAgC;IAChC,IAAI,EAAE,MAAM,CAAC;IACb,yBAAyB;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,qBAAqB;IACrB,SAAS,EAAE,MAAM,CAAC;IAClB,qDAAqD;IACrD,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB;AAED,MAAM,WAAW,cAAc;IAC7B,kCAAkC;IAClC,EAAE,EAAE,OAAO,CAAC;IACZ,qEAAqE;IACrE,MAAM,EAAE,WAAW,GAAG,YAAY,GAAG,QAAQ,CAAC;IAC9C,+BAA+B;IAC/B,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":""}
@@ -0,0 +1,63 @@
1
+ {
2
+ "name": "@agent-relay/openclaw",
3
+ "version": "3.1.1",
4
+ "description": "Relaycast bridge for OpenClaw — messaging, identity, runtime setup, and local spawning",
5
+ "type": "module",
6
+ "main": "./dist/index.js",
7
+ "types": "./dist/index.d.ts",
8
+ "bin": {
9
+ "relay-openclaw": "./bin/relay-openclaw.mjs"
10
+ },
11
+ "exports": {
12
+ ".": {
13
+ "types": "./dist/index.d.ts",
14
+ "import": "./dist/index.js",
15
+ "default": "./dist/index.js"
16
+ }
17
+ },
18
+ "repository": {
19
+ "type": "git",
20
+ "url": "git+https://github.com/AgentWorkforce/relay.git",
21
+ "directory": "packages/openclaw"
22
+ },
23
+ "scripts": {
24
+ "build": "tsc",
25
+ "dev": "tsc --watch",
26
+ "test": "vitest run",
27
+ "test:watch": "vitest",
28
+ "prepack": "npm run build",
29
+ "postinstall": "node -e \"try{require('child_process').execSync('ldd --version 2>&1',{stdio:'pipe'})}catch{try{require('child_process').execSync('apk info gcompat 2>/dev/null',{stdio:'pipe'})}catch{console.warn('\\n\\u26a0\\ufe0f @agent-relay/openclaw: Alpine detected without gcompat. Spawning requires glibc.\\n Install with: apk add gcompat libstdc++\\n')}}\""
30
+ },
31
+ "dependencies": {
32
+ "@agent-relay/sdk": "3.1.1",
33
+ "@relaycast/sdk": "^0.4.0",
34
+ "ws": "^8.0.0"
35
+ },
36
+ "optionalDependencies": {
37
+ "dockerode": "^4.0.0"
38
+ },
39
+ "devDependencies": {
40
+ "@types/node": "^22.13.10",
41
+ "@types/ws": "^8.0.0",
42
+ "typescript": "^5.7.3",
43
+ "vitest": "^2.1.0"
44
+ },
45
+ "files": [
46
+ "dist/",
47
+ "bin/",
48
+ "bridge/",
49
+ "skill/",
50
+ "templates/",
51
+ "README.md"
52
+ ],
53
+ "keywords": [
54
+ "openclaw",
55
+ "relaycast",
56
+ "agent-relay",
57
+ "multi-agent",
58
+ "messaging",
59
+ "spawn",
60
+ "ai-agents"
61
+ ],
62
+ "license": "Apache-2.0"
63
+ }