@xbrowser/cli 1.2.2 → 1.3.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.
@@ -399,8 +399,10 @@ var XBrowserPluginLoader = class {
399
399
  const instance = await this.loadPlugin(indexPath, entry.name);
400
400
  loaded.push(instance);
401
401
  } catch (err) {
402
- if (process.env.XBROWSER_DEBUG) {
403
- console.warn(`\u26A0\uFE0F Plugin "${entry.name}" load failed: ${err instanceof Error ? err.message : String(err)}`);
402
+ const errMsg = err instanceof Error ? err.message : String(err);
403
+ console.warn(`\u26A0\uFE0F Plugin "${entry.name}" load failed: ${errMsg}`);
404
+ if (errMsg.includes("Cannot find module") && errMsg.includes("shared/")) {
405
+ console.warn(` \u{1F4A1} This plugin needs shared/ dependencies. Try: xbrowser plugin install shared`);
404
406
  }
405
407
  }
406
408
  }
package/dist/cli.js CHANGED
@@ -6331,8 +6331,10 @@ var XBrowserPluginLoader = class {
6331
6331
  const instance = await this.loadPlugin(indexPath, entry.name);
6332
6332
  loaded.push(instance);
6333
6333
  } catch (err) {
6334
- if (process.env.XBROWSER_DEBUG) {
6335
- console.warn(`\u26A0\uFE0F Plugin "${entry.name}" load failed: ${err instanceof Error ? err.message : String(err)}`);
6334
+ const errMsg2 = err instanceof Error ? err.message : String(err);
6335
+ console.warn(`\u26A0\uFE0F Plugin "${entry.name}" load failed: ${errMsg2}`);
6336
+ if (errMsg2.includes("Cannot find module") && errMsg2.includes("shared/")) {
6337
+ console.warn(` \u{1F4A1} This plugin needs shared/ dependencies. Try: xbrowser plugin install shared`);
6336
6338
  }
6337
6339
  }
6338
6340
  }
@@ -7734,9 +7736,12 @@ import {
7734
7736
  existsSync as existsSync10,
7735
7737
  readdirSync as readdirSync2,
7736
7738
  mkdirSync as mkdirSync8,
7737
- rmSync as rmSync6
7739
+ rmSync as rmSync6,
7740
+ copyFileSync,
7741
+ cpSync as cpSync6,
7742
+ readFileSync as readFileSync8
7738
7743
  } from "fs";
7739
- import { resolve as resolve8, basename as basename2 } from "path";
7744
+ import { resolve as resolve8, basename as basename2, dirname as dirname3 } from "path";
7740
7745
  import { homedir as homedir8 } from "os";
7741
7746
 
7742
7747
  // src/plugin/install-sources/local.ts
@@ -8229,28 +8234,103 @@ var PluginInstaller = class {
8229
8234
  switch (type) {
8230
8235
  case "local":
8231
8236
  return await installFromLocal(source, name, targetDir).then((r) => {
8237
+ this.fixSharedDeps(targetDir);
8232
8238
  ensurePluginDependencies(this.pluginsDir);
8233
8239
  return r;
8234
8240
  });
8235
8241
  case "npm":
8236
8242
  return await installFromNpm(resolvedSource, name, targetDir).then((r) => {
8243
+ this.fixSharedDeps(targetDir);
8237
8244
  ensurePluginDependencies(this.pluginsDir);
8238
8245
  return r;
8239
8246
  });
8240
8247
  case "git":
8241
8248
  return await installFromGit(source, name, targetDir).then((r) => {
8249
+ this.fixSharedDeps(targetDir);
8242
8250
  ensurePluginDependencies(this.pluginsDir);
8243
8251
  return r;
8244
8252
  });
8245
8253
  case "url":
8246
8254
  return await installFromUrl(source, name, targetDir).then((r) => {
8255
+ this.fixSharedDeps(targetDir);
8247
8256
  ensurePluginDependencies(this.pluginsDir);
8248
8257
  return r;
8249
8258
  });
8250
8259
  }
8251
8260
  }
