create-openclaw-bot 5.7.6 → 5.7.8
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 +9 -10
- package/README.vi.md +9 -10
- package/dist/cli.js +25 -27
- package/dist/setup/shared/bot-config-gen.js +10 -14
- package/dist/setup/shared/common-gen.js +1 -1
- package/dist/setup/shared/docker-gen.js +62 -47
- package/dist/setup.js +39 -36
- package/package.json +39 -39
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.7.
|
|
6
|
+
<a href="https://github.com/tuanminhhole/openclaw-setup/releases"><img src="https://img.shields.io/badge/RELEASE-v5.7.8-0EA5E9?style=for-the-badge" alt="Version 5.7.8" /></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,19 +24,18 @@ 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.7.
|
|
27
|
+
## 🆕 What's new in v5.7.8
|
|
28
28
|
|
|
29
|
-
-
|
|
30
|
-
-
|
|
29
|
+
- 🧹 **Zalo Mod Plugin Cleanup** — Removed auto-injection of `zalo-mod` into generated configs. The plugin now must be installed manually via ClawHub, eliminating persistent installation loops and Docker permission conflicts.
|
|
30
|
+
- 🔧 **Cleaner Docker Build** — `openclaw-zalo-mod` is no longer baked into the Docker image during build or runtime entrypoint, reducing image size and startup errors.
|
|
31
|
+
- 📝 **Standardized Release Workflow** — Added `.agent/workflows/update.md` as the canonical release checklist for this repo.
|
|
31
32
|
|
|
32
33
|
<details>
|
|
33
|
-
<summary><b>Previous: What's new in v5.7.
|
|
34
|
+
<summary><b>Previous: What's new in v5.7.7</b></summary>
|
|
34
35
|
|
|
35
|
-
-
|
|
36
|
-
-
|
|
37
|
-
-
|
|
38
|
-
- 🐛 **Removed `autoReply` bug** — The `autoReply: true` field that caused gateway startup crashes on Zalo Personal has been permanently removed from all generators.
|
|
39
|
-
- 💬 **Standardized Zalo Personal config** — Zalo Personal (`zalouser`) channel now uses production-matching config with `groups`, `groupPolicy`, `historyLimit`, and proper `bindings`.
|
|
36
|
+
- 🛠️ **Infrastructure & Zalo Bot Stabilization** — Automatically pins `openclaw@2026.4.15` across all deployment scripts, eliminating gateway crashes caused by version mismatch when installing Zalo Personal.
|
|
37
|
+
- 📦 **Docker Volume & Gateway Deadlock Optimization** — Redesigned the `.openclaw` mount mechanism and implemented `tmpfs` for `plugin-runtime-deps`, preventing I/O lock conditions on Windows/WSL2.
|
|
38
|
+
- 🔄 **9Router Smart-Sync** — Automatically detects and syncs models (Gemini, Claude, GPT) from active AI providers directly into the `smart-route` combination every time the system starts up.
|
|
40
39
|
|
|
41
40
|
## </details>
|
|
42
41
|
|
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.7.
|
|
6
|
+
<a href="https://github.com/tuanminhhole/openclaw-setup/releases"><img src="https://img.shields.io/badge/RELEASE-v5.7.8-0EA5E9?style=for-the-badge" alt="Version 5.7.8" /></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,19 +24,18 @@ 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.7.
|
|
27
|
+
## 🆕 Có gì mới trong v5.7.8
|
|
28
28
|
|
|
29
|
-
-
|
|
30
|
-
-
|
|
29
|
+
- 🧹 **Dọn dẹp Plugin Zalo Mod** — Gỡ bỏ auto-inject `zalo-mod` khỏi config được generate. Plugin giờ phải cài thủ công qua ClawHub, loại bỏ vòng lặp cài đặt liên tục và xung đột quyền trong Docker.
|
|
30
|
+
- 🔧 **Docker Build Sạch Hơn** — `openclaw-zalo-mod` không còn được nhúng vào Docker image khi build hoặc trong entrypoint runtime, giảm kích thước image và lỗi khởi động.
|
|
31
|
+
- 📝 **Chuẩn Hóa Workflow Release** — Thêm `.agent/workflows/update.md` làm checklist release chuẩn cho repo này.
|
|
31
32
|
|
|
32
33
|
<details>
|
|
33
|
-
<summary><b>Trước đó: Có gì mới ở v5.7.
|
|
34
|
+
<summary><b>Trước đó: Có gì mới ở v5.7.7</b></summary>
|
|
34
35
|
|
|
35
|
-
-
|
|
36
|
-
-
|
|
37
|
-
-
|
|
38
|
-
- 🐛 **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.
|
|
39
|
-
- 💬 **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.
|
|
36
|
+
- 🛠️ **Ổn Định Infrastructure & Zalo Bot** — Tự động ghim `openclaw@2026.4.15` cho mọi nền tảng, loại bỏ hoàn toàn các lỗi crash do lệch version khi cài Zalo Personal.
|
|
37
|
+
- 📦 **Tối Ưu Docker Volume & Gateway Deadlock** — Thiết kế lại cơ chế mount thư mục `.openclaw` và triển khai `tmpfs` cho `plugin-runtime-deps`, triệt để ngăn chặn tình trạng I/O lock trên Windows/WSL2.
|
|
38
|
+
- 🔄 **9Router Smart-Sync** — Tự động nhận diện và đồng bộ danh sách models (Gemini, Claude, GPT) từ các AI provider đang kích hoạt trực tiếp vào combo `smart-route` mỗi khi khởi động hệ thống.
|
|
40
39
|
|
|
41
40
|
## </details>
|
|
42
41
|
|
package/dist/cli.js
CHANGED
|
@@ -488,14 +488,18 @@ async function patchProjectDocker9Router(projectDir) {
|
|
|
488
488
|
await fs.writeFile(path.join(dockerDir, 'sync.js'), build9RouterSmartRouteSyncScript('/root/.9router/db.json'));
|
|
489
489
|
await fs.writeFile(path.join(dockerDir, 'patch-9router.js'), build9RouterPatchScript());
|
|
490
490
|
let compose = await fs.readFile(composePath, 'utf8');
|
|
491
|
-
compose = compose.replace(
|
|
492
|
-
/node -e "require\('fs'\)\.writeFileSync\('\/tmp\/sync\.js',Buffer\.from\('[^']*','base64'\)\.toString\(\)\)"/,
|
|
493
|
-
"cp /opt/sync.js /tmp/sync.js"
|
|
494
|
-
);
|
|
495
|
-
compose = compose.replace(
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
);
|
|
491
|
+
compose = compose.replace(
|
|
492
|
+
/node -e "require\('fs'\)\.writeFileSync\('\/tmp\/sync\.js',Buffer\.from\('[^']*','base64'\)\.toString\(\)\)"/,
|
|
493
|
+
"cp /opt/sync.js /tmp/sync.js"
|
|
494
|
+
);
|
|
495
|
+
compose = compose.replace(
|
|
496
|
+
/\s*node -e "require\('fs'\)\.writeFileSync\('\/tmp\/patch-9router\.js',Buffer\.from\('[^']*','base64'\)\.toString\(\)\)"\n/,
|
|
497
|
+
''
|
|
498
|
+
);
|
|
499
|
+
compose = compose.replace(
|
|
500
|
+
/(npm install -g [^\n]+\n)/,
|
|
501
|
+
`$1 cp /opt/patch-9router.js /tmp/patch-9router.js\n`
|
|
502
|
+
);
|
|
499
503
|
if (!compose.includes('node /tmp/patch-9router.js || true')) {
|
|
500
504
|
compose = compose.replace(
|
|
501
505
|
/(\s*node \/tmp\/sync\.js > \/tmp\/sync\.log 2>&1 &\n)/,
|
|
@@ -2158,20 +2162,16 @@ async function main() {
|
|
|
2158
2162
|
|
|
2159
2163
|
|
|
2160
2164
|
// ── Docker artifacts: Dockerfile + docker-compose via shared buildDockerArtifacts() ──────
|
|
2161
|
-
const skillSlugs = SKILLS
|
|
2162
|
-
.filter(s => selectedSkills.includes(s.value) && s.slug)
|
|
2163
|
-
.map(s => s.slug);
|
|
2164
|
-
const skillInstallCmd = skillSlugs.length > 0
|
|
2165
|
-
? skillSlugs.map(s => `
|
|
2166
|
-
: '';
|
|
2165
|
+
const skillSlugs = SKILLS
|
|
2166
|
+
.filter(s => selectedSkills.includes(s.value) && s.slug)
|
|
2167
|
+
.map(s => s.slug);
|
|
2168
|
+
const skillInstallCmd = skillSlugs.length > 0
|
|
2169
|
+
? skillSlugs.map(s => `ensure_skill ${s}`).join('\n')
|
|
2170
|
+
: '';
|
|
2167
2171
|
const relayInstallCmd = (isMultiBot && channelKey === 'telegram')
|
|
2168
2172
|
? buildRelayPluginInstallCommand('openclaw')
|
|
2169
2173
|
: '';
|
|
2170
|
-
const
|
|
2171
|
-
? 'openclaw plugins install openclaw-zalo-mod 2>/dev/null || true'
|
|
2172
|
-
: '';
|
|
2173
|
-
const socatBridge = hasBrowserDesktop ? 'socat TCP-LISTEN:9222,fork,reuseaddr TCP:host.docker.internal:9222 &' : '';
|
|
2174
|
-
const deviceApproveLoop = 'while true; do sleep 5; openclaw devices approve --latest 2>/dev/null || true; done >/dev/null 2>&1 &';
|
|
2174
|
+
const deviceApproveLoop = 'while true; do sleep 5; openclaw devices approve --latest 2>/dev/null || true; done >/dev/null 2>&1 &';
|
|
2175
2175
|
|
|
2176
2176
|
// buildDockerArtifacts joins runtimeCommandParts with spaces, then appends 'openclaw gateway run'
|
|
2177
2177
|
// Each part should be a standalone command fragment (no trailing &&)
|
|
@@ -2183,14 +2183,12 @@ async function main() {
|
|
|
2183
2183
|
isMultiBot,
|
|
2184
2184
|
hasBrowser: hasBrowserDesktop || hasBrowserServer,
|
|
2185
2185
|
selectedModel: modelsPrimary,
|
|
2186
|
-
agentId,
|
|
2187
|
-
runtimeCommandParts: [
|
|
2188
|
-
|
|
2189
|
-
|
|
2190
|
-
|
|
2191
|
-
|
|
2192
|
-
deviceApproveLoop,
|
|
2193
|
-
].filter(Boolean),
|
|
2186
|
+
agentId,
|
|
2187
|
+
runtimeCommandParts: [
|
|
2188
|
+
relayInstallCmd,
|
|
2189
|
+
skillInstallCmd,
|
|
2190
|
+
deviceApproveLoop,
|
|
2191
|
+
].filter(Boolean),
|
|
2194
2192
|
volumeMount: '../..:/root/project',
|
|
2195
2193
|
singleComposeName: `oc-${agentId}`,
|
|
2196
2194
|
multiComposeName: 'oc-multibot',
|
|
@@ -261,6 +261,14 @@
|
|
|
261
261
|
channels.zalouser = {
|
|
262
262
|
enabled: true,
|
|
263
263
|
defaultAccount: 'default',
|
|
264
|
+
accounts: {
|
|
265
|
+
default: {
|
|
266
|
+
dmPolicy: 'open',
|
|
267
|
+
allowFrom: ['*'],
|
|
268
|
+
groupPolicy: 'allowlist',
|
|
269
|
+
groupAllowFrom: ['*'],
|
|
270
|
+
},
|
|
271
|
+
},
|
|
264
272
|
dmPolicy: 'open',
|
|
265
273
|
allowFrom: ['*'],
|
|
266
274
|
groupPolicy: 'allowlist',
|
|
@@ -297,21 +305,9 @@
|
|
|
297
305
|
|
|
298
306
|
const allow = ['memory-core'];
|
|
299
307
|
|
|
300
|
-
// zalo-mod
|
|
308
|
+
// Zalo Personal channel is native; install openclaw-zalo-mod manually via ClawHub when needed.
|
|
301
309
|
if (isZaloPersonal(channelKey)) {
|
|
302
|
-
allow.push('
|
|
303
|
-
entries['zalo-mod'] = {
|
|
304
|
-
enabled: true,
|
|
305
|
-
config: {
|
|
306
|
-
botName: botName,
|
|
307
|
-
groupNames: {},
|
|
308
|
-
zaloDisplayNames: [botName],
|
|
309
|
-
welcomeEnabled: true,
|
|
310
|
-
spamRepeatN: 3,
|
|
311
|
-
spamWindowSeconds: 300,
|
|
312
|
-
},
|
|
313
|
-
};
|
|
314
|
-
entries.zalouser = { enabled: true };
|
|
310
|
+
allow.push('zalouser');
|
|
315
311
|
}
|
|
316
312
|
|
|
317
313
|
const plugins = { entries };
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
// @ts-nocheck
|
|
2
2
|
(function (root) {
|
|
3
|
-
const OPENCLAW_NPM_SPEC = 'openclaw@
|
|
3
|
+
const OPENCLAW_NPM_SPEC = 'openclaw@2026.4.15';
|
|
4
4
|
const OPENCLAW_RUNTIME_PACKAGES = 'grammy @grammyjs/runner @grammyjs/transformer-throttler @buape/carbon @larksuiteoapi/node-sdk @slack/web-api';
|
|
5
5
|
const NINE_ROUTER_NPM_SPEC = '9router@latest';
|
|
6
6
|
const NINE_ROUTER_PORT = 20128;
|
|
@@ -39,11 +39,26 @@ const sync = async () => {
|
|
|
39
39
|
if (!res.ok) { console.log('[sync-combo] API not ready, retrying...'); return; }
|
|
40
40
|
const d = await res.json();
|
|
41
41
|
const rawConnections = Array.isArray(d.connections) ? d.connections : Array.isArray(d.providerConnections) ? d.providerConnections : [];
|
|
42
|
-
const
|
|
43
|
-
|
|
42
|
+
const activeConns = rawConnections.filter(c => c && c.provider && c.isActive !== false && !c.disabled);
|
|
43
|
+
const a = [...new Set(activeConns.map(c => c.provider))];
|
|
44
|
+
if (!a.length) { console.log('[sync-combo] No active providers reported; keeping existing smart-route'); return; }
|
|
44
45
|
a.sort((x, y) => (PREF.indexOf(x) === -1 ? 99 : PREF.indexOf(x)) - (PREF.indexOf(y) === -1 ? 99 : PREF.indexOf(y)));
|
|
45
|
-
const m =
|
|
46
|
-
|
|
46
|
+
const m = [];
|
|
47
|
+
for (const pv of a) {
|
|
48
|
+
if (PM[pv]) m.push(...PM[pv]);
|
|
49
|
+
const conns = activeConns.filter(c => c.provider === pv);
|
|
50
|
+
for (const c of conns) {
|
|
51
|
+
if (Array.isArray(c.models)) {
|
|
52
|
+
for (const mdl of c.models) {
|
|
53
|
+
const mdlId = typeof mdl === 'string' ? mdl : mdl.id;
|
|
54
|
+
if (mdlId && !m.includes(mdlId) && !m.includes(pv + '/' + mdlId)) {
|
|
55
|
+
m.push(pv + '/' + mdlId);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
if (!m.length) { console.log('[sync-combo] No mapped models for active providers; keeping existing smart-route'); return; }
|
|
47
62
|
const c = { id: 'smart-route', name: 'smart-route', alias: 'smart-route', models: m };
|
|
48
63
|
const i = db.combos.findIndex(x => x.id === 'smart-route');
|
|
49
64
|
if (i >= 0) {
|
|
@@ -155,7 +170,7 @@ if(touched){console.log('[patch-9router] Applied Codex compatibility patch.');}e
|
|
|
155
170
|
dockerfilePlugins = [],
|
|
156
171
|
dockerfileSkillInstallMode = 'none',
|
|
157
172
|
runtimeCommandParts = [],
|
|
158
|
-
volumeMount = '
|
|
173
|
+
volumeMount = '../../.openclaw:/root/project/.openclaw\\n - ../../:/mnt/project',
|
|
159
174
|
singleComposeName = 'oc-bot',
|
|
160
175
|
multiComposeName = 'oc-multibot',
|
|
161
176
|
singleAppContainerName = 'openclaw-bot',
|
|
@@ -191,50 +206,50 @@ if(touched){console.log('[patch-9router] Applied Codex compatibility patch.');}e
|
|
|
191
206
|
: '';
|
|
192
207
|
const patchLine = `RUN node -e "const fs=require('fs');const path=require('path');const dir='/usr/local/lib/node_modules/openclaw/dist';const from='\\t\\t\\t\\t\\tonAgentRunStart: (runId) => {';const to='\\t\\t\\t\\t\\ttimeoutOverrideSeconds: Math.max(1, Math.ceil(timeoutMs / 1e3)),\\n\\t\\t\\t\\t\\tonAgentRunStart: (runId) => {';const files=fs.readdirSync(dir).filter(n=>/\\.js$/.test(n));let patched=0;for(const file of files){const p=path.join(dir,file);let s='';try{s=fs.readFileSync(p,'utf8');}catch{continue;}if(s.includes(to)||!s.includes(from))continue;s=s.replace(from,to);fs.writeFileSync(p,s);patched++;}if(!patched){process.exit(0);}"`;
|
|
193
208
|
|
|
194
|
-
// Dynamic runtime configuration: backup config before any first-run install, restore after.
|
|
195
|
-
// Missing plugin install may touch openclaw.json, so preserve critical fields.
|
|
209
|
+
// Dynamic runtime configuration: backup config before any first-run install, restore after.
|
|
210
|
+
// Missing plugin install may touch openclaw.json, so preserve critical fields.
|
|
196
211
|
const backupConfigScript = `const fs=require('fs'),path=require('path'),p=path.join(process.cwd(),'.openclaw','openclaw.json'),b=p.replace('openclaw.json','.openclaw-config-backup.json');if(fs.existsSync(p)){fs.copyFileSync(p,b);}`;
|
|
197
212
|
const backupConfigB64 = encodeBase64Utf8(backupConfigScript);
|
|
198
213
|
|
|
199
214
|
const restoreConfigScript = `const fs=require('fs'),os=require('os'),path=require('path'),p=path.join(process.cwd(),'.openclaw','openclaw.json'),b=p.replace('openclaw.json','.openclaw-config-backup.json');if(fs.existsSync(p)&&fs.existsSync(b)){const c=JSON.parse(fs.readFileSync(p,'utf8'));const bk=JSON.parse(fs.readFileSync(b,'utf8'));const keep=['agents','channels','bindings','commands','models','browser','skills'];for(const k of keep){if(bk[k]&&!c[k])c[k]=bk[k];}const a=new Set(['http://localhost:18791','http://127.0.0.1:18791','http://0.0.0.0:18791']);for(const entries of Object.values(os.networkInterfaces()||{})){for(const entry of entries||[]){if(!entry||entry.internal||entry.family!=='IPv4'||!entry.address)continue;a.add('http://'+entry.address+':18791');}}c.tools=Object.assign({},c.tools,{profile:'full',exec:{host:'gateway',security:'full',ask:'off'}});c.gateway=Object.assign({},c.gateway,{port:18791,bind:'custom',customBindHost:'0.0.0.0',mode:c.gateway?.mode||bk.gateway?.mode||'local',controlUi:Object.assign({},c.gateway?.controlUi,{allowedOrigins:Array.from(a).filter(Boolean)})});fs.writeFileSync(p,JSON.stringify(c,null,2));fs.unlinkSync(b);}`;
|
|
200
215
|
const restoreConfigB64 = encodeBase64Utf8(restoreConfigScript);
|
|
201
216
|
|
|
202
|
-
const runtimeParts = runtimeCommandParts.filter(Boolean);
|
|
203
|
-
const runtimePrelude = [
|
|
204
|
-
'export OPENCLAW_HOME="${OPENCLAW_HOME:-$PWD/.openclaw}"',
|
|
205
|
-
'export OPENCLAW_STATE_DIR="${OPENCLAW_STATE_DIR:-$OPENCLAW_HOME}"',
|
|
206
|
-
'mkdir -p "$OPENCLAW_HOME" "$OPENCLAW_STATE_DIR"',
|
|
207
|
-
'if [ "$OPENCLAW_STATE_DIR" != "$OPENCLAW_HOME" ]; then',
|
|
208
|
-
' for path in "$OPENCLAW_HOME"/*; do',
|
|
209
|
-
' [ -e "$path" ] || continue',
|
|
210
|
-
' name="$(basename "$path")"',
|
|
211
|
-
' [ "$name" = "plugin-runtime-deps" ] && continue',
|
|
212
|
-
' [ "$name" = "logs" ] && continue',
|
|
213
|
-
' [ -e "$OPENCLAW_STATE_DIR/$name" ] || ln -s "$path" "$OPENCLAW_STATE_DIR/$name"',
|
|
214
|
-
' done',
|
|
215
|
-
'fi',
|
|
216
|
-
'ensure_plugin() {',
|
|
217
|
-
' id="$1"',
|
|
218
|
-
' spec="$2"',
|
|
219
|
-
' if [ -d "$OPENCLAW_HOME/extensions/$id" ]; then',
|
|
220
|
-
' echo "[entrypoint] plugin $id already installed"',
|
|
221
|
-
' return 0',
|
|
222
|
-
' fi',
|
|
223
|
-
' echo "[entrypoint] plugin $id missing; installing $spec"',
|
|
224
|
-
' openclaw plugins install "$spec" 2>/dev/null || echo "[entrypoint] warning: failed to install plugin $spec"',
|
|
225
|
-
'}',
|
|
226
|
-
'ensure_skill() {',
|
|
227
|
-
' id="$1"',
|
|
228
|
-
' if find "$OPENCLAW_HOME" -maxdepth 4 -type d -path "*/skills/$id" -print -quit 2>/dev/null | grep -q .; then',
|
|
229
|
-
' echo "[entrypoint] skill $id already installed"',
|
|
230
|
-
' return 0',
|
|
231
|
-
' fi',
|
|
232
|
-
' echo "[entrypoint] skill $id missing; installing"',
|
|
233
|
-
' openclaw skills install "$id" 2>/dev/null || echo "[entrypoint] warning: failed to install skill $id"',
|
|
234
|
-
'}',
|
|
235
|
-
'echo "[entrypoint] ensuring runtime assets, then starting gateway"',
|
|
236
|
-
];
|
|
237
|
-
runtimeParts.unshift(...runtimePrelude);
|
|
217
|
+
const runtimeParts = runtimeCommandParts.filter(Boolean);
|
|
218
|
+
const runtimePrelude = [
|
|
219
|
+
'export OPENCLAW_HOME="${OPENCLAW_HOME:-$PWD/.openclaw}"',
|
|
220
|
+
'export OPENCLAW_STATE_DIR="${OPENCLAW_STATE_DIR:-$OPENCLAW_HOME}"',
|
|
221
|
+
'mkdir -p "$OPENCLAW_HOME" "$OPENCLAW_STATE_DIR"',
|
|
222
|
+
'if [ "$OPENCLAW_STATE_DIR" != "$OPENCLAW_HOME" ]; then',
|
|
223
|
+
' for path in "$OPENCLAW_HOME"/*; do',
|
|
224
|
+
' [ -e "$path" ] || continue',
|
|
225
|
+
' name="$(basename "$path")"',
|
|
226
|
+
' [ "$name" = "plugin-runtime-deps" ] && continue',
|
|
227
|
+
' [ "$name" = "logs" ] && continue',
|
|
228
|
+
' [ -e "$OPENCLAW_STATE_DIR/$name" ] || ln -s "$path" "$OPENCLAW_STATE_DIR/$name"',
|
|
229
|
+
' done',
|
|
230
|
+
'fi',
|
|
231
|
+
'ensure_plugin() {',
|
|
232
|
+
' id="$1"',
|
|
233
|
+
' spec="$2"',
|
|
234
|
+
' if [ -d "$OPENCLAW_HOME/extensions/$id" ]; then',
|
|
235
|
+
' echo "[entrypoint] plugin $id already installed"',
|
|
236
|
+
' return 0',
|
|
237
|
+
' fi',
|
|
238
|
+
' echo "[entrypoint] plugin $id missing; installing $spec"',
|
|
239
|
+
' openclaw plugins install "$spec" 2>/dev/null || echo "[entrypoint] warning: failed to install plugin $spec"',
|
|
240
|
+
'}',
|
|
241
|
+
'ensure_skill() {',
|
|
242
|
+
' id="$1"',
|
|
243
|
+
' if find "$OPENCLAW_HOME" -maxdepth 4 -type d -path "*/skills/$id" -print -quit 2>/dev/null | grep -q .; then',
|
|
244
|
+
' echo "[entrypoint] skill $id already installed"',
|
|
245
|
+
' return 0',
|
|
246
|
+
' fi',
|
|
247
|
+
' echo "[entrypoint] skill $id missing; installing"',
|
|
248
|
+
' openclaw skills install "$id" 2>/dev/null || echo "[entrypoint] warning: failed to install skill $id"',
|
|
249
|
+
'}',
|
|
250
|
+
'echo "[entrypoint] ensuring runtime assets, then starting gateway"',
|
|
251
|
+
];
|
|
252
|
+
runtimeParts.unshift(...runtimePrelude);
|
|
238
253
|
// Backup config BEFORE plugin installs (runtimeCommandParts may contain plugin install commands)
|
|
239
254
|
runtimeParts.unshift(`node -e 'eval(Buffer.from("${backupConfigB64}","base64").toString())'`);
|
|
240
255
|
// Restore config AFTER plugin installs (which may clobber openclaw.json)
|
|
@@ -253,7 +268,7 @@ RUN apt-get update && apt-get install -y git curl${browserAptExtra} && rm -rf /v
|
|
|
253
268
|
${browserInstallLines}
|
|
254
269
|
ARG OPENCLAW_VER="${openClawNpmSpec}"
|
|
255
270
|
ARG CACHE_BUST=""
|
|
256
|
-
RUN npm install -g $
|
|
271
|
+
RUN echo "CACHE_BUST=$CACHE_BUST" && npm install -g $OPENCLAW_VER ${openClawRuntimePackages}${skillLines}${pluginLines}
|
|
257
272
|
${patchLine}
|
|
258
273
|
RUN node -e "require('fs').writeFileSync('/usr/local/bin/openclaw-entrypoint.sh', Buffer.from('${runtimeScriptB64}','base64').toString())" && chmod +x /usr/local/bin/openclaw-entrypoint.sh
|
|
259
274
|
WORKDIR /root/project
|
|
@@ -264,12 +279,12 @@ CMD ["/bin/sh", "/usr/local/bin/openclaw-entrypoint.sh"]`;
|
|
|
264
279
|
|
|
265
280
|
const syncScript = build9RouterSmartRouteSyncScript('/root/.9router/db.json');
|
|
266
281
|
const syncScriptBase64 = encodeBase64Utf8(syncScript);
|
|
267
|
-
|
|
282
|
+
const patchScript = build9RouterPatchScript();
|
|
268
283
|
const patchScriptBase64 = encodeBase64Utf8(patchScript);
|
|
269
284
|
const docker9RouterEntrypointScript = build9RouterComposeEntrypointScript(syncScriptBase64, patchScriptBase64);
|
|
270
285
|
const extraHostsBlock = ` extra_hosts:\n - "host.docker.internal:host-gateway"`;
|
|
271
286
|
|
|
272
|
-
const appEnvironmentBlock = ' environment:\n - OPENCLAW_HOME=/root/project/.openclaw\n - OPENCLAW_STATE_DIR=/root/project/.openclaw\n';
|
|
287
|
+
const appEnvironmentBlock = ' environment:\n - OPENCLAW_HOME=/root/project/.openclaw\n - OPENCLAW_STATE_DIR=/root/project/.openclaw\n - OPENCLAW_ALLOW_INSECURE_PRIVATE_WS=1\n tmpfs:\n - /root/project/.openclaw/plugin-runtime-deps\n';
|
|
273
288
|
|
|
274
289
|
let compose;
|
|
275
290
|
if (isMultiBot) {
|
|
@@ -462,7 +477,7 @@ ${appEnvironmentBlock}${plainSingleExtraHosts ? `${extraHostsBlock}\n` : ''}
|
|
|
462
477
|
- "18791:18791"`;
|
|
463
478
|
}
|
|
464
479
|
|
|
465
|
-
return {
|
|
480
|
+
return {
|
|
466
481
|
dockerfile,
|
|
467
482
|
compose,
|
|
468
483
|
syncScript,
|
package/dist/setup.js
CHANGED
|
@@ -619,7 +619,7 @@
|
|
|
619
619
|
// ── Shared runtime constants, relay helpers, auth profile builders (setup/shared/common-gen.js)
|
|
620
620
|
// @ts-nocheck
|
|
621
621
|
(function (root) {
|
|
622
|
-
const OPENCLAW_NPM_SPEC = 'openclaw@
|
|
622
|
+
const OPENCLAW_NPM_SPEC = 'openclaw@2026.4.15';
|
|
623
623
|
const OPENCLAW_RUNTIME_PACKAGES = 'grammy @grammyjs/runner @grammyjs/transformer-throttler @buape/carbon @larksuiteoapi/node-sdk @slack/web-api';
|
|
624
624
|
const NINE_ROUTER_NPM_SPEC = '9router@latest';
|
|
625
625
|
const NINE_ROUTER_PORT = 20128;
|
|
@@ -1699,6 +1699,14 @@ if (typeof exports !== 'undefined' && workspaceRoot.__openclawWorkspace) {
|
|
|
1699
1699
|
channels.zalouser = {
|
|
1700
1700
|
enabled: true,
|
|
1701
1701
|
defaultAccount: 'default',
|
|
1702
|
+
accounts: {
|
|
1703
|
+
default: {
|
|
1704
|
+
dmPolicy: 'open',
|
|
1705
|
+
allowFrom: ['*'],
|
|
1706
|
+
groupPolicy: 'allowlist',
|
|
1707
|
+
groupAllowFrom: ['*'],
|
|
1708
|
+
},
|
|
1709
|
+
},
|
|
1702
1710
|
dmPolicy: 'open',
|
|
1703
1711
|
allowFrom: ['*'],
|
|
1704
1712
|
groupPolicy: 'allowlist',
|
|
@@ -1735,21 +1743,9 @@ if (typeof exports !== 'undefined' && workspaceRoot.__openclawWorkspace) {
|
|
|
1735
1743
|
|
|
1736
1744
|
const allow = ['memory-core'];
|
|
1737
1745
|
|
|
1738
|
-
// zalo-mod
|
|
1746
|
+
// Zalo Personal channel is native; install openclaw-zalo-mod manually via ClawHub when needed.
|
|
1739
1747
|
if (isZaloPersonal(channelKey)) {
|
|
1740
|
-
allow.push('
|
|
1741
|
-
entries['zalo-mod'] = {
|
|
1742
|
-
enabled: true,
|
|
1743
|
-
config: {
|
|
1744
|
-
botName: botName,
|
|
1745
|
-
groupNames: {},
|
|
1746
|
-
zaloDisplayNames: [botName],
|
|
1747
|
-
welcomeEnabled: true,
|
|
1748
|
-
spamRepeatN: 3,
|
|
1749
|
-
spamWindowSeconds: 300,
|
|
1750
|
-
},
|
|
1751
|
-
};
|
|
1752
|
-
entries.zalouser = { enabled: true };
|
|
1748
|
+
allow.push('zalouser');
|
|
1753
1749
|
}
|
|
1754
1750
|
|
|
1755
1751
|
const plugins = { entries };
|
|
@@ -2513,11 +2509,26 @@ const sync = async () => {
|
|
|
2513
2509
|
if (!res.ok) { console.log('[sync-combo] API not ready, retrying...'); return; }
|
|
2514
2510
|
const d = await res.json();
|
|
2515
2511
|
const rawConnections = Array.isArray(d.connections) ? d.connections : Array.isArray(d.providerConnections) ? d.providerConnections : [];
|
|
2516
|
-
const
|
|
2517
|
-
|
|
2512
|
+
const activeConns = rawConnections.filter(c => c && c.provider && c.isActive !== false && !c.disabled);
|
|
2513
|
+
const a = [...new Set(activeConns.map(c => c.provider))];
|
|
2514
|
+
if (!a.length) { console.log('[sync-combo] No active providers reported; keeping existing smart-route'); return; }
|
|
2518
2515
|
a.sort((x, y) => (PREF.indexOf(x) === -1 ? 99 : PREF.indexOf(x)) - (PREF.indexOf(y) === -1 ? 99 : PREF.indexOf(y)));
|
|
2519
|
-
const m =
|
|
2520
|
-
|
|
2516
|
+
const m = [];
|
|
2517
|
+
for (const pv of a) {
|
|
2518
|
+
if (PM[pv]) m.push(...PM[pv]);
|
|
2519
|
+
const conns = activeConns.filter(c => c.provider === pv);
|
|
2520
|
+
for (const c of conns) {
|
|
2521
|
+
if (Array.isArray(c.models)) {
|
|
2522
|
+
for (const mdl of c.models) {
|
|
2523
|
+
const mdlId = typeof mdl === 'string' ? mdl : mdl.id;
|
|
2524
|
+
if (mdlId && !m.includes(mdlId) && !m.includes(pv + '/' + mdlId)) {
|
|
2525
|
+
m.push(pv + '/' + mdlId);
|
|
2526
|
+
}
|
|
2527
|
+
}
|
|
2528
|
+
}
|
|
2529
|
+
}
|
|
2530
|
+
}
|
|
2531
|
+
if (!m.length) { console.log('[sync-combo] No mapped models for active providers; keeping existing smart-route'); return; }
|
|
2521
2532
|
const c = { id: 'smart-route', name: 'smart-route', alias: 'smart-route', models: m };
|
|
2522
2533
|
const i = db.combos.findIndex(x => x.id === 'smart-route');
|
|
2523
2534
|
if (i >= 0) {
|
|
@@ -2629,7 +2640,7 @@ if(touched){console.log('[patch-9router] Applied Codex compatibility patch.');}e
|
|
|
2629
2640
|
dockerfilePlugins = [],
|
|
2630
2641
|
dockerfileSkillInstallMode = 'none',
|
|
2631
2642
|
runtimeCommandParts = [],
|
|
2632
|
-
volumeMount = '
|
|
2643
|
+
volumeMount = '../../.openclaw:/root/project/.openclaw\\n - ../../:/mnt/project',
|
|
2633
2644
|
singleComposeName = 'oc-bot',
|
|
2634
2645
|
multiComposeName = 'oc-multibot',
|
|
2635
2646
|
singleAppContainerName = 'openclaw-bot',
|
|
@@ -2727,7 +2738,7 @@ RUN apt-get update && apt-get install -y git curl${browserAptExtra} && rm -rf /v
|
|
|
2727
2738
|
${browserInstallLines}
|
|
2728
2739
|
ARG OPENCLAW_VER="${openClawNpmSpec}"
|
|
2729
2740
|
ARG CACHE_BUST=""
|
|
2730
|
-
RUN npm install -g $
|
|
2741
|
+
RUN echo "CACHE_BUST=$CACHE_BUST" && npm install -g $OPENCLAW_VER ${openClawRuntimePackages}${skillLines}${pluginLines}
|
|
2731
2742
|
${patchLine}
|
|
2732
2743
|
RUN node -e "require('fs').writeFileSync('/usr/local/bin/openclaw-entrypoint.sh', Buffer.from('${runtimeScriptB64}','base64').toString())" && chmod +x /usr/local/bin/openclaw-entrypoint.sh
|
|
2733
2744
|
WORKDIR /root/project
|
|
@@ -2738,12 +2749,12 @@ CMD ["/bin/sh", "/usr/local/bin/openclaw-entrypoint.sh"]`;
|
|
|
2738
2749
|
|
|
2739
2750
|
const syncScript = build9RouterSmartRouteSyncScript('/root/.9router/db.json');
|
|
2740
2751
|
const syncScriptBase64 = encodeBase64Utf8(syncScript);
|
|
2741
|
-
|
|
2752
|
+
const patchScript = build9RouterPatchScript();
|
|
2742
2753
|
const patchScriptBase64 = encodeBase64Utf8(patchScript);
|
|
2743
2754
|
const docker9RouterEntrypointScript = build9RouterComposeEntrypointScript(syncScriptBase64, patchScriptBase64);
|
|
2744
2755
|
const extraHostsBlock = ` extra_hosts:\n - "host.docker.internal:host-gateway"`;
|
|
2745
2756
|
|
|
2746
|
-
const appEnvironmentBlock = ' environment:\n - OPENCLAW_HOME=/root/project/.openclaw\n - OPENCLAW_STATE_DIR=/root/project/.openclaw\n';
|
|
2757
|
+
const appEnvironmentBlock = ' environment:\n - OPENCLAW_HOME=/root/project/.openclaw\n - OPENCLAW_STATE_DIR=/root/project/.openclaw\n - OPENCLAW_ALLOW_INSECURE_PRIVATE_WS=1\n tmpfs:\n - /root/project/.openclaw/plugin-runtime-deps\n';
|
|
2747
2758
|
|
|
2748
2759
|
let compose;
|
|
2749
2760
|
if (isMultiBot) {
|
|
@@ -2996,7 +3007,6 @@ function buildNativeScriptCtx(options) {
|
|
|
2996
3007
|
const p = PLUGINS.find((x) => x.id === pid);
|
|
2997
3008
|
if (p) allPlugins.push(p.package);
|
|
2998
3009
|
});
|
|
2999
|
-
if (ch && ch.hasZaloPersonal) allPlugins.push('openclaw-zalo-mod');
|
|
3000
3010
|
if (isMultiBot && state.channel === 'telegram') allPlugins.push(relayPluginSpec);
|
|
3001
3011
|
const uniquePlugins = [...new Set(allPlugins)];
|
|
3002
3012
|
const pluginCmd = uniquePlugins.length > 0 ? uniquePlugins.map(function(pkg) { return 'call npm exec -- openclaw plugins install ' + pkg + ' || echo [WARN] Plugin ' + pkg + ' cai dat that bai (co the do rate limit). Ban co the cai thu cong sau.'; }).join('\r\n') : '';
|
|
@@ -3963,7 +3973,7 @@ function generateWinBat(ctx) {
|
|
|
3963
3973
|
'echo [1/5] Kiem tra Node.js...',
|
|
3964
3974
|
'where node >nul 2>&1 || (echo ERROR: Node.js chua cai! Tai tai: https://nodejs.org && pause && exit /b 1)',
|
|
3965
3975
|
'echo [2/5] Cai OpenClaw CLI...',
|
|
3966
|
-
`call npm install -g
|
|
3976
|
+
`call npm install -g ${OPENCLAW_NPM_SPEC} ${openClawRuntimePackages} || goto :fail`,
|
|
3967
3977
|
'echo [OK] OpenClaw da duoc cai dat thanh cong.',
|
|
3968
3978
|
];
|
|
3969
3979
|
|
|
@@ -4153,7 +4163,7 @@ function generateMacOsSh(ctx) {
|
|
|
4153
4163
|
'grep -Fqx \'export PATH="$HOME/.local/bin:$PATH"\' "$HOME/.zshrc" 2>/dev/null || echo \'export PATH="$HOME/.local/bin:$PATH"\' >> "$HOME/.zshrc"',
|
|
4154
4164
|
'grep -Fqx \'export PATH="$HOME/.local/bin:$PATH"\' "$HOME/.profile" 2>/dev/null || echo \'export PATH="$HOME/.local/bin:$PATH"\' >> "$HOME/.profile"',
|
|
4155
4165
|
'# Install openclaw (user-local first, sudo fallback)',
|
|
4156
|
-
`npm install -g
|
|
4166
|
+
`npm install -g ${OPENCLAW_NPM_SPEC} ${openClawRuntimePackages} || sudo npm install -g ${OPENCLAW_NPM_SPEC} ${openClawRuntimePackages}`,
|
|
4157
4167
|
];
|
|
4158
4168
|
providerLines(sh, 'sh');
|
|
4159
4169
|
if (pluginCmd) sh.push(pluginCmd);
|
|
@@ -4219,7 +4229,7 @@ function generateVpsSh(ctx) {
|
|
|
4219
4229
|
'export DATA_DIR="$PROJECT_DIR/.9router"',
|
|
4220
4230
|
'grep -Fqx \'export PATH="$HOME/.local/bin:$PATH"\' "$HOME/.bashrc" 2>/dev/null || echo \'export PATH="$HOME/.local/bin:$PATH"\' >> "$HOME/.bashrc"',
|
|
4221
4231
|
'grep -Fqx \'export PATH="$HOME/.local/bin:$PATH"\' "$HOME/.profile" 2>/dev/null || echo \'export PATH="$HOME/.local/bin:$PATH"\' >> "$HOME/.profile"',
|
|
4222
|
-
`npm install -g
|
|
4232
|
+
`npm install -g ${OPENCLAW_NPM_SPEC} ${openClawRuntimePackages} pm2@latest`,
|
|
4223
4233
|
];
|
|
4224
4234
|
providerLines(vps, 'sh');
|
|
4225
4235
|
if (pluginCmd) vps.push(pluginCmd);
|
|
@@ -4342,7 +4352,7 @@ function generateLinuxSh(ctx) {
|
|
|
4342
4352
|
'export DATA_DIR="$PROJECT_DIR/.9router"',
|
|
4343
4353
|
'grep -Fqx \'export PATH="$HOME/.local/bin:$PATH"\' "$HOME/.bashrc" 2>/dev/null || echo \'export PATH="$HOME/.local/bin:$PATH"\' >> "$HOME/.bashrc"',
|
|
4344
4354
|
'grep -Fqx \'export PATH="$HOME/.local/bin:$PATH"\' "$HOME/.profile" 2>/dev/null || echo \'export PATH="$HOME/.local/bin:$PATH"\' >> "$HOME/.profile"',
|
|
4345
|
-
`npm install -g
|
|
4355
|
+
`npm install -g ${OPENCLAW_NPM_SPEC} ${openClawRuntimePackages}`,
|
|
4346
4356
|
];
|
|
4347
4357
|
providerLines(lnx, 'sh');
|
|
4348
4358
|
if (pluginCmd) lnx.push(pluginCmd);
|
|
@@ -5832,7 +5842,6 @@ Write-Host "Chrome se tu dong bat Debug Mode moi khi ban dang nhap Windows (dela
|
|
|
5832
5842
|
};
|
|
5833
5843
|
clawConfig.plugins = {
|
|
5834
5844
|
entries: {
|
|
5835
|
-
...(ch.hasZaloPersonal ? { 'zalo-mod': { enabled: true, config: {} } } : {}),
|
|
5836
5845
|
'memory-core': {
|
|
5837
5846
|
config: { dreaming: { enabled: state.config.skills.includes('memory') } },
|
|
5838
5847
|
},
|
|
@@ -5846,9 +5855,6 @@ Write-Host "Chrome se tu dong bat Debug Mode moi khi ban dang nhap Windows (dela
|
|
|
5846
5855
|
if (!plugin || plugin.hidden) return;
|
|
5847
5856
|
pluginEntries[plugin.package || pid] = { enabled: true };
|
|
5848
5857
|
});
|
|
5849
|
-
if (ch.hasZaloPersonal) {
|
|
5850
|
-
pluginEntries['zalo-mod'] = { enabled: true, config: {} };
|
|
5851
|
-
}
|
|
5852
5858
|
pluginEntries['memory-core'] = {
|
|
5853
5859
|
config: { dreaming: { enabled: state.config.skills.includes('memory') } },
|
|
5854
5860
|
};
|
|
@@ -5888,7 +5894,6 @@ model:
|
|
|
5888
5894
|
// 3. Dockerfile + docker-compose.yml
|
|
5889
5895
|
const allPlugins = [];
|
|
5890
5896
|
if (ch.pluginInstall) allPlugins.push(ch.pluginInstall);
|
|
5891
|
-
if (ch.hasZaloPersonal) allPlugins.push('openclaw-zalo-mod');
|
|
5892
5897
|
state.config.plugins.forEach((pid) => {
|
|
5893
5898
|
const plug = PLUGINS.find((p) => p.id === pid);
|
|
5894
5899
|
if (plug) allPlugins.push(plug.package);
|
|
@@ -5904,7 +5909,6 @@ model:
|
|
|
5904
5909
|
const relayPluginInstallCmd = isMultiBot ? buildRelayPluginInstallCommand('openclaw') : '';
|
|
5905
5910
|
const pluginRuntimeSpecs = allPlugins.filter((p) => p && p !== '@openclaw/zalouser');
|
|
5906
5911
|
const pluginIdForSpec = (spec) => {
|
|
5907
|
-
if (String(spec).includes('zalo-mod')) return 'zalo-mod';
|
|
5908
5912
|
return String(spec).replace(/^@openclaw\//, '').replace(/^openclaw-/, '');
|
|
5909
5913
|
};
|
|
5910
5914
|
const pluginInstallCmd = [
|
|
@@ -5925,7 +5929,6 @@ model:
|
|
|
5925
5929
|
dockerfileSkillInstallMode: 'build',
|
|
5926
5930
|
runtimeCommandParts: [
|
|
5927
5931
|
pluginInstallCmd,
|
|
5928
|
-
hasBrowser ? 'socat TCP-LISTEN:9222,fork,reuseaddr TCP:host.docker.internal:9222 &' : '',
|
|
5929
5932
|
'while true; do sleep 5; openclaw devices approve --latest 2>/dev/null || true; done >/dev/null 2>&1 &'
|
|
5930
5933
|
],
|
|
5931
5934
|
plainSingleExtraHosts: true,
|
|
@@ -6561,7 +6564,7 @@ fi
|
|
|
6561
6564
|
: 'Ubuntu / VPS: The script auto-installs Node.js 20 LTS, OpenClaw CLI, and PM2 to keep the bot running after reboot.');
|
|
6562
6565
|
}
|
|
6563
6566
|
steps.push(_isVi ? '✅ Kiểm tra Node.js (cài tự động trên Ubuntu/VPS nếu chưa có)' : '✅ Check Node.js (auto-install on Ubuntu/VPS if missing)');
|
|
6564
|
-
steps.push(_isVi ?
|
|
6567
|
+
steps.push(_isVi ? `📦 Cài OpenClaw CLI (<code>npm install -g ${common.OPENCLAW_NPM_SPEC}</code>)` : `📦 Install OpenClaw CLI (<code>npm install -g ${common.OPENCLAW_NPM_SPEC}</code>)`);
|
|
6565
6568
|
if (_is9Router) {
|
|
6566
6569
|
steps.push(_isVi ? '🔀 Cài 9Router (<code>npm install -g 9router</code>) và khởi động tự động' : '🔀 Install 9Router (<code>npm install -g 9router</code>) and start automatically');
|
|
6567
6570
|
} else if (_isOllama) {
|
package/package.json
CHANGED
|
@@ -1,39 +1,39 @@
|
|
|
1
|
-
|
|
2
|
-
"name": "create-openclaw-bot",
|
|
3
|
-
"version": "5.7.
|
|
4
|
-
"description": "Interactive CLI installer for OpenClaw Bot",
|
|
5
|
-
"main": "dist/cli.js",
|
|
6
|
-
"bin": {
|
|
7
|
-
"create-openclaw-bot": "./dist/cli.js"
|
|
8
|
-
},
|
|
9
|
-
"files": [
|
|
10
|
-
"dist"
|
|
11
|
-
],
|
|
12
|
-
"scripts": {
|
|
13
|
-
"build": "node src/build.mjs --deploy",
|
|
14
|
-
"dev": "node src/build.mjs --deploy --watch",
|
|
15
|
-
"test": "node src/tests/smoke-cli-logic.mjs && node src/tests/test-generation.mjs && node src/tests/test-matrix.mjs",
|
|
16
|
-
"bump": "node src/bump-version.mjs"
|
|
17
|
-
},
|
|
18
|
-
"keywords": [
|
|
19
|
-
"openclaw",
|
|
20
|
-
"cli",
|
|
21
|
-
"bot",
|
|
22
|
-
"zalo",
|
|
23
|
-
"telegram",
|
|
24
|
-
"ai"
|
|
25
|
-
],
|
|
26
|
-
"author": "tuanminhhole",
|
|
27
|
-
"license": "MIT",
|
|
28
|
-
"dependencies": {
|
|
29
|
-
"@inquirer/prompts": "^4.3.1",
|
|
30
|
-
"chalk": "^5.3.0",
|
|
31
|
-
"fs-extra": "^11.2.0"
|
|
32
|
-
},
|
|
33
|
-
"bundleDependencies": [
|
|
34
|
-
"@inquirer/prompts",
|
|
35
|
-
"chalk",
|
|
36
|
-
"fs-extra"
|
|
37
|
-
],
|
|
38
|
-
"type": "module"
|
|
39
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"name": "create-openclaw-bot",
|
|
3
|
+
"version": "5.7.8",
|
|
4
|
+
"description": "Interactive CLI installer for OpenClaw Bot",
|
|
5
|
+
"main": "dist/cli.js",
|
|
6
|
+
"bin": {
|
|
7
|
+
"create-openclaw-bot": "./dist/cli.js"
|
|
8
|
+
},
|
|
9
|
+
"files": [
|
|
10
|
+
"dist"
|
|
11
|
+
],
|
|
12
|
+
"scripts": {
|
|
13
|
+
"build": "node src/build.mjs --deploy",
|
|
14
|
+
"dev": "node src/build.mjs --deploy --watch",
|
|
15
|
+
"test": "node src/tests/smoke-cli-logic.mjs && node src/tests/test-generation.mjs && node src/tests/test-matrix.mjs",
|
|
16
|
+
"bump": "node src/bump-version.mjs"
|
|
17
|
+
},
|
|
18
|
+
"keywords": [
|
|
19
|
+
"openclaw",
|
|
20
|
+
"cli",
|
|
21
|
+
"bot",
|
|
22
|
+
"zalo",
|
|
23
|
+
"telegram",
|
|
24
|
+
"ai"
|
|
25
|
+
],
|
|
26
|
+
"author": "tuanminhhole",
|
|
27
|
+
"license": "MIT",
|
|
28
|
+
"dependencies": {
|
|
29
|
+
"@inquirer/prompts": "^4.3.1",
|
|
30
|
+
"chalk": "^5.3.0",
|
|
31
|
+
"fs-extra": "^11.2.0"
|
|
32
|
+
},
|
|
33
|
+
"bundleDependencies": [
|
|
34
|
+
"@inquirer/prompts",
|
|
35
|
+
"chalk",
|
|
36
|
+
"fs-extra"
|
|
37
|
+
],
|
|
38
|
+
"type": "module"
|
|
39
|
+
}
|