create-openclaw-bot 5.8.0 → 5.8.2

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/setup.js CHANGED
@@ -1,13 +1,13 @@
1
1
  /* ============================================
2
- OpenClaw Setup Wizard — Logic v2
2
+ OpenClaw Setup Wizard Logic v2
3
3
  Multi-model, Multi-plugin, Multi-channel
4
4
  ============================================ */
5
- // AUTO-GENERATED by build.mjs — edit files in src/setup/ instead
5
+ // AUTO-GENERATED by build.mjs edit files in src/setup/ instead
6
6
 
7
7
  (function () {
8
8
  'use strict';
9
9
 
10
- // ── Globals: CDN logos, state, shared utils (setup/data/header.js) ─
10
+ // ── ── Globals: CDN logos, state, shared utils (setup/data/header.js) ──
11
11
  // @ts-nocheck
12
12
  /* eslint-disable no-undef, no-unused-vars */
13
13
  /**
@@ -89,7 +89,7 @@
89
89
  return Array.from(origins);
90
90
  }
91
91
 
92
- // ── PROVIDERS object (setup/data/providers.js) ─────────────────────
92
+ // ── ── PROVIDERS object (setup/data/providers.js) ──────────────────────────────────────────
93
93
  // @ts-nocheck
94
94
  /* eslint-disable no-undef, no-unused-vars */
95
95
  /**
@@ -212,7 +212,7 @@
212
212
  };
213
213
 
214
214
 
215
- // ── CHANNELS, system prompts, security rules (setup/data/channels.js)
215
+ // ── ── CHANNELS, system prompts, security rules (setup/data/channels.js)
216
216
  // @ts-nocheck
217
217
  /* eslint-disable no-undef, no-unused-vars */
218
218
  /**
@@ -383,7 +383,7 @@
383
383
  - ✅ Limit exposed ports (only 38789)`,
384
384
  };
385
385
 
386
- // ── PLUGINS list (setup/data/plugins.js) ───────────────────────────
386
+ // ── ── PLUGINS list (setup/data/plugins.js) ──────────────────────────────────────────────────────
387
387
  // @ts-nocheck
388
388
  /* eslint-disable no-undef, no-unused-vars */
389
389
  /**
@@ -406,6 +406,13 @@
406
406
  */
407
407
  // ========== Available Plugins (npm packages — runtime/channel extensions) ==========
408
408
  const PLUGINS = [
409
+ {
410
+ id: 'browser-automation',
411
+ name: 'Browser Automation ⭐',
412
+ icon: '🌐',
413
+ descVi: 'Smart Search + Điều khiển trình duyệt Chrome/Chromium (ẩn & thật)', descEn: 'Smart Search + Chrome/Chromium browser control (headless & real)',
414
+ package: 'openclaw-browser-automation',
415
+ },
409
416
  {
410
417
  id: 'telegram-multibot-relay',
411
418
  name: 'Telegram Multi-Bot Relay',
@@ -445,7 +452,7 @@
445
452
  ];
446
453
 
447
454
 
448
- // ── SKILLS list (setup/data/skills.js) ─────────────────────────────
455
+ // ── ── SKILLS list (setup/data/skills.js) ──────────────────────────────────────────────────────────
449
456
  // @ts-nocheck
450
457
  /* eslint-disable no-undef, no-unused-vars */
451
458
  /**
@@ -468,14 +475,6 @@
468
475
  */
469
476
  // ========== Available Skills (ClawHub registry — agent capabilities) ==========
470
477
  const SKILLS = [
471
- {
472
- id: 'browser',
473
- name: 'Browser Automation ⭐(Khuyên dùng)',
474
- icon: '🌐',
475
- descVi: 'Tự động thao tác trình duyệt (Playwright)', descEn: 'Automated browser control (Playwright)',
476
- slug: 'browser-automation',
477
- noteVi: 'Cần bật Chrome Debug Mode trên máy host', noteEn: 'Requires Chrome Debug Mode on host',
478
- },
479
478
  {
480
479
  id: 'memory',
481
480
  name: 'Long-term Memory ⭐(Khuyên dùng)',
@@ -574,7 +573,7 @@
574
573
  className: 'plugin-card__badge plugin-card__badge--recommended'
575
574
  };
576
575
  }
577
- if (skill.id === 'browser' || skill.id === 'scheduler') {
576
+ if (skill.id === 'scheduler') {
578
577
  return {
579
578
  text: isVi ? 'Khuyên dùng' : 'Recommended',
580
579
  className: 'plugin-card__badge plugin-card__badge--recommended'
@@ -616,7 +615,7 @@
616
615
  }
617
616
 
618
617
 
619
- // ── Shared runtime constants, relay helpers, auth profile builders (setup/shared/common-gen.js)
618
+ // ── ── Shared runtime constants, relay helpers, auth profile builders (setup/shared/common-gen.js)
620
619
  // @ts-nocheck
621
620
  (function (root) {
622
621
  const OPENCLAW_NPM_SPEC = 'openclaw@latest';
@@ -931,7 +930,7 @@ if (typeof exports !== 'undefined' && typeof globalThis !== 'undefined' && globa
931
930
  Object.assign(exports, globalThis.__openclawCommon);
932
931
  }
933
932
 
934
- // ── Shared workspace file builders (IDENTITY, SOUL, AGENTS, TOOLS, TEAMS...) (setup/shared/workspace-gen.js)
933
+ // ── ── Shared workspace file builders (IDENTITY, SOUL, AGENTS, TOOLS, TEAMS...) (setup/shared/workspace-gen.js)
935
934
  /** @typedef {typeof globalThis & { __openclawWorkspace?: Record<string, Function> }} OpenClawWorkspaceRoot */
936
935
 
937
936
  const workspaceRoot = /** @type {OpenClawWorkspaceRoot} */ (
@@ -1059,6 +1058,226 @@ function buildBootstrapDoc(options = {}) {
1059
1058
  : `# BOOTSTRAP\n\n## Startup role\n- You are **${botName}**.\n- Your identity, role, and style are already defined in **IDENTITY.md**, **SOUL.md**, and **AGENTS.md**.\n- Use those files as the highest-priority source of truth for your persona in this workspace.\n\n## Mandatory\n- Do not ask the user to redefine your name, vibe, persona, signature emoji, or assistant style.\n- Do not say you just woke up, just came online, are choosing your identity, or any similar onboarding line.\n- Do not behave like a blank freshly-created bot.\n- If the user only sends a short opener like "hi" or "alo", greet briefly and reply in your existing role.\n\n## Telegram\n- Before EVERY user-visible Telegram reply, if the current turn exposes a native reaction tool/action, use it to add \`👍\` first unless \`👍\` is already present.\n- Never claim that you reacted unless the tool actually ran and the reaction is real on the chat.\n- If the target chat does not support real reactions or the tool is not exposed, still reply normally and do not mention the technical limitation.\n`;
1060
1059
  }
1061
1060
 
1061
+ function buildSearchToolJs() {
1062
+ return `/**
1063
+ * search-tool.js — Stealth search via Playwright Headless Chromium or CDP fallback
1064
+ * Zero tokens, no API keys, concurrent multi-engine scraping (Google + Bing + DuckDuckGo).
1065
+ * Usage: node search-tool.js "<query>" [limit]
1066
+ */
1067
+ let playwright;
1068
+ try {
1069
+ playwright = require('playwright-core');
1070
+ } catch (e) {
1071
+ try {
1072
+ playwright = require('/usr/local/lib/node_modules/openclaw/node_modules/playwright-core');
1073
+ } catch (err) {
1074
+ try {
1075
+ const path = require('path');
1076
+ playwright = require(path.join(process.cwd(), 'node_modules', 'playwright-core'));
1077
+ } catch (x) {
1078
+ console.error(JSON.stringify({ error: 'Playwright not found! Install it or run within OpenClaw environment.' }));
1079
+ process.exit(1);
1080
+ }
1081
+ }
1082
+ }
1083
+ const { chromium } = playwright;
1084
+
1085
+ const query = process.argv[2];
1086
+ const limit = parseInt(process.argv[3]) || 5;
1087
+ const CDP_URL = 'http://127.0.0.1:9222';
1088
+
1089
+ if (!query) {
1090
+ console.error(JSON.stringify({ error: 'Usage: node search-tool.js "<query>" [limit]' }));
1091
+ process.exit(1);
1092
+ }
1093
+
1094
+ (async () => {
1095
+ let browser;
1096
+ let ctx;
1097
+ let isStandalone = false;
1098
+ try {
1099
+ // Try connecting to active Chrome CDP first
1100
+ try {
1101
+ browser = await chromium.connectOverCDP(CDP_URL, { timeout: 3000 });
1102
+ ctx = browser.contexts()[0];
1103
+ } catch (e) {
1104
+ // Fallback to standalone headless Chromium launch
1105
+ browser = await chromium.launch({
1106
+ headless: true,
1107
+ args: [
1108
+ '--no-sandbox',
1109
+ '--disable-gpu',
1110
+ '--disable-dev-shm-usage',
1111
+ '--disable-blink-features=AutomationControlled'
1112
+ ]
1113
+ });
1114
+ isStandalone = true;
1115
+ ctx = await browser.newContext({
1116
+ userAgent: 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36'
1117
+ });
1118
+ }
1119
+
1120
+ // Run search queries concurrently on three search engines
1121
+ const [googleResults, bingResults, ddgResults] = await Promise.all([
1122
+ // Google
1123
+ (async () => {
1124
+ const page = await ctx.newPage();
1125
+ try {
1126
+ await page.goto('https://www.google.com/search?q=' + encodeURIComponent(query) + '&hl=vi', { waitUntil: 'domcontentloaded', timeout: 10000 });
1127
+ const res = await page.evaluate(() => {
1128
+ const list = [];
1129
+ const links = Array.from(document.querySelectorAll('a h3'));
1130
+ for (const head of links) {
1131
+ const a = head.closest('a');
1132
+ if (!a) continue;
1133
+ const url = a.href;
1134
+ const title = head.textContent || '';
1135
+ let snippet = '';
1136
+ let parent = a.parentElement;
1137
+ while (parent && parent.tagName !== 'DIV') {
1138
+ parent = parent.parentElement;
1139
+ }
1140
+ if (parent) {
1141
+ const descEl = parent.parentElement?.querySelector('.VwiC3b, .yHGvwa, div[style*="-webkit-line-clamp"]');
1142
+ if (descEl) {
1143
+ snippet = descEl.textContent || '';
1144
+ } else {
1145
+ const texts = Array.from(parent.parentElement?.querySelectorAll('div, span') || [])
1146
+ .map(el => el.textContent.trim())
1147
+ .filter(txt => txt.length > 30 && !txt.includes(title));
1148
+ if (texts.length > 0) snippet = texts[0];
1149
+ }
1150
+ }
1151
+ if (url && title) {
1152
+ list.push({ title, url, snippet });
1153
+ }
1154
+ }
1155
+ return list;
1156
+ });
1157
+ await page.close();
1158
+ return res;
1159
+ } catch (e) {
1160
+ if (page) await page.close();
1161
+ return [];
1162
+ }
1163
+ })(),
1164
+
1165
+ // Bing
1166
+ (async () => {
1167
+ const page = await ctx.newPage();
1168
+ try {
1169
+ await page.goto('https://www.bing.com/search?q=' + encodeURIComponent(query), { waitUntil: 'domcontentloaded', timeout: 10000 });
1170
+ const res = await page.evaluate(() => {
1171
+ const list = [];
1172
+ const items = document.querySelectorAll('li.b_algo');
1173
+ for (const item of items) {
1174
+ const titleEl = item.querySelector('h2 a');
1175
+ if (!titleEl) continue;
1176
+ const title = titleEl.textContent || '';
1177
+ const url = titleEl.href;
1178
+ let snippet = '';
1179
+ const snippetEl = item.querySelector('.b_caption p, .b_snippet, p');
1180
+ if (snippetEl) {
1181
+ snippet = snippetEl.textContent || '';
1182
+ }
1183
+ if (url && title) {
1184
+ list.push({ title, url, snippet });
1185
+ }
1186
+ }
1187
+ return list;
1188
+ });
1189
+ await page.close();
1190
+ return res;
1191
+ } catch (e) {
1192
+ if (page) await page.close();
1193
+ return [];
1194
+ }
1195
+ })(),
1196
+
1197
+ // DuckDuckGo
1198
+ (async () => {
1199
+ const page = await ctx.newPage();
1200
+ try {
1201
+ await page.goto('https://html.duckduckgo.com/html/?q=' + encodeURIComponent(query), { waitUntil: 'domcontentloaded', timeout: 10000 });
1202
+ const res = await page.evaluate(() => {
1203
+ const list = [];
1204
+ const elements = document.querySelectorAll('.result');
1205
+ for (const el of elements) {
1206
+ const titleEl = el.querySelector('.result__title a');
1207
+ const snippetEl = el.querySelector('.result__snippet');
1208
+ if (titleEl) {
1209
+ list.push({
1210
+ title: titleEl.textContent.trim(),
1211
+ url: titleEl.href,
1212
+ snippet: snippetEl ? snippetEl.textContent.trim() : ''
1213
+ });
1214
+ }
1215
+ }
1216
+ return list;
1217
+ });
1218
+ await page.close();
1219
+ return res;
1220
+ } catch (e) {
1221
+ if (page) await page.close();
1222
+ return [];
1223
+ }
1224
+ })()
1225
+ ]);
1226
+
1227
+ // Deduplicate results by normalized URL
1228
+ const allResults = [...googleResults, ...bingResults, ...ddgResults];
1229
+ const uniqueResults = [];
1230
+ const seenUrls = new Set();
1231
+ for (const res of allResults) {
1232
+ if (!res.url || !res.title) continue;
1233
+ let normUrl = res.url.replace(/^(https?:\\/\\/)?(www\\.)?/, '').toLowerCase();
1234
+ if (normUrl.endsWith('/')) normUrl = normUrl.slice(0, -1);
1235
+ if (!seenUrls.has(normUrl)) {
1236
+ seenUrls.add(normUrl);
1237
+ uniqueResults.push(res);
1238
+ }
1239
+ }
1240
+
1241
+ // Score results to prioritize numeric price data for financial queries
1242
+ const isPriceQuery = /giá|vàng|đô|usd|sjc|sh|hôm nay|price|gold|rate|vnd|xe|vnđ/i.test(query);
1243
+ const scoredResults = uniqueResults.map(res => {
1244
+ let score = 0;
1245
+ // Base length score
1246
+ score += Math.min(res.snippet.length / 50, 5);
1247
+
1248
+ if (isPriceQuery) {
1249
+ // Number density check
1250
+ const numCount = (res.snippet.match(/\\d+/g) || []).length;
1251
+ score += Math.min(numCount * 2, 10);
1252
+
1253
+ // Priority keywords boost
1254
+ if (/lượng|chỉ|triệu|nghìn|vnd|usd|sjc|xe|bán|mua|giá/i.test(res.snippet)) {
1255
+ score += 8;
1256
+ }
1257
+ }
1258
+ return { ...res, score };
1259
+ });
1260
+
1261
+ // Sort by score desc
1262
+ scoredResults.sort((a, b) => b.score - a.score);
1263
+
1264
+ // Map back to output format and limit
1265
+ const output = scoredResults.map(({ score, ...rest }) => rest).slice(0, limit);
1266
+ console.log(JSON.stringify(output, null, 2));
1267
+
1268
+ } catch (err) {
1269
+ console.error(JSON.stringify({ error: err.message }));
1270
+ } finally {
1271
+ if (browser && isStandalone) {
1272
+ try {
1273
+ await browser.close();
1274
+ } catch(e) {}
1275
+ }
1276
+ }
1277
+ })();
1278
+ `;
1279
+ }
1280
+
1062
1281
  function buildBrowserToolJs(variant = 'wizard') {
1063
1282
  // v2: Full-featured browser-tool.js matching OpenClaw native browser plugin capabilities
1064
1283
  // Both 'cli' and 'wizard' variants now use the same full script
@@ -1185,7 +1404,16 @@ const CDP_URL = 'http://127.0.0.1:9222';
1185
1404
  const { isVi = true, variant = 'wizard', workspaceRoot = '' } = options;
1186
1405
  const wsRoot = workspaceRoot.replace(/\/+$/, '');
1187
1406
  const btPath = wsRoot ? `${wsRoot}/browser-tool.js` : 'browser-tool.js';
1188
- const modeHeading = variant === 'cli-server' ? '# Headless Server Mode\n\n' : '';
1407
+ let modeHeading = '';
1408
+ if (variant === 'cli-server') {
1409
+ modeHeading = isVi
1410
+ ? `# 🌍 Trình duyệt ảo (Browser Automation)\n\n## 💡 Hướng dẫn vận hành:\n- **Script điều khiển:** \`browser-tool.js\` (Mọi câu lệnh browser đều chạy qua script này).\n- **Môi trường chạy:**\n - **Trên VPS / Linux Server (Headless):** Trình duyệt chạy ngầm hoàn toàn độc lập (Headless) bên trong Docker / Server qua Xvfb. Không thể mở màn hình Chrome thật.\n - **Trên Máy tính cá nhân (Windows/Mac) - Dù chạy Docker hay Native:**\n - **Mặc định:** Chạy ngầm (headless) cực kỳ ổn định.\n - **Chế độ quan sát (Xem bot click):** Nếu bạn muốn xem trực tiếp Chrome thật hoạt động trên màn hình, hãy chạy file \`start-chrome-debug.bat\` (trên Windows) hoặc \`start-chrome-debug.sh\` (trên Mac) ở máy của bạn **trước khi** bot kết nối! Bot sẽ tự động chuyển sang điều khiển màn hình Chrome thật của bạn.\n- **Kết nối mặc định:** \`http://127.0.0.1:9222\`\n\n`
1411
+ : `# 🌍 Browser Automation\n\n## 💡 Operating Guide:\n- **Control script:** \`browser-tool.js\` (All browser commands are executed through this script).\n- **Running environment:**\n - **On VPS / Linux Server (Headless Server Mode):** The browser runs fully headless and isolated inside Docker / Server via Xvfb. No GUI Chrome can be launched.\n - **On Personal Computers (Windows/Mac) - Docker or Native:**\n - **Default:** Runs headless and stable in the background.\n - **Observer Mode (Visual Chrome GUI):** If you want to see the real Chrome window being controlled, run \`start-chrome-debug.bat\` (on Windows) or \`start-chrome-debug.sh\` (on Mac) on your host machine **before** the bot connects! The bot will automatically hook into your real desktop Chrome.\n- **Default endpoint:** \`http://127.0.0.1:9222\`\n\n`;
1412
+ } else {
1413
+ modeHeading = isVi
1414
+ ? `# 🌍 Hướng dẫn Browser (Chrome CDP)\n- **Script điều khiển:** \`browser-tool.js\`\n- **Kết nối Chrome debug:** \`http://127.0.0.1:9222\`\n- **Xem trực quan:** Hãy chạy file \`start-chrome-debug.bat\` (trên Windows) hoặc \`start-chrome-debug.sh\` (trên Mac) để mở Chrome chế độ Debug.\n\n`
1415
+ : `# 🌍 Browser Guide (Chrome CDP)\n- **Control script:** \`browser-tool.js\`\n- **Chrome debug endpoint:** \`http://127.0.0.1:9222\`\n- **Visual interface:** Run \`start-chrome-debug.bat\` (on Windows) or \`start-chrome-debug.sh\` (on Mac) to open Chrome in Debug mode.\n\n`;
1416
+ }
1189
1417
 
1190
1418
  return `${modeHeading}# Navigation
1191
1419
  node ${btPath} status
@@ -1290,11 +1518,37 @@ node ${btPath} close_tab 2`;
1290
1518
  const browserRef = hasBrowser
1291
1519
  ? (browserDocVariant === 'cli-server'
1292
1520
  ? (isVi
1293
- ? `\n\n## \uD83C\uDF10 Browser Automation\n- Xem hướng dẫn chi tiết tại **BROWSER.md**\n- Chế độ hiện tại: browser native/headless của OpenClaw trong Docker hoặc server\n- Nếu browser lỗi, thử lại 1 lần rồi mới báo user với lỗi cụ thể`
1294
- : `\n\n## \uD83C\uDF10 Browser Automation\n- See detailed guide at **BROWSER.md**\n- Current mode: native/headless OpenClaw browser inside Docker or server\n- If browser fails, retry once before reporting the concrete error to the user`)
1521
+ ? `\n\n## 🌐 Browser Automation
1522
+ - Xem hướng dẫn chi tiết tại **BROWSER.md**
1523
+ - Script điều khiển: \`browser-tool.js\`
1524
+ - Chế độ hiện tại:
1525
+ - **Trên VPS / Linux Server:** Chạy ngầm độc lập qua Docker hoặc Xvfb.
1526
+ - **Trên Windows/Mac (Docker hoặc Native):** Chạy ngầm mặc định, hoặc chạy file \`start-chrome-debug.bat\` / \`start-chrome-debug.sh\` để xem trình duyệt trực quan trên màn hình.
1527
+ - Kết nối mặc định: \`http://127.0.0.1:9222\`
1528
+ - **Tìm kiếm Web:** Nếu không có công cụ Web Search (hoặc Web Search không khả dụng/bị lỗi), hãy **luôn sử dụng ngay công cụ terminal (exec/run_command) để chạy lệnh: \`node search-tool.js "<từ khóa>" 5\`**! Lệnh này sẽ tự động chạy ngầm qua DuckDuckGo/Google/Bing bằng trình duyệt ngầm tàng hình của bạn và trả về kết quả JSON sạch ngay lập tức. Tuyệt đối KHÔNG được mở trình duyệt thủ công, chụp ảnh màn hình hay click tìm kiếm bằng tay từng bước!
1529
+ - Nếu browser lỗi, thử lại 1 lần rồi mới báo user với lỗi cụ thể`
1530
+ : `\n\n## 🌐 Browser Automation
1531
+ - See detailed guide at **BROWSER.md**
1532
+ - Control script: \`browser-tool.js\`
1533
+ - Current mode:
1534
+ - **On VPS / Linux Server:** Runs headless via Docker or Xvfb.
1535
+ - **On Windows/Mac (Docker or Native):** Runs headless by default, or run \`start-chrome-debug.bat\` / \`start-chrome-debug.sh\` to see the GUI.
1536
+ - Default endpoint: \`http://127.0.0.1:9222\`
1537
+ - **Web Searching:** If the Web Search tool is unavailable or fails, **always use your terminal execution tool (exec/run_command) to run: \`node search-tool.js "<query>" 5\`**! This will automatically execute the search via DuckDuckGo/Google/Bing under stealth browser mode and return a clean JSON result immediately. Never open the browser manually, take screenshots, or click the search button step-by-step!
1538
+ - If browser fails, retry once before reporting the concrete error to the user`)
1295
1539
  : (isVi
1296
- ? `\n\n## \uD83C\uDF10 Browser Automation\n- Xem hướng dẫn chi tiết tại **BROWSER.md**\n- Script điều khiển: \`browser-tool.js\`\n- Kết nối Chrome debug: \`http://127.0.0.1:9222\`\n- Nếu tool/profile hỏi đường browser desktop, dùng profile \`host-chrome\` trước`
1297
- : `\n\n## \uD83C\uDF10 Browser Automation\n- See detailed guide at **BROWSER.md**\n- Control script: \`browser-tool.js\`\n- Chrome debug endpoint: \`http://127.0.0.1:9222\`\n- If a desktop browser profile is needed, use the \`host-chrome\` profile first`))
1540
+ ? `\n\n## 🌐 Browser Automation
1541
+ - Xem hướng dẫn chi tiết tại **BROWSER.md**
1542
+ - Script điều khiển: \`browser-tool.js\`
1543
+ - Kết nối Chrome debug: \`http://127.0.0.1:9222\`
1544
+ - **Tìm kiếm Web:** Hãy **luôn sử dụng ngay công cụ terminal (exec/run_command) để chạy lệnh: \`node search-tool.js "<từ khóa>" 5\`**! Lệnh này sẽ tự động chạy ngầm qua DuckDuckGo/Google/Bing bằng trình duyệt ngầm tàng hình của bạn và trả về kết quả JSON sạch ngay lập tức. Tuyệt đối KHÔNG được mở trình duyệt thủ công, chụp ảnh màn hình hay click tìm kiếm bằng tay từng bước!
1545
+ - Nếu tool/profile hỏi đường browser desktop, dùng profile \`host-chrome\` trước`
1546
+ : `\n\n## 🌐 Browser Automation
1547
+ - See detailed guide at **BROWSER.md**
1548
+ - Control script: \`browser-tool.js\`
1549
+ - Chrome debug endpoint: \`http://127.0.0.1:9222\`
1550
+ - **Web Searching:** If the Web Search tool is unavailable or fails, **always use your terminal execution tool (exec/run_command) to run: \`node search-tool.js "<query>" 5\`**! This will automatically execute the search via DuckDuckGo/Google/Bing under stealth browser mode and return a clean JSON result immediately. Never open the browser manually, take screenshots, or click the search button step-by-step!
1551
+ - If a desktop browser profile is needed, use the \`host-chrome\` profile first`))
1298
1552
  : '';
1299
1553
 
1300
1554
  const telegramSection = (variant === 'relay')
@@ -1305,8 +1559,38 @@ node ${btPath} close_tab 2`;
1305
1559
 
1306
1560
  const cronSection = hasScheduler
1307
1561
  ? (isVi
1308
- ? `\n\n## \u23F0 Cron / Lên lịch nhắc nhở\n- OpenClaw có hỗ trợ tool hệ thống để chạy Cron Job.\n- Khi user yêu cầu tạo nhắc nhở / lệnh tự động định kỳ, bạn hãy TỰ ĐỘNG dùng tool hệ thống để tạo. **Tuyệt đối không** bắt user dùng crontab hay Task Scheduler chạy tay trên host.\n- Khi thao tác tool cho cron/scheduler, **không điền \`current\` vào thư mục Session**.\n- Bỏ qua việc tra cứu docs nội bộ như \`cron-jobs.mdx\`; tin tưởng khả năng dùng tool hiện có để hoàn thành yêu cầu.`
1309
- : `\n\n## \u23F0 Cron / Scheduled Tasks\n- OpenClaw natively supports system tools for Cron Jobs.\n- When the user asks to schedule tasks or reminders, use the built-in tools automatically. Do NOT ask users to run crontab or Task Scheduler manually on the host.\n- When operating cron/scheduler tools, do **not** put \`current\` into the Session directory.\n- Skip internal doc lookups such as \`cron-jobs.mdx\`; rely on the available tools and complete the scheduling task directly.`)
1562
+ ? `\n\n## \u23F0 Cron / Lên lịch nhắc nhở (tool: \`cron\`)
1563
+ - **Tên tool chính xác:** Tên công cụ \`cron\` (tuyệt đối không nhầm \`native\` hay command line bên ngoài).
1564
+ - **Khi tạo cronjob mới (action \`add\`):**
1565
+ - **TUYỆT ĐỐI KHÔNG điền trường \`agentId\`** trong object \`job\` (hãy bỏ qua/omitted trường này). Hệ thống OpenClaw sẽ tự động gán chính xác ID của bạn vào job đó.
1566
+ - Tuyệt đối **không tự điền** \`agentId\` là \`"bot"\` hay \`"main"\`, vì làm vậy sẽ khiến cronjob thuộc về agent khác và bạn sẽ mất quyền kiểm soát/xóa nó sau này.
1567
+ - **Khi user yêu cầu tắt/bật/xóa cronjob:**
1568
+ 1. **Bước 1 (Tìm kiếm):** Gọi tool \`cron\` với action \`list\` (và \`includeDisabled: true\`) để xem danh sách tất cả cronjob đang chạy trên hệ thống và tìm đúng \`jobId\` phù hợp với yêu cầu.
1569
+ 2. **Bước 2 (Xử lý):**
1570
+ - Để xóa: Gọi action \`remove\` với \`id\` tìm được.
1571
+ - Để tắt/tạm dừng: Gọi action \`update\` với \`id\` và patch \`{"enabled": false}\`.
1572
+ - Để bật lại: Gọi action \`update\` với \`id\` và patch \`{"enabled": true}\`.
1573
+ 3. **Tuyên bố trung thực:** Tuyệt đối không bao giờ trả lời "đã xóa" hay "không có" dựa trên suy đoán của bản thân mà chưa gọi tool \`cron\` để kiểm tra thực tế.
1574
+ - Khi user yêu cầu tạo nhắc nhở / lệnh tự động định kỳ, bạn hãy TỰ ĐỘNG dùng tool \`cron\` (action \`add\`) để tạo. **Tuyệt đối không** bắt user dùng crontab hay Task Scheduler chạy tay trên host.
1575
+ - Khi thao tác tool cho cron/scheduler, **không điền \`current\` vào thư mục Session**.
1576
+ - **QUAN TRỌNG VỀ TARGETING GROUP CHAT**: Khi tạo hoặc cấu hình cron job gửi tin nhắn thông báo (announce mode) đến một Group Chat, giá trị của trường \`delivery.to\` **bắt buộc** phải sử dụng tiền tố \`group:\` trước ID của group (ví dụ: \`group:3815464776067464419\` hoặc \`group:xxxx\`). Tuyệt đối không được chỉ điền ID thuần túy vì hệ thống sẽ hiểu nhầm đó là một DM chat cá nhân (direct message) và gửi sai địa chỉ.
1577
+ - Bỏ qua việc tra cứu docs nội bộ như \`cron-jobs.mdx\`; tin tưởng khả năng dùng tool hiện có để hoàn thành yêu cầu.`
1578
+ : `\n\n## \u23F0 Cron / Scheduled Tasks (tool: \`cron\`)
1579
+ - **Exact tool name:** The tool name is \`cron\` (never mistake it for \`native\` or external command lines).
1580
+ - **When creating a new cronjob (action \`add\`):**
1581
+ - **ABSOLUTELY DO NOT specify the \`agentId\` field** in the \`job\` object (leave this field omitted). The OpenClaw system will automatically assign your correct agent ID to that job.
1582
+ - Never manually specify \`agentId\` as \`"bot"\` or \`"main"\`, as this will cause the cronjob to belong to another agent and you will lose control to manage/delete it later.
1583
+ - **When the user requests to disable/enable/delete a cronjob:**
1584
+ 1. **Step 1 (Search):** Call the \`cron\` tool with action \`list\` (and \`includeDisabled: true\`) to view all cron jobs on the system and find the matching \`jobId\`.
1585
+ 2. **Step 2 (Processing):**
1586
+ - To delete: Call action \`remove\` with the \`id\` found.
1587
+ - To disable/pause: Call action \`update\` with \`id\` and patch \`{"enabled": false}\`.
1588
+ - To enable: Call action \`update\` with \`id\` and patch \`{"enabled": true}\`.
1589
+ 3. **Honest statement:** Never claim a job is "deleted" or "not found" based on guessing without calling the \`cron\` tool to verify the actual state.
1590
+ - When the user asks to schedule tasks or reminders, use the built-in \`cron\` tool (action \`add\`) automatically. Do NOT ask users to run crontab or Task Scheduler manually on the host.
1591
+ - When operating cron/scheduler tools, do **not** put \`current\` into the Session directory.
1592
+ - **IMPORTANT ABOUT GROUP CHAT TARGETING**: When creating or configuring a cron job to send messages (announce mode) to a Group Chat, the value of the \`delivery.to\` field **must** use the \`group:\` prefix before the group ID (e.g., \`group:3815464776067464419\` or \`group:xxxx\`). Never specify just the numeric ID, as the system will interpret it as a private DM and deliver to the wrong destination.
1593
+ - Skip internal doc lookups such as \`cron-jobs.mdx\`; rely on the available tools and complete the scheduling task directly.`)
1310
1594
  : '';
1311
1595
 
1312
1596
  const zaloModSection = '';
@@ -1322,8 +1606,8 @@ node ${btPath} close_tab 2`;
1322
1606
  }
1323
1607
 
1324
1608
  return isVi
1325
- ? `# Hướng dẫn sử dụng Tools\n\n## Danh sách skills đã cài\n${skillsSection}\n\n## Nguyên tắc chung\n- Ưu tiên dùng tool/skill phù hợp thay vì tự suy đoán\n- Nếu tool trả về lỗi — thử lại 1 lần, sau đó báo user\n- Không chạy tool liên tục mà không có mục đích rõ ràng\n- Luôn tóm tắt kết quả tool cho user thay vì dump raw output${browserRef}\n\n## Quy ước\n- Web Search: chỉ dùng khi cần thông tin realtime hoặc user yêu cầu\n- Browser: chỉ mở trang khi user yêu cầu cụ thể\n- Memory: tự ghi nhớ thông tin tự nhiên, không cần user nhắc${cronSection}${zaloModSection}\n\n## \uD83D\uDCC1 File & Workspace\n- Bot có thể đọc/ghi file trong thư mục workspace: \`${workspacePath}\`\n- Dùng để lưu notes, scripts, cấu hình tạm\n\n## \u26A0\uFE0F Tool Error Handling\n- Retry tối đa 2 lần nếu tool lỗi network\n- Nếu vẫn lỗi: báo user kèm mô tả lỗi cụ thể và gợi ý workaround${dmOverride}\n`
1326
- : `# Tool Usage Guide\n\n## Installed Skills\n${skillsSection}\n\n## General Principles\n- Prefer using the right tool/skill over guessing\n- If a tool returns an error — retry once, then report to user\n- Don't run tools repeatedly without a clear purpose\n- Always summarize tool output for user instead of dumping raw data${browserRef}\n\n## Conventions\n- Web Search: only use when needing real-time info or user explicitly asks\n- Browser: only open pages when user specifically requests\n- Memory: proactively remember important info without user prompting${cronSection}${zaloModSection}\n\n## \uD83D\uDCC1 File & Workspace\n- Bot can read/write files in workspace: \`${workspacePath}\`\n\n## \u26A0\uFE0F Tool Error Handling\n- Retry up to 2 times on network errors\n- If still failing: report to user with specific error description and workaround${dmOverride}\n`;
1609
+ ? `# Hướng dẫn sử dụng Tools\n\n## Danh sách skills đã cài\n${skillsSection}\n\n## Nguyên tắc chung\n- Ưu tiên dùng tool/skill phù hợp thay vì tự suy đoán\n- Nếu tool trả về lỗi — thử lại 1 lần, sau đó báo user\n- Không chạy tool liên tục mà không có mục đích rõ ràng\n- Luôn tóm tắt kết quả tool cho user thay vì dump raw output${browserRef}\n\n## Quy ước\n- Web Search: TUYỆT ĐỐI KHÔNG dùng tool \`web_search\` native vì nó đã bị vô hiệu hóa hoàn toàn trên hệ thống. Thay vào đó, mỗi khi cần tìm kiếm Internet/Web, bạn BẮT BUỘC phải gọi công cụ \`exec\` để chạy lệnh terminal: \`node search-tool.js "<từ khóa>" 5\`! Lệnh này cực kỳ nhanh, tàng hình và miễn phí.\n- Browser: chỉ mở trang khi user yêu cầu cụ thể\n- Memory: tự ghi nhớ thông tin tự nhiên, không cần user nhắc${cronSection}${zaloModSection}\n\n## \uD83D\uDCC1 File & Workspace\n- Bot có thể đọc/ghi file trong thư mục workspace: \`${workspacePath}\`\n- Dùng để lưu notes, scripts, cấu hình tạm\n\n## \u26A0\uFE0F Tool Error Handling\n- Retry tối đa 2 lần nếu tool lỗi network\n- Nếu vẫn lỗi: báo user kèm mô tả lỗi cụ thể và gợi ý workaround${dmOverride}\n`
1610
+ : `# Tool Usage Guide\n\n## Installed Skills\n${skillsSection}\n\n## General Principles\n- Prefer using the right tool/skill over guessing\n- If a tool returns an error — retry once, then report to user\n- Don't run tools repeatedly without a clear purpose\n- Always summarize tool output for user instead of dumping raw data${browserRef}\n\n## Conventions\n- Web Search: DO NOT use the native \`web_search\` tool as it is completely disabled. Instead, whenever you need to search the Internet/Web, you MUST call the \`exec\` tool to run terminal command: \`node search-tool.js "<query>" 5\`! This is extremely fast, stealthy and free.\n- Browser: only open pages when user specifically requests\n- Memory: proactively remember important info without user prompting${cronSection}${zaloModSection}\n\n## \uD83D\uDCC1 File & Workspace\n- Bot can read/write files in workspace: \`${workspacePath}\`\n\n## \u26A0\uFE0F Tool Error Handling\n- Retry up to 2 times on network errors\n- If still failing: report to user with specific error description and workaround${dmOverride}\n`;
1327
1611
  }
1328
1612
  function buildTeamsDoc(options = {}) {
1329
1613
  const {
@@ -1418,6 +1702,7 @@ node ${btPath} close_tab 2`;
1418
1702
  'HEARTBEAT.md': buildHeartbeatDoc({ isVi }),
1419
1703
  'BOOTSTRAP.md': buildBootstrapDoc({ isVi, botName }),
1420
1704
  'DREAMS.md': buildDreamsDoc({ isVi }),
1705
+ 'search-tool.js': buildSearchToolJs(),
1421
1706
  };
1422
1707
 
1423
1708
  if (isMultiBot) {
@@ -1445,6 +1730,7 @@ node ${btPath} close_tab 2`;
1445
1730
  buildDreamsDoc,
1446
1731
  buildHeartbeatDoc,
1447
1732
  buildBootstrapDoc,
1733
+ buildSearchToolJs,
1448
1734
  buildBrowserToolJs,
1449
1735
  buildBrowserDoc,
1450
1736
  buildSecurityRules,
@@ -1459,7 +1745,7 @@ if (typeof exports !== 'undefined' && workspaceRoot.__openclawWorkspace) {
1459
1745
  Object.assign(exports, workspaceRoot.__openclawWorkspace);
1460
1746
  }
1461
1747
 
1462
- // ── Centralized bot config builders (openclaw.json, exec-approvals, .env) (setup/shared/bot-config-gen.js)
1748
+ // ── ── Centralized bot config builders (openclaw.json, exec-approvals, .env) (setup/shared/bot-config-gen.js)
1463
1749
  // @ts-nocheck
1464
1750
  /**
1465
1751
  * @fileoverview Centralized bot configuration builders — single source of truth.
@@ -1930,7 +2216,7 @@ if (typeof exports !== 'undefined' && typeof globalThis !== 'undefined' && globa
1930
2216
  Object.assign(exports, globalThis.__openclawBotConfig);
1931
2217
  }
1932
2218
 
1933
- // ── Shared install artifacts: Chrome debug, uninstall, skill catalog (setup/shared/install-gen.js)
2219
+ // ── ── Shared install artifacts: Chrome debug, uninstall, skill catalog (setup/shared/install-gen.js)
1934
2220
  // @ts-nocheck
1935
2221
  // install-gen.js — Build install/runtime artifacts (Chrome debug, uninstall, skill catalog)
1936
2222
  // Workspace .md files are in workspace-gen.js (single source of truth).
@@ -2498,7 +2784,7 @@ if (typeof exports !== 'undefined' && typeof globalThis !== 'undefined' && globa
2498
2784
  Object.assign(exports, globalThis.__openclawInstall);
2499
2785
  }
2500
2786
 
2501
- // ── Shared Docker artifact helpers for wizard + CLI (setup/shared/docker-gen.js)
2787
+ // ── ── Shared Docker artifact helpers for wizard + CLI (setup/shared/docker-gen.js)
2502
2788
  // @ts-nocheck
2503
2789
  (function (root) {
2504
2790
  const common = (typeof globalThis !== 'undefined' && globalThis.__openclawCommon) || {};
@@ -2705,7 +2991,7 @@ if(touched){console.log('[patch-9router] Applied Codex compatibility patch.');}e
2705
2991
  is9Router,
2706
2992
  isLocal,
2707
2993
  isMultiBot,
2708
- hasBrowser,
2994
+ hasBrowser = false,
2709
2995
  selectedModel,
2710
2996
  agentId,
2711
2997
  allSkills = [],
@@ -2724,23 +3010,9 @@ if(touched){console.log('[patch-9router] Applied Codex compatibility patch.');}e
2724
3010
  plainSingleExtraHosts = false,
2725
3011
  multiOllamaNumParallel = 1,
2726
3012
  singleOllamaNumParallel = 1,
2727
- emitBrowserInstall = true,
2728
3013
  gatewayPort = 18789,
2729
3014
  routerPort = 20128,
2730
3015
  } = options;
2731
-
2732
- const browserAptExtra = hasBrowser ? ' xvfb socat' : '';
2733
- const browserInstallLines = hasBrowser && emitBrowserInstall
2734
- ? [
2735
- '',
2736
- '# Browser Automation: Playwright engine (needed for native CDP)',
2737
- 'RUN npm install -g agent-browser playwright \\',
2738
- ' && npx playwright install chromium --with-deps \\',
2739
- ' && ln -f -s /root/.cache/ms-playwright/chromium-*/chrome-linux*/chrome /usr/bin/google-chrome',
2740
- '',
2741
- ''
2742
- ].join('\n')
2743
- : '';
2744
3016
  const skillLines = dockerfileSkillInstallMode === 'build' && allSkills.length > 0
2745
3017
  ? `\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`
2746
3018
  : '';
@@ -2780,6 +3052,20 @@ if(touched){console.log('[patch-9router] Applied Codex compatibility patch.');}e
2780
3052
  ' echo "[entrypoint] plugin $id missing; installing $spec"',
2781
3053
  ' openclaw plugins install "$spec" 2>/dev/null || echo "[entrypoint] warning: failed to install plugin $spec"',
2782
3054
  '}',
3055
+ 'ensure_zalouser() {',
3056
+ ' NPM_DIR="$OPENCLAW_HOME/npm"',
3057
+ ' PKG_DIR="$NPM_DIR/node_modules/@openclaw/zalouser"',
3058
+ ' if [ -d "$PKG_DIR" ]; then',
3059
+ ' echo "[entrypoint] zalouser plugin already installed"',
3060
+ ' else',
3061
+ ' echo "[entrypoint] zalouser plugin missing; installing via npm"',
3062
+ ' mkdir -p "$NPM_DIR"',
3063
+ ' cd "$NPM_DIR"',
3064
+ ' npm init -y 2>/dev/null || true',
3065
+ ' npm install @openclaw/zalouser@latest 2>/dev/null || echo "[entrypoint] warning: failed to install @openclaw/zalouser"',
3066
+ ' cd /root/project',
3067
+ ' fi',
3068
+ '}',
2783
3069
  'ensure_skill() {',
2784
3070
  ' id="$1"',
2785
3071
  ' if find "$OPENCLAW_HOME" -maxdepth 4 -type d -path "*/skills/$id" -print -quit 2>/dev/null | grep -q .; then',
@@ -2805,7 +3091,7 @@ if(touched){console.log('[patch-9router] Applied Codex compatibility patch.');}e
2805
3091
  ' sed -i "s/LISTENER_WATCHDOG_MAX_GAP_MS\\\\s*=\\\\s*35e3/LISTENER_WATCHDOG_MAX_GAP_MS = 90e3/" "$ZALO_JS"',
2806
3092
  ' echo "[entrypoint] patched zalouser watchdog gap: 35s -> 90s"',
2807
3093
  'fi',
2808
- ].join('\\n'));
3094
+ ].join('\n'));
2809
3095
  runtimeParts.push([
2810
3096
  '# Zalo channel auto-restart monitor (background)',
2811
3097
  '(',
@@ -2815,27 +3101,27 @@ if(touched){console.log('[patch-9router] Applied Codex compatibility patch.');}e
2815
3101
  ' STATUS=$(openclaw channels status 2>/dev/null | grep -i "Zalo Personal" || true)',
2816
3102
  ' if echo "$STATUS" | grep -qi "stopped"; then',
2817
3103
  ' echo "[zalo-monitor] Zalo channel stopped - restarting container in 5s"',
2818
- ' sleep 5',
3104
+ ' sleep 5',
2819
3105
  ' kill 1 2>/dev/null || true',
2820
3106
  ' fi',
2821
3107
  ' done',
2822
3108
  ') &',
2823
- ].join('\\n'));
3109
+ ].join('\n'));
3110
+ runtimeParts.push('openclaw gateway run');
3111
+ const runtimeScript = ['#!/bin/sh', 'set -e', ...runtimeParts].join('\n');
3112
+ let browserInstall = '';
2824
3113
  if (hasBrowser) {
2825
- runtimeParts.push('socat TCP-LISTEN:9222,fork,reuseaddr TCP:host.docker.internal:9222 &');
2826
- runtimeParts.push('Xvfb :99 -screen 0 1280x720x24 > /dev/null 2>&1 & DISPLAY=:99 openclaw gateway run');
2827
- } else {
2828
- runtimeParts.push('openclaw gateway run');
3114
+ browserInstall = '\n# Install browser and system dependencies for Playwright\nRUN npx playwright install-deps chromium && npx playwright install chromium\n';
2829
3115
  }
