|
| 1 | +/** |
| 2 | + * openclaw_deploy: trigger deployment scripts on the OpenClaw server via SSH. |
| 3 | + * |
| 4 | + * Scripts live in OPENCLAW_DEPLOY_SCRIPT_DIR (default: ~/deploy) and follow |
| 5 | + * the naming convention: deploy-{service}.sh, rollback-{service}.sh |
| 6 | + * Status reads the last 30 lines of ~/deploy/logs/{service}.log if it exists. |
| 7 | + */ |
| 8 | + |
| 9 | +import { z } from 'zod'; |
| 10 | +import { Config } from '../config.js'; |
| 11 | +import { sshExec, SshConfig } from '../ssh.js'; |
| 12 | + |
| 13 | +// --- Schema --- |
| 14 | + |
| 15 | +export const openclawDeploySchema = z.object({ |
| 16 | + service: z.string().describe('Service name to deploy, e.g. "api", "worker", "frontend"'), |
| 17 | + action: z.enum(['deploy', 'rollback', 'status']) |
| 18 | + .describe('deploy: run deploy script, rollback: run rollback script, status: show last deploy log'), |
| 19 | +}); |
| 20 | + |
| 21 | +// --- Handler --- |
| 22 | + |
| 23 | +export async function handleOpenclawDeploy( |
| 24 | + args: z.infer<typeof openclawDeploySchema>, |
| 25 | + config: Config, |
| 26 | +): Promise<{ success: boolean; output?: string; error?: string; service: string; action: string }> { |
| 27 | + const cfg: SshConfig = { |
| 28 | + host: config.sshHost, |
| 29 | + port: config.sshPort, |
| 30 | + username: config.sshUser, |
| 31 | + keyPath: config.sshKeyPath, |
| 32 | + }; |
| 33 | + |
| 34 | + const scriptDir = config.deployScriptDir ?? '~/deploy'; |
| 35 | + const { service, action } = args; |
| 36 | + |
| 37 | + const cmds: Record<string, string> = { |
| 38 | + deploy: `bash ${scriptDir}/deploy-${service}.sh 2>&1`, |
| 39 | + rollback: `bash ${scriptDir}/rollback-${service}.sh 2>&1`, |
| 40 | + status: `if [ -f ${scriptDir}/logs/${service}.log ]; then tail -30 ${scriptDir}/logs/${service}.log; else echo "No log found at ${scriptDir}/logs/${service}.log"; fi`, |
| 41 | + }; |
| 42 | + |
| 43 | + try { |
| 44 | + const output = await sshExec(cfg, cmds[action]!, 120_000); |
| 45 | + return { success: true, output: output.trimEnd(), service, action }; |
| 46 | + } catch (err) { |
| 47 | + return { |
| 48 | + success: false, |
| 49 | + error: err instanceof Error ? err.message : String(err), |
| 50 | + service, |
| 51 | + action, |
| 52 | + }; |
| 53 | + } |
| 54 | +} |
0 commit comments