create-openclaw-bot 5.6.14 → 5.7.0

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/README.md CHANGED
@@ -3,7 +3,7 @@
3
3
  # 🦞 OpenClaw Setup
4
4
 
5
5
  <p align="center">
6
- <a href="https://github.com/tuanminhhole/openclaw-setup/releases"><img src="https://img.shields.io/badge/RELEASE-v5.6.14-0EA5E9?style=for-the-badge" alt="Version 5.6.14" /></a>
6
+ <a href="https://github.com/tuanminhhole/openclaw-setup/releases"><img src="https://img.shields.io/badge/RELEASE-v5.7.0-0EA5E9?style=for-the-badge" alt="Version 5.7.0" /></a>
7
7
  <a href="https://github.com/tuanminhhole/openclaw-setup?tab=MIT-1-ov-file"><img src="https://img.shields.io/badge/LICENSE-MIT-success?style=for-the-badge" alt="MIT License" /></a>
8
8
  <a href="https://www.npmjs.com/package/create-openclaw-bot"><img src="https://img.shields.io/npm/v/create-openclaw-bot?style=for-the-badge&label=CLI&color=2563EB&logo=npm&logoColor=white" alt="NPM Version" /></a>
9
9
  <a href="https://github.com/tuanminhhole/openclaw-setup/stargazers"><img src="https://img.shields.io/github/stars/tuanminhhole/openclaw-setup?style=for-the-badge&color=eab308&logo=github&logoColor=white" alt="GitHub Stars" /></a>
@@ -24,22 +24,21 @@ An interactive **CLI tool** and **Setup Wizard** to deploy your own free AI Bot
24
24
 
25
25
  ---
26
26
 
27
- ## 🆕 What's new in v5.6.14
27
+ ## 🆕 What's new in v5.7.0
28
+
29
+ - 🏗️ **Centralized config architecture** — All `openclaw.json`, `.env`, and `exec-approvals.json` generation now flows through a single `bot-config-gen.js` module. Both the Web Wizard and CLI share the same builder, eliminating config drift between surfaces.
30
+ - 🔄 **Rolling `@latest` versioning** — Installation scripts now use `openclaw@latest` instead of pinned versions, ensuring users always get the newest release without waiting for a setup update.
31
+ - 🧪 **Comprehensive test matrix** — Added 422 new matrix tests covering all OS × Deploy × Channel × Bot Count combinations, plus Wizard IIFE sandbox evaluation and CLI structural validation.
32
+ - 🐛 **Removed `autoReply` bug** — The `autoReply: true` field that caused gateway startup crashes on Zalo Personal has been permanently removed from all generators.
33
+ - 💬 **Standardized Zalo Personal config** — Zalo Personal (`zalouser`) channel now uses production-matching config with `groups`, `groupPolicy`, `historyLimit`, and proper `bindings`.
34
+
35
+ <details>
36
+ <summary><b>Previous: What's new in v5.7.0</b></summary>
28
37
 
29
38
  - 🔧 **OpenAI Codex provider fix** — Updated Codex model registry to match OpenAI's current API. Removed 6 deprecated models, retained 4 active ones: `gpt-5.4`, `gpt-5.3-codex`, `gpt-5.2`, `gpt-5.4-mini`.
30
39
  - 🔀 **9Router API mode switch** — Switched from `openai-completions` to `openai-responses` to align with OpenAI's Responses API.
31
40
  - 🩹 **Auto-patch 9Router** — New `patch-9router.js` automatically patches 9Router source files on setup, upgrade, and before every launch to stay compatible with Codex API changes.
32
41
  - 🎯 **Direct Codex model targeting** — 9Router config now exposes individual Codex models alongside `smart-route` so users can pick a specific model.