2830
- const runtimeScript = ['#!/bin/sh', 'set -e', ...runtimeParts].join('\n');
2831
3116
  const dockerfile = `FROM node:22-slim
2832
3117
 
2833
- RUN apt-get update && apt-get install -y git curl python3${browserAptExtra} && rm -rf /var/lib/apt/lists/*
2834
- ${browserInstallLines}
3118
+ RUN apt-get update && apt-get install -y git curl python3 && rm -rf /var/lib/apt/lists/*
3119
+
2835
3120
  ARG OPENCLAW_VER="${openClawNpmSpec}"
2836
3121
  ARG CACHE_BUST=""
2837
3122
  RUN echo "CACHE_BUST=$CACHE_BUST" && npm install -g $OPENCLAW_VER ${openClawRuntimePackages}${skillLines}${pluginLines}
2838
- ${patchLine}
3123
+ ${patchLine}${browserInstall}
3124
+
2839
3125
  COPY entrypoint.sh /usr/local/bin/openclaw-entrypoint.sh
2840
3126
  RUN chmod +x /usr/local/bin/openclaw-entrypoint.sh
2841
3127
  WORKDIR /root/project
@@ -2858,7 +3144,7 @@ CMD ["/bin/sh", "/usr/local/bin/openclaw-entrypoint.sh"]`;
2858
3144
  : isLocal
