openclaw/src/media/remote.ts

45 lines
1.1 KiB
TypeScript

import { spawn } from "node:child_process";
const SINGLE_QUOTE_ESCAPE = "'\"'\"'";
export function quoteScpPath(value: string): string {
return `'${value.replace(/'/g, SINGLE_QUOTE_ESCAPE)}'`;
}
export function formatScpSource(remoteHost: string, remotePath: string): string {
return `${remoteHost}:${quoteScpPath(remotePath)}`;
}
export async function copyRemoteFileViaScp(params: {
remoteHost: string;
remotePath: string;
localPath: string;
}): Promise<void> {
return await new Promise((resolve, reject) => {
const child = spawn(
"/usr/bin/scp",
[
"-o",
"BatchMode=yes",
"-o",
"StrictHostKeyChecking=accept-new",
formatScpSource(params.remoteHost, params.remotePath),
params.localPath,
],
{ stdio: ["ignore", "ignore", "pipe"] },
);
let stderr = "";
child.stderr?.setEncoding("utf8");
child.stderr?.on("data", (chunk) => {
stderr += chunk;
});
child.once("error", reject);
child.once("exit", (code) => {
if (code === 0) resolve();
else reject(new Error(`scp failed (${code}): ${stderr.trim()}`));
});
});
}