33
- - 💬 **Zalo Personal group config** — Added `defaultAccount`, `groupAllowFrom`, `historyLimit`, wildcard group config and `autoReply` for better out-of-the-box group handling.
34
-
35
- <details>
36
- <summary><b>Previous: What's new in v5.6.0</b></summary>
37
-
38
- - 🧠 **Memory & Dreaming enabled by default** — Long-term Memory skill is now pre-selected for all new installations. The `memory-core` plugin with `dreaming.enabled: true` is auto-injected into `openclaw.json`, and `DREAMS.md` is seeded in every workspace.
39
- - 🤝 **Relay plugin card auto-shows** — When selecting Telegram multi-bot (≥2 bots), the Relay plugin card appears with an "Auto-enabled" badge and locked checkbox. Switching back to 1 bot hides it.
40
- - 🔑 **Relay trigger keywords in TEAMS.md** — `TEAMS.md` now documents all relay trigger keywords (question/task/reminder patterns) from the v5.0.9 relay plugin, helping bots understand and coordinate cross-bot communication.
41
- - 🌍 **Proper Vietnamese diacritics** — All workspace `.md` files now use proper UTF-8 Vietnamese with full diacritics, eliminating mojibake.
42
- - 👍 **Tool-based reaction** — `TOOLS.md` mandates bots call the `react` action with 👍 before replying, replacing unreliable gateway auto-ack.
43
42
 
44
43
  </details>
45
44
 
package/README.vi.md CHANGED
@@ -3,7 +3,7 @@
3
3
  # 🦞 OpenClaw Setup
4
4
 
5
5
  <p align="center">
6
- <a href="https://github.com/tuanminhhole/openclaw-setup/releases"><img src="https://img.shields.io/badge/RELEASE-v5.6.14-0EA5E9?style=for-the-badge" alt="Version 5.6.14" /></a>
6
+ <a href="https://github.com/tuanminhhole/openclaw-setup/releases"><img src="https://img.shields.io/badge/RELEASE-v5.7.0-0EA5E9?style=for-the-badge" alt="Version 5.7.0" /></a>
7
7
  <a href="https://github.com/tuanminhhole/openclaw-setup?tab=MIT-1-ov-file"><img src="https://img.shields.io/badge/LICENSE-MIT-success?style=for-the-badge" alt="MIT License" /></a>
8
8
  <a href="https://www.npmjs.com/package/create-openclaw-bot"><img src="https://img.shields.io/npm/v/create-openclaw-bot?style=for-the-badge&label=CLI&color=2563EB&logo=npm&logoColor=white" alt="NPM Version" /></a>
9
9
  <a href="https://github.com/tuanminhhole/openclaw-setup/stargazers"><img src="https://img.shields.io/github/stars/tuanminhhole/openclaw-setup?style=for-the-badge&color=eab308&logo=github&logoColor=white" alt="GitHub Stars" /></a>
@@ -24,22 +24,21 @@ Công cụ **CLI tương tác** và **Setup Wizard** để tự triển khai Bot
24
24
 
25
25
  ---
26
26
 
27
- ## 🆕 Có gì mới trong v5.6.14
27
+ ## 🆕 Có gì mới trong v5.7.0
28
+
29
+ - 🏗️ **Kiến trúc config tập trung** — Toàn bộ logic tạo `openclaw.json`, `.env`, và `exec-approvals.json` giờ chạy qua module duy nhất `bot-config-gen.js`. Cả Web Wizard và CLI dùng chung cùng một builder, loại bỏ sai lệch config giữa 2 bề mặt.
30
+ - 🔄 **Phiên bản rolling `@latest`** — Script cài đặt giờ dùng `openclaw@latest` thay vì version cố định, đảm bảo người dùng luôn nhận bản mới nhất.
31
+ - 🧪 **Bộ test matrix toàn diện** — Thêm 422 test mới phủ tất cả tổ hợp OS × Deploy × Channel × Số bot, kèm sandbox Wizard IIFE và kiểm tra cấu trúc CLI.
32
+ - 🐛 **Xóa lỗi `autoReply`** — Trường `autoReply: true` gây crash gateway khi khởi động Zalo Personal đã bị loại bỏ vĩnh viễn khỏi mọi generator.
33
+ - 💬 **Chuẩn hóa config Zalo Personal** — Kênh Zalo Personal (`zalouser`) giờ dùng config khớp production với `groups`, `groupPolicy`, `historyLimit`, và `bindings` đúng.
34
+
35
+ <details>
36
+ <summary><b>Trước đó: Có gì mới ở v5.7.0</b></summary>
28
37
 
29
38
  - 🔧 **Sửa provider OpenAI Codex** — Cập nhật registry model Codex phù hợp API hiện tại của OpenAI. Loại 6 model đã dừng, giữ 4 model đang hoạt động: `gpt-5.4`, `gpt-5.3-codex`, `gpt-5.2`, `gpt-5.4-mini`.
30
39
  - 🔀 **Chuyển chế độ API 9Router** — Đổi từ `openai-completions` sang `openai-responses` cho khớp với Responses API mới của OpenAI.
