agent-relay 3.0.2 → 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.
- package/README.md +8 -0
- package/bin/agent-relay-broker-linux-x64 +0 -0
- package/dist/index.cjs +273 -56
- package/dist/src/cli/commands/core.d.ts +2 -0
- package/dist/src/cli/commands/core.d.ts.map +1 -1
- package/dist/src/cli/commands/core.js +9 -2
- package/dist/src/cli/commands/core.js.map +1 -1
- package/dist/src/cli/lib/broker-lifecycle.d.ts.map +1 -1
- package/dist/src/cli/lib/broker-lifecycle.js +87 -28
- package/dist/src/cli/lib/broker-lifecycle.js.map +1 -1
- package/package.json +9 -9
- package/packages/acp-bridge/README.md +50 -67
- package/packages/acp-bridge/package.json +2 -2
- package/packages/config/package.json +1 -1
- package/packages/hooks/package.json +4 -4
- package/packages/memory/package.json +2 -2
- package/packages/openclaw/README.md +78 -0
- package/packages/openclaw/bin/relay-openclaw.mjs +2 -0
- package/packages/openclaw/bridge/bridge.mjs +305 -0
- package/packages/openclaw/dist/__tests__/gateway-threads.test.d.ts +2 -0
- package/packages/openclaw/dist/__tests__/gateway-threads.test.d.ts.map +1 -0
- package/packages/openclaw/dist/__tests__/gateway-threads.test.js +320 -0
- package/packages/openclaw/dist/__tests__/gateway-threads.test.js.map +1 -0
- package/packages/openclaw/dist/__tests__/naming.test.d.ts +2 -0
- package/packages/openclaw/dist/__tests__/naming.test.d.ts.map +1 -0
- package/packages/openclaw/dist/__tests__/naming.test.js +21 -0
- package/packages/openclaw/dist/__tests__/naming.test.js.map +1 -0
- package/packages/openclaw/dist/__tests__/spawn-manager.test.d.ts +2 -0
- package/packages/openclaw/dist/__tests__/spawn-manager.test.d.ts.map +1 -0
- package/packages/openclaw/dist/__tests__/spawn-manager.test.js +126 -0
- package/packages/openclaw/dist/__tests__/spawn-manager.test.js.map +1 -0
- package/packages/openclaw/dist/auth/converter.d.ts +28 -0
- package/packages/openclaw/dist/auth/converter.d.ts.map +1 -0
- package/packages/openclaw/dist/auth/converter.js +64 -0
- package/packages/openclaw/dist/auth/converter.js.map +1 -0
- package/packages/openclaw/dist/cli.d.ts +2 -0
- package/packages/openclaw/dist/cli.d.ts.map +1 -0
- package/packages/openclaw/dist/cli.js +230 -0
- package/packages/openclaw/dist/cli.js.map +1 -0
- package/packages/openclaw/dist/config.d.ts +27 -0
- package/packages/openclaw/dist/config.d.ts.map +1 -0
- package/packages/openclaw/dist/config.js +97 -0
- package/packages/openclaw/dist/config.js.map +1 -0
- package/packages/openclaw/dist/control.d.ts +22 -0
- package/packages/openclaw/dist/control.d.ts.map +1 -0
- package/packages/openclaw/dist/control.js +58 -0
- package/packages/openclaw/dist/control.js.map +1 -0
- package/packages/openclaw/dist/gateway.d.ts +71 -0
- package/packages/openclaw/dist/gateway.d.ts.map +1 -0
- package/packages/openclaw/dist/gateway.js +785 -0
- package/packages/openclaw/dist/gateway.js.map +1 -0
- package/packages/openclaw/dist/identity/contract.d.ts +11 -0
- package/packages/openclaw/dist/identity/contract.d.ts.map +1 -0
- package/packages/openclaw/dist/identity/contract.js +40 -0
- package/packages/openclaw/dist/identity/contract.js.map +1 -0
- package/packages/openclaw/dist/identity/files.d.ts +33 -0
- package/packages/openclaw/dist/identity/files.d.ts.map +1 -0
- package/packages/openclaw/dist/identity/files.js +145 -0
- package/packages/openclaw/dist/identity/files.js.map +1 -0
- package/packages/openclaw/dist/identity/model.d.ts +11 -0
- package/packages/openclaw/dist/identity/model.d.ts.map +1 -0
- package/packages/openclaw/dist/identity/model.js +28 -0
- package/packages/openclaw/dist/identity/model.js.map +1 -0
- package/packages/openclaw/dist/identity/naming.d.ts +5 -0
- package/packages/openclaw/dist/identity/naming.d.ts.map +1 -0
- package/packages/openclaw/dist/identity/naming.js +7 -0
- package/packages/openclaw/dist/identity/naming.js.map +1 -0
- package/packages/openclaw/dist/index.d.ts +20 -0
- package/packages/openclaw/dist/index.d.ts.map +1 -0
- package/packages/openclaw/dist/index.js +27 -0
- package/packages/openclaw/dist/index.js.map +1 -0
- package/packages/openclaw/dist/inject.d.ts +14 -0
- package/packages/openclaw/dist/inject.d.ts.map +1 -0
- package/packages/openclaw/dist/inject.js +66 -0
- package/packages/openclaw/dist/inject.js.map +1 -0
- package/packages/openclaw/dist/mcp/server.d.ts +8 -0
- package/packages/openclaw/dist/mcp/server.d.ts.map +1 -0
- package/packages/openclaw/dist/mcp/server.js +105 -0
- package/packages/openclaw/dist/mcp/server.js.map +1 -0
- package/packages/openclaw/dist/mcp/tools.d.ts +17 -0
- package/packages/openclaw/dist/mcp/tools.d.ts.map +1 -0
- package/packages/openclaw/dist/mcp/tools.js +145 -0
- package/packages/openclaw/dist/mcp/tools.js.map +1 -0
- package/packages/openclaw/dist/runtime/openclaw-config.d.ts +20 -0
- package/packages/openclaw/dist/runtime/openclaw-config.d.ts.map +1 -0
- package/packages/openclaw/dist/runtime/openclaw-config.js +50 -0
- package/packages/openclaw/dist/runtime/openclaw-config.js.map +1 -0
- package/packages/openclaw/dist/runtime/patch.d.ts +24 -0
- package/packages/openclaw/dist/runtime/patch.d.ts.map +1 -0
- package/packages/openclaw/dist/runtime/patch.js +92 -0
- package/packages/openclaw/dist/runtime/patch.js.map +1 -0
- package/packages/openclaw/dist/runtime/setup.d.ts +26 -0
- package/packages/openclaw/dist/runtime/setup.d.ts.map +1 -0
- package/packages/openclaw/dist/runtime/setup.js +58 -0
- package/packages/openclaw/dist/runtime/setup.js.map +1 -0
- package/packages/openclaw/dist/setup.d.ts +29 -0
- package/packages/openclaw/dist/setup.d.ts.map +1 -0
- package/packages/openclaw/dist/setup.js +300 -0
- package/packages/openclaw/dist/setup.js.map +1 -0
- package/packages/openclaw/dist/spawn/docker.d.ts +58 -0
- package/packages/openclaw/dist/spawn/docker.d.ts.map +1 -0
- package/packages/openclaw/dist/spawn/docker.js +222 -0
- package/packages/openclaw/dist/spawn/docker.js.map +1 -0
- package/packages/openclaw/dist/spawn/manager.d.ts +45 -0
- package/packages/openclaw/dist/spawn/manager.d.ts.map +1 -0
- package/packages/openclaw/dist/spawn/manager.js +140 -0
- package/packages/openclaw/dist/spawn/manager.js.map +1 -0
- package/packages/openclaw/dist/spawn/process.d.ts +16 -0
- package/packages/openclaw/dist/spawn/process.d.ts.map +1 -0
- package/packages/openclaw/dist/spawn/process.js +241 -0
- package/packages/openclaw/dist/spawn/process.js.map +1 -0
- package/packages/openclaw/dist/spawn/types.d.ts +42 -0
- package/packages/openclaw/dist/spawn/types.d.ts.map +1 -0
- package/packages/openclaw/dist/spawn/types.js +2 -0
- package/packages/openclaw/dist/spawn/types.js.map +1 -0
- package/packages/openclaw/dist/types.d.ts +37 -0
- package/packages/openclaw/dist/types.d.ts.map +1 -0
- package/packages/openclaw/dist/types.js +2 -0
- package/packages/openclaw/dist/types.js.map +1 -0
- package/packages/openclaw/package.json +63 -0
- package/packages/openclaw/skill/SKILL.md +194 -0
- package/packages/openclaw/src/__tests__/gateway-threads.test.ts +384 -0
- package/packages/openclaw/src/__tests__/naming.test.ts +24 -0
- package/packages/openclaw/src/__tests__/spawn-manager.test.ts +152 -0
- package/packages/openclaw/src/auth/converter.ts +90 -0
- package/packages/openclaw/src/cli.ts +269 -0
- package/packages/openclaw/src/config.ts +124 -0
- package/packages/openclaw/src/control.ts +100 -0
- package/packages/openclaw/src/gateway.ts +941 -0
- package/packages/openclaw/src/identity/contract.ts +44 -0
- package/packages/openclaw/src/identity/files.ts +198 -0
- package/packages/openclaw/src/identity/model.ts +27 -0
- package/packages/openclaw/src/identity/naming.ts +6 -0
- package/packages/openclaw/src/index.ts +59 -0
- package/packages/openclaw/src/inject.ts +77 -0
- package/packages/openclaw/src/mcp/server.ts +121 -0
- package/packages/openclaw/src/mcp/tools.ts +174 -0
- package/packages/openclaw/src/runtime/openclaw-config.ts +64 -0
- package/packages/openclaw/src/runtime/patch.ts +103 -0
- package/packages/openclaw/src/runtime/setup.ts +89 -0
- package/packages/openclaw/src/setup.ts +336 -0
- package/packages/openclaw/src/spawn/docker.ts +261 -0
- package/packages/openclaw/src/spawn/manager.ts +181 -0
- package/packages/openclaw/src/spawn/process.ts +272 -0
- package/packages/openclaw/src/spawn/types.ts +43 -0
- package/packages/openclaw/src/types.ts +38 -0
- package/packages/openclaw/templates/SOUL.md.template +34 -0
- package/packages/openclaw/tsconfig.json +12 -0
- package/packages/policy/package.json +2 -2
- package/packages/sdk/README.md +169 -64
- package/packages/sdk/dist/__tests__/contract-fixtures.test.js +76 -9
- package/packages/sdk/dist/__tests__/contract-fixtures.test.js.map +1 -1
- package/packages/sdk/dist/__tests__/integration.test.js +5 -4
- package/packages/sdk/dist/__tests__/integration.test.js.map +1 -1
- package/packages/sdk/dist/client.d.ts +34 -3
- package/packages/sdk/dist/client.d.ts.map +1 -1
- package/packages/sdk/dist/client.js +120 -10
- package/packages/sdk/dist/client.js.map +1 -1
- package/packages/sdk/dist/protocol.d.ts +7 -1
- package/packages/sdk/dist/protocol.d.ts.map +1 -1
- package/packages/sdk/dist/relay.d.ts +47 -11
- package/packages/sdk/dist/relay.d.ts.map +1 -1
- package/packages/sdk/dist/relay.js +114 -23
- package/packages/sdk/dist/relay.js.map +1 -1
- package/packages/sdk/dist/workflows/runner.d.ts.map +1 -1
- package/packages/sdk/dist/workflows/runner.js +71 -36
- package/packages/sdk/dist/workflows/runner.js.map +1 -1
- package/packages/sdk/dist/workflows/types.d.ts +1 -1
- package/packages/sdk/dist/workflows/types.d.ts.map +1 -1
- package/packages/sdk/package.json +2 -2
- package/packages/sdk/src/__tests__/contract-fixtures.test.ts +88 -9
- package/packages/sdk/src/__tests__/error-scenarios.test.ts +1 -1
- package/packages/sdk/src/__tests__/idle-nudge.test.ts +205 -257
- package/packages/sdk/src/__tests__/integration.test.ts +5 -4
- package/packages/sdk/src/__tests__/orchestration-upgrades.test.ts +277 -13
- package/packages/sdk/src/__tests__/swarm-coordinator.test.ts +1 -0
- package/packages/sdk/src/__tests__/workflow-runner.test.ts +67 -7
- package/packages/sdk/src/__tests__/workflow-trajectory.test.ts +4 -5
- package/packages/sdk/src/client.ts +171 -14
- package/packages/sdk/src/examples/workflows/runner-idle-refactor.yaml +306 -0
- package/packages/sdk/src/protocol.ts +7 -2
- package/packages/sdk/src/relay.ts +196 -34
- package/packages/sdk/src/workflows/runner.ts +73 -42
- package/packages/sdk/src/workflows/schema.json +1 -1
- package/packages/sdk/src/workflows/types.ts +1 -1
- package/packages/sdk/vitest.config.ts +1 -0
- package/packages/sdk-py/README.md +89 -102
- package/packages/sdk-py/agent_relay/__init__.py +16 -19
- package/packages/sdk-py/pyproject.toml +5 -1
- package/packages/sdk-py/src/agent_relay/__init__.py +35 -1
- package/packages/sdk-py/src/agent_relay/client.py +776 -0
- package/packages/sdk-py/src/agent_relay/models.py +27 -0
- package/packages/sdk-py/src/agent_relay/protocol.py +114 -0
- package/packages/sdk-py/src/agent_relay/relay.py +860 -0
- package/packages/sdk-py/tests/test_relay_lifecycle_hooks.py +250 -0
- package/packages/telemetry/package.json +1 -1
- package/packages/trajectory/package.json +2 -2
- package/packages/user-directory/package.json +2 -2
- package/packages/utils/package.json +2 -2
- package/bin/agent-relay-broker-darwin-arm64 +0 -0
- package/bin/agent-relay-broker-darwin-x64 +0 -0
- package/bin/agent-relay-broker-linux-arm64 +0 -0
- package/packages/sdk/.trajectories/active/traj_1771875803391_84ca57b2.json +0 -50
- package/packages/sdk/.trajectories/active/traj_1771891934534_06504121.json +0 -50
- package/packages/sdk/.trajectories/active/traj_1771891957929_211afc4e.json +0 -50
- package/packages/sdk/.trajectories/active/traj_1771891982509_38c84638.json +0 -50
- package/packages/sdk/.trajectories/completed/traj_1771875803188_cd6d181c.json +0 -80
- package/packages/sdk/.trajectories/completed/traj_1771875803204_f2aeb8c8.json +0 -80
- package/packages/sdk/.trajectories/completed/traj_1771875803210_d65f3f1a.json +0 -80
- package/packages/sdk/.trajectories/completed/traj_1771875803218_e454a25d.json +0 -80
- package/packages/sdk/.trajectories/completed/traj_1771875803223_d7a64815.json +0 -80
- package/packages/sdk/.trajectories/completed/traj_1771875803227_7e56da5b.json +0 -80
- package/packages/sdk/.trajectories/completed/traj_1771875803235_4fbf93b4.json +0 -80
- package/packages/sdk/.trajectories/completed/traj_1771875803243_47931c71.json +0 -80
- package/packages/sdk/.trajectories/completed/traj_1771875803258_3816f3fe.json +0 -80
- package/packages/sdk/.trajectories/completed/traj_1771875803268_8061140e.json +0 -80
- package/packages/sdk/.trajectories/completed/traj_1771875803326_ae6f9c78.json +0 -80
- package/packages/sdk/.trajectories/completed/traj_1771875808396_cbde0a6c.json +0 -91
- package/packages/sdk/.trajectories/completed/traj_1771875812026_aa2442bb.json +0 -91
- package/packages/sdk/.trajectories/completed/traj_1771875815431_c2c656c5.json +0 -91
- package/packages/sdk/.trajectories/completed/traj_1771875818645_3a4dbf02.json +0 -91
- package/packages/sdk/.trajectories/completed/traj_1771891934403_24923c03.json +0 -80
- package/packages/sdk/.trajectories/completed/traj_1771891934421_dca16e24.json +0 -80
- package/packages/sdk/.trajectories/completed/traj_1771891934430_057706f7.json +0 -80
- package/packages/sdk/.trajectories/completed/traj_1771891934442_faf97382.json +0 -80
- package/packages/sdk/.trajectories/completed/traj_1771891934454_5542ecd5.json +0 -80
- package/packages/sdk/.trajectories/completed/traj_1771891934464_12202a08.json +0 -80
- package/packages/sdk/.trajectories/completed/traj_1771891934487_94378275.json +0 -80
- package/packages/sdk/.trajectories/completed/traj_1771891934503_ca728c13.json +0 -80
- package/packages/sdk/.trajectories/completed/traj_1771891934519_100af69a.json +0 -80
- package/packages/sdk/.trajectories/completed/traj_1771891934536_62ad39d9.json +0 -80
- package/packages/sdk/.trajectories/completed/traj_1771891934553_d6798a52.json +0 -80
- package/packages/sdk/.trajectories/completed/traj_1771891939537_541c8096.json +0 -91
- package/packages/sdk/.trajectories/completed/traj_1771891942985_36ab9a4d.json +0 -91
- package/packages/sdk/.trajectories/completed/traj_1771891946453_e8a6e05f.json +0 -91
- package/packages/sdk/.trajectories/completed/traj_1771891949838_5de0de84.json +0 -91
- package/packages/sdk/.trajectories/completed/traj_1771891957807_0ecfb4f4.json +0 -80
- package/packages/sdk/.trajectories/completed/traj_1771891957827_c4539239.json +0 -80
- package/packages/sdk/.trajectories/completed/traj_1771891957836_91168b48.json +0 -80
- package/packages/sdk/.trajectories/completed/traj_1771891957848_8c5cad0b.json +0 -80
- package/packages/sdk/.trajectories/completed/traj_1771891957857_0986b293.json +0 -80
- package/packages/sdk/.trajectories/completed/traj_1771891957872_8a3113af.json +0 -80
- package/packages/sdk/.trajectories/completed/traj_1771891957884_0bb85208.json +0 -80
- package/packages/sdk/.trajectories/completed/traj_1771891957892_86c75e2e.json +0 -80
- package/packages/sdk/.trajectories/completed/traj_1771891957907_98ca0e6f.json +0 -80
- package/packages/sdk/.trajectories/completed/traj_1771891957918_d9091231.json +0 -80
- package/packages/sdk/.trajectories/completed/traj_1771891957931_dcaf77ed.json +0 -80
- package/packages/sdk/.trajectories/completed/traj_1771891962931_eb1fdee2.json +0 -91
- package/packages/sdk/.trajectories/completed/traj_1771891966262_9061a93f.json +0 -91
- package/packages/sdk/.trajectories/completed/traj_1771891969915_1adaba19.json +0 -91
- package/packages/sdk/.trajectories/completed/traj_1771891973588_f08b79e9.json +0 -91
- package/packages/sdk/.trajectories/completed/traj_1771891982421_f1985bce.json +0 -80
- package/packages/sdk/.trajectories/completed/traj_1771891982432_e7a84163.json +0 -80
- package/packages/sdk/.trajectories/completed/traj_1771891982447_369b842a.json +0 -80
- package/packages/sdk/.trajectories/completed/traj_1771891982469_5fc45199.json +0 -80
- package/packages/sdk/.trajectories/completed/traj_1771891982495_454c7cb3.json +0 -80
- package/packages/sdk/.trajectories/completed/traj_1771891982514_08098e03.json +0 -80
- package/packages/sdk/.trajectories/completed/traj_1771891982526_b351d778.json +0 -80
- package/packages/sdk/.trajectories/completed/traj_1771891982533_fa542d83.json +0 -80
- package/packages/sdk/.trajectories/completed/traj_1771891982540_18ab24dc.json +0 -80
- package/packages/sdk/.trajectories/completed/traj_1771891982544_5b4fa163.json +0 -80
- package/packages/sdk/.trajectories/completed/traj_1771891982548_c13f089a.json +0 -80
- package/packages/sdk/.trajectories/completed/traj_1771891987510_23f6da1f.json +0 -91
- package/packages/sdk/.trajectories/completed/traj_1771891991466_912c2e04.json +0 -91
- package/packages/sdk/.trajectories/completed/traj_1771891994891_60604be2.json +0 -91
- package/packages/sdk/.trajectories/completed/traj_1771891998370_cfaf9b8b.json +0 -91
|
@@ -0,0 +1,300 @@
|
|
|
1
|
+
import { mkdir, writeFile, copyFile } from 'node:fs/promises';
|
|
2
|
+
import { join, dirname } from 'node:path';
|
|
3
|
+
import { existsSync } from 'node:fs';
|
|
4
|
+
import { hostname } from 'node:os';
|
|
5
|
+
import { fileURLToPath } from 'node:url';
|
|
6
|
+
import { spawn as spawnProcess, execFileSync } from 'node:child_process';
|
|
7
|
+
import { detectOpenClaw, saveGatewayConfig } from './config.js';
|
|
8
|
+
/**
|
|
9
|
+
* Install the Relaycast bridge into an OpenClaw workspace.
|
|
10
|
+
*
|
|
11
|
+
* 1. Detect OpenClaw installation
|
|
12
|
+
* 2. Create/join workspace via Relaycast API (if no key provided)
|
|
13
|
+
* 3. Install SKILL.md
|
|
14
|
+
* 4. Write .env config
|
|
15
|
+
* 5. Configure MCP server in openclaw.json
|
|
16
|
+
* 6. Print success summary
|
|
17
|
+
*/
|
|
18
|
+
export async function setup(options) {
|
|
19
|
+
const detection = await detectOpenClaw();
|
|
20
|
+
const clawName = options.clawName ?? hostname() ?? 'my-claw';
|
|
21
|
+
const baseUrl = options.baseUrl ?? 'https://api.relaycast.dev';
|
|
22
|
+
const channels = options.channels ?? ['general'];
|
|
23
|
+
if (!detection.installed) {
|
|
24
|
+
// Auto-create ~/.openclaw/ if OpenClaw binary is available but the config dir
|
|
25
|
+
// doesn't exist yet (common in Docker images before onboarding).
|
|
26
|
+
try {
|
|
27
|
+
await mkdir(detection.homeDir, { recursive: true });
|
|
28
|
+
await mkdir(join(detection.homeDir, 'workspace'), { recursive: true });
|
|
29
|
+
// Write a minimal openclaw.json so MCP servers can be registered
|
|
30
|
+
const configPath = join(detection.homeDir, 'openclaw.json');
|
|
31
|
+
if (!existsSync(configPath)) {
|
|
32
|
+
await writeFile(configPath, JSON.stringify({ mcpServers: {} }, null, 2) + '\n', 'utf-8');
|
|
33
|
+
}
|
|
34
|
+
// Re-detect after creating
|
|
35
|
+
const redetection = await detectOpenClaw();
|
|
36
|
+
Object.assign(detection, redetection);
|
|
37
|
+
}
|
|
38
|
+
catch {
|
|
39
|
+
return {
|
|
40
|
+
ok: false,
|
|
41
|
+
apiKey: '',
|
|
42
|
+
clawName,
|
|
43
|
+
skillDir: '',
|
|
44
|
+
message: 'OpenClaw not found. Please install OpenClaw first (expected ~/.openclaw/ directory).',
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
// Enable the OpenResponses HTTP API so the inbound gateway can inject
|
|
49
|
+
// messages via POST /v1/responses on the local OpenClaw gateway.
|
|
50
|
+
try {
|
|
51
|
+
execFileSync('openclaw', [
|
|
52
|
+
'config', 'set',
|
|
53
|
+
'gateway.http.endpoints.responses.enabled', 'true',
|
|
54
|
+
], { stdio: 'pipe' });
|
|
55
|
+
}
|
|
56
|
+
catch {
|
|
57
|
+
console.warn('Could not enable OpenResponses API (non-fatal). Enable manually:');
|
|
58
|
+
console.warn(' openclaw config set gateway.http.endpoints.responses.enabled true');
|
|
59
|
+
}
|
|
60
|
+
// Resolve API key: use provided key or create a new workspace
|
|
61
|
+
let apiKey = options.apiKey;
|
|
62
|
+
if (!apiKey) {
|
|
63
|
+
try {
|
|
64
|
+
const res = await fetch(`${baseUrl}/v1/workspaces`, {
|
|
65
|
+
method: 'POST',
|
|
66
|
+
headers: { 'Content-Type': 'application/json' },
|
|
67
|
+
body: JSON.stringify({ name: `${clawName}-workspace` }),
|
|
68
|
+
});
|
|
69
|
+
if (res.status === 409) {
|
|
70
|
+
// Workspace already exists — look up its API key
|
|
71
|
+
const lookupRes = await fetch(`${baseUrl}/v1/workspaces/by-name/${encodeURIComponent(`${clawName}-workspace`)}`, {
|
|
72
|
+
headers: { 'Content-Type': 'application/json' },
|
|
73
|
+
});
|
|
74
|
+
if (lookupRes.ok) {
|
|
75
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
76
|
+
const lookupBody = (await lookupRes.json());
|
|
77
|
+
apiKey = lookupBody.apiKey ?? lookupBody.api_key ?? lookupBody.data?.apiKey ?? lookupBody.data?.api_key;
|
|
78
|
+
}
|
|
79
|
+
if (!apiKey) {
|
|
80
|
+
return {
|
|
81
|
+
ok: false,
|
|
82
|
+
apiKey: '',
|
|
83
|
+
clawName,
|
|
84
|
+
skillDir: '',
|
|
85
|
+
message: `Workspace "${clawName}-workspace" already exists. Pass the workspace key: @agent-relay/openclaw setup <key> --name ${clawName}`,
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
else if (!res.ok) {
|
|
90
|
+
const body = await res.text();
|
|
91
|
+
return {
|
|
92
|
+
ok: false,
|
|
93
|
+
apiKey: '',
|
|
94
|
+
clawName,
|
|
95
|
+
skillDir: '',
|
|
96
|
+
message: `Failed to create workspace: ${res.status} ${body}`,
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
else {
|
|
100
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
101
|
+
const successBody = (await res.json());
|
|
102
|
+
apiKey = successBody.apiKey ?? successBody.api_key ?? successBody.data?.apiKey ?? successBody.data?.api_key;
|
|
103
|
+
}
|
|
104
|
+
if (!apiKey) {
|
|
105
|
+
return {
|
|
106
|
+
ok: false,
|
|
107
|
+
apiKey: '',
|
|
108
|
+
clawName,
|
|
109
|
+
skillDir: '',
|
|
110
|
+
message: 'Workspace created but no API key returned.',
|
|
111
|
+
};
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
catch (err) {
|
|
115
|
+
return {
|
|
116
|
+
ok: false,
|
|
117
|
+
apiKey: '',
|
|
118
|
+
clawName,
|
|
119
|
+
skillDir: '',
|
|
120
|
+
message: `Failed to create workspace: ${err instanceof Error ? err.message : String(err)}`,
|
|
121
|
+
};
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
// Agent registration is done after mcporter is configured (see below),
|
|
125
|
+
// since the register tool is accessed via mcporter call relaycast.register.
|
|
126
|
+
// Install SKILL.md
|
|
127
|
+
const skillDir = join(detection.workspaceDir, 'relaycast');
|
|
128
|
+
await mkdir(skillDir, { recursive: true });
|
|
129
|
+
const skillSrc = resolveSkillPath();
|
|
130
|
+
if (existsSync(skillSrc)) {
|
|
131
|
+
await copyFile(skillSrc, join(skillDir, 'SKILL.md'));
|
|
132
|
+
}
|
|
133
|
+
else {
|
|
134
|
+
// Write a minimal SKILL.md inline if the bundled one isn't found
|
|
135
|
+
await writeFile(join(skillDir, 'SKILL.md'), FALLBACK_SKILL_MD, 'utf-8');
|
|
136
|
+
}
|
|
137
|
+
// Save gateway config (.env)
|
|
138
|
+
const gatewayConfig = {
|
|
139
|
+
apiKey,
|
|
140
|
+
clawName,
|
|
141
|
+
baseUrl,
|
|
142
|
+
channels,
|
|
143
|
+
};
|
|
144
|
+
await saveGatewayConfig(gatewayConfig);
|
|
145
|
+
// Register MCP servers via mcporter
|
|
146
|
+
let mcpConfigured = false;
|
|
147
|
+
{
|
|
148
|
+
const envArgs = [
|
|
149
|
+
'--env', `RELAY_API_KEY=${apiKey}`,
|
|
150
|
+
...(baseUrl !== 'https://api.relaycast.dev'
|
|
151
|
+
? ['--env', `RELAY_BASE_URL=${baseUrl}`]
|
|
152
|
+
: []),
|
|
153
|
+
];
|
|
154
|
+
try {
|
|
155
|
+
// Register relaycast messaging MCP server
|
|
156
|
+
execFileSync('mcporter', [
|
|
157
|
+
'config', 'add', 'relaycast',
|
|
158
|
+
'--command', 'npx',
|
|
159
|
+
'--arg', '@relaycast/mcp',
|
|
160
|
+
...envArgs,
|
|
161
|
+
'--scope', 'home',
|
|
162
|
+
'--description', 'Relaycast messaging MCP server',
|
|
163
|
+
], { stdio: 'pipe' });
|
|
164
|
+
// Register openclaw-spawner MCP server
|
|
165
|
+
execFileSync('mcporter', [
|
|
166
|
+
'config', 'add', 'openclaw-spawner',
|
|
167
|
+
'--command', 'npx',
|
|
168
|
+
'--arg', '@agent-relay/openclaw',
|
|
169
|
+
'--arg', 'mcp-server',
|
|
170
|
+
...envArgs,
|
|
171
|
+
'--scope', 'home',
|
|
172
|
+
'--description', 'OpenClaw spawner MCP server',
|
|
173
|
+
], { stdio: 'pipe' });
|
|
174
|
+
mcpConfigured = true;
|
|
175
|
+
// Register this claw as an agent via mcporter and persist the agent token
|
|
176
|
+
try {
|
|
177
|
+
const registerOutput = execFileSync('mcporter', [
|
|
178
|
+
'call', 'relaycast.register',
|
|
179
|
+
'name=' + clawName,
|
|
180
|
+
'type=agent',
|
|
181
|
+
], { stdio: 'pipe', encoding: 'utf-8' });
|
|
182
|
+
// Parse the agent token from the register output
|
|
183
|
+
let agentToken;
|
|
184
|
+
try {
|
|
185
|
+
const parsed = JSON.parse(registerOutput);
|
|
186
|
+
agentToken = parsed.token ?? parsed.agentToken ?? parsed.agent_token;
|
|
187
|
+
}
|
|
188
|
+
catch {
|
|
189
|
+
// Try to find token in raw output
|
|
190
|
+
const tokenMatch = registerOutput.match(/"token"\s*:\s*"([^"]+)"/);
|
|
191
|
+
if (tokenMatch)
|
|
192
|
+
agentToken = tokenMatch[1];
|
|
193
|
+
}
|
|
194
|
+
if (agentToken) {
|
|
195
|
+
// Reconfigure mcporter with the agent token so subsequent calls are authenticated
|
|
196
|
+
try {
|
|
197
|
+
execFileSync('mcporter', ['config', 'remove', 'relaycast'], { stdio: 'pipe' });
|
|
198
|
+
}
|
|
199
|
+
catch { /* may not exist */ }
|
|
200
|
+
execFileSync('mcporter', [
|
|
201
|
+
'config', 'add', 'relaycast',
|
|
202
|
+
'--command', 'npx',
|
|
203
|
+
'--arg', '@relaycast/mcp',
|
|
204
|
+
...envArgs,
|
|
205
|
+
'--env', `RELAY_AGENT_TOKEN=${agentToken}`,
|
|
206
|
+
'--scope', 'home',
|
|
207
|
+
'--description', 'Relaycast messaging MCP server',
|
|
208
|
+
], { stdio: 'pipe' });
|
|
209
|
+
console.log(`Agent "${clawName}" registered with token.`);
|
|
210
|
+
}
|
|
211
|
+
else {
|
|
212
|
+
console.warn('Agent registered but no token found in response.');
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
catch (regErr) {
|
|
216
|
+
console.warn(`Agent registration via mcporter failed (non-fatal): ${regErr instanceof Error ? regErr.message : String(regErr)}`);
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
catch (err) {
|
|
220
|
+
// mcporter not installed — non-fatal, print manual instructions
|
|
221
|
+
console.warn('mcporter not found. Install MCP servers manually:');
|
|
222
|
+
console.warn(` mcporter config add relaycast --command npx --arg @relaycast/mcp --env RELAY_API_KEY=${apiKey} --scope home`);
|
|
223
|
+
console.warn(` mcporter config add openclaw-spawner --command npx --arg @agent-relay/openclaw --arg mcp-server --env RELAY_API_KEY=${apiKey} --scope home`);
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
// Auto-start the inbound gateway in the background
|
|
227
|
+
let gatewayStarted = false;
|
|
228
|
+
try {
|
|
229
|
+
const child = spawnProcess('npx', ['@agent-relay/openclaw', 'gateway'], {
|
|
230
|
+
stdio: 'ignore',
|
|
231
|
+
detached: true,
|
|
232
|
+
env: { ...process.env, RELAY_API_KEY: apiKey, RELAY_CLAW_NAME: clawName, RELAY_BASE_URL: baseUrl },
|
|
233
|
+
});
|
|
234
|
+
child.unref();
|
|
235
|
+
gatewayStarted = true;
|
|
236
|
+
}
|
|
237
|
+
catch {
|
|
238
|
+
// Non-fatal — user can start manually
|
|
239
|
+
}
|
|
240
|
+
const parts = [
|
|
241
|
+
`Relaycast bridge installed at ${skillDir}`,
|
|
242
|
+
mcpConfigured ? 'MCP server configured in openclaw.json.' : '',
|
|
243
|
+
`Claw name: ${clawName}`,
|
|
244
|
+
`Channels: ${channels.join(', ')}`,
|
|
245
|
+
gatewayStarted
|
|
246
|
+
? 'Inbound gateway started in background.'
|
|
247
|
+
: 'Start the inbound gateway manually:\n relay-openclaw gateway',
|
|
248
|
+
].filter(Boolean);
|
|
249
|
+
return {
|
|
250
|
+
ok: true,
|
|
251
|
+
apiKey,
|
|
252
|
+
clawName,
|
|
253
|
+
skillDir,
|
|
254
|
+
message: parts.join('\n'),
|
|
255
|
+
};
|
|
256
|
+
}
|
|
257
|
+
/** Resolve the path to the bundled SKILL.md. */
|
|
258
|
+
function resolveSkillPath() {
|
|
259
|
+
try {
|
|
260
|
+
const thisDir = dirname(fileURLToPath(import.meta.url));
|
|
261
|
+
return join(thisDir, '..', 'skill', 'SKILL.md');
|
|
262
|
+
}
|
|
263
|
+
catch {
|
|
264
|
+
return join(process.cwd(), 'skill', 'SKILL.md');
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
const FALLBACK_SKILL_MD = `# Relaycast Bridge
|
|
268
|
+
|
|
269
|
+
Structured messaging for multi-claw communication. Provides channels, threads,
|
|
270
|
+
DMs, reactions, search, and persistent message history across OpenClaw instances.
|
|
271
|
+
|
|
272
|
+
## Environment
|
|
273
|
+
|
|
274
|
+
- \`RELAY_API_KEY\` — Your Relaycast workspace key (required)
|
|
275
|
+
- \`RELAY_CLAW_NAME\` — This claw's agent name in Relaycast (required)
|
|
276
|
+
- \`RELAY_BASE_URL\` — API endpoint (default: https://api.relaycast.dev)
|
|
277
|
+
|
|
278
|
+
## Setup
|
|
279
|
+
|
|
280
|
+
\`\`\`bash
|
|
281
|
+
relay-openclaw setup [YOUR_WORKSPACE_KEY]
|
|
282
|
+
\`\`\`
|
|
283
|
+
|
|
284
|
+
## MCP Tools
|
|
285
|
+
|
|
286
|
+
Once installed, use the Relaycast MCP tools:
|
|
287
|
+
- \`post_message\` — Send to a channel
|
|
288
|
+
- \`send_dm\` — Direct message another agent
|
|
289
|
+
- \`reply_to_thread\` — Reply in a thread
|
|
290
|
+
- \`check_inbox\` — See unread messages
|
|
291
|
+
|
|
292
|
+
## Commands
|
|
293
|
+
|
|
294
|
+
\`\`\`bash
|
|
295
|
+
relay-openclaw setup [key] # Install & configure
|
|
296
|
+
relay-openclaw gateway # Start inbound gateway
|
|
297
|
+
relay-openclaw status # Check connection
|
|
298
|
+
\`\`\`
|
|
299
|
+
`;
|
|
300
|
+
//# sourceMappingURL=setup.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"setup.js","sourceRoot":"","sources":["../src/setup.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import type { SpawnProvider, SpawnOptions, SpawnHandle } from './types.js';
|
|
2
|
+
export interface DockerSpawnProviderOptions {
|
|
3
|
+
/** Docker image to use. Default: 'openclaw:local'. */
|
|
4
|
+
image?: string;
|
|
5
|
+
/** Fallback image if primary not found. Default: 'clawrunner-sandbox:latest'. */
|
|
6
|
+
imageFallback?: string;
|
|
7
|
+
/** Docker network mode. Default: 'bridge'. */
|
|
8
|
+
networkMode?: string;
|
|
9
|
+
/** Docker socket path. Default: '/var/run/docker.sock'. */
|
|
10
|
+
socketPath?: string;
|
|
11
|
+
/** Path to host codex auth.json. Default: ~/.codex/auth.json. */
|
|
12
|
+
codexAuthFile?: string;
|
|
13
|
+
/** Path to host codex config.toml. Default: ~/.codex/config.toml. */
|
|
14
|
+
codexConfigFile?: string;
|
|
15
|
+
/** Container home dir. Default: '/home/node'. */
|
|
16
|
+
containerHome?: string;
|
|
17
|
+
/**
|
|
18
|
+
* Custom container command. If set, overrides the default entrypoint.
|
|
19
|
+
* Use this for ClawRunner-managed images that have /opt/clawrunner/start-claw.sh.
|
|
20
|
+
* Default: uses @agent-relay/openclaw runtime-setup + openclaw gateway + agent-relay broker-spawn.
|
|
21
|
+
*/
|
|
22
|
+
containerCmd?: string[];
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Spawn OpenClaw instances as Docker containers.
|
|
26
|
+
* Requires `dockerode` as an optional peer dependency — dynamically imported at runtime.
|
|
27
|
+
*
|
|
28
|
+
* By default, the container runs:
|
|
29
|
+
* 1. `npx @agent-relay/openclaw runtime-setup` — auth conversion, config, identity files, dist patching
|
|
30
|
+
* 2. `openclaw gateway` in background
|
|
31
|
+
* 3. `agent-relay broker-spawn --from-env` as PID 1
|
|
32
|
+
*
|
|
33
|
+
* For ClawRunner-managed images, set containerCmd to ['/opt/clawrunner/start-claw.sh'].
|
|
34
|
+
*/
|
|
35
|
+
export declare class DockerSpawnProvider implements SpawnProvider {
|
|
36
|
+
private docker;
|
|
37
|
+
private readonly image;
|
|
38
|
+
private readonly imageFallback;
|
|
39
|
+
private readonly networkMode;
|
|
40
|
+
private readonly socketPath;
|
|
41
|
+
private readonly codexAuthFile;
|
|
42
|
+
private readonly codexConfigFile;
|
|
43
|
+
private readonly containerHome;
|
|
44
|
+
private readonly containerCmd;
|
|
45
|
+
private readonly handles;
|
|
46
|
+
constructor(options?: DockerSpawnProviderOptions);
|
|
47
|
+
private getDocker;
|
|
48
|
+
/**
|
|
49
|
+
* Build the default container entrypoint script.
|
|
50
|
+
* This script works with any vanilla OpenClaw image that has `openclaw` and `node` on PATH.
|
|
51
|
+
* It runs runtime-setup via the package CLI, starts the gateway, then hands off to broker-spawn.
|
|
52
|
+
*/
|
|
53
|
+
private buildEntrypointScript;
|
|
54
|
+
spawn(options: SpawnOptions): Promise<SpawnHandle>;
|
|
55
|
+
destroy(id: string): Promise<void>;
|
|
56
|
+
list(): Promise<SpawnHandle[]>;
|
|
57
|
+
}
|
|
58
|
+
//# sourceMappingURL=docker.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"docker.d.ts","sourceRoot":"","sources":["../../src/spawn/docker.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,aAAa,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AA0B3E,MAAM,WAAW,0BAA0B;IACzC,sDAAsD;IACtD,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,iFAAiF;IACjF,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,8CAA8C;IAC9C,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,2DAA2D;IAC3D,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,iEAAiE;IACjE,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,qEAAqE;IACrE,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,iDAAiD;IACjD,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB;;;;OAIG;IACH,YAAY,CAAC,EAAE,MAAM,EAAE,CAAC;CACzB;AAED;;;;;;;;;;GAUG;AACH,qBAAa,mBAAoB,YAAW,aAAa;IAEvD,OAAO,CAAC,MAAM,CAAa;IAC3B,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAS;IAC/B,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAS;IACvC,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAS;IACrC,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAS;IACpC,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAS;IACvC,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAS;IACzC,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAS;IACvC,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAkB;IAC/C,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAkC;gBAE9C,OAAO,GAAE,0BAA+B;YActC,SAAS;IAevB;;;;OAIG;IACH,OAAO,CAAC,qBAAqB;IAoCvB,KAAK,CAAC,OAAO,EAAE,YAAY,GAAG,OAAO,CAAC,WAAW,CAAC;IAiGlD,OAAO,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAYlC,IAAI,IAAI,OAAO,CAAC,WAAW,EAAE,CAAC;CAGrC"}
|
|
@@ -0,0 +1,222 @@
|
|
|
1
|
+
import { access } from 'node:fs/promises';
|
|
2
|
+
import { join } from 'node:path';
|
|
3
|
+
import { homedir } from 'node:os';
|
|
4
|
+
import { randomUUID } from 'node:crypto';
|
|
5
|
+
import { normalizeModelRef } from '../identity/model.js';
|
|
6
|
+
import { buildIdentityTask } from '../identity/contract.js';
|
|
7
|
+
import { buildAgentName } from '../identity/naming.js';
|
|
8
|
+
import { convertCodexAuth } from '../auth/converter.js';
|
|
9
|
+
async function pathExists(targetPath) {
|
|
10
|
+
try {
|
|
11
|
+
await access(targetPath);
|
|
12
|
+
return true;
|
|
13
|
+
}
|
|
14
|
+
catch {
|
|
15
|
+
return false;
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
function expandHomeDir(input) {
|
|
19
|
+
if (input === '~')
|
|
20
|
+
return homedir();
|
|
21
|
+
if (input.startsWith('~/'))
|
|
22
|
+
return join(homedir(), input.slice(2));
|
|
23
|
+
return input;
|
|
24
|
+
}
|
|
25
|
+
function sanitizeContainerSegment(value) {
|
|
26
|
+
const normalized = value.trim().toLowerCase().replace(/[^a-z0-9_.-]+/g, '-');
|
|
27
|
+
return normalized.replace(/^-+|-+$/g, '') || 'claw';
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Spawn OpenClaw instances as Docker containers.
|
|
31
|
+
* Requires `dockerode` as an optional peer dependency — dynamically imported at runtime.
|
|
32
|
+
*
|
|
33
|
+
* By default, the container runs:
|
|
34
|
+
* 1. `npx @agent-relay/openclaw runtime-setup` — auth conversion, config, identity files, dist patching
|
|
35
|
+
* 2. `openclaw gateway` in background
|
|
36
|
+
* 3. `agent-relay broker-spawn --from-env` as PID 1
|
|
37
|
+
*
|
|
38
|
+
* For ClawRunner-managed images, set containerCmd to ['/opt/clawrunner/start-claw.sh'].
|
|
39
|
+
*/
|
|
40
|
+
export class DockerSpawnProvider {
|
|
41
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
42
|
+
docker = null;
|
|
43
|
+
image;
|
|
44
|
+
imageFallback;
|
|
45
|
+
networkMode;
|
|
46
|
+
socketPath;
|
|
47
|
+
codexAuthFile;
|
|
48
|
+
codexConfigFile;
|
|
49
|
+
containerHome;
|
|
50
|
+
containerCmd;
|
|
51
|
+
handles = new Map();
|
|
52
|
+
constructor(options = {}) {
|
|
53
|
+
this.image = options.image ?? process.env.CLAW_IMAGE ?? 'openclaw:local';
|
|
54
|
+
this.imageFallback = options.imageFallback ?? process.env.CLAW_IMAGE_FALLBACK ?? 'clawrunner-sandbox:latest';
|
|
55
|
+
this.networkMode = options.networkMode ?? process.env.CLAW_NETWORK ?? 'bridge';
|
|
56
|
+
this.socketPath = options.socketPath ?? process.env.DOCKER_SOCKET ?? '/var/run/docker.sock';
|
|
57
|
+
this.codexAuthFile = expandHomeDir(options.codexAuthFile ?? process.env.CLAW_CODEX_AUTH_FILE ?? '~/.codex/auth.json');
|
|
58
|
+
this.codexConfigFile = expandHomeDir(options.codexConfigFile ?? process.env.CLAW_CODEX_CONFIG_FILE ?? '~/.codex/config.toml');
|
|
59
|
+
this.containerHome = options.containerHome ?? process.env.CLAW_CONTAINER_HOME ?? '/home/node';
|
|
60
|
+
this.containerCmd = options.containerCmd ?? (process.env.CLAW_CONTAINER_CMD
|
|
61
|
+
? process.env.CLAW_CONTAINER_CMD.split(' ')
|
|
62
|
+
: null);
|
|
63
|
+
}
|
|
64
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
65
|
+
async getDocker() {
|
|
66
|
+
if (this.docker)
|
|
67
|
+
return this.docker;
|
|
68
|
+
try {
|
|
69
|
+
// @ts-expect-error dockerode is an optional dependency
|
|
70
|
+
const mod = await import('dockerode');
|
|
71
|
+
const Docker = mod.default ?? mod;
|
|
72
|
+
this.docker = new Docker({ socketPath: this.socketPath });
|
|
73
|
+
return this.docker;
|
|
74
|
+
}
|
|
75
|
+
catch {
|
|
76
|
+
throw new Error('dockerode is required for Docker spawning. Install it with: npm install dockerode');
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* Build the default container entrypoint script.
|
|
81
|
+
* This script works with any vanilla OpenClaw image that has `openclaw` and `node` on PATH.
|
|
82
|
+
* It runs runtime-setup via the package CLI, starts the gateway, then hands off to broker-spawn.
|
|
83
|
+
*/
|
|
84
|
+
buildEntrypointScript(gatewayPort) {
|
|
85
|
+
// Shell script that runs setup, starts gateway, waits for health, then execs broker-spawn.
|
|
86
|
+
// Uses sh -c so it works in minimal alpine images.
|
|
87
|
+
// Runtime setup via package CLI, then gateway, then SDK's spawnFromEnv()
|
|
88
|
+
// which handles broker + agent lifecycle without needing the agent-relay CLI.
|
|
89
|
+
const script = [
|
|
90
|
+
'set -e',
|
|
91
|
+
// Runtime setup: auth conversion, openclaw.json, identity files, dist patching
|
|
92
|
+
'npx @agent-relay/openclaw runtime-setup',
|
|
93
|
+
// Resolve bridge.mjs from the installed package and symlink to the known AGENT_ARGS path.
|
|
94
|
+
// This handles any npm install location (global, local, npx cache).
|
|
95
|
+
'node -e "' +
|
|
96
|
+
"const p = require('path');" +
|
|
97
|
+
"const m = require('module');" +
|
|
98
|
+
"const r = m.createRequire(require.resolve('@agent-relay/openclaw/package.json'));" +
|
|
99
|
+
"const bp = p.join(p.dirname(require.resolve('@agent-relay/openclaw/package.json')), 'bridge', 'bridge.mjs');" +
|
|
100
|
+
"require('fs').symlinkSync(bp, '/tmp/openclaw-bridge.mjs');" +
|
|
101
|
+
"console.log('[entrypoint] Bridge resolved: ' + bp);" +
|
|
102
|
+
'"',
|
|
103
|
+
// Start gateway in background
|
|
104
|
+
`openclaw gateway --port ${gatewayPort} --bind loopback --allow-unconfigured --auth token &`,
|
|
105
|
+
// Wait for gateway health
|
|
106
|
+
`for i in $(seq 1 30); do`,
|
|
107
|
+
` if openclaw health --port ${gatewayPort} 2>/dev/null; then break; fi`,
|
|
108
|
+
` if [ "$i" -eq 30 ]; then echo "Gateway failed to start" >&2; exit 1; fi`,
|
|
109
|
+
` sleep 1`,
|
|
110
|
+
`done`,
|
|
111
|
+
// Use SDK's spawnFromEnv() instead of shelling out to agent-relay CLI.
|
|
112
|
+
// This reads AGENT_NAME, AGENT_CLI, RELAY_API_KEY etc. from env,
|
|
113
|
+
// creates a broker internally, spawns the agent via PTY, and waits for exit.
|
|
114
|
+
`node -e "import('@agent-relay/sdk').then(m => m.spawnFromEnv())"`,
|
|
115
|
+
].join('\n');
|
|
116
|
+
return ['sh', '-c', script];
|
|
117
|
+
}
|
|
118
|
+
async spawn(options) {
|
|
119
|
+
const docker = await this.getDocker();
|
|
120
|
+
const { preferredProvider } = await convertCodexAuth();
|
|
121
|
+
const modelRef = normalizeModelRef(options.model, preferredProvider);
|
|
122
|
+
const workspaceId = options.workspaceId ?? `local-${Date.now().toString(36)}`;
|
|
123
|
+
const agentName = buildAgentName(workspaceId, options.name);
|
|
124
|
+
const gatewayPort = 18789; // Internal to container — each container is isolated
|
|
125
|
+
const identityTask = buildIdentityTask(agentName, workspaceId, modelRef);
|
|
126
|
+
const channels = options.channels?.length ? options.channels : ['general'];
|
|
127
|
+
const gatewayToken = randomUUID().replace(/-/g, '').slice(0, 32);
|
|
128
|
+
const suffix = `${Date.now().toString(36)}-${randomUUID().slice(0, 8)}`;
|
|
129
|
+
const containerName = `openclaw-${sanitizeContainerSegment(agentName)}-${suffix}`.slice(0, 63);
|
|
130
|
+
const binds = [];
|
|
131
|
+
if (options.workspacePath) {
|
|
132
|
+
binds.push(`${options.workspacePath}:/workspace:rw`);
|
|
133
|
+
}
|
|
134
|
+
if (await pathExists(this.codexAuthFile)) {
|
|
135
|
+
binds.push(`${this.codexAuthFile}:${this.containerHome}/.codex/auth.json:rw`);
|
|
136
|
+
}
|
|
137
|
+
if (await pathExists(this.codexConfigFile)) {
|
|
138
|
+
binds.push(`${this.codexConfigFile}:${this.containerHome}/.codex/config.toml:ro`);
|
|
139
|
+
}
|
|
140
|
+
const envVars = {
|
|
141
|
+
AGENT_NAME: agentName,
|
|
142
|
+
AGENT_CLI: 'node',
|
|
143
|
+
// Bridge path: resolved dynamically inside the container via the entrypoint script.
|
|
144
|
+
// The entrypoint writes the resolved path to /tmp/bridge-path.txt after runtime-setup.
|
|
145
|
+
AGENT_ARGS: '/tmp/openclaw-bridge.mjs',
|
|
146
|
+
RELAY_API_KEY: options.relayApiKey,
|
|
147
|
+
RELAY_BASE_URL: options.relayBaseUrl ?? '',
|
|
148
|
+
AGENT_TASK: options.systemPrompt
|
|
149
|
+
? `${options.systemPrompt}\n\n${identityTask}`
|
|
150
|
+
: identityTask,
|
|
151
|
+
AGENT_CWD: '/workspace',
|
|
152
|
+
AGENT_CHANNELS: channels.join(','),
|
|
153
|
+
GATEWAY_PORT: String(gatewayPort),
|
|
154
|
+
OPENCLAW_GATEWAY_TOKEN: gatewayToken,
|
|
155
|
+
OPENCLAW_WORKSPACE_ID: workspaceId,
|
|
156
|
+
OPENCLAW_NAME: options.name,
|
|
157
|
+
OPENCLAW_ROLE: options.role ?? 'general',
|
|
158
|
+
OPENCLAW_MODEL: modelRef,
|
|
159
|
+
BROKER_NO_REMOTE_SPAWN: '1',
|
|
160
|
+
};
|
|
161
|
+
// Try to remove stale container with same name
|
|
162
|
+
try {
|
|
163
|
+
const stale = docker.getContainer(containerName);
|
|
164
|
+
await stale.stop({ t: 5 }).catch(() => { });
|
|
165
|
+
await stale.remove({ force: true }).catch(() => { });
|
|
166
|
+
}
|
|
167
|
+
catch {
|
|
168
|
+
// No stale container
|
|
169
|
+
}
|
|
170
|
+
let imageToUse = this.image;
|
|
171
|
+
try {
|
|
172
|
+
await docker.getImage(this.image).inspect();
|
|
173
|
+
}
|
|
174
|
+
catch {
|
|
175
|
+
imageToUse = this.imageFallback;
|
|
176
|
+
}
|
|
177
|
+
// Use custom cmd if provided, otherwise generate a vanilla-compatible entrypoint
|
|
178
|
+
const cmd = this.containerCmd ?? this.buildEntrypointScript(gatewayPort);
|
|
179
|
+
const container = await docker.createContainer({
|
|
180
|
+
Image: imageToUse,
|
|
181
|
+
name: containerName,
|
|
182
|
+
Env: Object.entries(envVars).map(([k, v]) => `${k}=${v}`),
|
|
183
|
+
Cmd: cmd,
|
|
184
|
+
WorkingDir: '/workspace',
|
|
185
|
+
Labels: {
|
|
186
|
+
'@agent-relay/openclaw.spawn': 'true',
|
|
187
|
+
'@agent-relay/openclaw.agent': agentName,
|
|
188
|
+
},
|
|
189
|
+
HostConfig: {
|
|
190
|
+
NetworkMode: this.networkMode,
|
|
191
|
+
Binds: binds,
|
|
192
|
+
AutoRemove: false,
|
|
193
|
+
},
|
|
194
|
+
});
|
|
195
|
+
await container.start();
|
|
196
|
+
const handle = {
|
|
197
|
+
id: container.id,
|
|
198
|
+
displayName: options.name,
|
|
199
|
+
agentName,
|
|
200
|
+
gatewayPort,
|
|
201
|
+
destroy: () => this.destroy(container.id),
|
|
202
|
+
};
|
|
203
|
+
this.handles.set(container.id, handle);
|
|
204
|
+
return handle;
|
|
205
|
+
}
|
|
206
|
+
async destroy(id) {
|
|
207
|
+
this.handles.delete(id);
|
|
208
|
+
try {
|
|
209
|
+
const docker = await this.getDocker();
|
|
210
|
+
const container = docker.getContainer(id);
|
|
211
|
+
await container.stop({ t: 5 }).catch(() => { });
|
|
212
|
+
await container.remove({ force: true }).catch(() => { });
|
|
213
|
+
}
|
|
214
|
+
catch {
|
|
215
|
+
// Already gone
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
async list() {
|
|
219
|
+
return Array.from(this.handles.values());
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
//# sourceMappingURL=docker.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"docker.js","sourceRoot":"","sources":["../../src/spawn/docker.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import type { SpawnOptions, SpawnHandle } from './types.js';
|
|
2
|
+
export type SpawnMode = 'process' | 'docker';
|
|
3
|
+
interface PersistedSpawn {
|
|
4
|
+
id: string;
|
|
5
|
+
displayName: string;
|
|
6
|
+
agentName: string;
|
|
7
|
+
gatewayPort: number;
|
|
8
|
+
spawnedAt: string;
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* SpawnManager — tracks active spawns and provides a unified interface
|
|
12
|
+
* for spawning, listing, and releasing OpenClaw instances.
|
|
13
|
+
*
|
|
14
|
+
* Security controls:
|
|
15
|
+
* - maxSpawns: Maximum concurrent spawns (default: 10)
|
|
16
|
+
* - maxDepth: Maximum spawn depth to prevent recursive chains (default: 3)
|
|
17
|
+
* - Persistent state in spawns.json for recovery on restart
|
|
18
|
+
*/
|
|
19
|
+
export declare class SpawnManager {
|
|
20
|
+
private readonly provider;
|
|
21
|
+
private readonly handles;
|
|
22
|
+
private readonly maxSpawns;
|
|
23
|
+
private readonly maxDepth;
|
|
24
|
+
private readonly stateFile;
|
|
25
|
+
private currentDepth;
|
|
26
|
+
constructor(options?: {
|
|
27
|
+
mode?: SpawnMode;
|
|
28
|
+
maxSpawns?: number;
|
|
29
|
+
maxDepth?: number;
|
|
30
|
+
spawnDepth?: number;
|
|
31
|
+
});
|
|
32
|
+
spawn(options: SpawnOptions): Promise<SpawnHandle>;
|
|
33
|
+
release(id: string): Promise<boolean>;
|
|
34
|
+
releaseByName(name: string): Promise<boolean>;
|
|
35
|
+
releaseAll(): Promise<void>;
|
|
36
|
+
list(): SpawnHandle[];
|
|
37
|
+
get(id: string): SpawnHandle | undefined;
|
|
38
|
+
get size(): number;
|
|
39
|
+
/** Persist spawn state to disk for recovery. */
|
|
40
|
+
private persistState;
|
|
41
|
+
/** Load persisted state (for display/diagnostics only — processes can't be recovered). */
|
|
42
|
+
loadPersistedState(): Promise<PersistedSpawn[]>;
|
|
43
|
+
}
|
|
44
|
+
export {};
|
|
45
|
+
//# sourceMappingURL=manager.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"manager.d.ts","sourceRoot":"","sources":["../../src/spawn/manager.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAiB,YAAY,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAI3E,MAAM,MAAM,SAAS,GAAG,SAAS,GAAG,QAAQ,CAAC;AAQ7C,UAAU,cAAc;IACtB,EAAE,EAAE,MAAM,CAAC;IACX,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,MAAM,CAAC;CACnB;AAeD;;;;;;;;GAQG;AACH,qBAAa,YAAY;IACvB,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAgB;IACzC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAkC;IAC1D,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAS;IACnC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAS;IAClC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAS;IACnC,OAAO,CAAC,YAAY,CAAS;gBAEjB,OAAO,CAAC,EAAE;QACpB,IAAI,CAAC,EAAE,SAAS,CAAC;QACjB,SAAS,CAAC,EAAE,MAAM,CAAC;QACnB,QAAQ,CAAC,EAAE,MAAM,CAAC;QAClB,UAAU,CAAC,EAAE,MAAM,CAAC;KACrB;IAkBK,KAAK,CAAC,OAAO,EAAE,YAAY,GAAG,OAAO,CAAC,WAAW,CAAC;IA8BlD,OAAO,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IASrC,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAa7C,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;IAKjC,IAAI,IAAI,WAAW,EAAE;IAIrB,GAAG,CAAC,EAAE,EAAE,MAAM,GAAG,WAAW,GAAG,SAAS;IAIxC,IAAI,IAAI,IAAI,MAAM,CAEjB;IAED,gDAAgD;YAClC,YAAY;IAqB1B,0FAA0F;IACpF,kBAAkB,IAAI,OAAO,CAAC,cAAc,EAAE,CAAC;CAUtD"}
|