Clawdbot(Moltbot)源码部署实战
一、背景
最近技术圈关注较多的是 Clawdbot(后更名为 Moltbot),支持 WhatsApp、Telegram 等通道,可私有化部署。本文记录从源码拉取到环境搭建的完整过程及踩坑经验。
二、环境准备
Windows 环境下推荐优先使用 WSL2(Ubuntu/Debian 镜像)进行部署,原生 CMD 易报依赖错误。
- 启用 WSL2:在 Windows 功能中勾选'适用于 Linux 的 Windows 子系统'和'虚拟机平台',重启后安装 Ubuntu 22.04。
- 配置 WSL2:打开终端更新系统源(建议换阿里源),执行
sudo apt update && sudo apt upgrade -y。 - 安装 Git:执行
sudo apt install git,验证git --version。
三、Node.js 安装与依赖
仓库文档要求 Node.js ≥ 22,建议使用 nvm 管理环境并切换至最新版本。
注意:版本低于 22 时
pnpm install可能报错。
1. 拉取源码 & 装依赖
git clone https://github.com/openclaw/openclaw.git
cd openclaw
pnpm install
常见问题:安装时 node-llama-cpp 的 postinstall 脚本可能失败(错误码 3221225477)。该依赖仅用于本地嵌入,若使用远程模型(如 OpenAI)可忽略。解决方案是注释掉 package.json 中的 node-llama-cpp 依赖后重新运行 pnpm install。
2. 构建项目
先构建 UI:
pnpm ui:build
再构建主项目:
pnpm build
若在原生 Windows 上构建需 Bash 环境。检查是否有 Git Bash 可用,或在项目 /script 目录下创建 Node.js 版本的构建脚本 bundle-a2ui.mjs:
#!/usr/bin/env node
import { createHash } from "node:crypto";
import { promises as fs } from "node:fs";
import path from "node:path";
import { fileURLToPath } from "node:url";
{ spawn } ;
{ promisify } ;
spawnAsync = (spawn);
__filename = (..);
__dirname = path.(__filename);
= path.(__dirname, );
= path.(, );
= path.(, );
= path.(, );
= path.(, );
() {
{
stat = fs.(dir);
stat.();
} {
;
}
}
() {
st = fs.(entryPath);
(st.()) {
entries = fs.(entryPath);
( entry entries) {
(path.(entryPath, entry), files);
}
files;
}
files.(entryPath);
files;
}
() {
p.(path.).();
}
() {
inputPaths = [
path.(, ),
path.(, ),
,
,
];
files = [];
( inputPath inputPaths) {
{
stat = fs.(inputPath);
(stat.() || stat.()) {
(inputPath, files);
}
} {
}
}
files.( (a).((b)));
hash = ();
( filePath files) {
rel = (path.(, filePath));
hash.(rel);
hash.();
content = fs.(filePath);
hash.(content);
hash.();
}
hash.();
}
() {
( {
proc = (command, args, {
...options,
: ,
: ,
});
proc.(, {
(code === ) {
();
} {
( ());
}
});
proc.(, reject);
});
}
() {
{
(!( ()) || !( ())) {
.();
process.();
}
currentHash = ();
shouldBuild = ;
{
previousHash = fs.(, );
outputExists = fs.().( ).( );
(previousHash.() === currentHash && outputExists) {
.();
shouldBuild = ;
}
} {
}
(shouldBuild) {
.();
(, [, , , , path.(, )]);
(, [, , , , path.(, )]);
fs.(, currentHash, );
.();
}
} (error) {
.();
.();
.(error);
process.();
}
}
();


