create-openclaw-bot 5.11.0 → 5.12.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 +40 -36
- package/README.vi.md +40 -36
- package/dist/server/local-server.js +264 -353
- package/dist/setup/data/channels.js +13 -14
- package/dist/setup/shared/bot-config-gen.js +39 -32
- package/dist/setup/shared/common-gen.js +11 -0
- package/dist/setup/shared/docker-gen.js +45 -74
- package/dist/setup/shared/workspace-gen.js +828 -180
- package/dist/web/app.js +48 -13
- package/package.json +2 -2
|
@@ -55,31 +55,30 @@
|
|
|
55
55
|
},
|
|
56
56
|
// 'telegram+zalo-personal' — Combo mode tạm ngưng, nghiên cứu thêm.
|
|
57
57
|
'zalo-personal': {
|
|
58
|
-
name: 'Zalo
|
|
58
|
+
name: 'Zalo cá nhân — OpenClaw Zalo Connect',
|
|
59
59
|
hasZaloPersonal: true,
|
|
60
60
|
envKeys: [],
|
|
61
61
|
envExtra: '',
|
|
62
62
|
credSteps: [
|
|
63
|
-
{ textVi: '⚠️ Zalo
|
|
64
|
-
{ textVi: '
|
|
63
|
+
{ textVi: '⚠️ Zalo cá nhân chạy qua <strong>OpenClaw Zalo Connect (unofficial, zca-js)</strong> — tự động hoá tài khoản cá nhân có thể vi phạm điều khoản Zalo và khiến tài khoản bị hạn chế. <strong>Chỉ nên dùng tài khoản phụ.</strong>', textEn: '⚠️ Personal Zalo runs on <strong>OpenClaw Zalo Connect (unofficial, zca-js)</strong> — automating a personal account may violate Zalo terms and can get the account restricted. <strong>Use a secondary account.</strong>' },
|
|
64
|
+
{ textVi: 'Sau khi tạo bot, bấm <strong>Đăng nhập Zalo</strong> để quét QR ngay trong giao diện. Nếu cần chạy thủ công: <code>openclaw channels login --channel zalo-connect --account default</code>.', textEn: 'After creating the bot, click <strong>Zalo Login</strong> to scan the QR right in the UI. Manual fallback: <code>openclaw channels login --channel zalo-connect --account default</code>.' },
|
|
65
|
+
{ textVi: 'Mặc định an toàn: DM theo cơ chế pairing, group tắt hết — sau khi quét QR hãy tự chọn DM/nhóm được phép trong cấu hình.', textEn: 'Secure defaults: DM uses pairing, all groups start disabled — after the QR scan, explicitly choose the allowed DMs/groups in the config.' },
|
|
65
66
|
],
|
|
67
|
+
// Mirrors buildZaloConnectChannelConfig() in bot-config-gen.js — keys validated
|
|
68
|
+
// against OpenClaw Zalo Connect 3.0.0's strict channel schema.
|
|
66
69
|
channelConfig: {
|
|
67
|
-
|
|
70
|
+
'zalo-connect': {
|
|
68
71
|
enabled: true,
|
|
69
72
|
defaultAccount: 'default',
|
|
70
73
|
accounts: {
|
|
71
|
-
default: {
|
|
72
|
-
dmPolicy: 'open',
|
|
73
|
-
allowFrom: ['*'],
|
|
74
|
-
groupPolicy: 'allowlist',
|
|
75
|
-
groupAllowFrom: ['*'],
|
|
76
|
-
},
|
|
74
|
+
default: { enabled: true },
|
|
77
75
|
},
|
|
78
|
-
dmPolicy: '
|
|
79
|
-
allowFrom: [
|
|
76
|
+
dmPolicy: 'pairing',
|
|
77
|
+
allowFrom: [],
|
|
80
78
|
groupPolicy: 'allowlist',
|
|
81
|
-
|
|
82
|
-
|
|
79
|
+
groups: {
|
|
80
|
+
'*': { enabled: false, requireMention: true },
|
|
81
|
+
},
|
|
83
82
|
},
|
|
84
83
|
},
|
|
85
84
|
pluginInstall: '',
|
|
@@ -248,14 +248,14 @@
|
|
|
248
248
|
});
|
|
249
249
|
cfg.plugins = pluginsConfig.plugins;
|
|
250
250
|
|
|
251
|
-
// ── bindings for
|
|
251
|
+
// ── bindings for zalo-connect ────────────────────────────────────────────────
|
|
252
252
|
if (agentMetas.length > 0 && isZaloPersonal(channelKey)) {
|
|
253
253
|
cfg.bindings = cfg.bindings || [];
|
|
254
254
|
const firstAgentId = agentMetas[0]?.agentId || 'bot';
|
|
255
|
-
if (!cfg.bindings.some(b => b.match && b.match.channel === '
|
|
256
|
-
// Account-specific from
|
|
257
|
-
//
|
|
258
|
-
cfg.bindings.push({ agentId: firstAgentId, match: { channel: '
|
|
255
|
+
if (!cfg.bindings.some(b => b.match && b.match.channel === 'zalo-connect')) {
|
|
256
|
+
// Account-specific from day one (plan §5.2): each account needs its own
|
|
257
|
+
// binding + credential namespace even while zalo-connect 2.4.6 is single-account.
|
|
258
|
+
cfg.bindings.push({ agentId: firstAgentId, match: { channel: 'zalo-connect', accountId: 'default' } });
|
|
259
259
|
}
|
|
260
260
|
}
|
|
261
261
|
|
|
@@ -309,31 +309,15 @@
|
|
|
309
309
|
|
|
310
310
|
channels.telegram = telegramConfig;
|
|
311
311
|
} else if (isZaloPersonal(channelKey)) {
|
|
312
|
-
// Zalo Personal
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
groupAllowFrom: ['*'],
|
|
322
|
-
},
|
|
323
|
-
},
|
|
324
|
-
dmPolicy: 'open',
|
|
325
|
-
allowFrom: ['*'],
|
|
326
|
-
groupPolicy: 'allowlist',
|
|
327
|
-
groupAllowFrom: ['*'],
|
|
328
|
-
historyLimit: 50,
|
|
329
|
-
// NOTE: do NOT add `reactionLevel`/`actions` here — the zalouser plugin's config
|
|
330
|
-
// schema is strict and rejects them ("must not have additional properties"), which
|
|
331
|
-
// crashes the gateway on boot. zalouser already supports the `react` action by
|
|
332
|
-
// default; reaction behavior is driven by the prompt (TOOLS.md), not channel config.
|
|
333
|
-
groups: {
|
|
334
|
-
'*': { enabled: true, requireMention: false },
|
|
335
|
-
},
|
|
336
|
-
};
|
|
312
|
+
// Zalo Personal → OpenClaw Zalo Connect, the only personal-Zalo backend.
|
|
313
|
+
// Secure defaults: DM pairing, empty
|
|
314
|
+
// allowFrom, all groups disabled + requireMention until the owner explicitly
|
|
315
|
+
// enables them post-QR. Never default to `allowFrom: ["*"]` / open groups.
|
|
316
|
+
// Every key below is validated against OpenClaw Zalo Connect 3.0.0's schema
|
|
317
|
+
// (`additionalProperties: false`) — do NOT add keys (e.g. historyLimit,
|
|
318
|
+
// groupAllowFrom) without re-checking `openclaw.plugin.json` first, an unknown
|
|
319
|
+
// key crashes the gateway on boot.
|
|
320
|
+
channels['zalo-connect'] = buildZaloConnectChannelConfig();
|
|
337
321
|
} else if (channelKey === 'zalo-bot') {
|
|
338
322
|
channels.zalo = { enabled: true, provider: 'official_account' };
|
|
339
323
|
}
|
|
@@ -342,6 +326,26 @@
|
|
|
342
326
|
}
|
|
343
327
|
|
|
344
328
|
|
|
329
|
+
// ═══════════════════════════════════════════════════════════════════════════════
|
|
330
|
+
// buildZaloConnectChannelConfig — secure-default channels['zalo-connect'] block
|
|
331
|
+
// ═══════════════════════════════════════════════════════════════════════════════
|
|
332
|
+
function buildZaloConnectChannelConfig() {
|
|
333
|
+
return {
|
|
334
|
+
enabled: true,
|
|
335
|
+
defaultAccount: 'default',
|
|
336
|
+
accounts: {
|
|
337
|
+
default: { enabled: true },
|
|
338
|
+
},
|
|
339
|
+
dmPolicy: 'pairing',
|
|
340
|
+
allowFrom: [],
|
|
341
|
+
groupPolicy: 'allowlist',
|
|
342
|
+
groups: {
|
|
343
|
+
'*': { enabled: false, requireMention: true },
|
|
344
|
+
},
|
|
345
|
+
};
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
|
|
345
349
|
// ═══════════════════════════════════════════════════════════════════════════════
|
|
346
350
|
// buildPluginsConfig — returns { plugins: { ... } }
|
|
347
351
|
// ═══════════════════════════════════════════════════════════════════════════════
|
|
@@ -361,9 +365,11 @@
|
|
|
361
365
|
|
|
362
366
|
const allow = ['memory-core'];
|
|
363
367
|
|
|
364
|
-
// Zalo Personal channel
|
|
368
|
+
// Zalo Personal → zalo-connect channel plugin (pinned install happens in the
|
|
369
|
+
// entrypoint / creation flow). openclaw-zalo-mod stays a separate opt-in plugin.
|
|
365
370
|
if (isZaloPersonal(channelKey)) {
|
|
366
|
-
|
|
371
|
+
entries['zalo-connect'] = { enabled: true };
|
|
372
|
+
allow.push('zalo-connect');
|
|
367
373
|
}
|
|
368
374
|
|
|
369
375
|
// DuckDuckGo search plugin for web-search
|
|
@@ -518,6 +524,7 @@
|
|
|
518
524
|
generateToken,
|
|
519
525
|
buildOpenclawJson,
|
|
520
526
|
buildChannelConfig,
|
|
527
|
+
buildZaloConnectChannelConfig,
|
|
521
528
|
buildPluginsConfig,
|
|
522
529
|
buildSkillsEntries,
|
|
523
530
|
buildExecApprovalsJson,
|
|
@@ -40,6 +40,13 @@
|
|
|
40
40
|
const TELEGRAM_RELAY_PLUGIN_ID = 'telegram-multibot-relay';
|
|
41
41
|
const TELEGRAM_SETUP_GUIDE_FILENAME = 'TELEGRAM-GROUP-SETUP.md';
|
|
42
42
|
|
|
43
|
+
// ── OpenClaw Zalo Connect — single source of truth ──────────────────────────
|
|
44
|
+
// Pin the maintained fork tag so setup never falls back to upstream/ClawHub.
|
|
45
|
+
const ZALO_CHANNEL_ID = 'zalo-connect';
|
|
46
|
+
const ZALO_PLUGIN_ID = 'zalo-connect';
|
|
47
|
+
const ZALO_CONNECT_VERSION = '3.0.0';
|
|
48
|
+
const ZALO_CONNECT_PLUGIN_SPEC = 'https://github.com/tuanminhhole/openclaw-zalo-connect.git#v3.0.0';
|
|
49
|
+
|
|
43
50
|
function buildRelayPluginInstallCommand(prefix = 'openclaw') {
|
|
44
51
|
return `if [ ! -d "$OPENCLAW_STATE_DIR/extensions/${TELEGRAM_RELAY_PLUGIN_ID}" ]; then ${prefix} plugins install ${TELEGRAM_RELAY_PLUGIN_SPEC} 2>/dev/null || true; fi`;
|
|
45
52
|
}
|
|
@@ -298,6 +305,10 @@ If setup reported a plugin install error, run this after the bot is running:
|
|
|
298
305
|
TELEGRAM_RELAY_PLUGIN_SPEC,
|
|
299
306
|
TELEGRAM_RELAY_PLUGIN_ID,
|
|
300
307
|
TELEGRAM_SETUP_GUIDE_FILENAME,
|
|
308
|
+
ZALO_CHANNEL_ID,
|
|
309
|
+
ZALO_PLUGIN_ID,
|
|
310
|
+
ZALO_CONNECT_VERSION,
|
|
311
|
+
ZALO_CONNECT_PLUGIN_SPEC,
|
|
301
312
|
buildRelayPluginInstallCommand,
|
|
302
313
|
buildRelayPluginInstallCommandWin,
|
|
303
314
|
buildTelegramPostInstallChecklist,
|
|
@@ -223,6 +223,8 @@ if(touched){console.log('[patch-9router] Applied Codex compatibility patch.');}e
|
|
|
223
223
|
gatewayPort = 18789,
|
|
224
224
|
routerPort = 20128,
|
|
225
225
|
osChoice = '',
|
|
226
|
+
// Personal-Zalo backend: empty or the single supported `zalo-connect` channel.
|
|
227
|
+
zaloBackend = '',
|
|
226
228
|
} = options;
|
|
227
229
|
// Windows bind-mounts give ClawHub-installed plugins world-writable perms (which openclaw
|
|
228
230
|
// blocks), so on Windows we isolate extensions in a named volume. On macOS/Linux bind-mounts
|
|
@@ -231,6 +233,16 @@ if(touched){console.log('[patch-9router] Applied Codex compatibility patch.');}e
|
|
|
231
233
|
const useExtensionsVolume = osChoice === 'win';
|
|
232
234
|
const extVolMount = useExtensionsVolume ? '\n - openclaw-extensions:/home/node/project/.openclaw/extensions' : '';
|
|
233
235
|
const extVolDecl = useExtensionsVolume ? '\n openclaw-extensions:' : '';
|
|
236
|
+
// SQLite state on Docker Desktop (macOS/Windows): the host bind mount goes through a
|
|
237
|
+
// virtualized file share (virtiofs/gRPC-FUSE) whose locking/mmap semantics break SQLite WAL —
|
|
238
|
+
// OpenClaw crashes with `Error: disk I/O error` on write (e.g. when a Zalo message arrives).
|
|
239
|
+
// Keep `.openclaw/state` on a named volume (the Linux VM's native filesystem) instead; the
|
|
240
|
+
// rest of `.openclaw` stays bind-mounted so workspaces/config remain visible on the host.
|
|
241
|
+
// Linux/VPS bind mounts are native ext4 — unchanged there (and state stays host-visible).
|
|
242
|
+
const useStateVolume = osChoice === 'macos' || osChoice === 'win';
|
|
243
|
+
const stateVolMount = useStateVolume ? '\n - openclaw-state:/home/node/project/.openclaw/state' : '';
|
|
244
|
+
const stateVolDecl = useStateVolume ? '\n openclaw-state:' : '';
|
|
245
|
+
const stateVolBlock = useStateVolume ? '\n\nvolumes:\n openclaw-state:' : '';
|
|
234
246
|
const skillLines = dockerfileSkillInstallMode === 'build' && allSkills.length > 0
|
|
235
247
|
? `\n# Install skills (ClawHub)\n${allSkills.map((skill) => `RUN openclaw skills install ${skill} || echo "Warning: Failed to install ${skill} due to rate limits."`).join('\n')}\n`
|
|
236
248
|
: '';
|
|
@@ -268,21 +280,20 @@ if(touched){console.log('[patch-9router] Applied Codex compatibility patch.');}e
|
|
|
268
280
|
' return 0',
|
|
269
281
|
' fi',
|
|
270
282
|
' echo "[entrypoint] plugin $id missing; installing $spec"',
|
|
271
|
-
'
|
|
272
|
-
'
|
|
273
|
-
'
|
|
274
|
-
'
|
|
275
|
-
'
|
|
276
|
-
'
|
|
277
|
-
'
|
|
278
|
-
'
|
|
279
|
-
'
|
|
280
|
-
'
|
|
281
|
-
'
|
|
282
|
-
'
|
|
283
|
-
'
|
|
284
|
-
'
|
|
285
|
-
' fi',
|
|
283
|
+
' case "$spec" in',
|
|
284
|
+
' https://*.git#*)',
|
|
285
|
+
' repo="${spec%%#*}"',
|
|
286
|
+
' ref="${spec##*#}"',
|
|
287
|
+
' tmp="/tmp/openclaw-plugin-$id-$ref"',
|
|
288
|
+
' rm -rf "$tmp"',
|
|
289
|
+
' if git clone --depth 1 --branch "$ref" "$repo" "$tmp" 2>/dev/null; then',
|
|
290
|
+
' openclaw plugins install "$tmp" 2>/dev/null || echo "[entrypoint] warning: failed to install cloned plugin $id"',
|
|
291
|
+
' else',
|
|
292
|
+
' echo "[entrypoint] warning: failed to clone plugin $spec"',
|
|
293
|
+
' fi',
|
|
294
|
+
' ;;',
|
|
295
|
+
' *) openclaw plugins install "$spec" 2>/dev/null || echo "[entrypoint] warning: failed to install plugin $spec" ;;',
|
|
296
|
+
' esac',
|
|
286
297
|
'}',
|
|
287
298
|
'ensure_skill() {',
|
|
288
299
|
' id="$1"',
|
|
@@ -301,52 +312,14 @@ if(touched){console.log('[patch-9router] Applied Codex compatibility patch.');}e
|
|
|
301
312
|
// Restore config AFTER plugin installs (which may clobber openclaw.json)
|
|
302
313
|
runtimeParts.push(`node - <<'NODE'\n${restoreConfigScript}\nNODE`);
|
|
303
314
|
runtimeParts.push(`node - <<'NODE'\n${securityCompatScript}\nNODE`);
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
'fi',
|
|
312
|
-
'# Automatically run Zalo sticker-mention patch if skill is present',
|
|
313
|
-
'for MENTIONS_JS in $(find "$OPENCLAW_HOME" -maxdepth 5 -path "*/skills/*/mentions.js" -type f 2>/dev/null); do',
|
|
314
|
-
' if [ -f "$MENTIONS_JS" ]; then',
|
|
315
|
-
' echo "[entrypoint] Running patch: $MENTIONS_JS"',
|
|
316
|
-
' node "$MENTIONS_JS" || echo "[entrypoint] Warning: failed to run patch $MENTIONS_JS"',
|
|
317
|
-
' fi',
|
|
318
|
-
'done',
|
|
319
|
-
].join('\n'));
|
|
320
|
-
// Expose zalouser's ZCA API map (globalThis.__zcaApiByProfile) BEFORE the gateway imports
|
|
321
|
-
// zalouser, so openclaw-zalo-mod can reach the live Zalo API (dashboard Sync Account, group
|
|
322
|
-
// admin lookups, …). zalo-mod's own runtime patch lands AFTER zalouser is already imported,
|
|
323
|
-
// so it never takes effect on the running module — patching here (post sticker-mention restore,
|
|
324
|
-
// pre gateway-run) is the reliable fix.
|
|
325
|
-
{
|
|
326
|
-
const exposeZcaScript = [
|
|
327
|
-
"const fs=require('fs'),cp=require('child_process');",
|
|
328
|
-
"let files=[];",
|
|
329
|
-
"try{ files=cp.execSync('find \"'+(process.env.OPENCLAW_HOME||'')+'/npm\" -path \"*/@openclaw/zalouser/dist/zalo-js-*.js\" -type f 2>/dev/null',{encoding:'utf8'}).split('\\n').filter(Boolean); }catch(e){}",
|
|
330
|
-
"const reps=[['const apiByProfile = /* @__PURE__ */ new Map();','const apiByProfile = globalThis.__zcaApiByProfile || (globalThis.__zcaApiByProfile = /* @__PURE__ */ new Map());'],['const apiByProfile = new Map();','const apiByProfile = globalThis.__zcaApiByProfile || (globalThis.__zcaApiByProfile = new Map());']];",
|
|
331
|
-
"for(const f of files){ try{ let s=fs.readFileSync(f,'utf8'); if(s.includes('globalThis.__zcaApiByProfile')) continue; for(const pair of reps){ if(s.includes(pair[0])){ s=s.replace(pair[0],pair[1]); fs.writeFileSync(f,s); console.log('[entrypoint] exposed __zcaApiByProfile for zalo-mod in '+f); break; } } }catch(e){} }",
|
|
332
|
-
].join('\n');
|
|
333
|
-
runtimeParts.push(`# Expose zalouser ZCA API map for openclaw-zalo-mod (before gateway imports zalouser)\nnode - <<'NODE'\n${exposeZcaScript}\nNODE`);
|
|
315
|
+
if (zaloBackend === 'zalo-connect') {
|
|
316
|
+
// Pinned ZaloConnect install (never `latest` — plan §4.1). ensure_plugin skips the
|
|
317
|
+
// install when extensions/zalo-connect already exists, so restarts never re-download
|
|
318
|
+
// and a reconnect never reinstalls. No dist patching, no mentions.js, no watchdog
|
|
319
|
+
// hacks: sticker/mention/reaction are native ZaloConnect actions.
|
|
320
|
+
const zaloConnectSpec = common.ZALO_CONNECT_PLUGIN_SPEC || 'https://github.com/tuanminhhole/openclaw-zalo-connect.git#v3.0.0';
|
|
321
|
+
runtimeParts.push(`ensure_plugin zalo-connect "${zaloConnectSpec}"`);
|
|
334
322
|
}
|
|
335
|
-
runtimeParts.push([
|
|
336
|
-
'# Zalo channel auto-restart monitor (background)',
|
|
337
|
-
'(',
|
|
338
|
-
' sleep 180',
|
|
339
|
-
' while true; do',
|
|
340
|
-
' sleep 60',
|
|
341
|
-
' STATUS=$(openclaw channels status 2>/dev/null | grep -i "Zalo Personal" || true)',
|
|
342
|
-
' if echo "$STATUS" | grep -qi "stopped"; then',
|
|
343
|
-
' echo "[zalo-monitor] Zalo channel stopped - restarting container in 5s"',
|
|
344
|
-
' sleep 5',
|
|
345
|
-
' kill 1 2>/dev/null || true',
|
|
346
|
-
' fi',
|
|
347
|
-
' done',
|
|
348
|
-
') &',
|
|
349
|
-
].join('\n'));
|
|
350
323
|
runtimeParts.push('openclaw gateway run');
|
|
351
324
|
const runtimeScript = ['#!/bin/sh', 'set -e', ...runtimeParts].join('\n');
|
|
352
325
|
let browserInstall = '';
|
|
@@ -395,7 +368,7 @@ services:
|
|
|
395
368
|
env_file:
|
|
396
369
|
- ../../.env
|
|
397
370
|
${appEnvironmentBlock}${dependsOn}${extraHosts} volumes:
|
|
398
|
-
- ${volumeMount}
|
|
371
|
+
- ${volumeMount}${stateVolMount}
|
|
399
372
|
ports:
|
|
400
373
|
- "127.0.0.1:${gatewayPort}:${gatewayPort}"
|
|
401
374
|
|
|
@@ -420,7 +393,7 @@ ${indentBlock(docker9RouterEntrypointScript, 8)}
|
|
|
420
393
|
- "127.0.0.1:${routerPort}:${routerPort}"
|
|
421
394
|
|
|
422
395
|
volumes:
|
|
423
|
-
9router-data
|
|
396
|
+
9router-data:${stateVolDecl}`;
|
|
424
397
|
} else if (isLocal) {
|
|
425
398
|
const ollamaModelTag = String(selectedModel || 'ollama/gemma4:e2b').replace('ollama/', '');
|
|
426
399
|
compose = `name: ${multiComposeName}
|
|
@@ -432,7 +405,7 @@ services:
|
|
|
432
405
|
env_file:
|
|
433
406
|
- ../../.env
|
|
434
407
|
${appEnvironmentBlock}${dependsOn}${extraHosts} volumes:
|
|
435
|
-
- ${volumeMount}
|
|
408
|
+
- ${volumeMount}${stateVolMount}
|
|
436
409
|
ports:
|
|
437
410
|
- "127.0.0.1:${gatewayPort}:${gatewayPort}"
|
|
438
411
|
|
|
@@ -461,7 +434,7 @@ ${appEnvironmentBlock}${dependsOn}${extraHosts} volumes:
|
|
|
461
434
|
start_period: 30s
|
|
462
435
|
|
|
463
436
|
volumes:
|
|
464
|
-
ollama-data
|
|
437
|
+
ollama-data:${stateVolDecl}`;
|
|
465
438
|
} else {
|
|
466
439
|
compose = `name: ${multiComposeName}
|
|
467
440
|
services:
|
|
@@ -472,9 +445,9 @@ services:
|
|
|
472
445
|
env_file:
|
|
473
446
|
- ../../.env
|
|
474
447
|
${appEnvironmentBlock}${extraHosts} volumes:
|
|
475
|
-
- ${volumeMount}
|
|
448
|
+
- ${volumeMount}${stateVolMount}
|
|
476
449
|
ports:
|
|
477
|
-
- "127.0.0.1:${gatewayPort}:${gatewayPort}"`;
|
|
450
|
+
- "127.0.0.1:${gatewayPort}:${gatewayPort}"${stateVolBlock}`;
|
|
478
451
|
}
|
|
479
452
|
} else if (is9Router) {
|
|
480
453
|
compose = `name: ${singleComposeName}
|
|
@@ -488,7 +461,7 @@ services:
|
|
|
488
461
|
depends_on:
|
|
489
462
|
- 9router
|
|
490
463
|
${appEnvironmentBlock}${extraHostsBlock}\n volumes:
|
|
491
|
-
- ${volumeMount}
|
|
464
|
+
- ${volumeMount}${stateVolMount}
|
|
492
465
|
- openclaw-plugins:/home/node/project/.openclaw/npm${extVolMount}
|
|
493
466
|
ports:
|
|
494
467
|
- "127.0.0.1:${gatewayPort}:${gatewayPort}"
|
|
@@ -515,7 +488,7 @@ ${indentBlock(docker9RouterEntrypointScript, 8)}
|
|
|
515
488
|
|
|
516
489
|
volumes:
|
|
517
490
|
9router-data:
|
|
518
|
-
openclaw-plugins:${extVolDecl}`;
|
|
491
|
+
openclaw-plugins:${extVolDecl}${stateVolDecl}`;
|
|
519
492
|
} else if (isLocal) {
|
|
520
493
|
const ollamaModelTag = String(selectedModel || 'ollama/gemma4:e2b').replace('ollama/', '');
|
|
521
494
|
compose = `name: ${singleComposeName}
|
|
@@ -531,7 +504,7 @@ ${appEnvironmentBlock} depends_on:
|
|
|
531
504
|
${extraHostsBlock}\n ports:
|
|
532
505
|
- "127.0.0.1:${gatewayPort}:${gatewayPort}"
|
|
533
506
|
volumes:
|
|
534
|
-
- ${volumeMount}
|
|
507
|
+
- ${volumeMount}${stateVolMount}
|
|
535
508
|
|
|
536
509
|
ollama:
|
|
537
510
|
image: ollama/ollama:latest
|
|
@@ -558,7 +531,7 @@ ${extraHostsBlock}\n ports:
|
|
|
558
531
|
start_period: 30s
|
|
559
532
|
|
|
560
533
|
volumes:
|
|
561
|
-
ollama-data
|
|
534
|
+
ollama-data:${stateVolDecl}`;
|
|
562
535
|
} else {
|
|
563
536
|
compose = `name: ${singleComposeName}
|
|
564
537
|
services:
|
|
@@ -569,9 +542,9 @@ services:
|
|
|
569
542
|
env_file:
|
|
570
543
|
- ../../.env
|
|
571
544
|
${appEnvironmentBlock}${plainSingleExtraHosts ? `${extraHostsBlock}\n` : ''} volumes:
|
|
572
|
-
- ${volumeMount}
|
|
545
|
+
- ${volumeMount}${stateVolMount}
|
|
573
546
|
ports:
|
|
574
|
-
- "127.0.0.1:${gatewayPort}:${gatewayPort}"`;
|
|
547
|
+
- "127.0.0.1:${gatewayPort}:${gatewayPort}"${stateVolBlock}`;
|
|
575
548
|
}
|
|
576
549
|
|
|
577
550
|
return {
|
|
@@ -599,5 +572,3 @@ ${appEnvironmentBlock}${plainSingleExtraHosts ? `${extraHostsBlock}\n` : ''}
|
|
|
599
572
|
if (typeof exports !== 'undefined' && typeof globalThis !== 'undefined' && globalThis.__openclawDockerGen) {
|
|
600
573
|
Object.assign(exports, globalThis.__openclawDockerGen);
|
|
601
574
|
}
|
|
602
|
-
|
|
603
|
-
|