create-openclaw-bot 5.8.16 → 5.8.17

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.8.16-0EA5E9?style=for-the-badge" alt="Version 5.8.16" /></a>
6
+ <a href="https://github.com/tuanminhhole/openclaw-setup/releases"><img src="https://img.shields.io/badge/RELEASE-v5.8.17-0EA5E9?style=for-the-badge" alt="Version 5.8.17" /></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>
@@ -23,7 +23,7 @@ A next-generation **Web UI Setup** and management dashboard that automates 100%
23
23
 
24
24
  ---
25
25
 
26
- ## 🆕 What's New in v5.8.16
26
+ ## 🆕 What's New in v5.8.17
27
27
 
28
28
  ### 🚀 New Features: Deep Integration of Infographic Image Generator, Zalo Sticker & Auto-Tag Skills, and Workspace Docs Optimization
29
29
 
@@ -173,6 +173,6 @@ Yes. You can edit the config JSON directly via the integrated File Editor in the
173
173
 
174
174
  <div align="center">
175
175
 
176
- Made with 🦞 by [Kent](https://github.com/tuanminhhole)
176
+ Made with 🦞 by [tuanminhhole](https://github.com/tuanminhhole)
177
177
 
178
178
  </div>
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.8.16-0EA5E9?style=for-the-badge" alt="Version 5.8.16" /></a>
6
+ <a href="https://github.com/tuanminhhole/openclaw-setup/releases"><img src="https://img.shields.io/badge/RELEASE-v5.8.17-0EA5E9?style=for-the-badge" alt="Version 5.8.17" /></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>
@@ -23,7 +23,7 @@ Trình cài đặt và quản trị **Web UI Setup** thế hệ mới giúp tự
23
23
 
24
24
  ---
25
25
 
26
- ## 🆕 Có gì mới trong v5.8.16
26
+ ## 🆕 Có gì mới trong v5.8.17
27
27
 
28
28
  ### 🚀 Tính năng mới: Tích hợp sâu Skill Tạo ảnh Infographic, Skill Sticker & Auto-Tag (Zalo) cùng Tối ưu hóa Workspace Docs
29
29
 
@@ -1085,7 +1085,7 @@ async function createBotInProject(projectDir, body = {}, runtime = {}) {
1085
1085
  providerKey: '9router',
1086
1086
  deployMode: runtime.mode || state.mode || 'docker',
1087
1087
  osChoice: runtime.os || state.os || detectOs(),
1088
- selectedSkills: ['memory', 'image-gen', 'web-search', 'scheduler'],
1088
+ selectedSkills: ['memory', 'web-search', 'scheduler'],
1089
1089
  skills: dataExport.SKILLS || [],
1090
1090
  agentMetas: [],
1091
1091
  }));
@@ -1156,7 +1156,7 @@ async function createBotInProject(projectDir, body = {}, runtime = {}) {
1156
1156
  workspacePath: `/home/node/project/.openclaw/${workspaceDir}`,
1157
1157
  channel,
1158
1158
  hasZaloMod: channel === 'zalo-personal',
1159
- hasZaloSticker: channel === 'zalo-personal',
1159
+ hasZaloSticker: false,
1160
1160
  hasScheduler,
1161
1161
  hasImageGen,
1162
1162
  });
@@ -1261,7 +1261,7 @@ async function updateBotInProject(projectDir, agentId, body = {}, runtime = {})
1261
1261
  workspacePath: `/home/node/project/.openclaw/${workspaceDir}`,
1262
1262
  channel,
1263
1263
  hasZaloMod: channel === 'zalo-personal',
1264
- hasZaloSticker: channel === 'zalo-personal',
1264
+ hasZaloSticker: false,
1265
1265
  hasScheduler,
1266
1266
  hasImageGen,
1267
1267
  });