8261
+ /**
8262
+ * Fix missing `../shared/` dependencies after installation.
8263
+ *
8264
+ * Some marketplace/npm packages import from `../shared/` (e.g. ssr-detect.js,
8265
+ * ai-chat-base.ts) but the `shared/` directory is not included in the package.
8266
+ * This method scans the installed plugin's index.ts for such imports and
8267
+ * copies the missing files from the local repository's `.xcli/plugins/shared/`
8268
+ * directory (if available).
8269
+ */
8270
+ fixSharedDeps(pluginDir) {
8271
+ const indexPath = resolve8(pluginDir, "index.ts");
8272
+ if (!existsSync10(indexPath)) return;
8273
+ let content;
8274
+ try {
8275
+ content = readFileSync8(indexPath, "utf8");
8276
+ } catch {
8277
+ return;
8278
+ }
8279
+ const sharedImportRegex = /from\s+['"]\.\.\/shared\/([^'"]+)['"]/g;
8280
+ const missingFiles = [];
8281
+ let match;
8282
+ while ((match = sharedImportRegex.exec(content)) !== null) {
8283
+ missingFiles.push(match[1]);
8284
+ }
8285
+ if (missingFiles.length === 0) return;
8286
+ const sharedDir = resolve8(pluginDir, "..", "shared");
8287
+ const toCopy = [];
8288
+ for (const file of missingFiles) {
8289
+ const targetPath = resolve8(sharedDir, file);
8290
+ if (!existsSync10(targetPath)) {
8291
+ toCopy.push(file);
8292
+ }
8293
+ }
8294
+ if (toCopy.length === 0) return;
8295
+ const repoSharedDirs = [
8296
+ resolve8(process.cwd(), ".xcli/plugins/shared"),
8297
+ resolve8(homedir8(), ".xbrowser/plugins/shared")
8298
+ ];
8299
+ let sourceSharedDir = null;
8300
+ for (const dir of repoSharedDirs) {
8301
+ if (existsSync10(dir)) {
8302
+ sourceSharedDir = dir;
8303
+ break;
8304
+ }
8305
+ }
8306
+ if (!sourceSharedDir) {
8307
+ console.warn(`\u26A0\uFE0F Plugin "${basename2(pluginDir)}" imports shared files but they are missing: ${toCopy.join(", ")}`);
8308
+ console.warn(` To fix: install the "shared" plugin or copy .xcli/plugins/shared/ to ~/.xbrowser/plugins/shared/`);
8309
+ return;
8310
+ }
8311
+ mkdirSync8(sharedDir, { recursive: true });
8312
+ for (const file of toCopy) {
8313
+ const src = resolve8(sourceSharedDir, file);
8314
+ const dst = resolve8(sharedDir, file);
8315
+ if (existsSync10(src)) {
8316
+ try {
8317
+ cpSync6(dirname3(src), dirname3(dst), { recursive: true });
8318
+ console.log(`\u2705 Copied shared/${file} for plugin "${basename2(pluginDir)}"`);
8319
+ } catch {
8320
+ try {
8321
+ copyFileSync(src, dst);
8322
+ console.log(`\u2705 Copied shared/${file} for plugin "${basename2(pluginDir)}"`);
8323
+ } catch {
8324
+ console.warn(`\u26A0\uFE0F Could not copy shared/${file}`);
8325
+ }
8326
+ }
8327
+ }
8328
+ }
8329
+ }
8252
8330
  async installFromMarketplace(slug, options) {
8253
8331
  const result = await installFromMarketplace(this.pluginsDir, slug, options);
8332
+ const targetDir = resolve8(this.pluginsDir, result.name);
8333
+ this.fixSharedDeps(targetDir);
8254
8334
  ensurePluginDependencies(this.pluginsDir);
8255
8335
  return result;
8256
8336
  }
