@xbrowser/cli 1.8.3 → 1.8.5
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 +2 -2
- package/dist/{browser-4PIVOYCW.js → browser-NSSCH4MJ.js} +1 -1
- package/dist/{browser-RJIRI2H5.js → browser-PTELW3WS.js} +1 -1
- package/dist/{browser-KVTJQKBA.js → browser-PUAJ3AHG.js} +1 -1
- package/dist/{chunk-IGWWPMEQ.js → chunk-7EOQV6ZW.js} +1 -1
- package/dist/{chunk-2SVQTI2O.js → chunk-BALOM2HW.js} +12 -12
- package/dist/{chunk-6QGZN5U7.js → chunk-TAHJCCME.js} +1 -1
- package/dist/{chunk-35DOHDTA.js → chunk-U25ZKXBJ.js} +1 -1
- package/dist/{chunk-ACFE6PKF.js → chunk-XU5WOJIV.js} +12 -12
- package/dist/cli.js +48 -22
- package/dist/daemon-main.js +3 -3
- package/dist/index.js +47 -21
- package/dist/{session-recorder-YI7YYM36.js → session-recorder-CV5EJSDY.js} +1 -1
- package/dist/{session-recorder-RTDGURIJ.js → session-recorder-H2WPBCSW.js} +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# xbrowser
|
|
2
2
|
|
|
3
|
-
> **Browser automation CLI** for web scraping, headless browsing, SEO analysis, and AI agent workflows. 51 commands,
|
|
3
|
+
> **Browser automation CLI** for web scraping, headless browsing, SEO analysis, and AI agent workflows. 51 commands, 75 plugins. A command-line alternative to Playwright, Puppeteer, and Selenium — **no code required**.
|
|
4
4
|
|
|
5
5
|
[](https://github.com/dyyz1993/xbrowser/actions)
|
|
6
6
|
[](https://codecov.io/gh/dyyz1993/xbrowser)
|
|
@@ -883,7 +883,7 @@ xbrowser/
|
|
|
883
883
|
| **Setup** | `npm i -g` — 0 config | Install + browser download | Install + browser download | Install + WebDriver + drivers |
|
|
884
884
|
| **Web Scraping** | Built-in (`scrape`, `crawl`, `map`) | Write custom scripts | Write custom scripts | Write custom scripts |
|
|
885
885
|
| **Search** | Built-in multi-engine (`search`) | No | No | No |
|
|
886
|
-
| **Plugin Ecosystem** |
|
|
886
|
+
| **Plugin Ecosystem** | 75 plugins | Limited | Limited | No |
|
|
887
887
|
| **No Code Required** | ✅ CLI commands | ❌ Must write JS/TS | ❌ Must write JS/TS | ❌ Must write code |
|
|
888
888
|
| **Headless Mode** | ✅ Default | ✅ | ✅ | ✅ |
|
|
889
889
|
| **Record/Replay** | ✅ Built-in (`record`/`replay`) | ✅ Codegen | ❌ | ❌ |
|
|
@@ -656,7 +656,7 @@ async function closeSessionByName(name) {
|
|
|
656
656
|
} catch {
|
|
657
657
|
}
|
|
658
658
|
try {
|
|
659
|
-
const { SessionRecorder } = await import("./session-recorder-
|
|
659
|
+
const { SessionRecorder } = await import("./session-recorder-H2WPBCSW.js");
|
|
660
660
|
SessionRecorder.cleanup(session.name);
|
|
661
661
|
} catch {
|
|
662
662
|
}
|
|
@@ -1725,6 +1725,16 @@ var SessionRecorder = class _SessionRecorder {
|
|
|
1725
1725
|
await this.page.addInitScript(getSelectorGeneratorScript());
|
|
1726
1726
|
await this.page.addInitScript(ACTION_SIGNAL_SCRIPT);
|
|
1727
1727
|
await this.page.addInitScript(CHECKPOINT_OVERLAY_SCRIPT);
|
|
1728
|
+
this.context.on("request", this.handleRequest);
|
|
1729
|
+
this.context.on("response", this.handleResponse);
|
|
1730
|
+
this.context.on("page", this.handleNewPage);
|
|
1731
|
+
for (const p of this.context.pages()) {
|
|
1732
|
+
p.on("request", this.handleRequest);
|
|
1733
|
+
p.on("response", this.handleResponse);
|
|
1734
|
+
}
|
|
1735
|
+
this.page.on("framenavigated", this.handleFrameNavigated);
|
|
1736
|
+
this.page.on("dialog", this.handleDialog);
|
|
1737
|
+
this.page.on("filechooser", this.handleFileChooser);
|
|
1728
1738
|
if (url) {
|
|
1729
1739
|
await this.page.goto(url, { waitUntil: "domcontentloaded", timeout: 3e4 });
|
|
1730
1740
|
this.startUrl = url;
|
|
@@ -1740,17 +1750,7 @@ var SessionRecorder = class _SessionRecorder {
|
|
|
1740
1750
|
};
|
|
1741
1751
|
writeFileSync2(this.controlFilePath, JSON.stringify(control, null, 2), "utf-8");
|
|
1742
1752
|
await this.injectActionScript(this.page);
|
|
1743
|
-
this.context.on("request", this.handleRequest);
|
|
1744
|
-
this.context.on("response", this.handleResponse);
|
|
1745
|
-
this.context.on("page", this.handleNewPage);
|
|
1746
|
-
for (const p of this.context.pages()) {
|
|
1747
|
-
p.on("request", this.handleRequest);
|
|
1748
|
-
p.on("response", this.handleResponse);
|
|
1749
|
-
}
|
|
1750
1753
|
this.context.on("page", this.handleNewPage);
|
|
1751
|
-
this.page.on("framenavigated", this.handleFrameNavigated);
|
|
1752
|
-
this.page.on("dialog", this.handleDialog);
|
|
1753
|
-
this.page.on("filechooser", this.handleFileChooser);
|
|
1754
1754
|
this.pollTimer = setInterval(() => void this.pollActions(), 200);
|
|
1755
1755
|
this.flushTimer = setInterval(() => this.flushToDisk(), 5e3);
|
|
1756
1756
|
}
|
|
@@ -2066,7 +2066,7 @@ var SessionRecorder = class _SessionRecorder {
|
|
|
2066
2066
|
this.activePages.delete(page);
|
|
2067
2067
|
});
|
|
2068
2068
|
page.on("framenavigated", async (frame) => {
|
|
2069
|
-
if (frame
|
|
2069
|
+
if (frame.isDetached()) return;
|
|
2070
2070
|
const url = frame.url();
|
|
2071
2071
|
if (url && url !== "about:blank" && !url.startsWith("chrome")) {
|
|
2072
2072
|
try {
|
|
@@ -2077,7 +2077,7 @@ var SessionRecorder = class _SessionRecorder {
|
|
|
2077
2077
|
});
|
|
2078
2078
|
};
|
|
2079
2079
|
handleFrameNavigated = (frame) => {
|
|
2080
|
-
if (frame
|
|
2080
|
+
if (frame.isDetached()) return;
|
|
2081
2081
|
const newUrl = frame.url();
|
|
2082
2082
|
this.contextCounter++;
|
|
2083
2083
|
this.contextChanges.push({
|
|
@@ -2021,7 +2021,7 @@ async function closeSessionByName(name) {
|
|
|
2021
2021
|
} catch {
|
|
2022
2022
|
}
|
|
2023
2023
|
try {
|
|
2024
|
-
const { SessionRecorder } = await import("./session-recorder-
|
|
2024
|
+
const { SessionRecorder } = await import("./session-recorder-CV5EJSDY.js");
|
|
2025
2025
|
SessionRecorder.cleanup(session.name);
|
|
2026
2026
|
} catch {
|
|
2027
2027
|
}
|
|
@@ -4965,7 +4965,7 @@ async function closeSessionByName(name) {
|
|
|
4965
4965
|
} catch {
|
|
4966
4966
|
}
|
|
4967
4967
|
try {
|
|
4968
|
-
const { SessionRecorder } = await import("./session-recorder-
|
|
4968
|
+
const { SessionRecorder } = await import("./session-recorder-H2WPBCSW.js");
|
|
4969
4969
|
SessionRecorder.cleanup(session.name);
|
|
4970
4970
|
} catch {
|
|
4971
4971
|
}
|
|
@@ -1328,6 +1328,16 @@ var SessionRecorder = class _SessionRecorder {
|
|
|
1328
1328
|
await this.page.addInitScript(getSelectorGeneratorScript());
|
|
1329
1329
|
await this.page.addInitScript(ACTION_SIGNAL_SCRIPT);
|
|
1330
1330
|
await this.page.addInitScript(CHECKPOINT_OVERLAY_SCRIPT);
|
|
1331
|
+
this.context.on("request", this.handleRequest);
|
|
1332
|
+
this.context.on("response", this.handleResponse);
|
|
1333
|
+
this.context.on("page", this.handleNewPage);
|
|
1334
|
+
for (const p of this.context.pages()) {
|
|
1335
|
+
p.on("request", this.handleRequest);
|
|
1336
|
+
p.on("response", this.handleResponse);
|
|
1337
|
+
}
|
|
1338
|
+
this.page.on("framenavigated", this.handleFrameNavigated);
|
|
1339
|
+
this.page.on("dialog", this.handleDialog);
|
|
1340
|
+
this.page.on("filechooser", this.handleFileChooser);
|
|
1331
1341
|
if (url) {
|
|
1332
1342
|
await this.page.goto(url, { waitUntil: "domcontentloaded", timeout: 3e4 });
|
|
1333
1343
|
this.startUrl = url;
|
|
@@ -1343,17 +1353,7 @@ var SessionRecorder = class _SessionRecorder {
|
|
|
1343
1353
|
};
|
|
1344
1354
|
writeFileSync(this.controlFilePath, JSON.stringify(control, null, 2), "utf-8");
|
|
1345
1355
|
await this.injectActionScript(this.page);
|
|
1346
|
-
this.context.on("request", this.handleRequest);
|
|
1347
|
-
this.context.on("response", this.handleResponse);
|
|
1348
|
-
this.context.on("page", this.handleNewPage);
|
|
1349
|
-
for (const p of this.context.pages()) {
|
|
1350
|
-
p.on("request", this.handleRequest);
|
|
1351
|
-
p.on("response", this.handleResponse);
|
|
1352
|
-
}
|
|
1353
1356
|
this.context.on("page", this.handleNewPage);
|
|
1354
|
-
this.page.on("framenavigated", this.handleFrameNavigated);
|
|
1355
|
-
this.page.on("dialog", this.handleDialog);
|
|
1356
|
-
this.page.on("filechooser", this.handleFileChooser);
|
|
1357
1357
|
this.pollTimer = setInterval(() => void this.pollActions(), 200);
|
|
1358
1358
|
this.flushTimer = setInterval(() => this.flushToDisk(), 5e3);
|
|
1359
1359
|
}
|
|
@@ -1669,7 +1669,7 @@ var SessionRecorder = class _SessionRecorder {
|
|
|
1669
1669
|
this.activePages.delete(page);
|
|
1670
1670
|
});
|
|
1671
1671
|
page.on("framenavigated", async (frame) => {
|
|
1672
|
-
if (frame
|
|
1672
|
+
if (frame.isDetached()) return;
|
|
1673
1673
|
const url = frame.url();
|
|
1674
1674
|
if (url && url !== "about:blank" && !url.startsWith("chrome")) {
|
|
1675
1675
|
try {
|
|
@@ -1680,7 +1680,7 @@ var SessionRecorder = class _SessionRecorder {
|
|
|
1680
1680
|
});
|
|
1681
1681
|
};
|
|
1682
1682
|
handleFrameNavigated = (frame) => {
|
|
1683
|
-
if (frame
|
|
1683
|
+
if (frame.isDetached()) return;
|
|
1684
1684
|
const newUrl = frame.url();
|
|
1685
1685
|
this.contextCounter++;
|
|
1686
1686
|
this.contextChanges.push({
|
package/dist/cli.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
3
|
SessionRecorder
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-XU5WOJIV.js";
|
|
5
5
|
import {
|
|
6
6
|
addKnownIssue,
|
|
7
7
|
getKnowledgePath,
|
|
@@ -25,7 +25,7 @@ import {
|
|
|
25
25
|
resolveLaunchOpts,
|
|
26
26
|
saveSessionDiskMeta,
|
|
27
27
|
setActivePage
|
|
28
|
-
} from "./chunk-
|
|
28
|
+
} from "./chunk-U25ZKXBJ.js";
|
|
29
29
|
import "./chunk-TNEN6VQ2.js";
|
|
30
30
|
import {
|
|
31
31
|
forwardCommandLog,
|
|
@@ -7207,7 +7207,7 @@ async function executeCommand(commandName, params, sessionName = "default", extr
|
|
|
7207
7207
|
}
|
|
7208
7208
|
let targetPageOverride = null;
|
|
7209
7209
|
if (_target && extraOpts?.cdpEndpoint) {
|
|
7210
|
-
const { findTargetPage } = await import("./browser-
|
|
7210
|
+
const { findTargetPage } = await import("./browser-PUAJ3AHG.js");
|
|
7211
7211
|
targetPageOverride = await findTargetPage(extraOpts.cdpEndpoint, _target);
|
|
7212
7212
|
if (!targetPageOverride) {
|
|
7213
7213
|
return errorResult(`Target "${_target}" not found. Use 'xbrowser targets --cdp ${extraOpts.cdpEndpoint}' to list available pages.`);
|
|
@@ -7945,7 +7945,8 @@ import {
|
|
|
7945
7945
|
rmSync as rmSync6,
|
|
7946
7946
|
copyFileSync,
|
|
7947
7947
|
cpSync as cpSync6,
|
|
7948
|
-
readFileSync as readFileSync8
|
|
7948
|
+
readFileSync as readFileSync8,
|
|
7949
|
+
writeFileSync as writeFileSync10
|
|
7949
7950
|
} from "fs";
|
|
7950
7951
|
import { resolve as resolve8, basename as basename2, dirname as dirname3 } from "path";
|
|
7951
7952
|
import { homedir as homedir8 } from "os";
|
|
@@ -8439,26 +8440,26 @@ var PluginInstaller = class {
|
|
|
8439
8440
|
const resolvedSource = type === "npm" ? await resolveNpmPackageWithFallback(source) : source;
|
|
8440
8441
|
switch (type) {
|
|
8441
8442
|
case "local":
|
|
8442
|
-
return await installFromLocal(source, name, targetDir).then((r) => {
|
|
8443
|
-
this.fixSharedDeps(targetDir);
|
|
8443
|
+
return await installFromLocal(source, name, targetDir).then(async (r) => {
|
|
8444
|
+
await this.fixSharedDeps(targetDir);
|
|
8444
8445
|
ensurePluginDependencies(this.pluginsDir);
|
|
8445
8446
|
return r;
|
|
8446
8447
|
});
|
|
8447
8448
|
case "npm":
|
|
8448
|
-
return await installFromNpm(resolvedSource, name, targetDir).then((r) => {
|
|
8449
|
-
this.fixSharedDeps(targetDir);
|
|
8449
|
+
return await installFromNpm(resolvedSource, name, targetDir).then(async (r) => {
|
|
8450
|
+
await this.fixSharedDeps(targetDir);
|
|
8450
8451
|
ensurePluginDependencies(this.pluginsDir);
|
|
8451
8452
|
return r;
|
|
8452
8453
|
});
|
|
8453
8454
|
case "git":
|
|
8454
|
-
return await installFromGit(source, name, targetDir).then((r) => {
|
|
8455
|
-
this.fixSharedDeps(targetDir);
|
|
8455
|
+
return await installFromGit(source, name, targetDir).then(async (r) => {
|
|
8456
|
+
await this.fixSharedDeps(targetDir);
|
|
8456
8457
|
ensurePluginDependencies(this.pluginsDir);
|
|
8457
8458
|
return r;
|
|
8458
8459
|
});
|
|
8459
8460
|
case "url":
|
|
8460
|
-
return await installFromUrl(source, name, targetDir).then((r) => {
|
|
8461
|
-
this.fixSharedDeps(targetDir);
|
|
8461
|
+
return await installFromUrl(source, name, targetDir).then(async (r) => {
|
|
8462
|
+
await this.fixSharedDeps(targetDir);
|
|
8462
8463
|
ensurePluginDependencies(this.pluginsDir);
|
|
8463
8464
|
return r;
|
|
8464
8465
|
});
|
|
@@ -8473,7 +8474,7 @@ var PluginInstaller = class {
|
|
|
8473
8474
|
* copies the missing files from the local repository's `.xcli/plugins/shared/`
|
|
8474
8475
|
* directory (if available).
|
|
8475
8476
|
*/
|
|
8476
|
-
fixSharedDeps(pluginDir) {
|
|
8477
|
+
async fixSharedDeps(pluginDir) {
|
|
8477
8478
|
const indexPath = resolve8(pluginDir, "index.ts");
|
|
8478
8479
|
if (!existsSync10(indexPath)) return;
|
|
8479
8480
|
let content;
|
|
@@ -8510,8 +8511,33 @@ var PluginInstaller = class {
|
|
|
8510
8511
|
}
|
|
8511
8512
|
}
|
|
8512
8513
|
if (!sourceSharedDir) {
|
|
8513
|
-
|
|
8514
|
-
|
|
8514
|
+
const GITHUB_RAW = "https://raw.githubusercontent.com/dyyz1993/xbrowser/master/.xcli/plugins/shared";
|
|
8515
|
+
mkdirSync8(sharedDir, { recursive: true });
|
|
8516
|
+
let allDownloaded = true;
|
|
8517
|
+
for (const file of toCopy) {
|
|
8518
|
+
try {
|
|
8519
|
+
const url = `${GITHUB_RAW}/${file}`;
|
|
8520
|
+
const resp = await fetch(url, { signal: AbortSignal.timeout(1e4) });
|
|
8521
|
+
if (resp.ok) {
|
|
8522
|
+
const content2 = await resp.text();
|
|
8523
|
+
const dst = resolve8(sharedDir, file);
|
|
8524
|
+
const dstDir = dirname3(dst);
|
|
8525
|
+
if (!existsSync10(dstDir)) mkdirSync8(dstDir, { recursive: true });
|
|
8526
|
+
writeFileSync10(dst, content2, "utf-8");
|
|
8527
|
+
console.log(`\u2705 Downloaded shared/${file} from GitHub`);
|
|
8528
|
+
} else {
|
|
8529
|
+
allDownloaded = false;
|
|
8530
|
+
break;
|
|
8531
|
+
}
|
|
8532
|
+
} catch {
|
|
8533
|
+
allDownloaded = false;
|
|
8534
|
+
break;
|
|
8535
|
+
}
|
|
8536
|
+
}
|
|
8537
|
+
if (!allDownloaded) {
|
|
8538
|
+
console.warn(`\u26A0\uFE0F Plugin "${basename2(pluginDir)}" imports shared files but they are missing: ${toCopy.join(", ")}`);
|
|
8539
|
+
console.warn(` Could not download from GitHub. Try: git clone https://github.com/dyyz1993/xbrowser.git && cp -r xbrowser/.xcli/plugins/shared/ ~/.xbrowser/plugins/shared/`);
|
|
8540
|
+
}
|
|
8515
8541
|
return;
|
|
8516
8542
|
}
|
|
8517
8543
|
mkdirSync8(sharedDir, { recursive: true });
|
|
@@ -10244,9 +10270,9 @@ async function handleBrowserCommand(command, args, options, sessionName, mode, c
|
|
|
10244
10270
|
}
|
|
10245
10271
|
const outputFile = options.output;
|
|
10246
10272
|
if (outputFile && result.success && result.data) {
|
|
10247
|
-
const { writeFileSync:
|
|
10273
|
+
const { writeFileSync: writeFileSync12 } = await import("fs");
|
|
10248
10274
|
const content = typeof result.data === "string" ? result.data : result.data.content || result.data.text || JSON.stringify(result.data, null, 2);
|
|
10249
|
-
|
|
10275
|
+
writeFileSync12(outputFile, content, "utf-8");
|
|
10250
10276
|
console.log(`
|
|
10251
10277
|
\u{1F4C4} Written to ${outputFile}`);
|
|
10252
10278
|
}
|
|
@@ -11126,9 +11152,9 @@ async function handleFilter(args, _mode, options) {
|
|
|
11126
11152
|
console.log(` Original: ${result.originalCount}, After: ${result.filteredCount}, Removed: ${result.removed} (${result.percentage}%)`);
|
|
11127
11153
|
}
|
|
11128
11154
|
async function handleGeneratePlugin(sessionName, pluginName, outputDir) {
|
|
11129
|
-
const { SessionRecorder: SessionRecorder2 } = await import("./session-recorder-
|
|
11155
|
+
const { SessionRecorder: SessionRecorder2 } = await import("./session-recorder-H2WPBCSW.js");
|
|
11130
11156
|
const { readSiteKnowledge: readSiteKnowledge2, toMarkdown } = await import("./site-knowledge-SYC6VCDB.js");
|
|
11131
|
-
const { mkdirSync: mkdirSync10, writeFileSync:
|
|
11157
|
+
const { mkdirSync: mkdirSync10, writeFileSync: writeFileSync12 } = await import("fs");
|
|
11132
11158
|
const { join: join14 } = await import("path");
|
|
11133
11159
|
const data = SessionRecorder2.readData(sessionName);
|
|
11134
11160
|
if (!data) {
|
|
@@ -11146,9 +11172,9 @@ async function handleGeneratePlugin(sessionName, pluginName, outputDir) {
|
|
|
11146
11172
|
const knowledgeMd = knowledge ? toMarkdown(knowledge) : "";
|
|
11147
11173
|
const pluginCode = generatePluginCode(finalPluginName, domain, data, knowledgeMd);
|
|
11148
11174
|
mkdirSync10(join14(finalOutputDir), { recursive: true });
|
|
11149
|
-
|
|
11175
|
+
writeFileSync12(join14(finalOutputDir, "index.ts"), pluginCode, "utf-8");
|
|
11150
11176
|
if (knowledgeMd) {
|
|
11151
|
-
|
|
11177
|
+
writeFileSync12(join14(finalOutputDir, "SITE_KNOWLEDGE.md"), knowledgeMd, "utf-8");
|
|
11152
11178
|
}
|
|
11153
11179
|
console.log("");
|
|
11154
11180
|
console.log("=== Plugin Generated ===");
|
|
@@ -13333,7 +13359,7 @@ async function main() {
|
|
|
13333
13359
|
const command = process.argv[2];
|
|
13334
13360
|
const isLongRunning = command === "preview" || command === "serve";
|
|
13335
13361
|
if (!isLongRunning) {
|
|
13336
|
-
const { ensureProcessCanExit } = await import("./browser-
|
|
13362
|
+
const { ensureProcessCanExit } = await import("./browser-PUAJ3AHG.js");
|
|
13337
13363
|
await ensureProcessCanExit().catch(() => {
|
|
13338
13364
|
});
|
|
13339
13365
|
process.exit(exitCode);
|
package/dist/daemon-main.js
CHANGED
|
@@ -5,7 +5,7 @@ import {
|
|
|
5
5
|
} from "./chunk-VEDJ5XSQ.js";
|
|
6
6
|
import {
|
|
7
7
|
SessionRecorder
|
|
8
|
-
} from "./chunk-
|
|
8
|
+
} from "./chunk-BALOM2HW.js";
|
|
9
9
|
import {
|
|
10
10
|
closeEphemeralContext,
|
|
11
11
|
closeSessionByName,
|
|
@@ -21,7 +21,7 @@ import {
|
|
|
21
21
|
resolveLaunchOpts,
|
|
22
22
|
saveSessionDiskMeta,
|
|
23
23
|
setActivePage
|
|
24
|
-
} from "./chunk-
|
|
24
|
+
} from "./chunk-TAHJCCME.js";
|
|
25
25
|
import "./chunk-VJNMAWPZ.js";
|
|
26
26
|
import "./chunk-TNEN6VQ2.js";
|
|
27
27
|
import {
|
|
@@ -6744,7 +6744,7 @@ async function executeCommand(commandName, params, sessionName = "default", extr
|
|
|
6744
6744
|
}
|
|
6745
6745
|
let targetPageOverride = null;
|
|
6746
6746
|
if (_target && extraOpts?.cdpEndpoint) {
|
|
6747
|
-
const { findTargetPage } = await import("./browser-
|
|
6747
|
+
const { findTargetPage } = await import("./browser-NSSCH4MJ.js");
|
|
6748
6748
|
targetPageOverride = await findTargetPage(extraOpts.cdpEndpoint, _target);
|
|
6749
6749
|
if (!targetPageOverride) {
|
|
6750
6750
|
return errorResult(`Target "${_target}" not found. Use 'xbrowser targets --cdp ${extraOpts.cdpEndpoint}' to list available pages.`);
|
package/dist/index.js
CHANGED
|
@@ -57,7 +57,7 @@ import {
|
|
|
57
57
|
} from "./chunk-GJAV3QGG.js";
|
|
58
58
|
import {
|
|
59
59
|
SessionRecorder
|
|
60
|
-
} from "./chunk-
|
|
60
|
+
} from "./chunk-XU5WOJIV.js";
|
|
61
61
|
import {
|
|
62
62
|
addKnownIssue,
|
|
63
63
|
getKnowledgePath,
|
|
@@ -82,7 +82,7 @@ import {
|
|
|
82
82
|
resolveLaunchOpts,
|
|
83
83
|
saveSessionDiskMeta,
|
|
84
84
|
setActivePage
|
|
85
|
-
} from "./chunk-
|
|
85
|
+
} from "./chunk-7EOQV6ZW.js";
|
|
86
86
|
import "./chunk-VJNMAWPZ.js";
|
|
87
87
|
import "./chunk-TNEN6VQ2.js";
|
|
88
88
|
import {
|
|
@@ -7527,7 +7527,7 @@ async function executeCommand(commandName, params, sessionName = "default", extr
|
|
|
7527
7527
|
}
|
|
7528
7528
|
let targetPageOverride = null;
|
|
7529
7529
|
if (_target && extraOpts?.cdpEndpoint) {
|
|
7530
|
-
const { findTargetPage } = await import("./browser-
|
|
7530
|
+
const { findTargetPage } = await import("./browser-PTELW3WS.js");
|
|
7531
7531
|
targetPageOverride = await findTargetPage(extraOpts.cdpEndpoint, _target);
|
|
7532
7532
|
if (!targetPageOverride) {
|
|
7533
7533
|
return errorResult(`Target "${_target}" not found. Use 'xbrowser targets --cdp ${extraOpts.cdpEndpoint}' to list available pages.`);
|
|
@@ -8263,7 +8263,8 @@ import {
|
|
|
8263
8263
|
rmSync as rmSync6,
|
|
8264
8264
|
copyFileSync,
|
|
8265
8265
|
cpSync as cpSync6,
|
|
8266
|
-
readFileSync as readFileSync8
|
|
8266
|
+
readFileSync as readFileSync8,
|
|
8267
|
+
writeFileSync as writeFileSync10
|
|
8267
8268
|
} from "fs";
|
|
8268
8269
|
import { resolve as resolve8, basename as basename2, dirname as dirname3 } from "path";
|
|
8269
8270
|
import { homedir as homedir7 } from "os";
|
|
@@ -8757,26 +8758,26 @@ var PluginInstaller = class {
|
|
|
8757
8758
|
const resolvedSource = type === "npm" ? await resolveNpmPackageWithFallback(source) : source;
|
|
8758
8759
|
switch (type) {
|
|
8759
8760
|
case "local":
|
|
8760
|
-
return await installFromLocal(source, name, targetDir).then((r) => {
|
|
8761
|
-
this.fixSharedDeps(targetDir);
|
|
8761
|
+
return await installFromLocal(source, name, targetDir).then(async (r) => {
|
|
8762
|
+
await this.fixSharedDeps(targetDir);
|
|
8762
8763
|
ensurePluginDependencies(this.pluginsDir);
|
|
8763
8764
|
return r;
|
|
8764
8765
|
});
|
|
8765
8766
|
case "npm":
|
|
8766
|
-
return await installFromNpm(resolvedSource, name, targetDir).then((r) => {
|
|
8767
|
-
this.fixSharedDeps(targetDir);
|
|
8767
|
+
return await installFromNpm(resolvedSource, name, targetDir).then(async (r) => {
|
|
8768
|
+
await this.fixSharedDeps(targetDir);
|
|
8768
8769
|
ensurePluginDependencies(this.pluginsDir);
|
|
8769
8770
|
return r;
|
|
8770
8771
|
});
|
|
8771
8772
|
case "git":
|
|
8772
|
-
return await installFromGit(source, name, targetDir).then((r) => {
|
|
8773
|
-
this.fixSharedDeps(targetDir);
|
|
8773
|
+
return await installFromGit(source, name, targetDir).then(async (r) => {
|
|
8774
|
+
await this.fixSharedDeps(targetDir);
|
|
8774
8775
|
ensurePluginDependencies(this.pluginsDir);
|
|
8775
8776
|
return r;
|
|
8776
8777
|
});
|
|
8777
8778
|
case "url":
|
|
8778
|
-
return await installFromUrl(source, name, targetDir).then((r) => {
|
|
8779
|
-
this.fixSharedDeps(targetDir);
|
|
8779
|
+
return await installFromUrl(source, name, targetDir).then(async (r) => {
|
|
8780
|
+
await this.fixSharedDeps(targetDir);
|
|
8780
8781
|
ensurePluginDependencies(this.pluginsDir);
|
|
8781
8782
|
return r;
|
|
8782
8783
|
});
|
|
@@ -8791,7 +8792,7 @@ var PluginInstaller = class {
|
|
|
8791
8792
|
* copies the missing files from the local repository's `.xcli/plugins/shared/`
|
|
8792
8793
|
* directory (if available).
|
|
8793
8794
|
*/
|
|
8794
|
-
fixSharedDeps(pluginDir) {
|
|
8795
|
+
async fixSharedDeps(pluginDir) {
|
|
8795
8796
|
const indexPath = resolve8(pluginDir, "index.ts");
|
|
8796
8797
|
if (!existsSync10(indexPath)) return;
|
|
8797
8798
|
let content;
|
|
@@ -8828,8 +8829,33 @@ var PluginInstaller = class {
|
|
|
8828
8829
|
}
|
|
8829
8830
|
}
|
|
8830
8831
|
if (!sourceSharedDir) {
|
|
8831
|
-
|
|
8832
|
-
|
|
8832
|
+
const GITHUB_RAW = "https://raw.githubusercontent.com/dyyz1993/xbrowser/master/.xcli/plugins/shared";
|
|
8833
|
+
mkdirSync8(sharedDir, { recursive: true });
|
|
8834
|
+
let allDownloaded = true;
|
|
8835
|
+
for (const file of toCopy) {
|
|
8836
|
+
try {
|
|
8837
|
+
const url = `${GITHUB_RAW}/${file}`;
|
|
8838
|
+
const resp = await fetch(url, { signal: AbortSignal.timeout(1e4) });
|
|
8839
|
+
if (resp.ok) {
|
|
8840
|
+
const content2 = await resp.text();
|
|
8841
|
+
const dst = resolve8(sharedDir, file);
|
|
8842
|
+
const dstDir = dirname3(dst);
|
|
8843
|
+
if (!existsSync10(dstDir)) mkdirSync8(dstDir, { recursive: true });
|
|
8844
|
+
writeFileSync10(dst, content2, "utf-8");
|
|
8845
|
+
console.log(`\u2705 Downloaded shared/${file} from GitHub`);
|
|
8846
|
+
} else {
|
|
8847
|
+
allDownloaded = false;
|
|
8848
|
+
break;
|
|
8849
|
+
}
|
|
8850
|
+
} catch {
|
|
8851
|
+
allDownloaded = false;
|
|
8852
|
+
break;
|
|
8853
|
+
}
|
|
8854
|
+
}
|
|
8855
|
+
if (!allDownloaded) {
|
|
8856
|
+
console.warn(`\u26A0\uFE0F Plugin "${basename2(pluginDir)}" imports shared files but they are missing: ${toCopy.join(", ")}`);
|
|
8857
|
+
console.warn(` Could not download from GitHub. Try: git clone https://github.com/dyyz1993/xbrowser.git && cp -r xbrowser/.xcli/plugins/shared/ ~/.xbrowser/plugins/shared/`);
|
|
8858
|
+
}
|
|
8833
8859
|
return;
|
|
8834
8860
|
}
|
|
8835
8861
|
mkdirSync8(sharedDir, { recursive: true });
|
|
@@ -10567,9 +10593,9 @@ async function handleBrowserCommand(command, args, options, sessionName, mode, c
|
|
|
10567
10593
|
}
|
|
10568
10594
|
const outputFile = options.output;
|
|
10569
10595
|
if (outputFile && result.success && result.data) {
|
|
10570
|
-
const { writeFileSync:
|
|
10596
|
+
const { writeFileSync: writeFileSync13 } = await import("fs");
|
|
10571
10597
|
const content = typeof result.data === "string" ? result.data : result.data.content || result.data.text || JSON.stringify(result.data, null, 2);
|
|
10572
|
-
|
|
10598
|
+
writeFileSync13(outputFile, content, "utf-8");
|
|
10573
10599
|
console.log(`
|
|
10574
10600
|
\u{1F4C4} Written to ${outputFile}`);
|
|
10575
10601
|
}
|
|
@@ -11449,9 +11475,9 @@ async function handleFilter(args, _mode, options) {
|
|
|
11449
11475
|
console.log(` Original: ${result.originalCount}, After: ${result.filteredCount}, Removed: ${result.removed} (${result.percentage}%)`);
|
|
11450
11476
|
}
|
|
11451
11477
|
async function handleGeneratePlugin(sessionName, pluginName, outputDir) {
|
|
11452
|
-
const { SessionRecorder: SessionRecorder2 } = await import("./session-recorder-
|
|
11478
|
+
const { SessionRecorder: SessionRecorder2 } = await import("./session-recorder-H2WPBCSW.js");
|
|
11453
11479
|
const { readSiteKnowledge: readSiteKnowledge2, toMarkdown } = await import("./site-knowledge-SYC6VCDB.js");
|
|
11454
|
-
const { mkdirSync: mkdirSync11, writeFileSync:
|
|
11480
|
+
const { mkdirSync: mkdirSync11, writeFileSync: writeFileSync13 } = await import("fs");
|
|
11455
11481
|
const { join: join14 } = await import("path");
|
|
11456
11482
|
const data = SessionRecorder2.readData(sessionName);
|
|
11457
11483
|
if (!data) {
|
|
@@ -11469,9 +11495,9 @@ async function handleGeneratePlugin(sessionName, pluginName, outputDir) {
|
|
|
11469
11495
|
const knowledgeMd = knowledge ? toMarkdown(knowledge) : "";
|
|
11470
11496
|
const pluginCode = generatePluginCode(finalPluginName, domain, data, knowledgeMd);
|
|
11471
11497
|
mkdirSync11(join14(finalOutputDir), { recursive: true });
|
|
11472
|
-
|
|
11498
|
+
writeFileSync13(join14(finalOutputDir, "index.ts"), pluginCode, "utf-8");
|
|
11473
11499
|
if (knowledgeMd) {
|
|
11474
|
-
|
|
11500
|
+
writeFileSync13(join14(finalOutputDir, "SITE_KNOWLEDGE.md"), knowledgeMd, "utf-8");
|
|
11475
11501
|
}
|
|
11476
11502
|
console.log("");
|
|
11477
11503
|
console.log("=== Plugin Generated ===");
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@xbrowser/cli",
|
|
3
|
-
"version": "1.8.
|
|
3
|
+
"version": "1.8.5",
|
|
4
4
|
"description": "Browser automation CLI for web scraping, headless browsing, SEO analysis, and AI agent workflows. A command-line alternative to Playwright, Puppeteer, and Selenium.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|