@@ -1697,10 +1697,15 @@ async function recreateDockerBot(projectDir) {
1697
1697
  const channel = binding?.match?.channel || 'telegram';
1698
1698
  if (channel === 'zalo-personal' || channel === 'zalouser') {
1699
1699
  const workspaceDir = workspaceRelForAgent(a, cfg, projectDir) || `workspace-${a.id}`;
1700
- const mentionsJsPath = join(projectDir, '.openclaw', workspaceDir, 'skills/sticker-mention/mentions.js');
1700
+ let mentionsJsPath = join(projectDir, '.openclaw', workspaceDir, 'skills/zalo-sticker-mention/mentions.js');
1701
+ let containerJsPath = `/home/node/project/.openclaw/${workspaceDir}/skills/zalo-sticker-mention/mentions.js`;
1702
+ if (!existsSync(mentionsJsPath)) {
1703
+ mentionsJsPath = join(projectDir, '.openclaw', workspaceDir, 'skills/sticker-mention/mentions.js');
1704
+ containerJsPath = `/home/node/project/.openclaw/${workspaceDir}/skills/sticker-mention/mentions.js`;
1705
+ }
1701
1706
  if (existsSync(mentionsJsPath)) {
1702
1707
  sendLog(`[zalo-patch] Automatically running mentions.js inside container ${containerName}...`);
1703
- const patchCmd = await runCapture('docker', ['exec', containerName, 'node', `/home/node/project/.openclaw/${workspaceDir}/skills/sticker-mention/mentions.js`], { cwd: projectDir, shell: false });
1708
+ const patchCmd = await runCapture('docker', ['exec', containerName, 'node', containerJsPath], { cwd: projectDir, shell: false });
1704
1709
  sendLog(`[zalo-patch] Output: ${patchCmd.stdout || ''} ${patchCmd.stderr || ''}`);
1705
1710
  }
1706
1711
  }
@@ -1771,7 +1776,7 @@ async function writeCoreProject({ projectDir, osChoice, mode, gatewayPort = 1878
1771
1776
  await fsp.mkdir(openclawHome, { recursive: true });
1772
1777
  await fsp.mkdir(join(openclawHome, 'plugin-runtime-deps'), { recursive: true });
1773
1778
 
1774
- const selectedSkills = ['memory', 'image-gen', 'web-search', 'scheduler'];
1779
+ const selectedSkills = ['memory', 'web-search', 'scheduler'];
1775
1780
  const agentMetas = [];
1776
1781
  const common = { channelKey: 'telegram', providerKey: '9router', model: DEFAULT_MODEL, deployMode: mode, osChoice, selectedSkills, skills: dataExport.SKILLS || [], agentMetas, gatewayPort, routerPort };
1777
1782
  const cfg = buildOpenclawJson(common);
@@ -1833,7 +1838,7 @@ async function installCore({ osChoice, mode, projectDir, gatewayPort = 18789, ro
1833
1838
  await fsp.mkdir(dockerDir, { recursive: true });
1834
1839
  const envContent = existsSync(rootEnvPath)
1835
1840
  ? await fsp.readFile(rootEnvPath, 'utf8')
1836
- : buildEnvFileContent({ channelKey: 'telegram', providerKey: '9router', deployMode: mode, osChoice, selectedSkills: ['memory', 'image-gen', 'web-search', 'scheduler'], skills: dataExport.SKILLS || [], agentMetas: [], apiKey: '', botToken: '' });
1841
+ : buildEnvFileContent({ channelKey: 'telegram', providerKey: '9router', deployMode: mode, osChoice, selectedSkills: ['memory', 'web-search', 'scheduler'], skills: dataExport.SKILLS || [], agentMetas: [], apiKey: '', botToken: '' });
1837
1842
  await fsp.writeFile(dockerEnvPath, envContent, 'utf8');
1838
1843
  sendLog(`Docker env ready: ${dockerEnvPath}`);
1839
1844
  await run('docker', ['compose', 'up', '-d', '--build'], { cwd: dockerDir });
@@ -2324,19 +2329,6 @@ async function applyFeatureToggle(projectDir, agentId, kind, id, enabled) {
2324
2329
  cfg.skills.entries['image-gen'] = cfg.skills.entries['image-gen'] || {};
2325
2330
  cfg.skills.entries['image-gen'].enabled = !!enabled;
2326
2331
 
2327
- for (const a of cfg.agents.list) {
2328
- const sf = await readWorkspaceText(projectDir, a, 'skills/infographic-generator/SKILL.md');
2329
- const js = await readWorkspaceText(projectDir, a, 'skills/infographic-generator/image-generator.js');
2330
- if (enabled) {
2331
- await fsp.mkdir(dirname(sf.file), { recursive: true });
2332
- await fsp.writeFile(sf.file, buildInfographicGeneratorSkillMd(), 'utf8');
2333
- await fsp.writeFile(js.file, buildInfographicGeneratorJs(), 'utf8');
2334
- } else {
2335
- if (existsSync(sf.file)) await fsp.rm(sf.file, { force: true });
2336
- if (existsSync(js.file)) await fsp.rm(js.file, { force: true });
2337
- }
2338
- }
2339
-
2340
2332
  // Write cfgPath early so recreation reads updated openclaw.json
2341
2333
  await fsp.writeFile(cfgPath, JSON.stringify(cfg, null, 2), 'utf8');
2342
2334
 
@@ -2378,30 +2370,40 @@ async function applyFeatureToggle(projectDir, agentId, kind, id, enabled) {
2378
2370
  cfg.skills.entries['sticker-mention'].enabled = !!enabled;
2379
2371
 
2380
2372
  for (const a of cfg.agents.list) {
2381
- const sf = await readWorkspaceText(projectDir, a, 'skills/sticker-mention/SKILL.md');
2382
- const jsf = await readWorkspaceText(projectDir, a, 'skills/sticker-mention/mentions.js');
2383
- if (enabled) {
2384
- await fsp.mkdir(dirname(sf.file), { recursive: true });
2385
- await fsp.writeFile(sf.file, buildStickerMentionSkillMd(), 'utf8');
2386
- await fsp.writeFile(jsf.file, buildStickerMentionJs(), 'utf8');
2387
- } else {
2388
- const binding = (cfg.bindings || []).find((b) => b.agentId === a.id);
2389
- const channel = binding?.match?.channel || 'telegram';
2390
- if ((channel === 'zalo-personal' || channel === 'zalouser') && existsSync(jsf.file)) {
2391
- try {
2392
- const hasDocker = existsSync(join(projectDir, 'docker', 'openclaw', 'docker-compose.yml'));
2393
- if (hasDocker) {
2394
- const botContainer = getBotContainerName(projectDir);
2395
- const workspaceDir = workspaceRelForAgent(a, cfg, projectDir) || `workspace-${a.id}`;
2373
+ const binding = (cfg.bindings || []).find((b) => b.agentId === a.id);
2374
+ const channel = binding?.match?.channel || 'telegram';
2375
+ if (channel === 'zalo-personal' || channel === 'zalouser') {
2376
+ try {
2377
+ const hasDocker = existsSync(join(projectDir, 'docker', 'openclaw', 'docker-compose.yml'));
2378
+ const workspaceDir = workspaceRelForAgent(a, cfg, projectDir) || `workspace-${a.id}`;
2379
+ let mentionsJsPath = join(projectDir, '.openclaw', workspaceDir, 'skills/zalo-sticker-mention/mentions.js');
2380
+ let containerJsPath = `/home/node/project/.openclaw/${workspaceDir}/skills/zalo-sticker-mention/mentions.js`;
2381
+ if (!existsSync(mentionsJsPath)) {
2382
+ mentionsJsPath = join(projectDir, '.openclaw', workspaceDir, 'skills/sticker-mention/mentions.js');
2383
+ containerJsPath = `/home/node/project/.openclaw/${workspaceDir}/skills/sticker-mention/mentions.js`;
2384
+ }
2385
+ if (existsSync(mentionsJsPath)) {
2386
+ if (enabled) {
2387
+ sendLog('[zalo-patch] Running patch on enable...');
2388
+ if (hasDocker) {
2389
+ const botContainer = getBotContainerName(projectDir);
2390
+ await runCapture('docker', ['exec', botContainer, 'node', containerJsPath], { cwd: projectDir, shell: false });
2391
+ } else {
2392
+ await run('node', [mentionsJsPath], { cwd: projectDir });
2393
+ }
2394
+ } else {
2396
2395
  sendLog('[zalo-patch] Running restore before disabling skill...');
2397
- await runCapture('docker', ['exec', botContainer, 'node', `/home/node/project/.openclaw/${workspaceDir}/skills/sticker-mention/mentions.js`, '--restore'], { cwd: projectDir, shell: false });
2396
+ if (hasDocker) {
2397
+ const botContainer = getBotContainerName(projectDir);
2398
+ await runCapture('docker', ['exec', botContainer, 'node', containerJsPath, '--restore'], { cwd: projectDir, shell: false });
2399
+ } else {
2400
+ await run('node', [mentionsJsPath, '--restore'], { cwd: projectDir });
2401
+ }
2398
2402
  }
2399
- } catch (e) {
2400
- sendLog(`[zalo-patch] Restore failed: ${e.message}`);
2401
2403
  }
2404
+ } catch (e) {
2405
+ sendLog(`[zalo-patch] Zalo patch/restore action failed: ${e.message}`);
2402
2406
  }
2403
- if (existsSync(sf.file)) await fsp.rm(sf.file, { force: true });
2404
- if (existsSync(jsf.file)) await fsp.rm(jsf.file, { force: true });
2405
2407
  }
2406
2408
  }
2407
2409
 
@@ -2461,6 +2463,64 @@ async function applyFeatureToggle(projectDir, agentId, kind, id, enabled) {
2461
2463
  }
2462
2464
 
2463
2465
  async function installFeature(projectDir, agentId, kind, id) {
2466
+ if (kind === 'skill') {
2467
+ const skillSlugMap = {
2468
+ 'image-gen': 'infographic-generator',
2469
+ 'sticker-mention': 'zalo-sticker-mention',
2470
+ };
2471
+ const slug = skillSlugMap[id] || id;
2472
+
2473
+ let composeDir = null;
2474
+ if (existsSync(join(projectDir, 'docker-compose.yml'))) {
2475
+ composeDir = projectDir;
2476
+ } else if (existsSync(join(projectDir, 'docker', 'openclaw', 'docker-compose.yml'))) {
2477
+ composeDir = join(projectDir, 'docker', 'openclaw');
2478
+ }
2479
+
2480
+ if (composeDir) {
2481
+ const botContainer = getBotContainerName(projectDir);
2482
+ sendLog(`[skill] Installing/updating clawhub:${slug} inside container ${botContainer} for agent ${agentId}...`);
2483
+
2484
+ const cmd = `cd /home/node/project && openclaw skills install ${slug} --agent ${agentId} --force`;
2485
+ const cmdOut = await runCapture('docker', ['exec', botContainer, 'sh', '-lc', cmd], { cwd: projectDir, shell: false });
2486
+
2487
+ if (cmdOut) {
2488
+ for (const line of `${cmdOut.stdout}\n${cmdOut.stderr}`.split(/\r?\n/).filter(Boolean)) sendLog(line);
2489
+ }
2490
+
2491
+ if (cmdOut.code !== 0) {
2492
+ const installed = isSkillFolderExists(projectDir, agentId, slug);
2493
+ if (installed) {
2494
+ sendLog(`[skill] Warning: installation reported errors, but skill folder exists. Proceeding.`);
2495
+ } else {
2496
+ throw new Error(cmdOut.stderr || cmdOut.stdout || `Failed to install skill ${slug} inside container.`);
2497
+ }
2498
+ }
2499
+
2500
+ sendLog(`[skill] Restarting docker container to apply skill...`);
2501
+ await run('docker', ['restart', botContainer], { shell: false });
2502
+ } else {
2503
+ await run('openclaw', ['doctor', '--fix'], { cwd: projectDir, env: openclawProjectEnv(projectDir) }).catch((err) => sendLog(`[skill] doctor --fix skipped: ${err.message}`));
2504
+ sendLog(`[skill] Installing clawhub:${slug} for agent ${agentId}...`);
2505
+
2506
+ await run('openclaw', ['skills', 'install', slug, '--agent', agentId, '--force'], {
2507
+ cwd: projectDir,
2508
+ env: openclawProjectEnv(projectDir)
2509
+ });
2510
+ }
2511
+
2512
+ // Automatically enable it in config after install
2513
+ const cfgPath = join(projectDir, '.openclaw', 'openclaw.json');
2514
+ if (existsSync(cfgPath)) {
2515
+ const cfg = ensureConfigShape(JSON.parse(await fsp.readFile(cfgPath, 'utf8')));
2516
+ cfg.skills = cfg.skills || { entries: {} };
2517
+ cfg.skills.entries = cfg.skills.entries || {};
2518
+ cfg.skills.entries[id] = cfg.skills.entries[id] || {};
2519
+ cfg.skills.entries[id].enabled = true;
2520
+ await fsp.writeFile(cfgPath, JSON.stringify(cfg, null, 2), 'utf8');
2521
+ }
2522
+ }
2523
+
2464
2524
  if (kind === 'plugin') {
2465
2525
  let composeDir = null;
2466
2526
  if (existsSync(join(projectDir, 'docker-compose.yml'))) {
@@ -2624,6 +2684,48 @@ async function getInstalledPluginVersion(projectDir, aliases = []) {
2624
2684
  return '';
2625
2685
  }
2626
2686
 
2687
+ function isSkillFolderExists(projectDir, agentId, skillFolder, cfg = null) {
2688
+ if (!projectDir) return false;
2689
+ if (!cfg) {
2690
+ const cfgPath = join(projectDir, '.openclaw', 'openclaw.json');
2691
+ if (!existsSync(cfgPath)) return false;
2692
+ try {
2693
+ cfg = JSON.parse(fs.readFileSync(cfgPath, 'utf8'));
2694
+ } catch (e) {
2695
+ return false;
2696
+ }
2697
+ }
2698
+ const agent = cfg?.agents?.list?.find((a) => a.id === agentId) || cfg?.agents?.list?.[0];
2699
+ if (!agent) return false;
2700
+ const rel = workspaceRelForAgent(agent, cfg, projectDir);
2701
+ const skillPath = join(projectDir, '.openclaw', rel, 'skills', skillFolder);
2702
+ return existsSync(skillPath);
2703
+ }
2704
+
2705
+ async function getInstalledSkillVersion(projectDir, agentId, skillFolder, cfg = null) {
2706
+ if (!projectDir) return '';
2707
+ if (!cfg) {
2708
+ const cfgPath = join(projectDir, '.openclaw', 'openclaw.json');
2709
+ if (!existsSync(cfgPath)) return '';
2710
+ try {
2711
+ cfg = JSON.parse(await fsp.readFile(cfgPath, 'utf8'));
2712
+ } catch (e) {
2713
+ return '';
2714
+ }
2715
+ }
2716
+ const agent = cfg?.agents?.list?.find((a) => a.id === agentId) || cfg?.agents?.list?.[0];
2717
+ if (!agent) return '';
2718
+ const rel = workspaceRelForAgent(agent, cfg, projectDir);
2719
+ const pkgPath = join(projectDir, '.openclaw', rel, 'skills', skillFolder, 'package.json');
2720
+ try {
2721
+ if (existsSync(pkgPath)) {
2722
+ const pkg = JSON.parse(await fsp.readFile(pkgPath, 'utf8'));
2723
+ return pkg.version || '';
2724
+ }
2725
+ } catch (e) {}
2726
+ return '';
2727
+ }
2728
+
2627
2729
  async function getFeatureFlags(projectDir, agentId = '') {
2628
2730
  const cfgPath = join(projectDir || '', '.openclaw', 'openclaw.json');
2629
2731
  const cfg = existsSync(cfgPath) ? ensureConfigShape(JSON.parse(await fsp.readFile(cfgPath, 'utf8').catch(() => '{}'))) : {};
@@ -2682,12 +2784,16 @@ async function getFeatureFlags(projectDir, agentId = '') {
2682
2784
  const isActuallyInstalled = (aliases = []) =>
2683
2785
  extensionDirExists(aliases) || isInstalledByRecord(aliases);
2684
2786
  const installed = {
2787
+ 'skill:image-gen': isSkillFolderExists(projectDir, aid, 'infographic-generator', cfg),
2788
+ 'skill:sticker-mention': isSkillFolderExists(projectDir, aid, 'zalo-sticker-mention', cfg),
2685
2789
  'plugin:openclaw-browser-automation': isActuallyInstalled(aliases.browser),
2686
2790
  'plugin:openclaw-zalo-mod': isActuallyInstalled(aliases.zalo),
2687
2791
  'plugin:openclaw-facebook-crawler': isActuallyInstalled(aliases.crawler),
2688
2792
  'plugin:openclaw-n8n-facebook-poster': isActuallyInstalled(aliases.poster),
2689
2793
  };
2690
2794
  const versions = {
2795
+ 'skill:image-gen': await getInstalledSkillVersion(projectDir, aid, 'infographic-generator', cfg),
2796
+ 'skill:sticker-mention': await getInstalledSkillVersion(projectDir, aid, 'zalo-sticker-mention', cfg),
2691
2797
  'plugin:openclaw-browser-automation': await getInstalledPluginVersion(projectDir, aliases.browser),
2692
2798
  'plugin:openclaw-zalo-mod': await getInstalledPluginVersion(projectDir, aliases.zalo),
2693
2799
  'plugin:openclaw-facebook-crawler': await getInstalledPluginVersion(projectDir, aliases.crawler),
@@ -53,7 +53,7 @@
53
53
  userInfo: '',
54
54
  securityRules: '',
55
55
  plugins: [],
56
- skills: ['memory', 'image-gen', 'web-search'],
56
+ skills: ['memory', 'web-search'],
57
57
  // Persisted credential inputs (Bug 1+2 fix)
58
58
  botToken: '',
59
59
  apiKey: '',
@@ -304,6 +304,13 @@ if(touched){console.log('[patch-9router] Applied Codex compatibility patch.');}e
304
304
  ' sed -i "s/LISTENER_WATCHDOG_MAX_GAP_MS\\\\s*=\\\\s*35e3/LISTENER_WATCHDOG_MAX_GAP_MS = 90e3/" "$ZALO_JS"',
305
305
  ' echo "[entrypoint] patched zalouser watchdog gap: 35s -> 90s"',
306
306
  'fi',
307
+ '# Automatically run Zalo sticker-mention patch if skill is present',
308
+ 'for MENTIONS_JS in $(find "$OPENCLAW_HOME" -maxdepth 5 -path "*/skills/*/mentions.js" -type f 2>/dev/null); do',
309
+ ' if [ -f "$MENTIONS_JS" ]; then',
310
+ ' echo "[entrypoint] Running patch: $MENTIONS_JS"',
311
+ ' node "$MENTIONS_JS" || echo "[entrypoint] Warning: failed to run patch $MENTIONS_JS"',
312
+ ' fi',
313
+ 'done',
307
314
  ].join('\n'));
308
315
  runtimeParts.push([
309
316
  '# Zalo channel auto-restart monitor (background)',
@@ -531,8 +531,8 @@ for (let i = 0; i < 5; i++) {
531
531
  }
532
532
 
533
533
  // Resolve API Key and Base URL from openclaw.json
534
- let apiKey = 'sk-50599bc9642941c0-obzd49-1940044a'; // default fallback key
535
- let baseUrl = 'http://9router:20128/v1'; // default fallback URL
534
+ let apiKey = process.env.NINE_ROUTER_API_KEY || ''; // default fallback key
535
+ let baseUrl = process.env.NINE_ROUTER_BASE_URL || 'http://9router:20128/v1'; // default fallback URL
536
536
  if (openclawJsonPath) {
537
537
  try {
538
538
  const config = JSON.parse(fs.readFileSync(openclawJsonPath, 'utf8'));
package/dist/web/app.js CHANGED
@@ -445,7 +445,8 @@ function wireSkillsHandlers(scope = document) {
445
445
  await api('/api/features/install', { method:'POST', body:{ kind, id, agentId: currentBotId() } });
446
446
  await loadFeatureFlags(true);
447
447
  await loadFiles(true);
448
- showToast(t('Thành công', 'Success'), t('Cài đặt/Cập nhật thành công plugin: ', 'Successfully installed/updated plugin: ') + id, 'success');
448
+ const label = kind === 'skill' ? t('kỹ năng: ', 'skill: ') : t('plugin: ', 'plugin: ');
449
+ showToast(t('Thành công', 'Success'), t('Cài đặt/Cập nhật thành công ', 'Successfully installed/updated ') + label + id, 'success');
449
450
  } catch (err) {
450
451
  showToast(t('Thất bại', 'Failed'), err.message, 'error');
451
452
  } finally {
@@ -842,13 +843,13 @@ function botSkillsPanel() {
842
843
  const row = (item, group) => {
843
844
  const key = `${group}:${item.id}`;
844
845
  const loading = !!state.featureLoading[key];
845
- const isPlugin = group === 'plugin';
846
- const isInstalled = !isPlugin || !!state.featureInstalled?.[key];
846
+ const requiresInstall = group === 'plugin' || (group === 'skill' && (item.id === 'image-gen' || item.id === 'sticker-mention'));
847
+ const isInstalled = !requiresInstall || !!state.featureInstalled?.[key];
847
848
 
848
849
  let actionsHtml = '';
849
850
  if (isInstalled) {
850
851
  actionsHtml = `<div style="display:flex; align-items:center; gap:8px;">`;
851
- if (isPlugin) {
852
+ if (requiresInstall) {
852
853
  actionsHtml += `<button class="secondary icon-btn2 update-plugin-btn" type="button" data-feature-install="${key}" ${loading ? 'disabled' : ''} title="${t('Cập nhật lên bản mới nhất','Update to latest version')}" style="padding: 4px 8px; font-size: 11px; height: 28px; border-width: 1px; color:#ffb020; border-color: rgba(255,176,32,0.25); background: rgba(255,176,32,0.05);">${actionIcon('refresh')}<span>${t('Cập nhật','Update')}</span></button>`;
853
854
  }
854
855
  actionsHtml += `<label class="feature-switch"><input type="checkbox" data-feature-toggle="${key}" ${flags[key] ? 'checked' : ''} ${loading ? 'disabled' : ''}/><span></span></label></div>`;
@@ -856,7 +857,7 @@ function botSkillsPanel() {
856
857
  actionsHtml = `<button class="secondary icon-btn2" type="button" data-feature-install="${key}" ${loading ? 'disabled' : ''}>${actionIcon('download')} ${ui('installVerb')}</button>`;
857
858
  }
858
859
 
859
- const version = isPlugin && isInstalled ? (state.featureVersions?.[key] || '') : '';
860
+ const version = requiresInstall && isInstalled ? (state.featureVersions?.[key] || '') : '';
860
861
  const versionBadge = version ? `<span class="plugin-version-badge" style="display:inline-block; font-size: 11px; background: rgba(66, 133, 244, 0.15); color: #4285F4; padding: 2px 6px; border-radius: 4px; font-weight: 600; margin-left: 8px; border: 1px solid rgba(66,133,244,0.25);">v${escapeHtml(version)}</span>` : '';
861
862
 
862
863
  return `<article class="card feature-card ${loading ? 'is-loading' : ''}"><div class="feature-head"><div><b>${escapeHtml(item.title)}${versionBadge}</b><p>${escapeHtml(item.desc)}</p></div>` +
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-openclaw-bot",
3
- "version": "5.8.16",
3
+ "version": "5.8.17",
4
4
  "description": "Interactive CLI installer for OpenClaw Bot",
5
5
  "main": "dist/cli.js",
6
6
  "bin": {