2859
3145
  ? ' depends_on:\n ollama:\n condition: service_healthy\n'
2860
3146
  : '';
2861
- const extraHosts = hasBrowser ? `${extraHostsBlock}\n` : '';
3147
+ const extraHosts = `${extraHostsBlock}\n`;
2862
3148
  if (is9Router) {
2863
3149
  compose = `name: ${multiComposeName}
2864
3150
  services:
@@ -2961,7 +3247,7 @@ services:
2961
3247
  - ../../.env
2962
3248
  depends_on:
2963
3249
  - 9router
2964
- ${appEnvironmentBlock}${hasBrowser ? `${extraHostsBlock}\n` : ''} volumes:
3250
+ ${appEnvironmentBlock}${extraHostsBlock}\n volumes:
2965
3251
  - ${volumeMount}
2966
3252
  - openclaw-plugins:/root/project/.openclaw/npm
2967
3253
  ports:
@@ -3002,7 +3288,7 @@ services:
3002
3288
  ${appEnvironmentBlock} depends_on:
3003
3289
  ollama:
3004
3290
  condition: service_healthy
3005
- ${hasBrowser ? `${extraHostsBlock}\n` : ''} ports:
3291
+ ${extraHostsBlock}\n ports:
3006
3292
  - "${gatewayPort}:${gatewayPort}"
3007
3293
  volumes:
3008
3294
  - ${volumeMount}
@@ -3076,7 +3362,7 @@ if (typeof exports !== 'undefined' && typeof globalThis !== 'undefined' && globa
3076
3362
 
3077
3363
 
3078
3364
 
3079
- // ── buildNativeScriptCtx and shared native runtime helpers (setup/generators/native-helpers-gen.js)
3365
+ // ── ── buildNativeScriptCtx and shared native runtime helpers (setup/generators/native-helpers-gen.js)
3080
3366
  // @ts-nocheck
3081
3367
  /* eslint-disable no-undef, no-unused-vars */
3082
3368
  /**
@@ -3097,10 +3383,9 @@ function buildNativeScriptCtx(options) {
3097
3383
  const ch = CHANNELS[state.channel];
3098
3384
  const is9Router = !!(provider && provider.isProxy);
3099
3385
  const isOllama = !!(provider && provider.isLocal);
3100
- const hasBrowser = state.config.skills.includes('browser');
3101
3386
  const nativeSkillConfigs = state.config.skills
3102
3387
  .map((sid) => SKILLS.find((s) => s.id === sid))
3103
- .filter((skill) => skill && skill.id !== 'scheduler' && skill.slug && skill.slug !== 'browser-automation');
3388
+ .filter((skill) => skill && skill.id !== 'scheduler' && skill.slug);
3104
3389
  const selectedModel = (state.config.model || 'ollama/gemma4:e2b').replace('ollama/', '');
3105
3390
  const isMultiBot = state.botCount > 1 && state.channel === 'telegram';
3106
3391
  const projectDir = state.config.projectPath || '.';
@@ -3120,7 +3405,6 @@ function buildNativeScriptCtx(options) {
3120
3405
  Object.assign(globalThis, {
3121
3406
  isVi,
3122
3407
  provider,
3123
- hasBrowser,
3124
3408
  is9Router,
3125
3409
  selectedModel,
3126
3410
  isMultiBot,
@@ -3474,7 +3758,6 @@ setInterval(sync, INTERVAL);`;
3474
3758
  provider,
3475
3759
  is9Router,
3476
3760
  isOllama,
3477
- hasBrowser,
3478
3761
  selectedModel,
3479
3762
  isMultiBot,
3480
3763
  projectDir,
@@ -3494,7 +3777,7 @@ setInterval(sync, INTERVAL);`;
3494
3777
  };
3495
3778
  }
3496
3779
 
3497
- // ── botEnvContent, botConfigContent, botWorkspaceFiles, botFiles, helpers (setup/generators/config-gen.js)
3780
+ // ── ── botEnvContent, botConfigContent, botWorkspaceFiles, botFiles, helpers (setup/generators/config-gen.js)
3498
3781
  // @ts-nocheck
3499
3782
  /* eslint-disable no-undef, no-unused-vars */
3500
3783
  /**
@@ -3510,7 +3793,6 @@ setInterval(sync, INTERVAL);`;
3510
3793
  * @global {boolean} isVi - Vietnamese language mode
3511
3794
  * @global {object} provider - Current primary provider config
3512
3795
  * @global {boolean} isMultiBot - Multi-bot mode flag
3513
- * @global {boolean} hasBrowser - Browser plugin selected
3514
3796
  * @global {boolean} is9Router - 9Router proxy mode
3515
3797
  * @global {string} projectDir - Output project directory path
3516
3798
  * @global {Function} getGatewayAllowedOrigins
@@ -3575,8 +3857,8 @@ setInterval(sync, INTERVAL);`;
3575
3857
  groupId,
3576
3858
  selectedSkills: state.config.skills,
3577
3859
  skills: SKILLS,
3578
- hasBrowserDesktop: hasBrowser && state.browserMode === 'desktop',
3579
- hasBrowserServer: hasBrowser && state.browserMode !== 'desktop',
3860
+ hasBrowserDesktop: false,
3861
+ hasBrowserServer: false,
3580
3862
  gatewayPort: basePort,
3581
3863
  gatewayAllowedOrigins: getGatewayAllowedOrigins(basePort),
3582
3864
  osChoice: state.nativeOs || '',
@@ -3646,7 +3928,7 @@ setInterval(sync, INTERVAL);`;
3646
3928
  agentWorkspaceDir,
3647
3929
  persona: bot.persona || '',
3648
3930
  userInfo: state.config.userInfo || '',
3649
- hasBrowser,
3931
+ hasBrowser: false,
3650
3932
  soulVariant: 'wizard',
3651
3933
  memoryVariant: 'wizard',
3652
3934
  hasZaloMod: state.channel === 'zalo-personal',
@@ -3724,7 +4006,7 @@ setInterval(sync, INTERVAL);`;
3724
4006
  }));
3725
4007
  }
3726
4008
 
3727
- // ── generateZaloLoginBat, generateZaloLoginSh (unified) (setup/generators/zalo-login-gen.js)
4009
+ // ── ── generateZaloLoginBat, generateZaloLoginSh (unified) (setup/generators/zalo-login-gen.js)
3728
4010
  // @ts-nocheck
3729
4011
  /* eslint-disable no-undef, no-unused-vars */
3730
4012
  /**
@@ -3837,7 +4119,7 @@ function generateZaloLoginSh(opts) {
3837
4119
  ];
3838
4120
  }
3839
4121
 
3840
- // ── generateStartScript wizard wrapper (delegates to install-gen) (setup/generators/gateway-start-gen.js)
4122
+ // ── ── generateStartScript wizard wrapper (delegates to install-gen) (setup/generators/gateway-start-gen.js)
3841
4123
  // @ts-nocheck
3842
4124
  /* eslint-disable no-undef, no-unused-vars */
3843
4125
  /**
@@ -3884,7 +4166,7 @@ function generateStartScript() {
3884
4166
  return null;
3885
4167
  }
3886
4168
 
3887
- // ── generateUninstallScript, setup script download helpers (setup/generators/download-gen.js)
4169
+ // ── ── generateUninstallScript, setup script download helpers (setup/generators/download-gen.js)
3888
4170
  // @ts-nocheck
3889
4171
  /* eslint-disable no-undef, no-unused-vars */
3890
4172
  /**
@@ -4141,7 +4423,7 @@ window.__downloadGen = {
4141
4423
  updateDockerDlLabel,
4142
4424
  };
4143
4425
 
4144
- // ── Windows .bat — if (state.nativeOs === "win") block (setup/os/win-bat.js)
4426
+ // ── ── Windows .bat if (state.nativeOs === "win") block (setup/os/win-bat.js)
4145
4427
  // @ts-nocheck
4146
4428
  /* eslint-disable no-undef, no-unused-vars */
4147
4429
  /**
@@ -4151,7 +4433,7 @@ window.__downloadGen = {
4151
4433
  */
4152
4434
  function generateWinBat(ctx) {
4153
4435
  const {
4154
- ch, isVi, provider, is9Router, isOllama, hasBrowser, selectedModel, isMultiBot, projectDir, todayStamp, allPlugins, pluginCmd, nativeSkillInstallCmds, nativeSkillConfigs, providerLines, sharedNativeFileMap, sharedNativeEnvContent, sharedNativeExecApprovalsContent, sharedNativeConfigContent, native9RouterSyncScriptContent, native9RouterServerEntryLookup, windowsHiddenNodeLaunch, generateUninstallScript,
4436
+ ch, isVi, provider, is9Router, isOllama, selectedModel, isMultiBot, projectDir, todayStamp, allPlugins, pluginCmd, nativeSkillInstallCmds, nativeSkillConfigs, providerLines, sharedNativeFileMap, sharedNativeEnvContent, sharedNativeExecApprovalsContent, sharedNativeConfigContent, native9RouterSyncScriptContent, native9RouterServerEntryLookup, windowsHiddenNodeLaunch, generateUninstallScript,
4155
4437
  } = ctx;
4156
4438
  // state, PROVIDERS, SKILLS, PLUGINS, CHANNELS are IIFE-level globals
4157
4439
  let scriptContent;
@@ -4204,11 +4486,6 @@ function generateWinBat(ctx) {
4204
4486
  }
4205
4487
 
4206
4488
  providerLines(lines, 'bat');
4207
- if (hasBrowser) {
4208
- lines.push('echo Cai Browser Automation runtime...');
4209
- lines.push('call npm install -g agent-browser playwright || goto :fail');
4210
- lines.push('call npx playwright install chromium || goto :fail');
4211
- }
4212
4489
  if (nativeSkillInstallCmds.length > 0) {
4213
4490
  lines.push('echo Cai skills...');
4214
4491
  lines.push(...nativeSkillInstallCmds);
@@ -4286,7 +4563,7 @@ function generateWinBat(ctx) {
4286
4563
  return { scriptName, scriptContent };
4287
4564
  }
4288
4565
 
4289
- // ── macOS .sh — if (state.nativeOs === "macos") block (setup/os/macos-sh.js)
4566
+ // ── ── macOS .sh if (state.nativeOs === "macos") block (setup/os/macos-sh.js)
4290
4567
  // @ts-nocheck
4291
4568
  /* eslint-disable no-undef, no-unused-vars */
4292
4569
  /**
@@ -4296,7 +4573,7 @@ function generateWinBat(ctx) {
4296
4573
  */
4297
4574
  function generateMacOsSh(ctx) {
4298
4575
  const {
4299
- ch, isVi, provider, is9Router, isOllama, hasBrowser, selectedModel, isMultiBot, projectDir, todayStamp, allPlugins, pluginCmd, nativeSkillInstallCmds, nativeSkillConfigs, providerLines, sharedNativeFileMap, sharedNativeEnvContent, sharedNativeExecApprovalsContent, sharedNativeConfigContent, native9RouterSyncScriptContent, native9RouterServerEntryLookup, windowsHiddenNodeLaunch, generateUninstallScript,
4576
+ ch, isVi, provider, is9Router, isOllama, selectedModel, isMultiBot, projectDir, todayStamp, allPlugins, pluginCmd, nativeSkillInstallCmds, nativeSkillConfigs, providerLines, sharedNativeFileMap, sharedNativeEnvContent, sharedNativeExecApprovalsContent, sharedNativeConfigContent, native9RouterSyncScriptContent, native9RouterServerEntryLookup, windowsHiddenNodeLaunch, generateUninstallScript,
4300
4577
  } = ctx;
4301
4578
  // state, PROVIDERS, SKILLS, PLUGINS, CHANNELS are IIFE-level globals
4302
4579
  let scriptContent;
@@ -4404,7 +4681,7 @@ function generateMacOsSh(ctx) {
4404
4681
  return { scriptName, scriptContent };
4405
4682
  }
4406
4683
 
4407
- // ── VPS/PM2 .sh — if (state.nativeOs === "vps") block (setup/os/vps-sh.js)
4684
+ // ── ── VPS/PM2 .sh if (state.nativeOs === "vps") block (setup/os/vps-sh.js)
4408
4685
  // @ts-nocheck
4409
4686
  /* eslint-disable no-undef, no-unused-vars */
4410
4687
  /**
@@ -4414,7 +4691,7 @@ function generateMacOsSh(ctx) {
4414
4691
  */
4415
4692
  function generateVpsSh(ctx) {
4416
4693
  const {
4417
- ch, isVi, provider, is9Router, isOllama, hasBrowser, selectedModel, isMultiBot, projectDir, todayStamp, allPlugins, pluginCmd, nativeSkillInstallCmds, nativeSkillConfigs, providerLines, sharedNativeFileMap, sharedNativeEnvContent, sharedNativeExecApprovalsContent, sharedNativeConfigContent, native9RouterSyncScriptContent, native9RouterServerEntryLookup, windowsHiddenNodeLaunch, generateUninstallScript,
4694
+ ch, isVi, provider, is9Router, isOllama, selectedModel, isMultiBot, projectDir, todayStamp, allPlugins, pluginCmd, nativeSkillInstallCmds, nativeSkillConfigs, providerLines, sharedNativeFileMap, sharedNativeEnvContent, sharedNativeExecApprovalsContent, sharedNativeConfigContent, native9RouterSyncScriptContent, native9RouterServerEntryLookup, windowsHiddenNodeLaunch, generateUninstallScript,
4418
4695
  } = ctx;
4419
4696
  // state, PROVIDERS, SKILLS, PLUGINS, CHANNELS are IIFE-level globals
4420
4697
  let scriptContent;
@@ -4529,7 +4806,7 @@ GWEOF`);
4529
4806
  return { scriptName, scriptContent };
