create-openclaw-bot 5.8.0 → 5.8.1
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 +157 -159
- package/README.vi.md +162 -164
- package/dist/cli.js +125 -112
- package/dist/legacy-cli.js +11 -11
- package/dist/server/local-server.js +2568 -2372
- package/dist/setup/data/index.js +0 -1
- package/dist/setup/data/plugins.js +8 -1
- package/dist/setup/data/skills.js +2 -10
- package/dist/setup/shared/docker-gen.js +571 -576
- package/dist/setup/shared/workspace-gen.js +813 -526
- package/dist/setup.js +337 -299
- package/dist/web/app.js +1247 -1106
- package/dist/web/styles.css +1054 -286
- package/package.json +40 -40
package/dist/setup.js
CHANGED
|
@@ -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',
|
|
@@ -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 === '
|
|
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'
|
|
@@ -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
|
-
|
|
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##
|
|
1294
|
-
|
|
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##
|
|
1297
|
-
|
|
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
|
|
1309
|
-
|
|
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ụ là \`cron\` (tuyệt đối không nhầm là \`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:
|
|
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:
|
|
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,
|
|
@@ -2705,7 +2991,6 @@ if(touched){console.log('[patch-9router] Applied Codex compatibility patch.');}e
|
|
|
2705
2991
|
is9Router,
|
|
2706
2992
|
isLocal,
|
|
2707
2993
|
isMultiBot,
|
|
2708
|
-
hasBrowser,
|
|
2709
2994
|
selectedModel,
|
|
2710
2995
|
agentId,
|
|
2711
2996
|
allSkills = [],
|
|
@@ -2724,23 +3009,9 @@ if(touched){console.log('[patch-9router] Applied Codex compatibility patch.');}e
|
|
|
2724
3009
|
plainSingleExtraHosts = false,
|
|
2725
3010
|
multiOllamaNumParallel = 1,
|
|
2726
3011
|
singleOllamaNumParallel = 1,
|
|
2727
|
-
emitBrowserInstall = true,
|
|
2728
3012
|
gatewayPort = 18789,
|
|
2729
3013
|
routerPort = 20128,
|
|
2730
3014
|
} = 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
3015
|
const skillLines = dockerfileSkillInstallMode === 'build' && allSkills.length > 0
|
|
2745
3016
|
? `\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
3017
|
: '';
|
|
@@ -2780,6 +3051,20 @@ if(touched){console.log('[patch-9router] Applied Codex compatibility patch.');}e
|
|
|
2780
3051
|
' echo "[entrypoint] plugin $id missing; installing $spec"',
|
|
2781
3052
|
' openclaw plugins install "$spec" 2>/dev/null || echo "[entrypoint] warning: failed to install plugin $spec"',
|
|
2782
3053
|
'}',
|
|
3054
|
+
'ensure_zalouser() {',
|
|
3055
|
+
' NPM_DIR="$OPENCLAW_HOME/npm"',
|
|
3056
|
+
' PKG_DIR="$NPM_DIR/node_modules/@openclaw/zalouser"',
|
|
3057
|
+
' if [ -d "$PKG_DIR" ]; then',
|
|
3058
|
+
' echo "[entrypoint] zalouser plugin already installed"',
|
|
3059
|
+
' else',
|
|
3060
|
+
' echo "[entrypoint] zalouser plugin missing; installing via npm"',
|
|
3061
|
+
' mkdir -p "$NPM_DIR"',
|
|
3062
|
+
' cd "$NPM_DIR"',
|
|
3063
|
+
' npm init -y 2>/dev/null || true',
|
|
3064
|
+
' npm install @openclaw/zalouser@latest 2>/dev/null || echo "[entrypoint] warning: failed to install @openclaw/zalouser"',
|
|
3065
|
+
' cd /root/project',
|
|
3066
|
+
' fi',
|
|
3067
|
+
'}',
|
|
2783
3068
|
'ensure_skill() {',
|
|
2784
3069
|
' id="$1"',
|
|
2785
3070
|
' if find "$OPENCLAW_HOME" -maxdepth 4 -type d -path "*/skills/$id" -print -quit 2>/dev/null | grep -q .; then',
|
|
@@ -2805,7 +3090,7 @@ if(touched){console.log('[patch-9router] Applied Codex compatibility patch.');}e
|
|
|
2805
3090
|
' sed -i "s/LISTENER_WATCHDOG_MAX_GAP_MS\\\\s*=\\\\s*35e3/LISTENER_WATCHDOG_MAX_GAP_MS = 90e3/" "$ZALO_JS"',
|
|
2806
3091
|
' echo "[entrypoint] patched zalouser watchdog gap: 35s -> 90s"',
|
|
2807
3092
|
'fi',
|
|
2808
|
-
].join('
|
|
3093
|
+
].join('\n'));
|
|
2809
3094
|
runtimeParts.push([
|
|
2810
3095
|
'# Zalo channel auto-restart monitor (background)',
|
|
2811
3096
|
'(',
|
|
@@ -2815,27 +3100,23 @@ if(touched){console.log('[patch-9router] Applied Codex compatibility patch.');}e
|
|
|
2815
3100
|
' STATUS=$(openclaw channels status 2>/dev/null | grep -i "Zalo Personal" || true)',
|
|
2816
3101
|
' if echo "$STATUS" | grep -qi "stopped"; then',
|
|
2817
3102
|
' echo "[zalo-monitor] Zalo channel stopped - restarting container in 5s"',
|
|
2818
|
-
|
|
3103
|
+
' sleep 5',
|
|
2819
3104
|
' kill 1 2>/dev/null || true',
|
|
2820
3105
|
' fi',
|
|
2821
3106
|
' done',
|
|
2822
3107
|
') &',
|
|
2823
|
-
].join('
|
|
2824
|
-
|
|
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');
|
|
2829
|
-
}
|
|
3108
|
+
].join('\n'));
|
|
3109
|
+
runtimeParts.push('openclaw gateway run');
|
|
2830
3110
|
const runtimeScript = ['#!/bin/sh', 'set -e', ...runtimeParts].join('\n');
|
|
2831
3111
|
const dockerfile = `FROM node:22-slim
|
|
2832
3112
|
|
|
2833
|
-
RUN apt-get update && apt-get install -y git curl python3
|
|
2834
|
-
|
|
3113
|
+
RUN apt-get update && apt-get install -y git curl python3 && rm -rf /var/lib/apt/lists/*
|
|
3114
|
+
|
|
2835
3115
|
ARG OPENCLAW_VER="${openClawNpmSpec}"
|
|
2836
3116
|
ARG CACHE_BUST=""
|
|
2837
3117
|
RUN echo "CACHE_BUST=$CACHE_BUST" && npm install -g $OPENCLAW_VER ${openClawRuntimePackages}${skillLines}${pluginLines}
|
|
2838
3118
|
${patchLine}
|
|
3119
|
+
|
|
2839
3120
|
COPY entrypoint.sh /usr/local/bin/openclaw-entrypoint.sh
|
|
2840
3121
|
RUN chmod +x /usr/local/bin/openclaw-entrypoint.sh
|
|
2841
3122
|
WORKDIR /root/project
|
|
@@ -2858,7 +3139,7 @@ CMD ["/bin/sh", "/usr/local/bin/openclaw-entrypoint.sh"]`;
|
|
|
2858
3139
|
: isLocal
|
|
2859
3140
|
? ' depends_on:\n ollama:\n condition: service_healthy\n'
|
|
2860
3141
|
: '';
|
|
2861
|
-
const extraHosts =
|
|
3142
|
+
const extraHosts = `${extraHostsBlock}\n`;
|
|
2862
3143
|
if (is9Router) {
|
|
2863
3144
|
compose = `name: ${multiComposeName}
|
|
2864
3145
|
services:
|
|
@@ -2961,7 +3242,7 @@ services:
|
|
|
2961
3242
|
- ../../.env
|
|
2962
3243
|
depends_on:
|
|
2963
3244
|
- 9router
|
|
2964
|
-
${appEnvironmentBlock}${
|
|
3245
|
+
${appEnvironmentBlock}${extraHostsBlock}\n volumes:
|
|
2965
3246
|
- ${volumeMount}
|
|
2966
3247
|
- openclaw-plugins:/root/project/.openclaw/npm
|
|
2967
3248
|
ports:
|
|
@@ -3002,7 +3283,7 @@ services:
|
|
|
3002
3283
|
${appEnvironmentBlock} depends_on:
|
|
3003
3284
|
ollama:
|
|
3004
3285
|
condition: service_healthy
|
|
3005
|
-
${
|
|
3286
|
+
${extraHostsBlock}\n ports:
|
|
3006
3287
|
- "${gatewayPort}:${gatewayPort}"
|
|
3007
3288
|
volumes:
|
|
3008
3289
|
- ${volumeMount}
|
|
@@ -3097,10 +3378,9 @@ function buildNativeScriptCtx(options) {
|
|
|
3097
3378
|
const ch = CHANNELS[state.channel];
|
|
3098
3379
|
const is9Router = !!(provider && provider.isProxy);
|
|
3099
3380
|
const isOllama = !!(provider && provider.isLocal);
|
|
3100
|
-
const hasBrowser = state.config.skills.includes('browser');
|
|
3101
3381
|
const nativeSkillConfigs = state.config.skills
|
|
3102
3382
|
.map((sid) => SKILLS.find((s) => s.id === sid))
|
|
3103
|
-
.filter((skill) => skill && skill.id !== 'scheduler' && skill.slug
|
|
3383
|
+
.filter((skill) => skill && skill.id !== 'scheduler' && skill.slug);
|
|
3104
3384
|
const selectedModel = (state.config.model || 'ollama/gemma4:e2b').replace('ollama/', '');
|
|
3105
3385
|
const isMultiBot = state.botCount > 1 && state.channel === 'telegram';
|
|
3106
3386
|
const projectDir = state.config.projectPath || '.';
|
|
@@ -3120,7 +3400,6 @@ function buildNativeScriptCtx(options) {
|
|
|
3120
3400
|
Object.assign(globalThis, {
|
|
3121
3401
|
isVi,
|
|
3122
3402
|
provider,
|
|
3123
|
-
hasBrowser,
|
|
3124
3403
|
is9Router,
|
|
3125
3404
|
selectedModel,
|
|
3126
3405
|
isMultiBot,
|
|
@@ -3474,7 +3753,6 @@ setInterval(sync, INTERVAL);`;
|
|
|
3474
3753
|
provider,
|
|
3475
3754
|
is9Router,
|
|
3476
3755
|
isOllama,
|
|
3477
|
-
hasBrowser,
|
|
3478
3756
|
selectedModel,
|
|
3479
3757
|
isMultiBot,
|
|
3480
3758
|
projectDir,
|
|
@@ -3510,7 +3788,6 @@ setInterval(sync, INTERVAL);`;
|
|
|
3510
3788
|
* @global {boolean} isVi - Vietnamese language mode
|
|
3511
3789
|
* @global {object} provider - Current primary provider config
|
|
3512
3790
|
* @global {boolean} isMultiBot - Multi-bot mode flag
|
|
3513
|
-
* @global {boolean} hasBrowser - Browser plugin selected
|
|
3514
3791
|
* @global {boolean} is9Router - 9Router proxy mode
|
|
3515
3792
|
* @global {string} projectDir - Output project directory path
|
|
3516
3793
|
* @global {Function} getGatewayAllowedOrigins
|
|
@@ -3575,8 +3852,8 @@ setInterval(sync, INTERVAL);`;
|
|
|
3575
3852
|
groupId,
|
|
3576
3853
|
selectedSkills: state.config.skills,
|
|
3577
3854
|
skills: SKILLS,
|
|
3578
|
-
hasBrowserDesktop:
|
|
3579
|
-
hasBrowserServer:
|
|
3855
|
+
hasBrowserDesktop: false,
|
|
3856
|
+
hasBrowserServer: false,
|
|
3580
3857
|
gatewayPort: basePort,
|
|
3581
3858
|
gatewayAllowedOrigins: getGatewayAllowedOrigins(basePort),
|
|
3582
3859
|
osChoice: state.nativeOs || '',
|
|
@@ -3646,7 +3923,7 @@ setInterval(sync, INTERVAL);`;
|
|
|
3646
3923
|
agentWorkspaceDir,
|
|
3647
3924
|
persona: bot.persona || '',
|
|
3648
3925
|
userInfo: state.config.userInfo || '',
|
|
3649
|
-
hasBrowser,
|
|
3926
|
+
hasBrowser: false,
|
|
3650
3927
|
soulVariant: 'wizard',
|
|
3651
3928
|
memoryVariant: 'wizard',
|
|
3652
3929
|
hasZaloMod: state.channel === 'zalo-personal',
|
|
@@ -4151,7 +4428,7 @@ window.__downloadGen = {
|
|
|
4151
4428
|
*/
|
|
4152
4429
|
function generateWinBat(ctx) {
|
|
4153
4430
|
const {
|
|
4154
|
-
ch, isVi, provider, is9Router, isOllama,
|
|
4431
|
+
ch, isVi, provider, is9Router, isOllama, selectedModel, isMultiBot, projectDir, todayStamp, allPlugins, pluginCmd, nativeSkillInstallCmds, nativeSkillConfigs, providerLines, sharedNativeFileMap, sharedNativeEnvContent, sharedNativeExecApprovalsContent, sharedNativeConfigContent, native9RouterSyncScriptContent, native9RouterServerEntryLookup, windowsHiddenNodeLaunch, generateUninstallScript,
|
|
4155
4432
|
} = ctx;
|
|
4156
4433
|
// state, PROVIDERS, SKILLS, PLUGINS, CHANNELS are IIFE-level globals
|
|
4157
4434
|
let scriptContent;
|
|
@@ -4204,11 +4481,6 @@ function generateWinBat(ctx) {
|
|
|
4204
4481
|
}
|
|
4205
4482
|
|
|
4206
4483
|
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
4484
|
if (nativeSkillInstallCmds.length > 0) {
|
|
4213
4485
|
lines.push('echo Cai skills...');
|
|
4214
4486
|
lines.push(...nativeSkillInstallCmds);
|
|
@@ -4296,7 +4568,7 @@ function generateWinBat(ctx) {
|
|
|
4296
4568
|
*/
|
|
4297
4569
|
function generateMacOsSh(ctx) {
|
|
4298
4570
|
const {
|
|
4299
|
-
ch, isVi, provider, is9Router, isOllama,
|
|
4571
|
+
ch, isVi, provider, is9Router, isOllama, selectedModel, isMultiBot, projectDir, todayStamp, allPlugins, pluginCmd, nativeSkillInstallCmds, nativeSkillConfigs, providerLines, sharedNativeFileMap, sharedNativeEnvContent, sharedNativeExecApprovalsContent, sharedNativeConfigContent, native9RouterSyncScriptContent, native9RouterServerEntryLookup, windowsHiddenNodeLaunch, generateUninstallScript,
|
|
4300
4572
|
} = ctx;
|
|
4301
4573
|
// state, PROVIDERS, SKILLS, PLUGINS, CHANNELS are IIFE-level globals
|
|
4302
4574
|
let scriptContent;
|
|
@@ -4414,7 +4686,7 @@ function generateMacOsSh(ctx) {
|
|
|
4414
4686
|
*/
|
|
4415
4687
|
function generateVpsSh(ctx) {
|
|
4416
4688
|
const {
|
|
4417
|
-
ch, isVi, provider, is9Router, isOllama,
|
|
4689
|
+
ch, isVi, provider, is9Router, isOllama, selectedModel, isMultiBot, projectDir, todayStamp, allPlugins, pluginCmd, nativeSkillInstallCmds, nativeSkillConfigs, providerLines, sharedNativeFileMap, sharedNativeEnvContent, sharedNativeExecApprovalsContent, sharedNativeConfigContent, native9RouterSyncScriptContent, native9RouterServerEntryLookup, windowsHiddenNodeLaunch, generateUninstallScript,
|
|
4418
4690
|
} = ctx;
|
|
4419
4691
|
// state, PROVIDERS, SKILLS, PLUGINS, CHANNELS are IIFE-level globals
|
|
4420
4692
|
let scriptContent;
|
|
@@ -4539,7 +4811,7 @@ GWEOF`);
|
|
|
4539
4811
|
*/
|
|
4540
4812
|
function generateLinuxSh(ctx) {
|
|
4541
4813
|
const {
|
|
4542
|
-
ch, isVi, provider, is9Router, isOllama,
|
|
4814
|
+
ch, isVi, provider, is9Router, isOllama, selectedModel, isMultiBot, projectDir, todayStamp, allPlugins, pluginCmd, nativeSkillInstallCmds, nativeSkillConfigs, providerLines, sharedNativeFileMap, sharedNativeEnvContent, sharedNativeExecApprovalsContent, sharedNativeConfigContent, native9RouterSyncScriptContent, native9RouterServerEntryLookup, windowsHiddenNodeLaunch, generateUninstallScript,
|
|
4543
4815
|
} = ctx;
|
|
4544
4816
|
// state, PROVIDERS, SKILLS, PLUGINS, CHANNELS are IIFE-level globals
|
|
4545
4817
|
let scriptContent;
|
|
@@ -5794,68 +6066,6 @@ function generateLinuxSh(ctx) {
|
|
|
5794
6066
|
const routerNotice = document.getElementById('9router-notice');
|
|
5795
6067
|
if (routerNotice) routerNotice.style.display = is9Router ? '' : 'none';
|
|
5796
6068
|
|
|
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
6069
|
// Show/hide docker vs native output based on deployMode
|
|
5860
6070
|
const dockerOut = document.getElementById('docker-output');
|
|
5861
6071
|
const nativeOut = document.getElementById('native-output');
|
|
@@ -5884,8 +6094,6 @@ Write-Host "Chrome se tu dong bat Debug Mode moi khi ban dang nhap Windows (dela
|
|
|
5884
6094
|
: 'Script is generated from your choices. Download and run — everything else is handled automatically.';
|
|
5885
6095
|
|
|
5886
6096
|
const agentId = state.config.botName.toLowerCase().replace(/[^a-z0-9]+/g, '-').replace(/-$/, '') || 'chat';
|
|
5887
|
-
|
|
5888
|
-
const hasBrowser = state.config.skills.includes('browser');
|
|
5889
6097
|
// isMultiBot => unified into isMultiBot above
|
|
5890
6098
|
const multiBotAgentMetas = isMultiBot
|
|
5891
6099
|
? state.bots.slice(0, state.botCount).map((bot, idx) => {
|
|
@@ -5974,19 +6182,6 @@ Write-Host "Chrome se tu dong bat Debug Mode moi khi ban dang nhap Windows (dela
|
|
|
5974
6182
|
};
|
|
5975
6183
|
}
|
|
5976
6184
|
|
|
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
6185
|
|
|
5991
6186
|
// Skills: register all selected skills in openclaw.json → skills.entries
|
|
5992
6187
|
// This makes OpenClaw actually load and enable them at runtime
|
|
@@ -5995,8 +6190,6 @@ Write-Host "Chrome se tu dong bat Debug Mode moi khi ban dang nhap Windows (dela
|
|
|
5995
6190
|
state.config.skills.forEach((sid) => {
|
|
5996
6191
|
const skill = SKILLS.find((s) => s.id === sid);
|
|
5997
6192
|
if (!skill) return;
|
|
5998
|
-
// Native browser tools are loaded automatically via the root 'browser' config
|
|
5999
|
-
if (skill.slug === 'browser-automation') return;
|
|
6000
6193
|
// scheduler is now native cron (not a skill), skip registering in skills.entries
|
|
6001
6194
|
if (skill.id === 'scheduler' || !skill.slug) return;
|
|
6002
6195
|
|
|
@@ -6124,7 +6317,7 @@ model:
|
|
|
6124
6317
|
const allSkills = [];
|
|
6125
6318
|
state.config.skills.forEach((sid) => {
|
|
6126
6319
|
const skill = SKILLS.find((s) => s.id === sid);
|
|
6127
|
-
if (skill && skill.slug
|
|
6320
|
+
if (skill && skill.slug) {
|
|
6128
6321
|
allSkills.push(skill.slug);
|
|
6129
6322
|
}
|
|
6130
6323
|
});
|
|
@@ -6144,7 +6337,6 @@ model:
|
|
|
6144
6337
|
is9Router,
|
|
6145
6338
|
isLocal,
|
|
6146
6339
|
isMultiBot: state.botCount > 1 && (state.channel === 'telegram'),
|
|
6147
|
-
hasBrowser,
|
|
6148
6340
|
selectedModel: state.config.model || 'ollama/gemma4:e2b',
|
|
6149
6341
|
agentId: 'bot',
|
|
6150
6342
|
allSkills,
|
|
@@ -6304,12 +6496,6 @@ _This file is yours to evolve. If someone asks to change it, confirm with the us
|
|
|
6304
6496
|
`;
|
|
6305
6497
|
|
|
6306
6498
|
// ── 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
6499
|
|
|
6314
6500
|
const agentsMd = lang === 'vi'
|
|
6315
6501
|
? `# Hướng dẫn vận hành
|
|
@@ -6337,7 +6523,6 @@ Bạn hỗ trợ người dùng trong mọi tác vụ hàng ngày thông qua tin
|
|
|
6337
6523
|
- Luôn xác nhận kết quả tool trước khi trả lời user
|
|
6338
6524
|
- Nếu tool lỗi → thông báo rõ ràng, đề xuất cách khác
|
|
6339
6525
|
|
|
6340
|
-
${browserAgentSection}
|
|
6341
6526
|
${state.config.securityRules}
|
|
6342
6527
|
`
|
|
6343
6528
|
|
|
@@ -6421,143 +6606,6 @@ _Update this file as you learn more about the user. Ask before changing._
|
|
|
6421
6606
|
// ── MEMORY.md — via scaffold builder
|
|
6422
6607
|
const memoryMd = _scaffold.buildMemoryDoc({ isVi, variant: 'wizard' });
|
|
6423
6608
|
|
|
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
6609
|
|
|
6562
6610
|
const envText = (document.getElementById('env-content')?.textContent || '').trim();
|
|
6563
6611
|
const rootEnvContent = envText ? `${envText}\n` : '';
|
|
@@ -6612,10 +6660,6 @@ fi
|
|
|
6612
6660
|
});
|
|
6613
6661
|
sharedFiles[`.openclaw/${meta.workspaceDir}/TEAMS.md`] = _scaffold.buildTeamsDoc({ isVi });
|
|
6614
6662
|
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
6663
|
}
|
|
6620
6664
|
state._generatedFiles = sharedFiles;
|
|
6621
6665
|
} else {
|
|
@@ -6635,10 +6679,6 @@ fi
|
|
|
6635
6679
|
}),
|
|
6636
6680
|
[`.openclaw/workspace-${agentId}/MEMORY.md`]: memoryMd,
|
|
6637
6681
|
'.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
6682
|
};
|
|
6643
6683
|
if (rootEnvContent) {
|
|
6644
6684
|
singleFiles['.env'] = rootEnvContent;
|
|
@@ -6660,8 +6700,6 @@ fi
|
|
|
6660
6700
|
// chrome-debug, start-bot, uninstall added ONCE here, not per-bot-mode block
|
|
6661
6701
|
if (isNativeMode) {
|
|
6662
6702
|
const _files = state._generatedFiles;
|
|
6663
|
-
_files['start-chrome-debug.bat'] = chromeBatContent;
|
|
6664
|
-
_files['start-chrome-debug.sh'] = chromeShContent;
|
|
6665
6703
|
_files['start-bot.bat'] = generateStartBotBat({
|
|
6666
6704
|
projectDir: state.config.projectPath || '.',
|
|
6667
6705
|
openclawHome: (state.config.projectPath || '.') + '\\.openclaw',
|