31
40
  - 🩹 **Tự động patch 9Router** — Script `patch-9router.js` mới tự vá source files 9Router khi setup, upgrade và trước mỗi lần khởi động để tương thích thay đổi API Codex.
32
41
  - 🎯 **Chọn model Codex trực tiếp** — Config 9Router giờ hiển thị từng model Codex bên cạnh `smart-route` để người dùng có thể chọn model cụ thể.
33
- - 💬 **Config nhóm Zalo Personal** — Bổ sung `defaultAccount`, `groupAllowFrom`, `historyLimit`, wildcard group config và `autoReply` để xử lý nhóm tốt hơn ngay từ đầu.
34
-
35
- <details>
36
- <summary><b>Trước đó: Có gì mới ở v5.6.0</b></summary>
37
-
38
- - 🧠 **Memory & Dreaming bật mặc định** — Long-term Memory skill giờ được bật sẵn cho mọi cài đặt mới. Plugin `memory-core` với `dreaming.enabled: true` được inject tự động vào `openclaw.json`, `DREAMS.md` được tạo sẵn trong workspace.
39
- - 🤝 **Card Relay plugin tự động hiển thị** — Khi chọn Telegram multi-bot (≥2 bots), card Relay plugin hiện ra với badge "Tự động bật" và checkbox bị khóa. Chuyển về 1 bot sẽ ẩn card.
40
- - 🔑 **Từ khóa relay trong TEAMS.md** — `TEAMS.md` giờ liệt kê đầy đủ từ khóa kích hoạt relay (hỏi/giao việc/nhắc nhở) từ plugin v5.0.9, giúp bot hiểu và phối hợp tốt hơn.
41
- - 🌍 **Tiếng Việt có dấu chuẩn** — Tất cả file `.md` workspace giờ dùng UTF-8 chuẩn với dấu tiếng Việt đầy đủ, hết lỗi mojibake.
42
- - 👍 **Tool-based reaction** — `TOOLS.md` bắt buộc bot gọi action `react` thả 👍 trước khi trả lời, thay vì dùng gateway auto-ack không ổn định.
43
42
 
44
43
  </details>
45
44
 
package/dist/cli.js CHANGED
@@ -60,6 +60,13 @@ const {
60
60
  buildCliStartBotArtifacts,
61
61
  } = loadSharedModule('./setup/shared/install-gen.js', '__openclawInstall');
62
62
 