4530
4807
  }
4531
4808
 
4532
- // ── Linux Desktop .sh — if (state.nativeOs === "linux-desktop") block (setup/os/linux-sh.js)
4809
+ // ── ── Linux Desktop .sh if (state.nativeOs === "linux-desktop") block (setup/os/linux-sh.js)
4533
4810
  // @ts-nocheck
4534
4811
  /* eslint-disable no-undef, no-unused-vars */
4535
4812
  /**
@@ -4539,7 +4816,7 @@ GWEOF`);
4539
4816
  */
4540
4817
  function generateLinuxSh(ctx) {
4541
4818
  const {
4542
- ch, isVi, provider, is9Router, isOllama, hasBrowser, selectedModel, isMultiBot, projectDir, todayStamp, allPlugins, pluginCmd, nativeSkillInstallCmds, nativeSkillConfigs, providerLines, sharedNativeFileMap, sharedNativeEnvContent, sharedNativeExecApprovalsContent, sharedNativeConfigContent, native9RouterSyncScriptContent, native9RouterServerEntryLookup, windowsHiddenNodeLaunch, generateUninstallScript,
4819
+ ch, isVi, provider, is9Router, isOllama, selectedModel, isMultiBot, projectDir, todayStamp, allPlugins, pluginCmd, nativeSkillInstallCmds, nativeSkillConfigs, providerLines, sharedNativeFileMap, sharedNativeEnvContent, sharedNativeExecApprovalsContent, sharedNativeConfigContent, native9RouterSyncScriptContent, native9RouterServerEntryLookup, windowsHiddenNodeLaunch, generateUninstallScript,
4543
4820
  } = ctx;
4544
4821
  // state, PROVIDERS, SKILLS, PLUGINS, CHANNELS are IIFE-level globals
4545
4822
  let scriptContent;
@@ -4592,7 +4869,7 @@ function generateLinuxSh(ctx) {
4592
4869
  return { scriptName, scriptContent };
4593
4870
  }
4594
4871
 
4595
- // ── UI init, language/channel/deploy controllers, form rendering (setup/ui/controller.js)
4872
+ // ── ── UI init, language/channel/deploy controllers, form rendering (setup/ui/controller.js)
4596
4873
  // @ts-nocheck
4597
4874
  /* eslint-disable no-undef, no-unused-vars */
4598
4875
  /**
@@ -5241,7 +5518,7 @@ function generateLinuxSh(ctx) {
5241
5518
  envContent.textContent = lines.join('\n');
5242
5519
  }
5243
5520
 
5244
- // ── Multi-bot state + UI (setup/ui/multi-bot.js) ───────────────────
5521
+ // ── ── Multi-bot state + UI (setup/ui/multi-bot.js) ──────────────────────────────────────
5245
5522
  // @ts-nocheck
5246
5523
  /* eslint-disable no-undef, no-unused-vars */
5247
5524
  /**
@@ -5590,7 +5867,7 @@ function generateLinuxSh(ctx) {
5590
5867
 
5591
5868
  // ========== Step 1: Deploy Mode + OS ==========
5592
5869
 
5593
- // ── Step navigation, validation (setup/ui/steps.js) ────────────────
5870
+ // ── ── Step navigation, validation (setup/ui/steps.js) ────────────────────────────────
5594
5871
  // @ts-nocheck
5595
5872
  /* eslint-disable no-undef, no-unused-vars */
5596
5873
  /**
@@ -5750,7 +6027,7 @@ function generateLinuxSh(ctx) {
5750
6027
 
5751
6028
  // ========== Step 2: Bot Config ==========
5752
6029
 
5753
- // ── generateOutput + generateNativeScript + clipboard (setup/ui/output.js)
6030
+ // ── ── generateOutput + generateNativeScript + clipboard (setup/ui/output.js)
5754
6031
  // @ts-nocheck
5755
6032
  /* eslint-disable no-undef, no-unused-vars */
5756
6033
  /**
@@ -5794,68 +6071,6 @@ function generateLinuxSh(ctx) {
5794
6071
  const routerNotice = document.getElementById('9router-notice');
5795
6072
  if (routerNotice) routerNotice.style.display = is9Router ? '' : 'none';
5796
6073
 
5797
- // Show/hide Browser Automation notice + generate scripts
5798
- const browserNotice = document.getElementById('browser-notice');
5799
- const hasBrowserSkill = state.config.skills.includes('browser');
5800
- if (browserNotice) browserNotice.style.display = hasBrowserSkill ? '' : 'none';
5801
-
5802
- if (hasBrowserSkill) {
5803
- // Chrome Debug .bat script
5804
- const chromeBat = `@echo off
5805
- echo ============================================
5806
- echo OpenClaw - Chrome Debug Mode
5807
- echo ============================================
5808
- echo.
5809
- echo Dang tat Chrome cu (neu co)...
5810
- taskkill /F /IM chrome.exe >nul 2>&1
5811
- timeout /t 3 /nobreak >nul
5812
- echo Dang mo Chrome voi Debug Mode...
5813
- start "" "C:\\Program Files\\Google\\Chrome\\Application\\chrome.exe" ^
5814
- --remote-debugging-port=9222 ^
5815
- --remote-allow-origins=* ^
5816
- --user-data-dir="%TEMP%\\chrome-debug"
5817
- timeout /t 4 /nobreak >nul
5818
- powershell -Command "try { Invoke-WebRequest -Uri 'http://localhost:9222/json/version' -UseBasicParsing -TimeoutSec 5 | Out-Null; Write-Host 'OK! Chrome Debug Mode dang chay tren port 9222.' -ForegroundColor Green } catch { Write-Host 'LOI: Port 9222 chua mo. Thu lai.' -ForegroundColor Red }"
5819
- echo.
5820
- pause`;
5821
- setOutput('out-chrome-bat', chromeBat);
5822
-
5823
- // Task Scheduler PowerShell script
5824
- const taskPs1 = `# ============================================
5825
- # OpenClaw - Auto-start Chrome Debug khi logon
5826
- # Chay script nay 1 lan voi Run as Administrator
5827
- # ============================================
5828
-
5829
- # Duong dan toi file .bat
5830
- $batPath = "$env:USERPROFILE\\start-chrome-debug.bat"
5831
-
5832
- # Kiem tra file .bat ton tai
5833
- if (-not (Test-Path $batPath)) {
5834
- Write-Host "LOI: Khong tim thay $batPath" -ForegroundColor Red
5835
- Write-Host "Hay luu file start-chrome-debug.bat vao $env:USERPROFILE truoc." -ForegroundColor Yellow
5836
- exit 1
5837
- }
5838
-
5839
- # Tao Scheduled Task
5840
- $action = New-ScheduledTaskAction -Execute $batPath
5841
- $trigger = New-ScheduledTaskTrigger -AtLogOn
5842
- $trigger.Delay = "PT10S" # Delay 10 giay sau khi logon
5843
- $settings = New-ScheduledTaskSettingsSet -AllowStartIfOnBatteries -DontStopIfGoingOnBatteries -StartWhenAvailable
5844
-
5845
- Register-ScheduledTask \\
5846
- -TaskName "OpenClaw-ChromeDebug" \\
5847
- -Description "Tu dong bat Chrome Debug Mode cho OpenClaw Browser Automation" \\
5848
- -Action $action \\
5849
- -Trigger $trigger \\
5850
- -Settings $settings \\
5851
- -Force
5852
-
5853
- Write-Host ""
5854
- Write-Host "DONE! Task 'OpenClaw-ChromeDebug' da duoc tao." -ForegroundColor Green
5855
- Write-Host "Chrome se tu dong bat Debug Mode moi khi ban dang nhap Windows (delay 10s)." -ForegroundColor Cyan`;
5856
- setOutput('out-task-ps1', taskPs1);
5857
- }
5858
-
5859
6074
  // Show/hide docker vs native output based on deployMode
5860
6075
  const dockerOut = document.getElementById('docker-output');
5861
6076
  const nativeOut = document.getElementById('native-output');
@@ -5884,8 +6099,6 @@ Write-Host "Chrome se tu dong bat Debug Mode moi khi ban dang nhap Windows (dela
5884
6099
  : 'Script is generated from your choices. Download and run — everything else is handled automatically.';
5885
6100
 
5886
6101
  const agentId = state.config.botName.toLowerCase().replace(/[^a-z0-9]+/g, '-').replace(/-$/, '') || 'chat';
5887
-
5888
- const hasBrowser = state.config.skills.includes('browser');
5889
6102
  // isMultiBot => unified into isMultiBot above
5890
6103
  const multiBotAgentMetas = isMultiBot
5891
6104
  ? state.bots.slice(0, state.botCount).map((bot, idx) => {
@@ -5974,19 +6187,6 @@ Write-Host "Chrome se tu dong bat Debug Mode moi khi ban dang nhap Windows (dela
5974
6187
  };
5975
6188
  }
5976
6189
 
5977
- // Browser Automation: inject browser config
5978
- if (hasBrowser) {
5979
- clawConfig.browser = {
5980
- enabled: true,
5981
- defaultProfile: 'host-chrome',
5982
- profiles: {
5983
- 'host-chrome': {
5984
- cdpUrl: 'http://127.0.0.1:9222',
5985
- color: '#4285F4',
5986
- },
5987
- },
5988
- };
5989
- }
5990
6190
 
5991
6191
  // Skills: register all selected skills in openclaw.json → skills.entries
5992
6192
  // This makes OpenClaw actually load and enable them at runtime
@@ -5995,8 +6195,6 @@ Write-Host "Chrome se tu dong bat Debug Mode moi khi ban dang nhap Windows (dela
5995
6195
  state.config.skills.forEach((sid) => {
5996
6196
  const skill = SKILLS.find((s) => s.id === sid);
5997
6197
  if (!skill) return;
5998
- // Native browser tools are loaded automatically via the root 'browser' config
5999
- if (skill.slug === 'browser-automation') return;
6000
6198
  // scheduler is now native cron (not a skill), skip registering in skills.entries
6001
6199
  if (skill.id === 'scheduler' || !skill.slug) return;
6002
6200
 
@@ -6124,7 +6322,7 @@ model:
6124
6322
  const allSkills = [];
6125
6323
  state.config.skills.forEach((sid) => {
6126
6324
  const skill = SKILLS.find((s) => s.id === sid);
6127
- if (skill && skill.slug && skill.slug !== 'browser-automation') {
6325
+ if (skill && skill.slug) {
6128
6326
  allSkills.push(skill.slug);
6129
6327
  }
6130
6328
  });
@@ -6144,7 +6342,6 @@ model:
6144
6342
  is9Router,
6145
6343
  isLocal,
6146
6344
  isMultiBot: state.botCount > 1 && (state.channel === 'telegram'),
6147
- hasBrowser,
6148
6345
  selectedModel: state.config.model || 'ollama/gemma4:e2b',
6149
6346
  agentId: 'bot',
6150
6347
  allSkills,
@@ -6304,12 +6501,6 @@ _This file is yours to evolve. If someone asks to change it, confirm with the us
6304
6501
  `;
6305
6502
 
6306
6503
  // ── AGENTS.md — Hướng dẫn vận hành ("operating manual")
6307
- const browserAgentSection = hasBrowser ? `
6308
- ## Sử dụng Trình Duyệt (Browser Automation)
6309
- - BẠN SỞ HỮU GIAO DIỆN TRÌNH DUYỆT CHROME THẬT CỦA USER thông qua script \`browser-tool.js\`. ĐỌC NGAY FILE \`BROWSER.md\` để biết cách dùng.
6310
- - BẮT BUỘC dùng \`bash\` để gõ \`node ~/browser-tool.js ...\` khi có yêu cầu liên quan đến web thay vì dùng web_search!
6311
- - KHÔNG BAO GIỜ từ chối mở trình duyệt với lý do "không có giao diện" hay "máy chủ không có browser".
6312
- ` : '';
6313
6504
 
6314
6505
  const agentsMd = lang === 'vi'
6315
6506
  ? `# Hướng dẫn vận hành
@@ -6337,7 +6528,6 @@ Bạn hỗ trợ người dùng trong mọi tác vụ hàng ngày thông qua tin
6337
6528
  - Luôn xác nhận kết quả tool trước khi trả lời user
6338
6529
  - Nếu tool lỗi → thông báo rõ ràng, đề xuất cách khác
6339
6530
 
6340
- ${browserAgentSection}
6341
6531
  ${state.config.securityRules}
6342
6532
  `
6343
6533
 
@@ -6421,143 +6611,6 @@ _Update this file as you learn more about the user. Ask before changing._
6421
6611
  // ── MEMORY.md — via scaffold builder
6422
6612
  const memoryMd = _scaffold.buildMemoryDoc({ isVi, variant: 'wizard' });
6423
6613
 
6424
- // Browser tool files (generated into workspace when hasBrowser)
6425
- const browserToolJs = `/**
6426
- * browser-tool.js - Connect to real Windows Chrome via CDP
6427
- * Flow: Docker -> socat (port 9222) -> host.docker.internal:9222 -> user's Chrome
6428
- */
6429
- const { chromium } = require('/usr/local/lib/node_modules/openclaw/node_modules/playwright-core');
6430
- const action = process.argv[2];
6431
- const param1 = process.argv[3];
6432
- const param2 = process.argv[4];
6433
- const CDP_URL = 'http://127.0.0.1:9222';
6434
- (async () => {
6435
- let browser;
6436
- try {
6437
- browser = await chromium.connectOverCDP(CDP_URL, { timeout: 5000 });
6438
- const ctx = browser.contexts()[0];
6439
- const pages = ctx.pages();
6440
- let page = pages.length > 0 ? pages[0] : await ctx.newPage();
6441
- if (action === 'open') {
6442
- console.log('[Browser] Mo trang: ' + param1);
6443
- await page.goto(param1, { waitUntil: 'domcontentloaded', timeout: 30000 });
6444
- await page.waitForTimeout(1500);
6445
- console.log('[Browser] Da mo: ' + (await page.title()) + ' | ' + page.url());
6446
- } else if (action === 'get_text') {
6447
- const text = await page.evaluate(() => {
6448
- document.querySelectorAll('script,style,noscript,svg').forEach(e => e.remove());
6449
- return document.body.innerText.trim();
6450
- });
6451
- console.log(text.substring(0, 4000));
6452
- } else if (action === 'click') {
6453
- await page.locator(param1).first().click({ timeout: 5000 });
6454
- await page.waitForTimeout(600);
6455
- console.log('[Browser] Da click: ' + param1);
6456
- } else if (action === 'fill') {
6457
- await page.locator(param1).first().fill(param2, { timeout: 5000 });
6458
- console.log('[Browser] Da dien "' + param2 + '" vao: ' + param1);
6459
- } else if (action === 'press') {
6460
- await page.keyboard.press(param1);
6461
- await page.waitForTimeout(1000);
6462
- console.log('[Browser] Da nhan phim: ' + param1);
6463
- } else if (action === 'status') {
6464
- console.log('[Browser] Ket noi Chrome that! Tab: ' + (await page.title()) + ' | ' + page.url());
6465
- } else {
6466
- console.log('Lenh: open <url> | get_text | click <sel> | fill <sel> <text> | press <key> | status');
6467
- }
6468
- } catch(e) {
6469
- if (e.message.includes('ECONNREFUSED') || e.message.includes('Timeout')) {
6470
- console.error('[Browser] Ban chua bat Chrome Debug! Hay click dup vao start-chrome-debug.bat roi thu lai.');
6471
- } else {
6472
- console.error('[Browser] Loi:', e.message);
6473
- }
6474
- } finally {
6475
- if (browser) await browser.close();
6476
- }
6477
- `;
6478
-
6479
- const browserMd = `# Dieu Khien Trinh Duyet (Browser Automation)
6480
-
6481
- Bot dieu khien Chrome THAT tren man hinh Windows cua ban. Moi thao tac hien thi truc tiep!
6482
-
6483
- ## Lenh su dung (chay qua bash)
6484
-
6485
- \\\`\\\`\\\`bash
6486
- node ~/browser-tool.js status
6487
- node ~/browser-tool.js open "https://google.com"
6488
- node ~/browser-tool.js get_text
6489
- node ~/browser-tool.js fill "input[name='q']" "tu khoa"
6490
- node ~/browser-tool.js press "Enter"
6491
- node ~/browser-tool.js click "#button"
6492
- \\\`\\\`\\\`
6493
-
6494
- ## QUY TAC BAT BUOC
6495
- - KHONG BAO GIO tu choi mo trinh duyet.
6496
- - Neu loi ECONNREFUSED: bao user bat lai start-chrome-debug.bat.
6497
- - KHONG dung web_search khi user yeu cau browser.
6498
- `;
6499
-
6500
- const chromeBatContent = `@echo off
6501
- echo ====== OpenClaw - Chrome Debug Mode ======
6502
- echo.
6503
- echo Dang tat Chrome cu (neu co)...
6504
- taskkill /F /IM chrome.exe >nul 2>&1
6505
- timeout /t 3 /nobreak >nul
6506
- echo Dang mo Chrome voi Debug Mode...
6507
- start "" "C:\\Program Files\\Google\\Chrome\\Application\\chrome.exe" ^
6508
- --remote-debugging-port=9222 ^
6509
- --remote-allow-origins=* ^
6510
- --user-data-dir="%TEMP%\\chrome-debug"
6511
- timeout /t 4 /nobreak >nul
6512
- powershell -Command "try { Invoke-WebRequest -Uri 'http://localhost:9222/json/version' -UseBasicParsing -TimeoutSec 5 | Out-Null; Write-Host 'OK! Chrome Debug Mode dang chay.' -ForegroundColor Green } catch { Write-Host 'LOI: Port 9222 chua mo.' -ForegroundColor Red }"
6513
- echo.
6514
- pause
6515
- `;
6516
-
6517
- const chromeShContent = `#!/usr/bin/env bash
6518
- # ====== OpenClaw - Chrome Debug Mode (Mac/Linux) ======
6519
- set -e
6520
- echo "====== OpenClaw - Chrome Debug Mode ======"
6521
- echo ""
6522
-
6523
- # Detect Chrome path
6524
- if [[ "$OSTYPE" == "darwin"* ]]; then
6525
- CHROME_BIN="/Applications/Google Chrome.app/Contents/MacOS/Google Chrome"
6526
- [ ! -f "$CHROME_BIN" ] && CHROME_BIN="/Applications/Chromium.app/Contents/MacOS/Chromium"
6527
- [ ! -f "$CHROME_BIN" ] && CHROME_BIN="/Applications/Google Chrome Canary.app/Contents/MacOS/Google Chrome Canary"
6528
- else
6529
- CHROME_BIN="$(command -v google-chrome || command -v google-chrome-stable || command -v chromium-browser || command -v chromium || echo '')"
6530
- fi
6531
- [ -n "$CHROME_DEBUG_BIN" ] && CHROME_BIN="$CHROME_DEBUG_BIN"
6532
-
6533
- if [ -z "$CHROME_BIN" ] || { [ ! -f "$CHROME_BIN" ] && [ ! -x "$CHROME_BIN" ]; }; then
6534
- echo -e "\\033[31mERROR: Chrome/Chromium not found.\\033[0m"
6535
- echo "Install Chrome or: export CHROME_DEBUG_BIN=/path/to/chrome"
6536
- exit 1
6537
- fi
6538
-
6539
- echo "Using: $CHROME_BIN"
6540
- echo "Killing existing Chrome debug instances..."
6541
- pkill -f -- "--remote-debugging-port=9222" 2>/dev/null || true
6542
- sleep 2
6543
-
6544
- TMP_DIR="\${TMPDIR:-/tmp}/chrome-debug-openclaw"
6545
- mkdir -p "$TMP_DIR"
6546
-
6547
- echo "Starting Chrome in Debug Mode (port 9222)..."
6548
- "$CHROME_BIN" \\
6549
- --remote-debugging-port=9222 \\
6550
- --remote-allow-origins=* \\
6551
- --user-data-dir="$TMP_DIR" &
6552
-
6553
- sleep 4
6554
- if curl -s http://localhost:9222/json/version > /dev/null 2>&1; then
6555
- echo -e "\\033[32mOK! Chrome Debug Mode is running on port 9222.\\033[0m"
6556
- else
6557
- echo -e "\\033[31mERROR: Port 9222 not responding.\\033[0m"
6558
- exit 1
6559
- fi
6560
- `;
6561
6614
 
6562
6615
  const envText = (document.getElementById('env-content')?.textContent || '').trim();
6563
6616
  const rootEnvContent = envText ? `${envText}\n` : '';
@@ -6612,10 +6665,6 @@ fi
6612
6665
  });
6613
6666
  sharedFiles[`.openclaw/${meta.workspaceDir}/TEAMS.md`] = _scaffold.buildTeamsDoc({ isVi });
6614
6667
  sharedFiles[`.openclaw/${meta.workspaceDir}/MEMORY.md`] = memoryMd;
6615
- if (hasBrowser) {
6616
- sharedFiles[`.openclaw/${meta.workspaceDir}/browser-tool.js`] = browserToolJs;
6617
- sharedFiles[`.openclaw/${meta.workspaceDir}/BROWSER.md`] = browserMd;
6618
- }
6619
6668
  }
