repositories
loading repo index
repositories
loading repo index
repository
loading code, commits, and activity
public Clawd ADK gateway launch mirror
stars
latest
clone command
git clone gitlawb://did:key:z6Mkq5mY...iFZ5/my-project-publ...git clone gitlawb://did:key:z6Mkq5mY.../my-project-publ...2fa351d6docs: add automaton and perps launch sources16d ago| #1 | import type { Sandbox, Process } from '@cloudflare/sandbox'; |
| #2 | import type { MoltbotEnv } from '../types'; |
| #3 | import { MOLTBOT_PORT, STARTUP_TIMEOUT_MS } from '../config'; |
| #4 | import { buildEnvVars } from './env'; |
| #5 | import { mountR2Storage } from './r2'; |
| #6 | |
| #7 | /** |
| #8 | * Find an existing Moltbot gateway process |
| #9 | * |
| #10 | * @param sandbox - The sandbox instance |
| #11 | * @returns The process if found and running/starting, null otherwise |
| #12 | */ |
| #13 | export async function findExistingMoltbotProcess(sandbox: Sandbox): Promise<Process | null> { |
| #14 | try { |
| #15 | const processes = await sandbox.listProcesses(); |
| #16 | for (const proc of processes) { |
| #17 | // Only match the gateway process, not CLI commands like "clawdbot devices list" |
| #18 | // Note: CLI is still named "clawdbot" until upstream renames it |
| #19 | const isGatewayProcess = |
| #20 | proc.command.includes('start-moltbot.sh') || |
| #21 | proc.command.includes('clawdbot gateway'); |
| #22 | const isCliCommand = |
| #23 | proc.command.includes('clawdbot devices') || |
| #24 | proc.command.includes('clawdbot --version'); |
| #25 | |
| #26 | if (isGatewayProcess && !isCliCommand) { |
| #27 | if (proc.status === 'starting' || proc.status === 'running') { |
| #28 | return proc; |
| #29 | } |
| #30 | } |
| #31 | } |
| #32 | } catch (e) { |
| #33 | console.log('Could not list processes:', e); |
| #34 | } |
| #35 | return null; |
| #36 | } |
| #37 | |
| #38 | /** |
| #39 | * Ensure the Moltbot gateway is running |
| #40 | * |
| #41 | * This will: |
| #42 | * 1. Mount R2 storage if configured |
| #43 | * 2. Check for an existing gateway process |
| #44 | * 3. Wait for it to be ready, or start a new one |
| #45 | * |
| #46 | * @param sandbox - The sandbox instance |
| #47 | * @param env - Worker environment bindings |
| #48 | * @returns The running gateway process |
| #49 | */ |
| #50 | export async function ensureMoltbotGateway(sandbox: Sandbox, env: MoltbotEnv): Promise<Process> { |
| #51 | // Mount R2 storage for persistent data (non-blocking if not configured) |
| #52 | // R2 is used as a backup - the startup script will restore from it on boot |
| #53 | await mountR2Storage(sandbox, env); |
| #54 | |
| #55 | // Check if Moltbot is already running or starting |
| #56 | const existingProcess = await findExistingMoltbotProcess(sandbox); |
| #57 | if (existingProcess) { |
| #58 | console.log('Found existing Moltbot process:', existingProcess.id, 'status:', existingProcess.status); |
| #59 | |
| #60 | // Always use full startup timeout - a process can be "running" but not ready yet |
| #61 | // (e.g., just started by another concurrent request). Using a shorter timeout |
| #62 | // causes race conditions where we kill processes that are still initializing. |
| #63 | try { |
| #64 | console.log('Waiting for Moltbot gateway on port', MOLTBOT_PORT, 'timeout:', STARTUP_TIMEOUT_MS); |
| #65 | await existingProcess.waitForPort(MOLTBOT_PORT, { mode: 'tcp', timeout: STARTUP_TIMEOUT_MS }); |
| #66 | console.log('Moltbot gateway is reachable'); |
| #67 | return existingProcess; |
| #68 | } catch (e) { |
| #69 | // Timeout waiting for port - process is likely dead or stuck, kill and restart |
| #70 | console.log('Existing process not reachable after full timeout, killing and restarting...'); |
| #71 | try { |
| #72 | await existingProcess.kill(); |
| #73 | } catch (killError) { |
| #74 | console.log('Failed to kill process:', killError); |
| #75 | } |
| #76 | } |
| #77 | } |
| #78 | |
| #79 | // Start a new Moltbot gateway |
| #80 | console.log('Starting new Moltbot gateway...'); |
| #81 | const envVars = buildEnvVars(env); |
| #82 | const command = '/usr/local/bin/start-moltbot.sh'; |
| #83 | |
| #84 | console.log('Starting process with command:', command); |
| #85 | console.log('Environment vars being passed:', Object.keys(envVars)); |
| #86 | |
| #87 | let process: Process; |
| #88 | try { |
| #89 | process = await sandbox.startProcess(command, { |
| #90 | env: Object.keys(envVars).length > 0 ? envVars : undefined, |
| #91 | }); |
| #92 | console.log('Process started with id:', process.id, 'status:', process.status); |
| #93 | } catch (startErr) { |
| #94 | console.error('Failed to start process:', startErr); |
| #95 | throw startErr; |
| #96 | } |
| #97 | |
| #98 | // Wait for the gateway to be ready |
| #99 | try { |
| #100 | console.log('[Gateway] Waiting for Moltbot gateway to be ready on port', MOLTBOT_PORT); |
| #101 | await process.waitForPort(MOLTBOT_PORT, { mode: 'tcp', timeout: STARTUP_TIMEOUT_MS }); |
| #102 | console.log('[Gateway] Moltbot gateway is ready!'); |
| #103 | |
| #104 | const logs = await process.getLogs(); |
| #105 | if (logs.stdout) console.log('[Gateway] stdout:', logs.stdout); |
| #106 | if (logs.stderr) console.log('[Gateway] stderr:', logs.stderr); |
| #107 | } catch (e) { |
| #108 | console.error('[Gateway] waitForPort failed:', e); |
| #109 | try { |
| #110 | const logs = await process.getLogs(); |
| #111 | console.error('[Gateway] startup failed. Stderr:', logs.stderr); |
| #112 | console.error('[Gateway] startup failed. Stdout:', logs.stdout); |
| #113 | throw new Error(`Moltbot gateway failed to start. Stderr: ${logs.stderr || '(empty)'}`); |
| #114 | } catch (logErr) { |
| #115 | console.error('[Gateway] Failed to get logs:', logErr); |
| #116 | throw e; |
| #117 | } |
| #118 | } |
| #119 | |
| #120 | // Verify gateway is actually responding |
| #121 | console.log('[Gateway] Verifying gateway health...'); |
| #122 | |
| #123 | return process; |
| #124 | } |
| #125 |