create-openclaw-bot 5.6.14 → 5.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +11 -12
- package/README.vi.md +11 -12
- package/dist/cli.js +85 -263
- package/dist/setup/data/channels.js +1 -0
- package/dist/setup/shared/bot-config-gen.js +467 -0
- package/dist/setup/shared/common-gen.js +1 -1
- package/dist/setup/shared/docker-gen.js +443 -442
- package/dist/setup/shared/workspace-gen.js +129 -10
- package/dist/setup.js +5929 -5472
- package/package.json +39 -39
|
@@ -113,23 +113,142 @@ function buildBootstrapDoc(options = {}) {
|
|
|
113
113
|
}
|
|
114
114
|
|
|
115
115
|
function buildBrowserToolJs(variant = 'wizard') {
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
116
|
+
// v2: Full-featured browser-tool.js matching OpenClaw native browser plugin capabilities
|
|
117
|
+
// Both 'cli' and 'wizard' variants now use the same full script
|
|
118
|
+
const playwrightRequire = variant === 'cli'
|
|
119
|
+
? "require('playwright')"
|
|
120
|
+
: "require('/usr/local/lib/node_modules/openclaw/node_modules/playwright-core')";
|
|
121
|
+
|
|
122
|
+
return `/**
|
|
123
|
+
* browser-tool.js v2 — Full-featured Chrome CDP controller
|
|
124
|
+
* Commands: open|get_url|get_text|get_links|get_posts|evaluate|console|screenshot|screenshot_full|pdf|click|fill|press|hover|select|upload|scroll|wait|resize|tabs|new_tab|switch_tab|close_tab|status
|
|
125
|
+
*/
|
|
126
|
+
const { chromium } = ${playwrightRequire};
|
|
127
|
+
const action = process.argv[2];
|
|
128
|
+
const param1 = process.argv[3];
|
|
129
|
+
const param2 = process.argv[4];
|
|
130
|
+
const CDP_URL = 'http://127.0.0.1:9222';
|
|
131
|
+
(async () => {
|
|
132
|
+
let browser;
|
|
133
|
+
try {
|
|
134
|
+
browser = await chromium.connectOverCDP(CDP_URL, { timeout: 5000 });
|
|
135
|
+
const ctx = browser.contexts()[0];
|
|
136
|
+
const pages = ctx.pages();
|
|
137
|
+
let page = pages.length > 0 ? pages[0] : await ctx.newPage();
|
|
138
|
+
if (action === 'open') {
|
|
139
|
+
console.log('[Browser] Opening: ' + param1);
|
|
140
|
+
await page.goto(param1, { waitUntil: 'domcontentloaded', timeout: 30000 });
|
|
141
|
+
await page.waitForTimeout(1500);
|
|
142
|
+
console.log('[Browser] Opened: ' + (await page.title()) + ' | ' + page.url());
|
|
143
|
+
} else if (action === 'get_url') {
|
|
144
|
+
console.log(page.url());
|
|
145
|
+
} else if (action === 'status') {
|
|
146
|
+
const allPages = ctx.pages();
|
|
147
|
+
console.log('[Browser] Connected! Tabs: ' + allPages.length);
|
|
148
|
+
console.log('[Browser] Current: ' + (await page.title()) + ' | ' + page.url());
|
|
149
|
+
} else if (action === 'get_text') {
|
|
150
|
+
const maxLen = parseInt(param1) || 4000;
|
|
151
|
+
const text = await page.evaluate(() => { document.querySelectorAll('script,style,noscript,svg').forEach(e => e.remove()); return document.body.innerText.trim(); });
|
|
152
|
+
console.log(text.substring(0, maxLen));
|
|
153
|
+
} else if (action === 'get_links') {
|
|
154
|
+
const filter = param1 || '';
|
|
155
|
+
const links = await page.evaluate((f) => { const a = Array.from(document.querySelectorAll('a[href]')).map(e => e.href).filter(h => h && h.startsWith('http')); return [...new Set(f ? a.filter(h => h.includes(f)) : a)]; }, filter);
|
|
156
|
+
console.log(JSON.stringify(links.slice(0, 50), null, 2));
|
|
157
|
+
} else if (action === 'get_posts') {
|
|
158
|
+
const posts = await page.evaluate(() => {
|
|
159
|
+
const results = [];
|
|
160
|
+
const articles = document.querySelectorAll('[role="article"]');
|
|
161
|
+
for (const article of articles) {
|
|
162
|
+
const textEl = article.querySelector('[data-ad-comet-preview="message"],[data-ad-preview="message"]');
|
|
163
|
+
const fullText = (textEl ? textEl.innerText.trim() : '') || article.innerText.substring(0, 800);
|
|
164
|
+
const allLinks = Array.from(article.querySelectorAll('a[href]'));
|
|
165
|
+
let permalink = '';
|
|
166
|
+
for (const a of allLinks) { const h = a.href || ''; if (h.includes('/posts/') || h.includes('/permalink/') || h.includes('story_fbid')) { permalink = h.split('?')[0]; break; } }
|
|
167
|
+
let author = '';
|
|
168
|
+
for (const el of article.querySelectorAll('a[role="link"] strong, h2 a, h3 a, h4 a')) { const n = el.innerText.trim(); if (n && n.length > 1 && n.length < 50) { author = n; break; } }
|
|
169
|
+
let timePosted = '';
|
|
170
|
+
const timeLinks = allLinks.filter(a => { const h = a.href || ''; return h.includes('/posts/') || h.includes('/permalink/'); });
|
|
171
|
+
if (timeLinks.length > 0) { const t = timeLinks[0].innerText.trim(); if (t && t.length < 30) timePosted = t; }
|
|
172
|
+
if (!timePosted) { const te = article.querySelector('abbr,[data-utime]'); if (te) timePosted = te.innerText.trim() || te.getAttribute('title') || ''; }
|
|
173
|
+
if (fullText.length > 20) results.push({ author: author || 'N/A', text: fullText.substring(0, 500), permalink: permalink || 'N/A', time: timePosted || 'N/A' });
|
|
174
|
+
}
|
|
175
|
+
return results;
|
|
176
|
+
});
|
|
177
|
+
console.log(posts.length === 0 ? '[Browser] No posts found. Try scroll then get_posts again.' : JSON.stringify(posts.slice(0, 10), null, 2));
|
|
178
|
+
} else if (action === 'evaluate') {
|
|
179
|
+
const code = process.argv.slice(3).join(' ');
|
|
180
|
+
if (!code) { console.log('[Browser] Usage: evaluate <js_code>'); process.exit(1); }
|
|
181
|
+
const result = await page.evaluate(code);
|
|
182
|
+
console.log(result !== undefined && result !== null ? (typeof result === 'object' ? JSON.stringify(result, null, 2) : String(result)) : '[Browser] Done');
|
|
183
|
+
} else if (action === 'console') {
|
|
184
|
+
const msgs = []; page.on('console', m => msgs.push('[' + m.type() + '] ' + m.text()));
|
|
185
|
+
await page.waitForTimeout(2000);
|
|
186
|
+
console.log(msgs.length === 0 ? '[Browser] No console messages in 2s' : msgs.join('\\n'));
|
|
187
|
+
} else if (action === 'screenshot') {
|
|
188
|
+
const p = param1 || '/tmp/screenshot.png'; await page.screenshot({ path: p, fullPage: false }); console.log('[Browser] Screenshot: ' + p);
|
|
189
|
+
} else if (action === 'screenshot_full') {
|
|
190
|
+
const p = param1 || '/tmp/screenshot_full.png'; await page.screenshot({ path: p, fullPage: true }); console.log('[Browser] Full screenshot: ' + p);
|
|
191
|
+
} else if (action === 'pdf') {
|
|
192
|
+
const p = param1 || '/tmp/page.pdf'; await page.pdf({ path: p, format: 'A4' }); console.log('[Browser] PDF: ' + p);
|
|
193
|
+
} else if (action === 'click') {
|
|
194
|
+
await page.locator(param1).first().click({ timeout: 5000 }); await page.waitForTimeout(600); console.log('[Browser] Clicked: ' + param1);
|
|
195
|
+
} else if (action === 'fill') {
|
|
196
|
+
await page.locator(param1).first().fill(param2, { timeout: 5000 }); console.log('[Browser] Filled: ' + param1);
|
|
197
|
+
} else if (action === 'press') {
|
|
198
|
+
await page.keyboard.press(param1); await page.waitForTimeout(1000); console.log('[Browser] Pressed: ' + param1);
|
|
199
|
+
} else if (action === 'hover') {
|
|
200
|
+
await page.locator(param1).first().hover({ timeout: 5000 }); console.log('[Browser] Hovered: ' + param1);
|
|
201
|
+
} else if (action === 'select') {
|
|
202
|
+
await page.locator(param1).first().selectOption(param2, { timeout: 5000 }); console.log('[Browser] Selected: ' + param2);
|
|
203
|
+
} else if (action === 'upload') {
|
|
204
|
+
await page.locator(param1).first().setInputFiles(param2, { timeout: 5000 }); console.log('[Browser] Uploaded: ' + param2);
|
|
205
|
+
} else if (action === 'scroll') {
|
|
206
|
+
const px = parseInt(param1) || 800; await page.evaluate((p) => window.scrollBy(0, p), px); await page.waitForTimeout(2000); console.log('[Browser] Scrolled: ' + px + 'px');
|
|
207
|
+
} else if (action === 'wait') {
|
|
208
|
+
const ms = parseInt(param1) || 1000; await page.waitForTimeout(ms); console.log('[Browser] Waited: ' + ms + 'ms');
|
|
209
|
+
} else if (action === 'resize') {
|
|
210
|
+
const w = parseInt(param1) || 1280, h = parseInt(param2) || 720; await page.setViewportSize({ width: w, height: h }); console.log('[Browser] Resized: ' + w + 'x' + h);
|
|
211
|
+
} else if (action === 'tabs') {
|
|
212
|
+
const ap = ctx.pages(); for (let i = 0; i < ap.length; i++) { const t = await ap[i].title().catch(() => '(untitled)'); console.log('[' + i + '] ' + t + ' | ' + ap[i].url() + (ap[i] === page ? ' < current' : '')); }
|
|
213
|
+
} else if (action === 'new_tab') {
|
|
214
|
+
const np = await ctx.newPage(); if (param1) await np.goto(param1, { waitUntil: 'domcontentloaded', timeout: 30000 }); console.log('[Browser] New tab' + (param1 ? ': ' + param1 : ''));
|
|
215
|
+
} else if (action === 'switch_tab') {
|
|
216
|
+
const idx = parseInt(param1), ap = ctx.pages(); if (isNaN(idx) || idx < 0 || idx >= ap.length) { console.log('[Browser] Invalid index. Use tabs to list.'); } else { page = ap[idx]; await page.bringToFront(); console.log('[Browser] Switched to [' + idx + ']: ' + page.url()); }
|
|
217
|
+
} else if (action === 'close_tab') {
|
|
218
|
+
const ap = ctx.pages(), idx = param1 !== undefined ? parseInt(param1) : ap.indexOf(page); if (ap.length <= 1) { console.log('[Browser] Cannot close last tab.'); } else if (isNaN(idx) || idx < 0 || idx >= ap.length) { console.log('[Browser] Invalid index.'); } else { await ap[idx].close(); console.log('[Browser] Closed tab [' + idx + ']'); }
|
|
219
|
+
} else {
|
|
220
|
+
console.log('browser-tool.js v2 — Commands:');
|
|
221
|
+
console.log(' Nav: open <url> | get_url | status');
|
|
222
|
+
console.log(' Content: get_text [max] | get_links [filter] | get_posts | evaluate <js> | console');
|
|
223
|
+
console.log(' Export: screenshot [path] | screenshot_full [path] | pdf [path]');
|
|
224
|
+
console.log(' Interact: click <sel> | fill <sel> <txt> | press <key> | hover <sel> | select <sel> <val> | upload <sel> <path>');
|
|
225
|
+
console.log(' View: scroll [px] | wait <ms> | resize <w> <h>');
|
|
226
|
+
console.log(' Tabs: tabs | new_tab [url] | switch_tab <idx> | close_tab [idx]');
|
|
227
|
+
}
|
|
228
|
+
} catch(e) {
|
|
229
|
+
if (e.message.includes('ECONNREFUSED') || e.message.includes('Timeout')) {
|
|
230
|
+
console.error('[Browser] Chrome Debug not running! Start with --remote-debugging-port=9222');
|
|
231
|
+
} else { console.error('[Browser] Error:', e.message); }
|
|
232
|
+
} finally { if (browser) await browser.close(); }
|
|
233
|
+
})();
|
|
234
|
+
`;
|
|
120
235
|
}
|
|
121
236
|
|
|
122
237
|
function buildBrowserDoc(options = {}) {
|
|
123
238
|
const { isVi = true, variant = 'wizard', workspaceRoot = '' } = options;
|
|
239
|
+
// Normalize: strip trailing slash so path joins work cleanly
|
|
240
|
+
const wsRoot = workspaceRoot.replace(/\/+$/, '');
|
|
241
|
+
const btPath = wsRoot ? `${wsRoot}/browser-tool.js` : 'browser-tool.js';
|
|
242
|
+
|
|
124
243
|
if (variant === 'cli-desktop') {
|
|
125
|
-
return `# Browser Automation (Desktop Mode)\n\nBot controls your actual Chrome on screen through Chrome Debug at \`http://127.0.0.1:9222\`. Every action is visible.\n\n## Usage\n\`\`\`bash\nnode ${
|
|
244
|
+
return `# Browser Automation (Desktop Mode)\n\nBot controls your actual Chrome on screen through Chrome Debug at \`http://127.0.0.1:9222\`. Every action is visible.\n\n## Usage (v2)\n\`\`\`bash\n# Navigation\nnode ${btPath} status\nnode ${btPath} open "https://google.com"\nnode ${btPath} get_url\n\n# Content extraction\nnode ${btPath} get_text\nnode ${btPath} get_text 8000 # custom max length\nnode ${btPath} get_links # all links\nnode ${btPath} get_links "/posts/" # filtered\nnode ${btPath} get_posts # Facebook group posts w/ permalinks\nnode ${btPath} evaluate "document.title"\nnode ${btPath} console\n\n# Screenshots & export\nnode ${btPath} screenshot\nnode ${btPath} screenshot_full\nnode ${btPath} pdf\n\n# Interactions\nnode ${btPath} click "button.submit"\nnode ${btPath} fill "input[name='q']" "search"\nnode ${btPath} press "Enter"\nnode ${btPath} hover "a.link"\nnode ${btPath} select "select#country" "VN"\nnode ${btPath} upload "input[type=file]" "/tmp/photo.jpg"\n\n# Scrolling & viewport\nnode ${btPath} scroll\nnode ${btPath} scroll 1500\nnode ${btPath} wait 3000\nnode ${btPath} resize 1920 1080\n\n# Tab management\nnode ${btPath} tabs\nnode ${btPath} new_tab "https://example.com"\nnode ${btPath} switch_tab 1\nnode ${btPath} close_tab 2\n\`\`\`\n\n## MANDATORY RULES\n- NEVER refuse to open the browser when user asks.\n- In Desktop mode, always target the \`host-chrome\` / Chrome Debug session first.\n- If Chrome Debug is unreachable or returns \`ECONNREFUSED\`, tell user to run \`start-chrome-debug.bat\` again.\n- Use \`get_posts\` instead of \`get_text\` when scraping Facebook — it extracts permalinks.\n`;
|
|
126
245
|
}
|
|
127
246
|
if (variant === 'cli-server') {
|
|
128
247
|
return `# Browser Automation (Headless Server Mode)\n\nBot uses a headless Chromium instance running inside the Docker container. No GUI needed!\n\n## Notes\n- Running on Ubuntu Server / VPS (no GUI required)\n- Uses Playwright + Headless Chromium installed inside Docker\n- For Cloudflare bypass, switch to Desktop mode (requires Windows/Mac with Chrome)\n`;
|
|
129
248
|
}
|
|
130
249
|
return isVi
|
|
131
|
-
? `# Browser Automation\n\nDùng file \`browser-tool.js\` để điều khiển Chrome debug tại \`http://127.0.0.1:9222
|
|
132
|
-
: `# Browser Automation\n\nUse \`browser-tool.js\` to control Chrome debug on \`http://127.0.0.1:9222
|
|
250
|
+
? `# Browser Automation\n\nDùng file \`browser-tool.js\` để điều khiển Chrome debug tại \`http://127.0.0.1:9222\`.\nScript: \`${btPath}\`\nPhiên bản v2 hỗ trợ: open, get_text, get_links, get_posts, evaluate, screenshot, pdf, click, fill, press, hover, select, upload, scroll, tabs, và nhiều lệnh khác.`
|
|
251
|
+
: `# Browser Automation\n\nUse \`browser-tool.js\` to control Chrome debug on \`http://127.0.0.1:9222\`.\nScript: \`${btPath}\`\nVersion v2 supports: open, get_text, get_links, get_posts, evaluate, screenshot, pdf, click, fill, press, hover, select, upload, scroll, tabs, and more.`;
|
|
133
252
|
}
|
|
134
253
|
|
|
135
254
|
function buildSecurityRules(isVi = true) {
|
|
@@ -147,7 +266,7 @@ function buildBootstrapDoc(options = {}) {
|
|
|
147
266
|
ownAliases = [],
|
|
148
267
|
otherAgents = [], // [{ name, agentId }]
|
|
149
268
|
replyToDirectMessages = true,
|
|
150
|
-
workspacePath = '
|
|
269
|
+
workspacePath = '~/',
|
|
151
270
|
variant = 'single', // 'single' | 'relay'
|
|
152
271
|
includeSecurity = true,
|
|
153
272
|
} = options;
|
|
@@ -181,7 +300,7 @@ function buildBootstrapDoc(options = {}) {
|
|
|
181
300
|
const {
|
|
182
301
|
isVi = true,
|
|
183
302
|
skillListStr = '',
|
|
184
|
-
workspacePath = '
|
|
303
|
+
workspacePath = '~/',
|
|
185
304
|
variant = 'single', // 'single' | 'relay'
|
|
186
305
|
agentWorkspaceDir = 'workspace',
|
|
187
306
|
hasBrowser = false,
|
|
@@ -285,7 +404,7 @@ function buildBootstrapDoc(options = {}) {
|
|
|
285
404
|
ownAliases = [],
|
|
286
405
|
otherAgents = [],
|
|
287
406
|
skillListStr = '',
|
|
288
|
-
workspacePath = '
|
|
407
|
+
workspacePath = '~/',
|
|
289
408
|
agentWorkspaceDir = 'workspace',
|
|
290
409
|
persona = '',
|
|
291
410
|
userInfo = '',
|