@xbrowser/cli 1.8.2 → 1.8.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/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, 70+ plugins. A command-line alternative to Playwright, Puppeteer, and Selenium — **no code required**.
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
  [![CI Status](https://github.com/dyyz1993/xbrowser/workflows/CI/badge.svg)](https://github.com/dyyz1993/xbrowser/actions)
6
6
  [![codecov](https://codecov.io/gh/dyyz1993/xbrowser/branch/master/graph/badge.svg)](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** | 70+ plugins | Limited | Limited | No |
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 | ❌ | ❌ |
package/dist/cli.js CHANGED
@@ -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
- console.warn(`\u26A0\uFE0F Plugin "${basename2(pluginDir)}" imports shared files but they are missing: ${toCopy.join(", ")}`);
8514
- console.warn(` To fix: install the "shared" plugin or copy .xcli/plugins/shared/ to ~/.xbrowser/plugins/shared/`);
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: writeFileSync11 } = await import("fs");
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
- writeFileSync11(outputFile, content, "utf-8");
10275
+ writeFileSync12(outputFile, content, "utf-8");
10250
10276
  console.log(`
10251
10277
  \u{1F4C4} Written to ${outputFile}`);
10252
10278
  }
@@ -11128,7 +11154,7 @@ async function handleFilter(args, _mode, options) {
11128
11154
  async function handleGeneratePlugin(sessionName, pluginName, outputDir) {
11129
11155
  const { SessionRecorder: SessionRecorder2 } = await import("./session-recorder-RTDGURIJ.js");
11130
11156
  const { readSiteKnowledge: readSiteKnowledge2, toMarkdown } = await import("./site-knowledge-SYC6VCDB.js");
11131
- const { mkdirSync: mkdirSync10, writeFileSync: writeFileSync11 } = await import("fs");
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
- writeFileSync11(join14(finalOutputDir, "index.ts"), pluginCode, "utf-8");
11175
+ writeFileSync12(join14(finalOutputDir, "index.ts"), pluginCode, "utf-8");
11150
11176
  if (knowledgeMd) {
11151
- writeFileSync11(join14(finalOutputDir, "SITE_KNOWLEDGE.md"), knowledgeMd, "utf-8");
11177
+ writeFileSync12(join14(finalOutputDir, "SITE_KNOWLEDGE.md"), knowledgeMd, "utf-8");
11152
11178
  }
11153
11179
  console.log("");
11154
11180
  console.log("=== Plugin Generated ===");
@@ -7812,8 +7812,7 @@ async function injectRecording(page) {
7812
7812
  } catch {
7813
7813
  }
7814
7814
  try {
7815
- const cdp = await page.context().newCDPSession(page);
7816
- await cdp.send("Page.addScriptToEvaluateOnNewDocument", { source: RECORDING_INJECT_JS });
7815
+ await page.addInitScript(RECORDING_INJECT_JS);
7817
7816
  } catch {
7818
7817
  }
7819
7818
  }
package/dist/index.js CHANGED
@@ -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
- console.warn(`\u26A0\uFE0F Plugin "${basename2(pluginDir)}" imports shared files but they are missing: ${toCopy.join(", ")}`);
8832
- console.warn(` To fix: install the "shared" plugin or copy .xcli/plugins/shared/ to ~/.xbrowser/plugins/shared/`);
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: writeFileSync12 } = await import("fs");
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
- writeFileSync12(outputFile, content, "utf-8");
10598
+ writeFileSync13(outputFile, content, "utf-8");
10573
10599
  console.log(`
10574
10600
  \u{1F4C4} Written to ${outputFile}`);
10575
10601
  }
@@ -11451,7 +11477,7 @@ async function handleFilter(args, _mode, options) {
11451
11477
  async function handleGeneratePlugin(sessionName, pluginName, outputDir) {
11452
11478
  const { SessionRecorder: SessionRecorder2 } = await import("./session-recorder-RTDGURIJ.js");
11453
11479
  const { readSiteKnowledge: readSiteKnowledge2, toMarkdown } = await import("./site-knowledge-SYC6VCDB.js");
11454
- const { mkdirSync: mkdirSync11, writeFileSync: writeFileSync12 } = await import("fs");
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
- writeFileSync12(join14(finalOutputDir, "index.ts"), pluginCode, "utf-8");
11498
+ writeFileSync13(join14(finalOutputDir, "index.ts"), pluginCode, "utf-8");
11473
11499
  if (knowledgeMd) {
11474
- writeFileSync12(join14(finalOutputDir, "SITE_KNOWLEDGE.md"), knowledgeMd, "utf-8");
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.2",
3
+ "version": "1.8.4",
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": {