6620
6669
  state._generatedFiles = sharedFiles;
6621
6670
  } else {
@@ -6635,10 +6684,6 @@ fi
6635
6684
  }),
6636
6685
  [`.openclaw/workspace-${agentId}/MEMORY.md`]: memoryMd,
6637
6686
  '.gitignore': isNativeMode ? '.env\nnode_modules/' : '.env\ndocker/openclaw/.env\nnode_modules/',
6638
- ...(hasBrowser ? {
6639
- [`.openclaw/workspace-${agentId}/browser-tool.js`]: browserToolJs,
6640
- [`.openclaw/workspace-${agentId}/BROWSER.md`]: browserMd,
6641
- } : {}),
6642
6687
  };
6643
6688
  if (rootEnvContent) {
6644
6689
  singleFiles['.env'] = rootEnvContent;
@@ -6660,8 +6705,6 @@ fi
6660
6705
  // chrome-debug, start-bot, uninstall added ONCE here, not per-bot-mode block
6661
6706
  if (isNativeMode) {
6662
6707
  const _files = state._generatedFiles;
6663
- _files['start-chrome-debug.bat'] = chromeBatContent;
6664
- _files['start-chrome-debug.sh'] = chromeShContent;
6665
6708
  _files['start-bot.bat'] = generateStartBotBat({
6666
6709
  projectDir: state.config.projectPath || '.',
6667
6710
  openclawHome: (state.config.projectPath || '.') + '\\.openclaw',