create-openclaw-bot 5.8.2 → 5.8.4

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/dist/web/app.js CHANGED
@@ -311,7 +311,7 @@ function render() {
311
311
  if (!mainContainer) {
312
312
  $('#app').innerHTML = `
313
313
  <aside class="sidebar">
314
- <div class="brand"><img src="/openclaw-logo.svg" onerror="this.src='/openclaw-logo.png'" alt="OpenClaw"/><div style="display: flex; flex-direction: column; align-items: center; text-align: center;"><b>OpenClaw Setup</b><span style="display: block; width: 100%; text-align: center; font-size: 13.5px; font-weight: 600; margin-top: 6px; color: var(--muted);">v${state.system?.versions?.setup || '5.8.0'}</span></div></div>
314
+ <div class="brand"><img src="/openclaw-logo.svg" onerror="this.src='/openclaw-logo.png'" alt="OpenClaw"/><div style="display: flex; flex-direction: column; align-items: center; text-align: center;"><b>OpenClaw Setup</b><span id="sidebar-version" style="display: block; width: 100%; text-align: center; font-size: 13.5px; font-weight: 600; margin-top: 6px; color: var(--muted);">v${state.system?.versions?.setup || '...'}</span></div></div>
315
315
  <nav class="sidebar-nav">${tabs.map(([id,label]) => `<button class="nav ${state.tab===id?'active':''}" data-tab="${id}">${icon(id)}<span>${label}</span></button>`).join('')}</nav>
316
316
  ${sidebarExtras()}
317
317
  </aside>
@@ -346,6 +346,9 @@ function render() {
346
346
  const titleEl = $('#app-page-title');
347
347
  if (titleEl) titleEl.innerHTML = title();
348
348
 
349
+ const sidebarVerEl = $('#sidebar-version');
350
+ if (sidebarVerEl) sidebarVerEl.textContent = `v${state.system?.versions?.setup || '...'}`;
351
+
349
352
  const panelEl = $('.panel');
350
353
  if (panelEl) panelEl.innerHTML = content();
351
354
 
@@ -473,9 +476,10 @@ function dashboardView() {
473
476
  const cat = state.catalog || {};
474
477
  const allSkills = cat.skills || [];
475
478
  const allPlugins = cat.plugins || [];
476
- const featureFlags = state.featureInstalled || {};
477
- const installedSkillsCount = allSkills.filter(sk => featureFlags[`skill:${sk.id}`]).length;
478
- const installedPluginsCount = allPlugins.filter(pl => featureFlags[`plugin:${pl.id}`]).length;
479
+ const featureFlags = state.featureFlags || {};
480
+ const featureInstalled = state.featureInstalled || {};
481
+ const installedSkillsCount = allSkills.filter(sk => !!featureFlags[`skill:${sk.slug || sk.id}`]).length;
482
+ const installedPluginsCount = allPlugins.filter(pl => !!featureInstalled[`plugin:${pl.package || pl.id}`]).length;
479
483
 
480
484
  const openclawVer = String((s.runtimeVersions?.openclaw || sys.versions?.currentOpenclaw || sys.versions?.openclaw || '-')).replace(/^openclaw@/, '').replace(/^create-openclaw-bot@/, '');
481
485
  const routerVer = String((s.runtimeVersions?.nineRouter || sys.versions?.currentNineRouter || sys.versions?.nineRouter || '-')).replace(/^9router@/, '');
@@ -491,10 +495,10 @@ function dashboardView() {
491
495
  const pluginsPercent = allPlugins.length ? Math.round((installedPluginsCount / allPlugins.length) * 100) : 0;
492
496
 
493
497
  const widgets = [
494
- { label: t('Project hi\u1ec7n t\u1ea1i','Current project'), value: escapeHtml(fileBaseName(s.projectDir || '-')), meta: `${projects.length} projects` },
498
+ { label: t('Project hiện tại','Current project'), value: escapeHtml(fileBaseName(s.projectDir || '-')), meta: `${projects.length} projects` },
495
499
  { label: t('Bots','Bots'), value: String(bots.length), meta: `${byChannel('telegram')} Telegram \u00b7 ${byChannel('zalo-personal')} Zalo` },
496
- { label: t('Provider (LLM)','Provider (LLM)'), value: '9Router', meta: t('\u0110ang s\u1eed d\u1ee5ng nhi\u1ec1u nh\u1ea5t','Most used provider') },
497
- { label: t('Model (AI)','Model (AI)'), value: 'gemini-1.5-flash', meta: t('\u0110ang s\u1eed d\u1ee5ng nhi\u1ec1u nh\u1ea5t','Most used model') }
500
+ { label: t('Provider (LLM)','Provider (LLM)'), value: s.activeProvider || '9Router', meta: t('Đang sử dụng nhiều nhất','Most used provider') },
501
+ { label: t('Model (AI)','Model (AI)'), value: s.activeModel || 'smart-route', meta: t('Đang sử dụng nhiều nhất','Most used model') }
498
502
  ];
499
503
 
500
504
  return `<div class="dash-shell">
@@ -623,30 +627,62 @@ function botView() {
623
627
  const channelBots = bots.filter(b => b.channel === ch);
624
628
  if (channelBots.length && !channelBots.some(b => b.id === state.activeBotId)) state.activeBotId = (channelBots.find(b => b.id !== 'bot') || channelBots[0]).id;
625
629
  if (!channelBots.length && state.activeBotId) { state.activeBotId = ''; state.selectedFile = ''; state.files = []; }
626
- return `<div class="bot-layout bot-layout--single">
627
- <section class="card bot-meta">
628
- <div class="card-head"><h3>${t('Project & m\u00f4i tr\u01b0\u1eddng','Project & runtime')}</h3></div>
629
- <div class="project-switcher">${(sys.projects||[]).length ? (sys.projects||[]).map(p => `<button class="project-chip ${s.projectDir===p.projectDir?'active':''}" data-project-connect="${escapeHtml(p.projectDir)}"><b>${escapeHtml(fileBaseName(p.projectDir))}</b><small>${escapeHtml(p.projectDir)}</small></button>`).join('') : ''}</div>
630
- <div class="bot-meta-grid">
631
- <div><span>${t('Project','Project')}</span><b>${escapeHtml(s.projectDir || '-')}</b></div>
632
- <div><span>${t('K\u00eanh','Channel')}</span><b>${escapeHtml(ch)}</b></div>
633
- <div><span>OpenClaw</span><b>${statusBadge(s.gatewayStatus || 'offline')} ${escapeHtml(String(s.runtimeVersions?.openclaw || sys.versions?.openclaw || '-').replace(/^openclaw@/, '').replace(/^create-openclaw-bot@/, ''))}</b></div>
634
- <div><span>9Router</span><b>${statusBadge(s.routerStatus || 'offline')} ${escapeHtml(String(s.runtimeVersions?.nineRouter || sys.versions?.nineRouter || '-').replace(/^9router@/, ''))}</b></div>
635
- </div>
636
- </section>
637
- <section class="card bot-main">
638
- <div class="card-head">
639
- <h3>${t('Bot','Bot')}</h3>
640
- <div style="display:flex;gap:8px;">
641
- ${(ch === 'zalo-personal' && channelBots.length > 0) ? `<button class="secondary btn-inline" data-zalo-login-trigger type="button">🔑 ${t('Đăng nhập Zalo','Zalo Login')}</button>` : ''}
642
- <button class="primary btn-inline" data-bot-modal="open" type="button">+ ${t('Tạo mới','New')}</button>
630
+
631
+ const openclawVer = String((s.runtimeVersions?.openclaw || sys.versions?.currentOpenclaw || sys.versions?.openclaw || '-')).replace(/^openclaw@/, '').replace(/^create-openclaw-bot@/, '');
632
+ const routerVer = String((s.runtimeVersions?.nineRouter || sys.versions?.currentNineRouter || sys.versions?.nineRouter || '-')).replace(/^9router@/, '');
633
+ const nodeVer = String((s.runtimeVersions?.node || sys.versions?.currentNode || sys.versions?.node || sys.node?.output || '-')).replace(/^v/, '');
634
+ const machineLabel = `${sys.os || '-'} \u00b7 ${sys.arch || '-'}`;
635
+
636
+ return `<div class="bot-layout">
637
+ <div class="bot-main-col" style="display: grid; gap: 18px;">
638
+ <section class="card bot-meta bot-main bot-projects-and-bots">
639
+ <div class="card-head" style="margin-bottom: 12px;">
640
+ <h3>${t('Project & bot','Project & bot')}</h3>
643
641
  </div>
644
- </div>
645
- <div class="channel-tabs">${BOT_CHANNELS.map(c => `<button class="${ch===c.id?'active':''}" data-bot-channel="${c.id}"><img src="${c.icon}" onerror="this.style.display='none'"/>${c.title}<span>${bots.filter(b=>b.channel===c.id).length}</span></button>`).join('')}</div>
646
- ${botListPanel(channelBots)}
647
- </section>
648
- <section class="card bot-skills-panel"><div class="card-head"><h3>${ui('skills')} & ${ui('plugins')}</h3></div>${botSkillsPanel()}</section>
649
- <section class="card bot-files-panel">${channelBots.length ? botFilesPanel() : `<div class="bot-files-head"><div><h3>${t('C\u00e2y th\u01b0 m\u1ee5c bot','Bot file tree')}</h3>${projectPathLine()}</div></div><p>${t('Ch\u01b0a c\u00f3 bot trong k\u00eanh n\u00e0y. T\u1ea1o bot tr\u01b0\u1edbc \u0111\u1ec3 xem file workspace.','No bot in this channel. Create a bot first to view workspace files.')}</p>`}</section>
642
+ <div class="project-switcher">
643
+ ${(sys.projects||[]).length ? (sys.projects||[]).map(p => {
644
+ const active = s.projectDir===p.projectDir;
645
+ return `
646
+ <div class="project-tab-btn ${active?'active':''}" data-project-connect="${escapeHtml(p.projectDir)}">
647
+ <div class="project-tab-info">
648
+ <b>${escapeHtml(fileBaseName(p.projectDir))}</b>
649
+ <small>${escapeHtml(p.projectDir)}</small>
650
+ </div>
651
+ <button class="project-tab-delete" data-project-remove="${escapeHtml(p.projectDir)}" title="${t('Xóa project','Delete project')}">
652
+ <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5 4v6m4-6v6m1-10V4a1 1 0 00-1-1h-4a1 1 0 00-1 1v3M4 7h16" stroke-linecap="round" stroke-linejoin="round"/></svg>
653
+ </button>
654
+ </div>
655
+ `;
656
+ }).join('') : ''}
657
+ </div>
658
+
659
+ <div class="bot-main-content" style="margin-top: 14px;">
660
+ <div class="card-head" style="margin-bottom: 14px; display: flex; justify-content: space-between; align-items: center;">
661
+ <h3 style="margin: 0; font-size: 16px;">${t('Danh sách bot','Bot list')}</h3>
662
+ ${(ch === 'zalo-personal' && channelBots.length > 0) ? `<button class="secondary btn-inline" data-zalo-login-trigger type="button" style="min-height: 36px; padding: 6px 12px; font-size: 13px;">🔑 ${t('Đăng nhập Zalo','Zalo Login')}</button>` : ''}
663
+ </div>
664
+ <div class="channel-tabs" style="margin-bottom: 16px;">${BOT_CHANNELS.map(c => `<button class="${ch===c.id?'active':''}" data-bot-channel="${c.id}"><img src="${c.icon}" onerror="this.style.display='none'"/>${c.title}<span>${bots.filter(b=>b.channel===c.id).length}</span></button>`).join('')}</div>
665
+ ${botListPanel(channelBots)}
666
+ </div>
667
+ </section>
668
+ <section class="card bot-skills-panel"><div class="card-head"><h3>${ui('skills')} & ${ui('plugins')}</h3></div>${botSkillsPanel()}</section>
669
+ <section class="card bot-files-panel">${channelBots.length ? botFilesPanel() : `<div class="bot-files-head"><div><h3>${t('Cây thư mục bot','Bot file tree')}</h3>${projectPathLine()}</div></div><p>${t('Chưa có bot trong kênh này. Tạo bot trước để xem file workspace.','No bot in this channel. Create a bot first to view workspace files.')}</p>`}</section>
670
+ </div>
671
+
672
+ <div class="bot-side-col" style="display: grid; gap: 18px; position: sticky; top: 96px;">
673
+ <section class="card bot-status-card">
674
+ <div class="card-head"><h3>${t('Trạng thái','Status')}</h3></div>
675
+ <div class="runtime-status-grid" style="grid-template-columns: 1fr; margin-top: 14px;">
676
+ <div class="runtime-status-card"><div class="runtime-status-head"><span>OpenClaw</span>${statusBadge(s.gatewayStatus)}</div><div class="runtime-card-actions"><a class="runtime-open-btn secondary icon-btn2" href="${s.gatewayUrl||'http://127.0.0.1:18789'}" target="_blank" rel="noopener" style="justify-content:center; flex:1; font-size:12px; height:36px; border-width:1px;"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" style="width:14px; height:14px;"><path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path><polyline points="15 3 21 3 21 9"></polyline><line x1="10" y1="14" x2="21" y2="3"></line></svg>${t('Mở web','Open')}</a><button class="runtime-open-btn icon-btn2" data-update-app type="button" style="justify-content:center; flex:1; font-size:12px; height:36px; border:none; background:rgba(255,36,54,.15); color:#ff4b5d;"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" style="width:14px; height:14px;"><polyline points="23 4 23 10 17 10"></polyline><path d="M20.49 15a9 9 0 1 1-2.12-9.36L23 10"></path></svg>${t('Update','Update')}</button></div></div>
677
+ <div class="runtime-status-card"><div class="runtime-status-head"><span>9Router</span>${statusBadge(s.routerStatus)}</div><div class="runtime-card-actions"><a class="runtime-open-btn secondary icon-btn2" href="${s.routerUrl||'http://127.0.0.1:20128'}" target="_blank" rel="noopener" style="justify-content:center; flex:1; font-size:12px; height:36px; border-width:1px;"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" style="width:14px; height:14px;"><path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path><polyline points="15 3 21 3 21 9"></polyline><line x1="10" y1="14" x2="21" y2="3"></line></svg>${t('Mở web','Open')}</a><button class="runtime-open-btn icon-btn2" data-update-router type="button" style="justify-content:center; flex:1; font-size:12px; height:36px; border:none; background:rgba(255,36,54,.15); color:#ff4b5d;"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" style="width:14px; height:14px;"><polyline points="23 4 23 10 17 10"></polyline><path d="M20.49 15a9 9 0 1 1-2.12-9.36L23 10"></path></svg>${t('Update','Update')}</button></div></div>
678
+ </div>
679
+
680
+ <div class="dash-version-list" style="margin-top: 18px;">
681
+ <div><span>OpenClaw</span><b>${escapeHtml(openclawVer || '-')}</b></div>
682
+ <div><span>9Router</span><b>${escapeHtml(routerVer || '-')}</b></div>
683
+ </div>
684
+ </section>
685
+ </div>
650
686
  </div>`;
651
687
  }
652
688
 
@@ -661,6 +697,12 @@ function botCreateForm(ch, empty, data = {}) {
661
697
  : `<div class="choice-grid bot-channel-grid">${BOT_CHANNELS.map(o => choiceCard('bot-channel', o, ch)).join('')}</div>`}
662
698
  <div class="bot-form-grid">
663
699
  <label><span>${t('\u0054\u00ean bot','Bot name')}</span><input name="botName" required placeholder="Williams" value="${escapeHtml(data.botName || '')}"/></label>
700
+ ${data.mode !== 'edit' ? `
701
+ <label>
702
+ <span>${t('ID bot (viết liền, ko dấu)', 'Bot ID (no accent, lowercase)')}</span>
703
+ <input name="agentId" required pattern="^[a-z0-9-_]+$" title="${t('Chỉ dùng chữ cái viết thường không dấu, số, gạch ngang (-) và gạch dưới (_)', 'Only lowercase letters, numbers, hyphens (-) and underscores (_) are allowed')}" placeholder="william" value=""/>
704
+ </label>
705
+ ` : ''}
664
706
  <label><span>${t('\u0056ai tr\u00f2','Role')}</span><input name="role" required placeholder="${t('\u0054r\u1ee3 l\u00fd AI c\u00e1 nh\u00e2n','Personal AI assistant')}" value="${escapeHtml(data.role || '')}"/></label>
665
707
  <label><span>Emoji</span><input name="emoji" maxlength="8" placeholder="\uD83E\uDD16" value="${escapeHtml(data.emoji || '')}"/></label>
666
708
  ${needsToken ? `<label><span>Token</span><input name="token" ${tokenRequired ? 'required' : ''} autocomplete="off" placeholder="${ch==='telegram'?'123456:ABC...':'Zalo OA token'}" value="${escapeHtml(data.token || '')}"/></label>` : `<input name="token" type="hidden" value="${escapeHtml(data.token || '')}"/>`}
@@ -687,10 +729,17 @@ function botCreateModal() {
687
729
  }
688
730
 
689
731
  function botListPanel(bots) {
690
- return bots.length ? `<div class="bot-list">${bots.map(b => {
732
+ const listItems = bots.map(b => {
691
733
  const role = (b.role || b.desc || b.description || '').trim() || t('Tr\u1ee3 l\u00fd OpenClaw','OpenClaw assistant');
692
734
  return `<article class="bot-item ${state.activeBotId===b.id?'active':''}" data-bot-id="${escapeHtml(b.id)}"><div class="bot-item-actions"><button class="bot-edit" data-edit-bot="${escapeHtml(b.id)}" title="${t('Sửa bot','Edit bot')}" aria-label="${t('Sửa bot','Edit bot')}">${actionIcon('edit')}</button><button class="bot-delete" data-delete-bot="${escapeHtml(b.id)}" title="${t('X\u00f3a bot','Delete bot')}" aria-label="${t('X\u00f3a bot','Delete bot')}">&times;</button></div><b>${escapeHtml(b.name)}</b><small title="${escapeHtml(role)}">${escapeHtml(role)}</small></article>`;
693
- }).join('')}</div>` : `<div class="empty-create"><h3>${t('K\u00eanh n\u00e0y ch\u01b0a c\u00f3 bot','No bot in this channel')}</h3><button class="primary" data-bot-modal="open">+ ${t('T\u1ea1o bot','Create bot')}</button></div>`;
735
+ });
736
+ listItems.push(`
737
+ <article class="bot-item bot-create-card" data-bot-modal="open">
738
+ <span class="plus-icon">+</span>
739
+ <span>${t('T\u1ea1o m\u1edbi','New')}</span>
740
+ </article>
741
+ `);
742
+ return `<div class="bot-list">${listItems.join('')}</div>`;
694
743
  }
695
744
 
696
745
  function statusBadge(v) { return `<span class="runtime-badge ${v === 'online' ? 'ok' : v === 'unknown' ? 'warn' : 'bad'}">${v || 'offline'}</span>`; }
@@ -777,7 +826,9 @@ function filesView() { return `<div class="files">${state.files.map(f=>`<article
777
826
  function botSkillsPanel() {
778
827
  const flags = state.featureFlags || {};
779
828
  const skills = [
780
- { id: 'cron', title: 'Cron', desc: 'Cron guide in TOOLS.md' },
829
+ { id: 'cron', title: 'Cron', desc: 'Native scheduler (SQLite) — cron guide in TOOLS.md' },
830
+ { id: 'image-gen', title: 'Tạo ảnh Infographic', desc: 'Tạo ảnh infographic, poster tự động qua 9Router' },
831
+ { id: 'web-search', title: 'Web Search', desc: 'Tìm kiếm web thời gian thực (DuckDuckGo)' },
781
832
  ];
782
833
  const plugins = [
783
834
  { id: 'openclaw-browser-automation', title: 'openclaw-browser-automation', desc: 'Smart Search + Browser (headless & Chrome thật)' },
@@ -1191,6 +1242,29 @@ async function loadFiles(silent=false){
1191
1242
  async function loadCatalog(silent=false){ state.catalog = await api('/api/catalog'); if (!silent) render(); }
1192
1243
  async function loadFeatureFlags(silent=false){ const botId=currentBotId(); const data = (await api('/api/features' + (botId ? `?agentId=${encodeURIComponent(botId)}` : ''))) || {}; state.featureFlags = data.flags || {}; state.featureInstalled = data.installed || {}; state.featureVersions = data.versions || {}; if (!silent) render(); }
1193
1244
  function appendLogLine(line) {
1245
+ if (line.includes('Setup Wizard updated successfully! Please restart the installer.')) {
1246
+ showToast(t('Đang khởi động lại UI', 'Restarting Setup UI'), t('Hệ thống đang tự khởi động lại để áp dụng phiên bản mới...', 'The system is restarting to apply the new version...'), 'info', 12000);
1247
+ let attempts = 0;
1248
+ const interval = setInterval(async () => {
1249
+ attempts++;
1250
+ try {
1251
+ const res = await fetch('/api/system');
1252
+ if (res.ok) {
1253
+ clearInterval(interval);
1254
+ showToast(t('Cập nhật thành công', 'Update Success'), t('Setup Wizard đã được cập nhật lên phiên bản mới!', 'Setup Wizard has been updated to the new version!'), 'success');
1255
+ setTimeout(() => {
1256
+ window.location.reload();
1257
+ }, 1500);
1258
+ }
1259
+ } catch (e) {
1260
+ if (attempts > 30) {
1261
+ clearInterval(interval);
1262
+ showToast(t('Lỗi kết nối', 'Connection Error'), t('Không thể kết nối lại với Setup UI. Vui lòng tự chạy lại lệnh khởi động.', 'Cannot reconnect to Setup UI. Please run start command manually.'), 'error');
1263
+ }
1264
+ }
1265
+ }, 2000);
1266
+ }
1267
+
1194
1268
  const qrMatch = String(line).match(/^\[zalouser:qr\]\s+(data:image\/[a-zA-Z0-9.+-]+;base64,\S+)/);
1195
1269
  if (qrMatch) {
1196
1270
  state.zaloQrDataUrl = qrMatch[1];