63
+ const {
64
+ buildOpenclawJson,
65
+ buildExecApprovalsJson,
66
+ buildEnvFileContent,
67
+ buildSkillsEntries: _buildSkillsEntries,
68
+ } = loadSharedModule('./setup/shared/bot-config-gen.js', '__openclawBotConfig');
69
+
63
70
  function installRelayPluginForProject(projectDir, isVi) {
64
71
  try {
65
72
  execSync(`openclaw plugins install ${TELEGRAM_RELAY_PLUGIN_SPEC}`, { cwd: projectDir, stdio: 'ignore' });
@@ -2062,49 +2069,43 @@ async function main() {
2062
2069
 
2063
2070
  // ─── Helper: build .env content per bot ──────────────────────────────────
2064
2071
 
2065
- function buildEnvContent(botIndex) {
2066
- let env = '';
2067
- if (provider.isLocal) {
2068
- env += `OLLAMA_HOST=${ollamaHost}\n`;
2069
- env += 'OLLAMA_API_KEY=ollama-local\n';
2070
- } else if (!provider.isProxy) {
2071
- env += `${provider.envKey}=${providerKeyVal}\n`;
2072
- }
2072
+ function buildEnvContentForBot(botIndex) {
2073
2073
  const tok = bots[botIndex]?.token || botToken;
2074
- if (channelKey === 'telegram') {
2075
- env += `TELEGRAM_BOT_TOKEN=${tok}\n`;
2076
- if (isMultiBot && groupId) env += `TELEGRAM_GROUP_ID=${groupId}\n`;
2077
- } else if (channelKey === 'zalo-bot') {
2078
- env += `ZALO_APP_ID=\nZALO_APP_SECRET=\nZALO_BOT_TOKEN=${tok}\n`;
2079
- }
2080
- if (selectedSkills.includes('tts')) {
2081
- env += `\n# --- Text-To-Speech ---\n`;
2082
- if (ttsOpenaiKey) env += `OPENAI_API_KEY=${ttsOpenaiKey}\n`;
2083
- if (ttsElevenKey) env += `ELEVENLABS_API_KEY=${ttsElevenKey}\n`;
2084
- }
2085
- if (selectedSkills.includes('email')) {
2086
- env += `\n# --- Email ---\nSMTP_HOST=${smtpHost}\nSMTP_PORT=${smtpPort}\nSMTP_USER=${smtpUser}\nSMTP_PASS=${smtpPass}\n`;
2087
- }
2088
- return env;
2074
+ return buildEnvFileContent({
2075
+ provider,
2076
+ providerKeyVal,
2077
+ channelKey,
2078
+ botToken: tok,
2079
+ isMultiBot,
2080
+ groupId,
2081
+ selectedSkills,
2082
+ ttsOpenaiKey,
2083
+ ttsElevenKey,
2084
+ smtpHost,
2085
+ smtpPort,
2086
+ smtpUser,
2087
+ smtpPass,
2088
+ isSharedEnv: false,
2089
+ });
2089
2090
  }
2090
2091
 
2091
- function buildSharedEnvContent() {
2092
- let env = '';
2093
- if (provider.isLocal) {
2094
- env += `OLLAMA_HOST=${ollamaHost}\n`;
2095
- env += 'OLLAMA_API_KEY=ollama-local\n';
2096
- } else if (!provider.isProxy) {
2097
- env += `${provider.envKey}=${providerKeyVal}\n`;
2098
- }
2099
- if (selectedSkills.includes('tts')) {
2100
- env += `\n# --- Text-To-Speech ---\n`;
2101
- if (ttsOpenaiKey) env += `OPENAI_API_KEY=${ttsOpenaiKey}\n`;
2102
- if (ttsElevenKey) env += `ELEVENLABS_API_KEY=${ttsElevenKey}\n`;
2103
- }
2104
- if (selectedSkills.includes('email')) {
2105
- env += `\n# --- Email ---\nSMTP_HOST=${smtpHost}\nSMTP_PORT=${smtpPort}\nSMTP_USER=${smtpUser}\nSMTP_PASS=${smtpPass}\n`;
2106
- }
2107
- return env;
2092
+ function buildSharedEnvContentForBots() {
2093
+ return buildEnvFileContent({
2094
+ provider,
2095
+ providerKeyVal,
2096
+ channelKey,
2097
+ botToken: '',
2098
+ isMultiBot,
2099
+ groupId,
2100
+ selectedSkills,
2101
+ ttsOpenaiKey,
2102
+ ttsElevenKey,
2103
+ smtpHost,
2104
+ smtpPort,
2105
+ smtpUser,
2106
+ smtpPass,
2107
+ isSharedEnv: true,
2108
+ });
2108
2109
  }
2109
2110
 
2110
2111
  // ─── Create directories and write .env files ─────────────────────────────
@@ -2112,9 +2113,9 @@ async function main() {
2112
2113
  await fs.ensureDir(path.join(projectDir, '.openclaw'));
2113
2114
  if (deployMode === 'docker') {
2114
2115
  await fs.ensureDir(path.join(projectDir, 'docker', 'openclaw'));
2115
- await fs.writeFile(path.join(projectDir, 'docker', 'openclaw', '.env'), buildSharedEnvContent());
2116
+ await fs.writeFile(path.join(projectDir, 'docker', 'openclaw', '.env'), buildSharedEnvContentForBots());
2116
2117
  } else {
2117
- await fs.writeFile(path.join(projectDir, '.env'), buildSharedEnvContent());
2118
+ await fs.writeFile(path.join(projectDir, '.env'), buildSharedEnvContentForBots());
2118
2119
  }
2119
2120
  } else {
2120
2121
  await fs.ensureDir(path.join(projectDir, '.openclaw'));
@@ -2122,7 +2123,7 @@ async function main() {
2122
2123
  const envFilePath = deployMode === 'docker'
2123
2124
  ? path.join(projectDir, 'docker', 'openclaw', '.env')
2124
2125
  : path.join(projectDir, '.env');
2125
- await fs.writeFile(envFilePath, buildEnvContent(0));
2126
+ await fs.writeFile(envFilePath, buildEnvContentForBot(0));
2126
2127
  }
2127
2128
 
2128
2129
 
@@ -2169,6 +2170,7 @@ async function main() {
2169
2170
  multiOllamaNumParallel: 2,
2170
2171
  singleOllamaNumParallel: 1,
2171
2172
  emitBrowserInstall: hasBrowserServer || hasBrowserDesktop,
2173
+
2172
2174
  });
2173
2175
 
2174
2176
  const dockerDir = path.join(projectDir, 'docker', 'openclaw');
@@ -2248,113 +2250,24 @@ async function main() {
2248
2250
  workspaceDir: `workspace-${agentSlug}`,
2249
2251
  };
2250
2252
  });
2251
- const telegramAccounts = Object.fromEntries(agentMetas.map((meta) => [meta.accountId, {
2252
- botToken: meta.token,
2253
- }]));
2254
- const telegramChannelConfig = {
2255
- enabled: true,
2256
- defaultAccount: 'default',
2257
- dmPolicy: 'open',
2258
- allowFrom: ['*'],
2259
- groupPolicy: groupId ? 'allowlist' : 'open',
2260
- groupAllowFrom: ['*'],
2261
- groups: {
2262
- [groupId || '*']: { enabled: true, requireMention: false },
2263
- },
2264
- replyToMode: 'first',
2265
- reactionLevel: 'minimal',
2266
- actions: {
2267
- sendMessage: true,
2268
- reactions: true,
2269
- },
2270
- accounts: telegramAccounts,
2271
- };
2272
- const skillEntries = {};
2273
- SKILLS.forEach((s) => {
2274
- if (!selectedSkills.includes(s.value)) return;
2275
- if (!s.slug) return;
2276
- skillEntries[s.slug] = { enabled: true };
2253
+ const sharedConfig = buildOpenclawJson({
2254
+ channelKey,
2255
+ deployMode,
2256
+ providerKey,
2257
+ provider,
2258
+ model: modelsPrimary,
2259
+ isMultiBot: true,
2260
+ agentMetas,
2261
+ groupId,
2262
+ selectedSkills,
2263
+ skills: SKILLS,
2264
+ hasBrowserDesktop,
2265
+ hasBrowserServer,
2266
+ gatewayPort: 18791,
2267
+ gatewayAllowedOrigins: getGatewayAllowedOrigins(18791),
2268
+ osChoice,
2277
2269
  });
2278
2270
 
2279
- const sharedConfig = {
2280
- meta: { lastTouchedVersion: '2026.3.24' },
2281
- agents: {
2282
- defaults: {
2283
- model: { primary: modelsPrimary, fallbacks: [] },
2284
- compaction: { mode: 'safeguard' },
2285
- timeoutSeconds: provider.isLocal ? 900 : 120,
2286
- ...(provider.isLocal ? { llm: { idleTimeoutSeconds: 300 } } : {}),
2287
- },
2288
- list: agentMetas.map((meta) => ({
2289
- id: meta.agentId,
2290
- name: meta.name,
2291
- workspace: `.openclaw/${meta.workspaceDir}`,
2292
- agentDir: `agents/${meta.agentId}/agent`,
2293
- model: { primary: modelsPrimary, fallbacks: [] },
2294
- })),
2295
- },
2296
- ...(providerKey === '9router' ? {
2297
- models: {
2298
- mode: 'merge',
2299
- providers: {
2300
- '9router': build9RouterProviderConfig(get9RouterBaseUrl(deployMode)),
2301
- },
2302
- },
2303
- } : provider.isLocal ? {
2304
- models: {
2305
- mode: 'merge',
2306
- providers: {
2307
- ollama: {
2308
- baseUrl: 'http://ollama:11434',
2309
- api: 'ollama',
2310
- apiKey: 'ollama-local',
2311
- models: OLLAMA_MODELS,
2312
- },
2313
- },
2314
- },
2315
- } : {}),
2316
- commands: { native: 'auto', nativeSkills: 'auto', restart: true, ownerDisplay: 'raw' },
2317
- bindings: agentMetas.map((meta) => ({
2318
- agentId: meta.agentId,
2319
- match: { channel: 'telegram', accountId: meta.accountId },
2320
- })),
2321
- channels: {
2322
- telegram: telegramChannelConfig,
2323
- },
2324
- tools: {
2325
- profile: 'full',
2326
- exec: { host: 'gateway', security: 'full', ask: 'off' },
2327
- agentToAgent: {
2328
- enabled: true,
2329
- allow: agentMetas.map((meta) => meta.agentId),
2330
- },
2331
- },
2332
- gateway: {
2333
- port: 18791,
2334
- mode: 'local',
2335
- bind: 'custom',
2336
- customBindHost: '0.0.0.0',
2337
- controlUi: {
2338
- allowedOrigins: getGatewayAllowedOrigins(18791),
2339
- },
2340
- auth: { mode: 'token', token: 'cli-dummy-token-xyz123' },
2341
- },
2342
- };
2343
- sharedConfig.plugins = { entries: {} };
2344
-
2345
- if (hasBrowserDesktop) {
2346
- sharedConfig.browser = {
2347
- enabled: true,
2348
- defaultProfile: 'host-chrome',
2349
- profiles: { 'host-chrome': { cdpUrl: 'http://127.0.0.1:9222', color: '#4285F4' } },
2350
- };
2351
- } else if (hasBrowserServer) {
2352
- sharedConfig.browser = { enabled: true };
2353
- }
2354
- if (Object.keys(skillEntries).length > 0) {
2355
- sharedConfig.skills = { entries: skillEntries };
2356
- }
2357
-
2358
2271
  await fs.writeJson(path.join(rootClawDir, 'openclaw.json'), sharedConfig, { spaces: 2 });
2359
2272
  await fs.writeFile(
2360
2273
  path.join(projectDir, TELEGRAM_SETUP_GUIDE_FILENAME),
@@ -2408,14 +2321,7 @@ async function main() {
2408
2321
  await fs.writeJson(path.join(rootClawDir, 'auth-profiles.json'), authProfilesJson, { spaces: 2 });
2409
2322
  }
2410
2323
 
2411
- const execApprovalsConfig = {
2412
- version: 1,
2413
- defaults: { security: 'full', ask: 'off', askFallback: 'full' },
2414
- agents: Object.fromEntries([
2415
- ['main', { security: 'full', ask: 'off', askFallback: 'full', autoAllowSkills: true }],
2416
- ...agentMetas.map((meta) => [meta.agentId, { security: 'full', ask: 'off', askFallback: 'full', autoAllowSkills: true }]),
2417
- ]),
2418
- };
2324
+ const execApprovalsConfig = buildExecApprovalsJson({ agentMetas });
2419
2325
  await fs.writeJson(path.join(rootClawDir, 'exec-approvals.json'), execApprovalsConfig, { spaces: 2 });
2420
2326
 
2421
2327
  const teamMdRoster = agentMetas.map((meta) => ({
@@ -2477,114 +2383,30 @@ async function main() {
2477
2383
  }
2478
2384
 
2479
2385
 
2480
- const botConfig = {
2481
- meta: { lastTouchedVersion: '2026.3.24' },
2482
- agents: {
2483
- defaults: {
2484
- model: { primary: modelsPrimary, fallbacks: [] },
2485
- compaction: { mode: 'safeguard' },
2486
- timeoutSeconds: provider.isLocal ? 900 : 120,
2487
- ...(provider.isLocal ? { llm: { idleTimeoutSeconds: 300 } } : {}),
2488
- },
2489
- list: [{
2490
- id: loopAgentId,
2491
- workspace: `.openclaw/${loopWorkspaceDir}`,
2492
- agentDir: `agents/${loopAgentId}/agent`,
2493
- model: { primary: modelsPrimary, fallbacks: [] }
2494
- }]
2495
- },
2496
- ...(providerKey === '9router' ? {
2497
- models: {
2498
- mode: 'merge',
2499
- providers: {
2500
- '9router': build9RouterProviderConfig(get9RouterBaseUrl(deployMode))
2501
- }
2502
- }
2503
- } : provider.isLocal ? {
2504
- models: {
2505
- mode: 'merge',
2506
- providers: {
2507
- ollama: {
2508
- baseUrl: 'http://ollama:11434',
2509
- api: 'ollama',
2510
- apiKey: 'ollama-local',
2511
- models: OLLAMA_MODELS
2512
- }
2513
- }
2514
- }
2515
- } : {}),
2516
- commands: { native: 'auto', nativeSkills: 'auto', restart: true, ownerDisplay: 'raw' },
2517
- channels: {},
2518
- tools: { profile: 'full', exec: { host: 'gateway', security: 'full', ask: 'off' } },
2519
- gateway: {
2520
- port: 18791 + (isMultiBot ? bIndex : 0), mode: 'local', bind: 'custom', customBindHost: '0.0.0.0',
2521
- controlUi: {
2522
- allowedOrigins: getGatewayAllowedOrigins(18791 + (isMultiBot ? bIndex : 0)),
2523
- },
2524
- auth: { mode: 'token', token: 'cli-dummy-token-xyz123' }
2525
- }
2526
- };
2527
-
2528
- if (hasBrowserDesktop) {
2529
- botConfig.browser = {
2530
- enabled: true,
2531
- defaultProfile: 'host-chrome',
2532
- profiles: { 'host-chrome': { cdpUrl: 'http://127.0.0.1:9222', color: '#4285F4' } }
2533
- };
2534
- } else if (hasBrowserServer) {
2535
- botConfig.browser = { enabled: true };
2536
- }
2537
-
2538
- const skillEntries = {};
2539
- SKILLS.forEach(s => {
2540
- if (!selectedSkills.includes(s.value)) return;
2541
- if (!s.slug) return;
2542
- skillEntries[s.slug] = { enabled: true };
2386
+ const loopGatewayPort = 18791 + (isMultiBot ? bIndex : 0);
2387
+ const botConfig = buildOpenclawJson({
2388
+ channelKey,
2389
+ deployMode,
2390
+ providerKey,
2391
+ provider,
2392
+ model: modelsPrimary,
2393
+ isMultiBot: false,
2394
+ agentMetas: [{
2395
+ agentId: loopAgentId,
2396
+ name: loopBotName,
2397
+ token: loopBotToken,
2398
+ workspaceDir: loopWorkspaceDir,
2399
+ }],
2400
+ groupId,
2401
+ selectedSkills,
2402
+ skills: SKILLS,
2403
+ hasBrowserDesktop,
2404
+ hasBrowserServer,
2405
+ gatewayPort: loopGatewayPort,
2406
+ gatewayAllowedOrigins: getGatewayAllowedOrigins(loopGatewayPort),
2407
+ osChoice,
2408
+ selectedModel: selectedOllamaModel,
2543
2409
  });
2544
- if (Object.keys(skillEntries).length > 0) {
2545
- botConfig.skills = { entries: skillEntries };
2546
- }
2547
-
2548
- if (channelKey === 'telegram') {
2549
- const telegramConfig = {
2550
- enabled: true,
2551
- dmPolicy: 'open',
2552
- allowFrom: ['*'],
2553
- defaultAccount: 'default',
2554
- replyToMode: 'first',
2555
- reactionLevel: 'minimal',
2556
- actions: {
2557
- sendMessage: true,
2558
- reactions: true,
2559
- },
2560
- accounts: {
2561
- default: {
2562
- botToken: loopBotToken || '<your_bot_token>',
2563
- },
2564
- },
2565
- };
2566
- if (isMultiBot) {
2567
- telegramConfig.groupPolicy = groupId ? 'allowlist' : 'open';
2568
- telegramConfig.groupAllowFrom = ['*'];
2569
- telegramConfig.groups = {
2570
- [groupId || '*']: { enabled: true, requireMention: false }
2571
- };
2572
- }
2573
- botConfig.channels['telegram'] = telegramConfig;
2574
- } else if (hasZaloPersonal(channelKey)) {
2575
- botConfig.channels['zalouser'] = {
2576
- enabled: true,
2577
- defaultAccount: 'default',
2578
- dmPolicy: 'open',
2579
- allowFrom: ['*'],
2580
- groupPolicy: 'allowlist',
2581
- groupAllowFrom: ['*'],
2582
- historyLimit: 50,
2583
- autoReply: true,
2584
- };
2585
- } else if (channelKey === 'zalo-bot') {
2586
- botConfig.channels['zalo'] = { enabled: true, provider: 'official_account' };
2587
- }
2588
2410
 
2589
2411
  await fs.writeJson(path.join(loopBotDir, '.openclaw', 'openclaw.json'), botConfig, { spaces: 2 });
2590
2412
 
@@ -56,6 +56,7 @@
56
56
  // 'telegram+zalo-personal' — Combo mode tạm ngưng, nghiên cứu thêm.
57
57
  'zalo-personal': {
58
58
  name: 'Zalo Personal',
59
+ hasZaloPersonal: true,
59
60
  envKeys: [],
60
61
  envExtra: '',
61
62
  credSteps: [