create-openclaw-bot 4.0.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/CHANGELOG.md +121 -0
- package/CHANGELOG.vi.md +116 -0
- package/README.md +211 -0
- package/README.vi.md +215 -0
- package/SETUP.md +532 -0
- package/SETUP.vi.md +439 -0
- package/cli.js +231 -0
- package/docker/openclaw/Dockerfile +14 -0
- package/docker/openclaw/docker-compose.yml +18 -0
- package/docs/browser-automation-guide.md +207 -0
- package/docs/skills-plugins-guide.md +126 -0
- package/index.html +336 -0
- package/package.json +28 -0
- package/setup.js +1991 -0
- package/start-chrome-debug.bat +15 -0
- package/style.css +1347 -0
package/SETUP.vi.md
ADDED
|
@@ -0,0 +1,439 @@
|
|
|
1
|
+
# 🦞 OpenClaw — Hướng Dẫn Kỹ Thuật (cho AI Agent)
|
|
2
|
+
|
|
3
|
+
> **File này dành cho AI Agent (Antigravity) đọc và thực thi tự động.**
|
|
4
|
+
> Người dùng đã tạo sẵn file `.env` chứa API key và Bot token. AI **TUYỆT ĐỐI KHÔNG** được yêu cầu hoặc nhận credentials qua chat.
|
|
5
|
+
|
|
6
|
+
[English](SETUP.md) · [Tiếng Việt](#-quy-tắc-bảo-mật--bắt-buộc)
|
|
7
|
+
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
## 🔐 Quy Tắc Bảo Mật — BẮT BUỘC
|
|
11
|
+
|
|
12
|
+
> **AI Agent BẮT BUỘC tuân thủ TẤT CẢ quy tắc bên dưới. Vi phạm = DỪNG ngay.**
|
|
13
|
+
|
|
14
|
+
### File & thư mục hệ thống
|
|
15
|
+
|
|
16
|
+
- ❌ **KHÔNG** đọc, sao chép, hoặc truy cập bất kỳ file nào ngoài thư mục project
|
|
17
|
+
- ❌ **KHÔNG** quét hoặc liệt kê các thư mục hệ thống: `Documents`, `Desktop`, `Downloads`, `AppData`, `%USERPROFILE%`
|
|
18
|
+
- ❌ **KHÔNG** truy cập registry, system32, hoặc Program Files
|
|
19
|
+
- ❌ **KHÔNG** cài đặt phần mềm, driver, hoặc service ngoài Docker
|
|
20
|
+
- ❌ **KHÔNG** sửa đổi biến môi trường hệ thống
|
|
21
|
+
- ✅ **CHỈ** làm việc trong thư mục project do người dùng chỉ định
|
|
22
|
+
|
|
23
|
+
### API key & credentials
|
|
24
|
+
|
|
25
|
+
- ❌ **KHÔNG BAO GIỜ** hiển thị API key, token, hoặc mật khẩu trong chat
|
|
26
|
+
- ❌ **KHÔNG** viết API key trực tiếp vào mã nguồn
|
|
27
|
+
- ❌ **KHÔNG** commit file credentials lên Git
|
|
28
|
+
- ✅ **LUÔN** lưu credentials trong file `.env` riêng
|
|
29
|
+
- ✅ **LUÔN** thêm `.env` vào `.gitignore`
|
|
30
|
+
- ✅ **LUÔN** dùng biến môi trường (`${VAR}`) thay vì hardcode
|
|
31
|
+
|
|
32
|
+
### Ví crypto & tài sản số
|
|
33
|
+
|
|
34
|
+
- ❌ **TUYỆT ĐỐI KHÔNG** truy cập, đọc, hoặc quét các thư mục ví crypto:
|
|
35
|
+
- Metamask, Trust Wallet, Phantom, Exodus, Electrum
|
|
36
|
+
- File: `wallet.dat`, `keystore/`, seed phrases, private keys
|
|
37
|
+
- Extension trình duyệt chứa ví crypto
|
|
38
|
+
- ❌ **KHÔNG** quét clipboard (có thể chứa seed phrases)
|
|
39
|
+
- ❌ **KHÔNG** truy cập browser profile, cookie, hoặc mật khẩu đã lưu
|
|
40
|
+
- ❌ **KHÔNG** cài đặt npm package lạ (chỉ `openclaw` và plugin chính thức)
|
|
41
|
+
|
|
42
|
+
### Docker
|
|
43
|
+
|
|
44
|
+
- ✅ Chỉ mount **đúng** thư mục cần thiết (config + workspace)
|
|
45
|
+
- ❌ **KHÔNG** mount nguyên ổ đĩa (`C:/` hoặc `D:/`)
|
|
46
|
+
- ❌ **KHÔNG** chạy container với `--privileged`
|
|
47
|
+
- ✅ Giới hạn port expose (chỉ `18789`)
|
|
48
|
+
|
|
49
|
+
---
|
|
50
|
+
|
|
51
|
+
## 📂 Cấu Trúc Thư Mục Sau Setup
|
|
52
|
+
|
|
53
|
+
```
|
|
54
|
+
<PROJECT_DIR>/
|
|
55
|
+
├── .openclaw/ ← Config chính (KHÔNG commit)
|
|
56
|
+
│ ├── openclaw.json ← Gateway, agent, channel config
|
|
57
|
+
│ ├── auth-profiles.json ← API key profile
|
|
58
|
+
│ ├── credentials/
|
|
59
|
+
│ │ └── <provider> ← API key của nhà cung cấp AI
|
|
60
|
+
│ ├── agents/
|
|
61
|
+
│ │ └── <agent-name>.yaml ← Định nghĩa agent (chỉ name + model)
|
|
62
|
+
│ ├── workspace/ ← ⭐ Persona & hành vi bot
|
|
63
|
+
│ │ ├── IDENTITY.md ← Tên bot, emoji, vibe
|
|
64
|
+
│ │ ├── SOUL.md ← Tính cách, ranh giới
|
|
65
|
+
│ │ ├── AGENTS.md ← Quy tắc vận hành
|
|
66
|
+
│ │ ├── USER.md ← Thông tin người dùng
|
|
67
|
+
│ │ ├── TOOLS.md ← Hướng dẫn dùng tools
|
|
68
|
+
│ │ └── MEMORY.md ← Bộ nhớ dài hạn
|
|
69
|
+
│ ├── skills/ ← Slash commands (tùy chọn)
|
|
70
|
+
│ ├── identity/
|
|
71
|
+
│ │ └── device.json ← Device keypair
|
|
72
|
+
│ ├── memory/ ← Bộ nhớ agent (SQLite)
|
|
73
|
+
│ ├── cron/jobs.json
|
|
74
|
+
│ └── logs/
|
|
75
|
+
│ └── config-audit.jsonl
|
|
76
|
+
│
|
|
77
|
+
├── docker/openclaw/
|
|
78
|
+
│ ├── Dockerfile
|
|
79
|
+
│ ├── docker-compose.yml
|
|
80
|
+
│ └── .env ← API keys (KHÔNG commit)
|
|
81
|
+
│
|
|
82
|
+
└── .gitignore
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
---
|
|
86
|
+
|
|
87
|
+
## 🔌 Kênh & Model Hỗ Trợ
|
|
88
|
+
|
|
89
|
+
### Kênh chat
|
|
90
|
+
|
|
91
|
+
| Kênh | Key trong .env | Plugin cần cài |
|
|
92
|
+
|------|---------------|----------------|
|
|
93
|
+
| **Telegram** | `TELEGRAM_BOT_TOKEN` | Không (built-in) |
|
|
94
|
+
| **Zalo Bot API** | `ZALO_BOT_TOKEN` | `@openclaw/zalo` |
|
|
95
|
+
| **Zalo Cá nhân** | Không cần | `@openclaw/zalouser` |
|
|
96
|
+
|
|
97
|
+
### Nhà cung cấp AI
|
|
98
|
+
|
|
99
|
+
| Nhà cung cấp | Key trong .env | Model ID format |
|
|
100
|
+
|--------------|---------------|-----------------|
|
|
101
|
+
| **Google Gemini** | `GOOGLE_API_KEY` | `google/gemini-2.5-flash` |
|
|
102
|
+
| **Anthropic Claude** | `ANTHROPIC_API_KEY` | `anthropic/claude-sonnet-4` |
|
|
103
|
+
| **OpenAI** | `OPENAI_API_KEY` | `openai/gpt-4o` |
|
|
104
|
+
| **OpenRouter** | `OPENROUTER_API_KEY` | `openrouter/model-name` |
|
|
105
|
+
| **Ollama** | `OLLAMA_HOST` | `ollama/qwen3:8b` |
|
|
106
|
+
|
|
107
|
+
### Logic phát hiện kênh:
|
|
108
|
+
|
|
109
|
+
```
|
|
110
|
+
NẾU .env chứa TELEGRAM_BOT_TOKEN → Kênh = Telegram
|
|
111
|
+
NẾU .env chứa ZALO_BOT_TOKEN → Kênh = Zalo Bot API
|
|
112
|
+
NGƯỢC LẠI → Kênh = Zalo Cá nhân (hoặc hỏi người dùng)
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
### Logic phát hiện AI provider:
|
|
116
|
+
|
|
117
|
+
```
|
|
118
|
+
NẾU .env chứa GOOGLE_API_KEY → Provider = Google Gemini
|
|
119
|
+
NẾU .env chứa ANTHROPIC_API_KEY → Provider = Anthropic
|
|
120
|
+
NẾU .env chứa OPENAI_API_KEY → Provider = OpenAI
|
|
121
|
+
NẾU .env chứa OPENROUTER_API_KEY → Provider = OpenRouter
|
|
122
|
+
NẾU .env chứa OLLAMA_HOST → Provider = Ollama
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
---
|
|
126
|
+
|
|
127
|
+
## ⚙️ Các Bước Setup
|
|
128
|
+
|
|
129
|
+
### Bước 1: Tạo thư mục
|
|
130
|
+
|
|
131
|
+
```bash
|
|
132
|
+
mkdir -p <PROJECT_DIR>/docker/openclaw
|
|
133
|
+
mkdir -p <PROJECT_DIR>/.openclaw/credentials
|
|
134
|
+
mkdir -p <PROJECT_DIR>/.openclaw/agents
|
|
135
|
+
mkdir -p <PROJECT_DIR>/.openclaw/skills
|
|
136
|
+
mkdir -p <PROJECT_DIR>/.openclaw/identity
|
|
137
|
+
mkdir -p <PROJECT_DIR>/.openclaw/memory
|
|
138
|
+
mkdir -p <PROJECT_DIR>/.openclaw/cron
|
|
139
|
+
mkdir -p <PROJECT_DIR>/.openclaw/logs
|
|
140
|
+
mkdir -p <PROJECT_DIR>/.openclaw/completions
|
|
141
|
+
mkdir -p <PROJECT_DIR>/.openclaw/canvas
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
### Bước 2: Tạo Dockerfile
|
|
145
|
+
|
|
146
|
+
Tạo `<PROJECT_DIR>/docker/openclaw/Dockerfile`:
|
|
147
|
+
|
|
148
|
+
#### Telegram (không cần plugin):
|
|
149
|
+
|
|
150
|
+
```dockerfile
|
|
151
|
+
FROM node:22-slim
|
|
152
|
+
RUN apt-get update && apt-get install -y git curl && rm -rf /var/lib/apt/lists/*
|
|
153
|
+
RUN npm install -g openclaw@latest
|
|
154
|
+
WORKDIR /root/.openclaw
|
|
155
|
+
EXPOSE 18789
|
|
156
|
+
CMD ["openclaw", "gateway", "run"]
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
#### Zalo Bot API:
|
|
160
|
+
|
|
161
|
+
```dockerfile
|
|
162
|
+
FROM node:22-slim
|
|
163
|
+
RUN apt-get update && apt-get install -y git curl && rm -rf /var/lib/apt/lists/*
|
|
164
|
+
RUN npm install -g openclaw@latest
|
|
165
|
+
RUN openclaw plugins install @openclaw/zalo
|
|
166
|
+
WORKDIR /root/.openclaw
|
|
167
|
+
EXPOSE 18789
|
|
168
|
+
CMD ["openclaw", "gateway", "run"]
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
#### Zalo Cá nhân:
|
|
172
|
+
|
|
173
|
+
```dockerfile
|
|
174
|
+
FROM node:22-slim
|
|
175
|
+
RUN apt-get update && apt-get install -y git curl && rm -rf /var/lib/apt/lists/*
|
|
176
|
+
RUN npm install -g openclaw@latest
|
|
177
|
+
RUN openclaw plugins install @openclaw/zalouser
|
|
178
|
+
WORKDIR /root/.openclaw
|
|
179
|
+
EXPOSE 18789
|
|
180
|
+
CMD ["openclaw", "gateway", "run"]
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
#### Có thêm plugin (ví dụ Browser + Memory):
|
|
184
|
+
|
|
185
|
+
```dockerfile
|
|
186
|
+
FROM node:22-slim
|
|
187
|
+
RUN apt-get update && apt-get install -y git curl && rm -rf /var/lib/apt/lists/*
|
|
188
|
+
RUN npm install -g openclaw@latest
|
|
189
|
+
# Cài plugin kênh chat + plugin mở rộng
|
|
190
|
+
RUN openclaw plugins install @openclaw/zalo @openclaw/browser @openclaw/memory
|
|
191
|
+
WORKDIR /root/.openclaw
|
|
192
|
+
EXPOSE 18789
|
|
193
|
+
CMD ["openclaw", "gateway", "run"]
|
|
194
|
+
```
|
|
195
|
+
|
|
196
|
+
### Bước 3: Tạo docker-compose.yml
|
|
197
|
+
|
|
198
|
+
Tạo `<PROJECT_DIR>/docker/openclaw/docker-compose.yml`:
|
|
199
|
+
|
|
200
|
+
```yaml
|
|
201
|
+
services:
|
|
202
|
+
ai-bot:
|
|
203
|
+
build: .
|
|
204
|
+
container_name: openclaw-bot
|
|
205
|
+
restart: always
|
|
206
|
+
env_file:
|
|
207
|
+
- .env
|
|
208
|
+
extra_hosts:
|
|
209
|
+
- "host.docker.internal:host-gateway"
|
|
210
|
+
volumes:
|
|
211
|
+
- <PROJECT_DIR>/.openclaw:/root/.openclaw
|
|
212
|
+
ports:
|
|
213
|
+
- "18789:18789"
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
> Thay `<PROJECT_DIR>` bằng đường dẫn tuyệt đối thực tế. Ví dụ: `D:/MyAIBot/.openclaw:/root/.openclaw`
|
|
217
|
+
|
|
218
|
+
### Bước 4: Kiểm tra file .env (do người dùng đã tạo)
|
|
219
|
+
|
|
220
|
+
File `.env` đã được người dùng tạo tại `<PROJECT_DIR>/docker/openclaw/.env`.
|
|
221
|
+
|
|
222
|
+
**AI Agent PHẢI kiểm tra:**
|
|
223
|
+
1. File `.env` **tồn tại** tại `<PROJECT_DIR>/docker/openclaw/.env`
|
|
224
|
+
2. File chứa ít nhất 1 API key hợp lệ
|
|
225
|
+
3. **KHÔNG** đọc hoặc hiển thị giá trị key trong chat
|
|
226
|
+
|
|
227
|
+
Nếu file không tồn tại → **DỪNG** và yêu cầu người dùng tạo theo hướng dẫn trong README.
|
|
228
|
+
|
|
229
|
+
> **KHÔNG BAO GIỜ** tạo file `.env` thay người dùng. **KHÔNG BAO GIỜ** yêu cầu credentials qua chat.
|
|
230
|
+
|
|
231
|
+
### Bước 5: Tạo .gitignore
|
|
232
|
+
|
|
233
|
+
Tạo `<PROJECT_DIR>/.gitignore`:
|
|
234
|
+
|
|
235
|
+
```gitignore
|
|
236
|
+
# Credentials
|
|
237
|
+
.openclaw/credentials/
|
|
238
|
+
.openclaw/auth-profiles.json
|
|
239
|
+
.openclaw/openclaw.json
|
|
240
|
+
.openclaw/identity/
|
|
241
|
+
docker/openclaw/.env
|
|
242
|
+
|
|
243
|
+
# Runtime data
|
|
244
|
+
.openclaw/memory/
|
|
245
|
+
.openclaw/logs/
|
|
246
|
+
.openclaw/completions/
|
|
247
|
+
.openclaw/telegram/
|
|
248
|
+
.openclaw/canvas/
|
|
249
|
+
```
|
|
250
|
+
|
|
251
|
+
### Bước 6: Tạo cấu hình OpenClaw
|
|
252
|
+
|
|
253
|
+
**AI Agent thực hiện:**
|
|
254
|
+
|
|
255
|
+
1. Đọc API key (và channel token nếu có) từ `.env`
|
|
256
|
+
2. Phát hiện kênh chat và AI provider theo logic ở trên
|
|
257
|
+
3. Generate random gateway auth token
|
|
258
|
+
4. Ghi giá trị vào các file config bên dưới
|
|
259
|
+
5. **KHÔNG** hiển thị key/token trong chat
|
|
260
|
+
|
|
261
|
+
**Generate gateway auth token:**
|
|
262
|
+
|
|
263
|
+
```bash
|
|
264
|
+
node -e "console.log(require('crypto').randomBytes(24).toString('hex'))"
|
|
265
|
+
```
|
|
266
|
+
|
|
267
|
+
#### Config cho Telegram + Google Gemini (ví dụ):
|
|
268
|
+
|
|
269
|
+
**Tạo `<PROJECT_DIR>/.openclaw/openclaw.json`:**
|
|
270
|
+
|
|
271
|
+
```json
|
|
272
|
+
{
|
|
273
|
+
"meta": { "lastTouchedVersion": "2026.3.27" },
|
|
274
|
+
"agents": {
|
|
275
|
+
"defaults": {
|
|
276
|
+
"model": { "primary": "google/gemini-2.5-flash", "fallbacks": [] },
|
|
277
|
+
"compaction": { "mode": "safeguard" }
|
|
278
|
+
},
|
|
279
|
+
"list": []
|
|
280
|
+
},
|
|
281
|
+
"commands": {
|
|
282
|
+
"native": "auto",
|
|
283
|
+
"nativeSkills": "auto",
|
|
284
|
+
"restart": true,
|
|
285
|
+
"ownerDisplay": "raw"
|
|
286
|
+
},
|
|
287
|
+
"channels": {
|
|
288
|
+
"telegram": {
|
|
289
|
+
"enabled": true,
|
|
290
|
+
"dmPolicy": "open",
|
|
291
|
+
"botToken": "<BOT_TOKEN_TỪ_.ENV>",
|
|
292
|
+
"allowFrom": ["*"],
|
|
293
|
+
"groupPolicy": "allowlist",
|
|
294
|
+
"streaming": "partial"
|
|
295
|
+
}
|
|
296
|
+
},
|
|
297
|
+
"gateway": {
|
|
298
|
+
"port": 18789,
|
|
299
|
+
"mode": "local",
|
|
300
|
+
"auth": { "mode": "token", "token": "<GATEWAY_TOKEN_ĐÃ_GENERATE>" }
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
```
|
|
304
|
+
|
|
305
|
+
#### Config kênh Zalo Bot API:
|
|
306
|
+
|
|
307
|
+
Thay phần `channels` bằng:
|
|
308
|
+
|
|
309
|
+
```json
|
|
310
|
+
{ "channels": { "zalo": { "enabled": true, "botToken": "<ZALO_BOT_TOKEN_TỪ_.ENV>" } } }
|
|
311
|
+
```
|
|
312
|
+
|
|
313
|
+
#### Config kênh Zalo Cá nhân:
|
|
314
|
+
|
|
315
|
+
Thay phần `channels` bằng:
|
|
316
|
+
|
|
317
|
+
```json
|
|
318
|
+
{ "channels": { "zalouser": { "enabled": true } } }
|
|
319
|
+
```
|
|
320
|
+
|
|
321
|
+
> **Lưu ý:** Zalo Cá nhân cần quét QR code sau khi container chạy. Xem QR trong logs: `docker logs openclaw-bot`
|
|
322
|
+
|
|
323
|
+
---
|
|
324
|
+
|
|
325
|
+
**Tạo `<PROJECT_DIR>/.openclaw/auth-profiles.json`** — dùng API key tương ứng:
|
|
326
|
+
|
|
327
|
+
```json
|
|
328
|
+
{ "gemini": { "apiKey": "<GOOGLE_API_KEY_TỪ_.ENV>" } }
|
|
329
|
+
```
|
|
330
|
+
|
|
331
|
+
_(Đổi `gemini` thành `anthropic`, `openai`, `openrouter` tùy provider)_
|
|
332
|
+
|
|
333
|
+
**Tạo `<PROJECT_DIR>/.openclaw/credentials/<provider>`** — ghi API key (1 dòng, không xuống dòng).
|
|
334
|
+
|
|
335
|
+
**Tạo `<PROJECT_DIR>/.openclaw/cron/jobs.json`:**
|
|
336
|
+
|
|
337
|
+
```json
|
|
338
|
+
{ "version": 1, "jobs": [] }
|
|
339
|
+
```
|
|
340
|
+
|
|
341
|
+
### Bước 7: Tạo Agent & Workspace Files
|
|
342
|
+
|
|
343
|
+
#### 7a. Agent YAML (chỉ metadata, KHÔNG chứa system_prompt)
|
|
344
|
+
|
|
345
|
+
Tạo file YAML tại `.openclaw/agents/<tên>.yaml`. Ví dụ — `.openclaw/agents/chat.yaml`:
|
|
346
|
+
|
|
347
|
+
```yaml
|
|
348
|
+
name: chat
|
|
349
|
+
description: "Trợ lý AI cá nhân"
|
|
350
|
+
|
|
351
|
+
model:
|
|
352
|
+
primary: google/gemini-2.5-flash
|
|
353
|
+
```
|
|
354
|
+
|
|
355
|
+
> **Lưu ý:** File YAML chỉ khai báo `name`, `description`, `model`. Tính cách bot nằm ở workspace files bên dưới.
|
|
356
|
+
|
|
357
|
+
#### 7b. Workspace Markdown Files (⭐ Bot nhận diện từ đây)
|
|
358
|
+
|
|
359
|
+
OpenClaw **tự động inject** tất cả file `.md` trong `.openclaw/workspace/` vào context đầu mỗi session. Đây là cách bot "biết" tên mình, tính cách, và quy tắc.
|
|
360
|
+
|
|
361
|
+
| File | Mục đích | Bắt buộc |
|
|
362
|
+
|------|----------|----------|
|
|
363
|
+
| `IDENTITY.md` | Tên bot, emoji, cách xưng hô | ✅ |
|
|
364
|
+
| `SOUL.md` | Tính cách, phong cách, ranh giới | ✅ |
|
|
365
|
+
| `AGENTS.md` | Quy tắc vận hành, cách trả lời | ✅ |
|
|
366
|
+
| `USER.md` | Thông tin về user (ngôn ngữ, sở thích) | Nên có |
|
|
367
|
+
| `TOOLS.md` | Hướng dẫn dùng tool/skill | Nên có |
|
|
368
|
+
| `MEMORY.md` | Bộ nhớ dài hạn (bot tự cập nhật) | Tùy chọn |
|
|
369
|
+
|
|
370
|
+
> **Thứ tự ưu tiên:** Per-agent files (`.openclaw/agents/<id>/`) → Global workspace files (`.openclaw/workspace/`) → Config defaults.
|
|
371
|
+
|
|
372
|
+
> **Bảo mật hệ thống** (không xóa file, không truy cập thư mục nhạy cảm, không lộ API key...) được OpenClaw **tự động áp dụng** — không cần viết vào workspace files.
|
|
373
|
+
|
|
374
|
+
#### 7c. Cập nhật `openclaw.json`
|
|
375
|
+
|
|
376
|
+
Thêm agent vào `agents.list`:
|
|
377
|
+
|
|
378
|
+
```json
|
|
379
|
+
{
|
|
380
|
+
"agents": {
|
|
381
|
+
"list": [
|
|
382
|
+
{ "id": "chat", "model": { "primary": "google/gemini-2.5-flash", "fallbacks": [] } }
|
|
383
|
+
]
|
|
384
|
+
}
|
|
385
|
+
}
|
|
386
|
+
```
|
|
387
|
+
|
|
388
|
+
### Bước 8: Build & Chạy
|
|
389
|
+
|
|
390
|
+
```bash
|
|
391
|
+
cd <PROJECT_DIR>/docker/openclaw
|
|
392
|
+
docker compose build
|
|
393
|
+
docker compose up -d
|
|
394
|
+
docker logs -f openclaw-bot
|
|
395
|
+
```
|
|
396
|
+
|
|
397
|
+
### Bước 9: Kiểm tra
|
|
398
|
+
|
|
399
|
+
**Telegram:**
|
|
400
|
+
1. Mở Telegram → Tìm bot của bạn
|
|
401
|
+
2. Gửi tin nhắn bất kỳ
|
|
402
|
+
3. Bot trả lời = **Thành công!** 🎉
|
|
403
|
+
|
|
404
|
+
**Zalo Bot API:**
|
|
405
|
+
1. Mở Zalo → Tìm bot
|
|
406
|
+
2. Gửi tin nhắn
|
|
407
|
+
3. Bot trả lời = **Thành công!** 🎉
|
|
408
|
+
|
|
409
|
+
**Zalo Cá nhân:**
|
|
410
|
+
1. Xem `docker logs openclaw-bot` để lấy QR code
|
|
411
|
+
2. Quét QR bằng app Zalo
|
|
412
|
+
3. Gửi tin nhắn từ tài khoản Zalo khác
|
|
413
|
+
4. Bot trả lời = **Thành công!** 🎉
|
|
414
|
+
|
|
415
|
+
Nếu bot không phản hồi:
|
|
416
|
+
|
|
417
|
+
```bash
|
|
418
|
+
docker logs openclaw-bot --tail 50
|
|
419
|
+
docker compose restart
|
|
420
|
+
```
|
|
421
|
+
|
|
422
|
+
Nếu bot **không tạo được cron job** (lỗi "pairing required"):
|
|
423
|
+
|
|
424
|
+
```bash
|
|
425
|
+
docker exec -i openclaw-bot openclaw devices approve --latest
|
|
426
|
+
```
|
|
427
|
+
|
|
428
|
+
> **Lưu ý:** Từ OpenClaw v2026.3.x, gateway yêu cầu device pairing cho CLI connections. Dockerfile đã tự động approve khi khởi động, nhưng nếu lỗi vẫn xảy ra, chạy lệnh trên 1 lần.
|
|
429
|
+
|
|
430
|
+
---
|
|
431
|
+
|
|
432
|
+
## ✅ Checklist Bảo Mật Sau Setup
|
|
433
|
+
|
|
434
|
+
- [ ] `.env` **không** xuất hiện trong `git status`
|
|
435
|
+
- [ ] `.openclaw/credentials/` **không** bị Git track
|
|
436
|
+
- [ ] `openclaw.json` **không** bị Git track
|
|
437
|
+
- [ ] Docker **không** mount nguyên ổ đĩa
|
|
438
|
+
- [ ] Gateway auth token được generate ngẫu nhiên
|
|
439
|
+
- [ ] Zalo Cá nhân: đang dùng tài khoản **phụ** (nếu có)
|
package/cli.js
ADDED
|
@@ -0,0 +1,231 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import { input, select, checkbox, confirm } from '@inquirer/prompts';
|
|
4
|
+
import fs from 'fs-extra';
|
|
5
|
+
import path from 'path';
|
|
6
|
+
import chalk from 'chalk';
|
|
7
|
+
import { spawn } from 'child_process';
|
|
8
|
+
|
|
9
|
+
const LOGO = `
|
|
10
|
+
\\/
|
|
11
|
+
/\\O _ O/\\
|
|
12
|
+
// /_\\ \\\\
|
|
13
|
+
\\// / \\ \\\\/
|
|
14
|
+
`;
|
|
15
|
+
|
|
16
|
+
const CHANNELS = {
|
|
17
|
+
'telegram': { name: 'Telegram', type: 'telegram', icon: '🤖' },
|
|
18
|
+
'zalo-bot': { name: 'Zalo OA (Bot Platform)', type: 'zalo-bot', icon: '🔑' },
|
|
19
|
+
'zalo-personal': { name: 'Zalo Personal (Quét QR)', type: 'zalo-personal', icon: '📱' }
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
const PROVIDERS = {
|
|
23
|
+
'proxy': { name: '9Router Proxy (Khuyên dùng)', icon: '🔀', isProxy: true },
|
|
24
|
+
'openai': { name: 'OpenAI (ChatGPT)', icon: '🧠', envKey: 'OPENAI_API_KEY' },
|
|
25
|
+
'ollama': { name: 'Local Ollama', icon: '🏠', isLocal: true },
|
|
26
|
+
'google': { name: 'Google (Gemini)', icon: '⚡', envKey: 'GEMINI_API_KEY' },
|
|
27
|
+
'anthropic': { name: 'Anthropic (Claude)', icon: '🦄', envKey: 'ANTHROPIC_API_KEY' },
|
|
28
|
+
'xai': { name: 'xAI (Grok)', icon: '✖️', envKey: 'XAI_API_KEY' },
|
|
29
|
+
'groq': { name: 'Groq (LPU)', icon: '🏎️', envKey: 'GROQ_API_KEY' }
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
const SKILLS = [
|
|
33
|
+
{ value: 'browser', name: 'Web Browser Automation', checked: false },
|
|
34
|
+
{ value: 'tavily', name: 'Web Search (Tavily)', checked: false },
|
|
35
|
+
{ value: 'tts', name: 'Text-To-Speech (OpenAI/ElevenLabs)', checked: false }
|
|
36
|
+
];
|
|
37
|
+
|
|
38
|
+
async function main() {
|
|
39
|
+
console.log(chalk.red('\n=================================='));
|
|
40
|
+
console.log(chalk.redBright(LOGO));
|
|
41
|
+
console.log(chalk.greenBright(' OpenClaw Auto Setup CLI '));
|
|
42
|
+
console.log(chalk.red('==================================\n'));
|
|
43
|
+
|
|
44
|
+
// 1. Language
|
|
45
|
+
const lang = await select({
|
|
46
|
+
message: 'Select language / Chọn ngôn ngữ:',
|
|
47
|
+
choices: [
|
|
48
|
+
{ name: 'Tiếng Việt', value: 'vi' },
|
|
49
|
+
{ name: 'English', value: 'en' }
|
|
50
|
+
]
|
|
51
|
+
});
|
|
52
|
+
const isVi = lang === 'vi';
|
|
53
|
+
|
|
54
|
+
// 2. Channel
|
|
55
|
+
const channelKey = await select({
|
|
56
|
+
message: isVi ? 'Chọn nền tảng bot:' : 'Select bot platform:',
|
|
57
|
+
choices: Object.entries(CHANNELS).map(([k, v]) => ({ name: `${v.icon} ${v.name}`, value: k }))
|
|
58
|
+
});
|
|
59
|
+
const channel = CHANNELS[channelKey];
|
|
60
|
+
|
|
61
|
+
let botToken = '';
|
|
62
|
+
if (channelKey !== 'zalo-personal') {
|
|
63
|
+
botToken = await input({
|
|
64
|
+
message: isVi ? `Nhập ${channel.name} Token:` : `Enter ${channel.name} Token:`,
|
|
65
|
+
required: true
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
// 3. Provider
|
|
70
|
+
const providerKey = await select({
|
|
71
|
+
message: isVi ? 'Chọn AI Provider:' : 'Select AI Provider:',
|
|
72
|
+
choices: Object.entries(PROVIDERS).map(([k, v]) => ({ name: `${v.icon} ${v.name}`, value: k }))
|
|
73
|
+
});
|
|
74
|
+
const provider = PROVIDERS[providerKey];
|
|
75
|
+
|
|
76
|
+
let providerKeyVal = '';
|
|
77
|
+
if (!provider.isProxy && !provider.isLocal) {
|
|
78
|
+
providerKeyVal = await input({
|
|
79
|
+
message: isVi ? `Nhập ${provider.envKey}:` : `Enter ${provider.envKey}:`,
|
|
80
|
+
required: true
|
|
81
|
+
});
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
// 4. Skills
|
|
85
|
+
const selectedSkills = await checkbox({
|
|
86
|
+
message: isVi ? 'Bật tính năng bổ sung (Space để chọn):' : 'Enable extra skills (Space to select):',
|
|
87
|
+
choices: SKILLS
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
let tavilyKey = '';
|
|
91
|
+
if (selectedSkills.includes('tavily')) {
|
|
92
|
+
tavilyKey = await input({ message: isVi ? 'Nhập TAVILY_API_KEY:' : 'Enter TAVILY_API_KEY:' });
|
|
93
|
+
}
|
|
94
|
+
let ttsOpenaiKey = '';
|
|
95
|
+
let ttsElevenKey = '';
|
|
96
|
+
if (selectedSkills.includes('tts')) {
|
|
97
|
+
ttsOpenaiKey = await input({ message: isVi ? 'Nhập OPENAI_API_KEY (cho TTS, bỏ trống nếu dùng ElevenLabs):' : 'Enter OPENAI_API_KEY (for TTS, leave empty for ElevenLabs):' });
|
|
98
|
+
ttsElevenKey = await input({ message: isVi ? 'Nhập ELEVENLABS_API_KEY (hoặc bỏ trống):' : 'Enter ELEVENLABS_API_KEY (or leave empty):' });
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
// 5. Bot Info
|
|
102
|
+
const botName = await input({ message: isVi ? 'Tên Bot:' : 'Bot Name:', default: 'Chat Bot' });
|
|
103
|
+
const botDesc = await input({ message: isVi ? 'Mô tả Bot:' : 'Bot Description:', default: 'Personal AI assistant' });
|
|
104
|
+
|
|
105
|
+
// 6. Project Dir
|
|
106
|
+
let defaultDir = process.cwd();
|
|
107
|
+
if (!defaultDir.endsWith('openclaw-setup') && !defaultDir.endsWith('openclaw')) {
|
|
108
|
+
defaultDir = path.join(defaultDir, 'openclaw-setup');
|
|
109
|
+
}
|
|
110
|
+
const projectDir = await input({
|
|
111
|
+
message: isVi ? 'Thư mục cài đặt project:' : 'Project install directory:',
|
|
112
|
+
default: defaultDir
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
console.log(chalk.cyan(`\n🚀 ${isVi ? 'Đang tạo thư mục và file cấu hình...' : 'Generating directories and configurations...'}`));
|
|
116
|
+
|
|
117
|
+
await fs.ensureDir(projectDir);
|
|
118
|
+
await fs.ensureDir(path.join(projectDir, '.openclaw'));
|
|
119
|
+
await fs.ensureDir(path.join(projectDir, 'docker', 'openclaw'));
|
|
120
|
+
|
|
121
|
+
// ================= GENERATE FILES =================
|
|
122
|
+
let envContent = '';
|
|
123
|
+
if (provider.isLocal) {
|
|
124
|
+
envContent += 'OLLAMA_HOST=http://host.docker.internal:11434\n';
|
|
125
|
+
} else if (!provider.isProxy) {
|
|
126
|
+
envContent += `${provider.envKey}=${providerKeyVal}\n`;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
if (channelKey === 'telegram') {
|
|
130
|
+
envContent += `TELEGRAM_BOT_TOKEN=${botToken}\n`;
|
|
131
|
+
} else if (channelKey === 'zalo-bot') {
|
|
132
|
+
envContent += `ZALO_APP_ID=\nZALO_APP_SECRET=\nZALO_BOT_TOKEN=${botToken}\n`;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
if (selectedSkills.includes('tavily') && tavilyKey) {
|
|
136
|
+
envContent += `\n# --- Web Search ---\nTAVILY_API_KEY=${tavilyKey}\n`;
|
|
137
|
+
}
|
|
138
|
+
if (selectedSkills.includes('tts')) {
|
|
139
|
+
envContent += `\n# --- Text-To-Speech ---\n`;
|
|
140
|
+
if (ttsOpenaiKey) envContent += `OPENAI_API_KEY=${ttsOpenaiKey}\n`;
|
|
141
|
+
if (ttsElevenKey) envContent += `ELEVENLABS_API_KEY=${ttsElevenKey}\n`;
|
|
142
|
+
}
|
|
143
|
+
await fs.writeFile(path.join(projectDir, 'docker', 'openclaw', '.env'), envContent);
|
|
144
|
+
|
|
145
|
+
const dockerfile = `FROM ghcr.io/williamskyze/openclaw:latest
|
|
146
|
+
${selectedSkills.includes('browser') ? 'RUN apt-get update && apt-get install -y chromium xvfb dbus socat' : '# (No browser config needed)'}`;
|
|
147
|
+
await fs.writeFile(path.join(projectDir, 'docker', 'openclaw', 'Dockerfile'), dockerfile);
|
|
148
|
+
|
|
149
|
+
const compose = `services:
|
|
150
|
+
openclaw:
|
|
151
|
+
build: .
|
|
152
|
+
restart: always
|
|
153
|
+
env_file: .env
|
|
154
|
+
volumes:
|
|
155
|
+
- ../../.openclaw:/app/.openclaw
|
|
156
|
+
- ../../auth-profiles.json:/app/auth-profiles.json
|
|
157
|
+
${selectedSkills.includes('browser') ? ` extra_hosts:
|
|
158
|
+
- "host.docker.internal:host-gateway"
|
|
159
|
+
` : ''}`;
|
|
160
|
+
await fs.writeFile(path.join(projectDir, 'docker', 'openclaw', 'docker-compose.yml'), compose);
|
|
161
|
+
|
|
162
|
+
await fs.writeFile(path.join(projectDir, 'auth-profiles.json'), '{}');
|
|
163
|
+
|
|
164
|
+
const botConfig = {
|
|
165
|
+
meta: { version: '1.0' },
|
|
166
|
+
agents: {
|
|
167
|
+
defaults: {
|
|
168
|
+
model: { primary: providerKey === 'openai' ? 'gpt-4o' : (providerKey === 'google' ? 'google/gemini-2.5-flash' : 'smart-route'), fallbacks: [] },
|
|
169
|
+
identity: {
|
|
170
|
+
name: botName,
|
|
171
|
+
description: botDesc,
|
|
172
|
+
system_prompt: isVi ? "Bạn là một trợ lý AI hữu ích." : "You are a helpful AI assistant."
|
|
173
|
+
},
|
|
174
|
+
skills: selectedSkills
|
|
175
|
+
}
|
|
176
|
+
},
|
|
177
|
+
channels: {}
|
|
178
|
+
};
|
|
179
|
+
|
|
180
|
+
if (channelKey === 'telegram') {
|
|
181
|
+
botConfig.channels['telegram'] = { enabled: true };
|
|
182
|
+
} else if (channelKey === 'zalo-personal') {
|
|
183
|
+
botConfig.channels['zalo-personal'] = { enabled: true, autoReply: true };
|
|
184
|
+
} else if (channelKey === 'zalo-bot') {
|
|
185
|
+
botConfig.channels['zalo-bot'] = { enabled: true };
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
await fs.writeJson(path.join(projectDir, '.openclaw', 'openclaw.json'), botConfig, { spaces: 2 });
|
|
189
|
+
|
|
190
|
+
if (selectedSkills.includes('browser')) {
|
|
191
|
+
const batPath = path.join(projectDir, 'start-chrome-debug.bat');
|
|
192
|
+
await fs.writeFile(batPath, `@echo off\necho OpenClaw Chrome Debug\nstart "" "C:\\Program Files\\Google\\Chrome\\Application\\chrome.exe" --remote-debugging-port=9222 --remote-allow-origins=* --user-data-dir="%TEMP%\\chrome-debug"\npause`);
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
console.log(chalk.green(`✅ ${isVi ? 'Tạo cấu hình thành công!' : 'Configs created successfully!'}`));
|
|
196
|
+
|
|
197
|
+
// 7. Auto Run
|
|
198
|
+
const autoRun = await confirm({
|
|
199
|
+
message: isVi ? 'Bạn có muốn tự động tải Docker và khởi động Bot luôn không?' : 'Do you want to run Docker compose and start the bot now?',
|
|
200
|
+
default: true
|
|
201
|
+
});
|
|
202
|
+
|
|
203
|
+
if (autoRun) {
|
|
204
|
+
console.log(chalk.yellow(`\n🐳 ${isVi ? 'Đang khởi động Docker (có thể mất vài phút)...' : 'Starting Docker (might take a few minutes)...'}`));
|
|
205
|
+
const dockerPath = path.join(projectDir, 'docker', 'openclaw');
|
|
206
|
+
|
|
207
|
+
const child = spawn('docker', ['compose', 'up', '-d', '--build'], {
|
|
208
|
+
cwd: dockerPath,
|
|
209
|
+
stdio: 'inherit'
|
|
210
|
+
});
|
|
211
|
+
|
|
212
|
+
child.on('close', (code) => {
|
|
213
|
+
if (code === 0) {
|
|
214
|
+
console.log(chalk.green(`\n🎉 ${isVi ? 'Setup hoàn tất! Bot đang chạy.' : 'Setup complete! Bot is running.'}`));
|
|
215
|
+
if (channelKey === 'zalo-personal') {
|
|
216
|
+
console.log(chalk.yellow(`\n📱 ${isVi ? 'Vui lòng chạy lệnh sau để đăng nhập Zalo Personal (1 lần duy nhất):' : 'Please run this command to login to Zalo Personal (once):'}`));
|
|
217
|
+
console.log(`cd ${projectDir} && docker compose exec -it openclaw bun run core:onboard`);
|
|
218
|
+
}
|
|
219
|
+
} else {
|
|
220
|
+
console.log(chalk.red(`\n❌ Docker exited with code ${code}`));
|
|
221
|
+
}
|
|
222
|
+
});
|
|
223
|
+
} else {
|
|
224
|
+
console.log(chalk.cyan(`\n👉 ${isVi ? 'Tiếp theo, hãy chạy:' : 'Next, run:'}\n cd ${projectDir}/docker/openclaw\n docker compose build\n docker compose up -d`));
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
main().catch(err => {
|
|
229
|
+
console.error(chalk.red('Error:'), err);
|
|
230
|
+
process.exit(1);
|
|
231
|
+
});
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
FROM node:22-slim
|
|
2
|
+
|
|
3
|
+
RUN apt-get update && apt-get install -y git curl socat && rm -rf /var/lib/apt/lists/*
|
|
4
|
+
|
|
5
|
+
RUN npm install -g openclaw@latest
|
|
6
|
+
|
|
7
|
+
# Browser Automation: Playwright engine (needed for native CDP)
|
|
8
|
+
RUN npm install -g agent-browser playwright && npx playwright install chromium --with-deps && ln -f -s /root/.cache/ms-playwright/chromium-*/chrome-linux*/chrome /usr/bin/google-chrome
|
|
9
|
+
|
|
10
|
+
WORKDIR /root/.openclaw
|
|
11
|
+
|
|
12
|
+
EXPOSE 18791
|
|
13
|
+
|
|
14
|
+
CMD sh -c "node -e \"const fs=require('fs'),p='/root/.openclaw/openclaw.json';if(fs.existsSync(p)){const c=JSON.parse(fs.readFileSync(p,'utf8'));c.tools=Object.assign({},c.tools,{profile:'full'});c.gateway=Object.assign({},c.gateway,{port:18791,bind:'0.0.0.0'});fs.writeFileSync(p,JSON.stringify(c,null,2));}\" && socat TCP-LISTEN:9222,fork,reuseaddr TCP:host.docker.internal:9222 & openclaw gateway run"
|