@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
|
-
|
|
403
|
-
|
|
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
|
-
|
|
6335
|
-
|
|
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
|
|
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
|
-
|
|
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 =
|
|
11416
|
+
src = readFileSync9(pluginPath, "utf-8");
|
|
11337
11417
|
} catch {
|
|
11338
11418
|
return null;
|
|
11339
11419
|
}
|
package/dist/daemon-main.js
CHANGED
|
@@ -26,7 +26,7 @@ import "./chunk-QFROODUU.js";
|
|
|
26
26
|
import "./chunk-TNEN6VQ2.js";
|
|
27
27
|
import {
|
|
28
28
|
getPluginLoader
|
|
29
|
-
} from "./chunk-
|
|
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-
|
|
7866
|
+
const { resetPluginLoader } = await import("./plugin-singleton-SYJF6BD6.js");
|
|
7867
7867
|
resetPluginLoader();
|
|
7868
|
-
const loader = await import("./plugin-singleton-
|
|
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
|
-
|
|
6652
|
-
|
|
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
|
|
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
|
-
|
|
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 =
|
|
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:
|
|
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 =
|
|
14537
|
+
const data = readFileSync11(targetPath);
|
|
14458
14538
|
const base64 = data.toString("base64");
|
|
14459
14539
|
const ext = targetPath.split(".").pop()?.toLowerCase() || "";
|
|
14460
14540
|
const mimeMap = {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@xbrowser/cli",
|
|
3
|
-
"version": "1.
|
|
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": {
|