@@ -11313,7 +11393,7 @@ async function handleNetCommand(args, options, mode, sessionName) {
11313
11393
 
11314
11394
  // src/cli/test-routes.ts
11315
11395
  import { execSync as execSync3 } from "child_process";
11316
- import { readFileSync as readFileSync8 } from "fs";
11396
+ import { readFileSync as readFileSync9 } from "fs";
11317
11397
  import { resolve as resolve9 } from "path";
11318
11398
  function findPluginPath(plugin) {
11319
11399
  const candidates = [
@@ -11322,7 +11402,7 @@ function findPluginPath(plugin) {
11322
11402
  ];
11323
11403
  for (const p of candidates) {
11324
11404
  try {
11325
- readFileSync8(p, "utf-8");
11405
+ readFileSync9(p, "utf-8");
11326
11406
  return p;
11327
11407
  } catch {
11328
11408
  }
@@ -11333,7 +11413,7 @@ function extractSchema(plugin, command) {
11333
11413
  const pluginPath = findPluginPath(plugin);
11334
11414
  let src;
11335
11415
  try {
11336
- src = readFileSync8(pluginPath, "utf-8");
11416
+ src = readFileSync9(pluginPath, "utf-8");
11337
11417
  } catch {
11338
11418
  return null;
11339
11419
  }
@@ -26,7 +26,7 @@ import "./chunk-QFROODUU.js";
26
26
  import "./chunk-TNEN6VQ2.js";
27
27
  import {
28
28
  getPluginLoader
29
- } from "./chunk-PHBK3TRN.js";
29
+ } from "./chunk-2QQDTXDL.js";
30
30
  import {
31
31
  getDaemonConfig,
32
32
  getDaemonProcessStatus
@@ -7863,9 +7863,9 @@ function createRPCHandler() {
7863
7863
  return result;
7864
7864
  }
7865
7865
  async function handlePluginsReload() {
7866
- const { resetPluginLoader } = await import("./plugin-singleton-ZBVTWEYK.js");
7866
+ const { resetPluginLoader } = await import("./plugin-singleton-SYJF6BD6.js");
7867
7867
  resetPluginLoader();
7868
- const loader = await import("./plugin-singleton-ZBVTWEYK.js").then((m) => m.getPluginLoader());
7868
+ const loader = await import("./plugin-singleton-SYJF6BD6.js").then((m) => m.getPluginLoader());
7869
7869
  const sites = loader.getCore().loader.getSites();
7870
7870
  return { ok: true, plugins: sites.length };
7871
7871
  }
package/dist/index.d.ts CHANGED
@@ -1497,6 +1497,16 @@ declare class PluginInstaller {
1497
1497
  * @throws If the plugin already exists without `force`, or if installation fails.
1498
1498
  */
1499
1499
  install(source: string, options?: InstallOptions): Promise<InstalledPlugin>;
1500
+ /**
1501
+ * Fix missing `../shared/` dependencies after installation.
1502
+ *
1503
+ * Some marketplace/npm packages import from `../shared/` (e.g. ssr-detect.js,
1504
+ * ai-chat-base.ts) but the `shared/` directory is not included in the package.
1505
+ * This method scans the installed plugin's index.ts for such imports and
1506
+ * copies the missing files from the local repository's `.xcli/plugins/shared/`
1507
+ * directory (if available).
1508
+ */
1509
+ private fixSharedDeps;
1500
1510
  installFromMarketplace(slug: string, options?: InstallOptions): Promise<InstalledPlugin>;
1501
1511
  installWithMarketplaceFallback(source: string, options?: InstallOptions): Promise<InstalledPlugin>;
1502
1512
  /**
package/dist/index.js CHANGED
@@ -6648,8 +6648,10 @@ var XBrowserPluginLoader = class {
6648
6648
  const instance = await this.loadPlugin(indexPath, entry.name);
6649
6649
  loaded.push(instance);
6650
6650
  } catch (err) {
6651
- if (process.env.XBROWSER_DEBUG) {
6652
- console.warn(`\u26A0\uFE0F Plugin "${entry.name}" load failed: ${err instanceof Error ? err.message : String(err)}`);
6651
+ const errMsg2 = err instanceof Error ? err.message : String(err);
6652
+ console.warn(`\u26A0\uFE0F Plugin "${entry.name}" load failed: ${errMsg2}`);
6653
+ if (errMsg2.includes("Cannot find module") && errMsg2.includes("shared/")) {
6654
+ console.warn(` \u{1F4A1} This plugin needs shared/ dependencies. Try: xbrowser plugin install shared`);
6653
6655
  }
6654
6656
  }
6655
6657
  }
@@ -8069,9 +8071,12 @@ import {
8069
8071
  existsSync as existsSync10,
8070
8072
  readdirSync as readdirSync2,
8071
8073
  mkdirSync as mkdirSync8,
8072
- rmSync as rmSync6
8074
+ rmSync as rmSync6,
8075
+ copyFileSync,
8076
+ cpSync as cpSync6,
8077
+ readFileSync as readFileSync8
8073
8078
  } from "fs";
8074
- import { resolve as resolve8, basename as basename2 } from "path";
8079
+ import { resolve as resolve8, basename as basename2, dirname as dirname3 } from "path";
8075
8080
  import { homedir as homedir7 } from "os";
8076
8081
 
8077
8082
  // src/plugin/install-sources/local.ts
@@ -8564,28 +8569,103 @@ var PluginInstaller = class {
8564
8569
  switch (type) {
8565
8570
  case "local":
8566
8571
  return await installFromLocal(source, name, targetDir).then((r) => {
8572
+ this.fixSharedDeps(targetDir);
8567
8573
  ensurePluginDependencies(this.pluginsDir);
8568
8574
  return r;
8569
8575
  });
8570
8576
  case "npm":
8571
8577
  return await installFromNpm(resolvedSource, name, targetDir).then((r) => {
8578
+ this.fixSharedDeps(targetDir);
8572
8579
  ensurePluginDependencies(this.pluginsDir);
8573
8580
  return r;
8574
8581
  });
8575
8582
  case "git":
8576
8583
  return await installFromGit(source, name, targetDir).then((r) => {
8584
+ this.fixSharedDeps(targetDir);
8577
8585
  ensurePluginDependencies(this.pluginsDir);
8578
8586
  return r;
8579
8587
  });
8580
8588
  case "url":
8581
8589
  return await installFromUrl(source, name, targetDir).then((r) => {
8590
+ this.fixSharedDeps(targetDir);
8582
8591
  ensurePluginDependencies(this.pluginsDir);
8583
8592
  return r;
8584
8593
  });
8585
8594
  }
8586
8595
  }
8596
+ /**
8597
+ * Fix missing `../shared/` dependencies after installation.
8598
+ *
8599
+ * Some marketplace/npm packages import from `../shared/` (e.g. ssr-detect.js,
8600
+ * ai-chat-base.ts) but the `shared/` directory is not included in the package.
8601
+ * This method scans the installed plugin's index.ts for such imports and
8602
+ * copies the missing files from the local repository's `.xcli/plugins/shared/`
8603
+ * directory (if available).
8604
+ */
8605
+ fixSharedDeps(pluginDir) {
8606
+ const indexPath = resolve8(pluginDir, "index.ts");
8607
+ if (!existsSync10(indexPath)) return;
8608
+ let content;
8609
+ try {
8610
+ content = readFileSync8(indexPath, "utf8");
8611
+ } catch {
8612
+ return;
8613
+ }
8614
+ const sharedImportRegex = /from\s+['"]\.\.\/shared\/([^'"]+)['"]/g;
8615
+ const missingFiles = [];
8616
+ let match;
8617
+ while ((match = sharedImportRegex.exec(content)) !== null) {
8618
+ missingFiles.push(match[1]);
8619
+ }
8620
+ if (missingFiles.length === 0) return;
8621
+ const sharedDir = resolve8(pluginDir, "..", "shared");
8622
+ const toCopy = [];
8623
+ for (const file of missingFiles) {
8624
+ const targetPath = resolve8(sharedDir, file);
8625
+ if (!existsSync10(targetPath)) {
8626
+ toCopy.push(file);
8627
+ }
8628
+ }
8629
+ if (toCopy.length === 0) return;
8630
+ const repoSharedDirs = [
8631
+ resolve8(process.cwd(), ".xcli/plugins/shared"),
8632
+ resolve8(homedir7(), ".xbrowser/plugins/shared")
8633
+ ];
8634
+ let sourceSharedDir = null;
8635
+ for (const dir of repoSharedDirs) {
8636
+ if (existsSync10(dir)) {
8637
+ sourceSharedDir = dir;
8638
+ break;
8639
+ }
8640
+ }
8641
+ if (!sourceSharedDir) {
8642
+ console.warn(`\u26A0\uFE0F Plugin "${basename2(pluginDir)}" imports shared files but they are missing: ${toCopy.join(", ")}`);
8643
+ console.warn(` To fix: install the "shared" plugin or copy .xcli/plugins/shared/ to ~/.xbrowser/plugins/shared/`);
8644
+ return;
8645
+ }
8646
+ mkdirSync8(sharedDir, { recursive: true });
8647
+ for (const file of toCopy) {
8648
+ const src = resolve8(sourceSharedDir, file);
8649
+ const dst = resolve8(sharedDir, file);
8650
+ if (existsSync10(src)) {
8651
+ try {
8652
+ cpSync6(dirname3(src), dirname3(dst), { recursive: true });
8653
+ console.log(`\u2705 Copied shared/${file} for plugin "${basename2(pluginDir)}"`);
8654
+ } catch {
8655
+ try {
8656
+ copyFileSync(src, dst);
8657
+ console.log(`\u2705 Copied shared/${file} for plugin "${basename2(pluginDir)}"`);
8658
+ } catch {
8659
+ console.warn(`\u26A0\uFE0F Could not copy shared/${file}`);
8660
+ }
8661
+ }
8662
+ }
8663
+ }
8664
+ }
8587
8665
  async installFromMarketplace(slug, options) {
8588
8666
  const result = await installFromMarketplace(this.pluginsDir, slug, options);
8667
+ const targetDir = resolve8(this.pluginsDir, result.name);
8668
+ this.fixSharedDeps(targetDir);
8589
8669
  ensurePluginDependencies(this.pluginsDir);
8590
8670
  return result;
8591
8671
  }
@@ -11653,7 +11733,7 @@ async function handleNetCommand(args, options, mode, sessionName) {
11653
11733
 
11654
11734
  // src/cli/test-routes.ts
11655
11735
  import { execSync as execSync3 } from "child_process";
11656
- import { readFileSync as readFileSync8 } from "fs";
11736
+ import { readFileSync as readFileSync9 } from "fs";
11657
11737
  import { resolve as resolve9 } from "path";
11658
11738
  function findPluginPath(plugin) {
11659
11739
  const candidates = [
@@ -11662,7 +11742,7 @@ function findPluginPath(plugin) {
11662
11742
  ];
11663
11743
  for (const p of candidates) {
11664
11744
  try {
11665
- readFileSync8(p, "utf-8");
11745
+ readFileSync9(p, "utf-8");
11666
11746
  return p;
11667
11747
  } catch {
11668
11748
  }
@@ -11673,7 +11753,7 @@ function extractSchema(plugin, command) {
11673
11753
  const pluginPath = findPluginPath(plugin);
11674
11754
  let src;
11675
11755
  try {
11676
- src = readFileSync8(pluginPath, "utf-8");
11756
+ src = readFileSync9(pluginPath, "utf-8");
11677
11757
  } catch {
11678
11758
  return null;
11679
11759
  }
@@ -14451,10 +14531,10 @@ var FileDownloadHandler = class {
14451
14531
  async handle(ctx) {
14452
14532
  const msg = ctx.message;
14453
14533
  try {
14454
- const { readFileSync: readFileSync10 } = await import("fs");
14534
+ const { readFileSync: readFileSync11 } = await import("fs");
14455
14535
  const { resolve: resolve10, basename: basename3 } = await import("path");
14456
14536
  const targetPath = resolve10(msg.path);
14457
- const data = readFileSync10(targetPath);
14537
+ const data = readFileSync11(targetPath);
14458
14538
  const base64 = data.toString("base64");
14459
14539
  const ext = targetPath.split(".").pop()?.toLowerCase() || "";
14460
14540
  const mimeMap = {
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  getPluginLoader,
3
3
  resetPluginLoader
4
- } from "./chunk-PHBK3TRN.js";
4
+ } from "./chunk-2QQDTXDL.js";
5
5
  import "./chunk-KFQGP6VL.js";
6
6
  export {
7
7
  getPluginLoader,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@xbrowser/cli",
3
- "version": "1.2.2",
3
+ "version": "1.3.0",
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": {