@xbrowser/cli 0.14.3 → 0.15.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 +63 -1
- package/dist/cli.js +126 -99
- package/dist/daemon-main.js +67 -34
- package/dist/index.d.ts +2026 -5
- package/dist/index.js +124 -97
- package/package.json +19 -3
package/dist/index.js
CHANGED
|
@@ -191,7 +191,18 @@ function parsePluginParams(args, schema, base = {}) {
|
|
|
191
191
|
if (value === "true") params[key] = true;
|
|
192
192
|
else if (value === "false") params[key] = false;
|
|
193
193
|
else if (/^\d+$/.test(value)) params[key] = parseInt(value, 10);
|
|
194
|
-
else
|
|
194
|
+
else {
|
|
195
|
+
try {
|
|
196
|
+
const parsed = JSON.parse(value);
|
|
197
|
+
if (Array.isArray(parsed) || typeof parsed === "object" && parsed !== null) {
|
|
198
|
+
params[key] = parsed;
|
|
199
|
+
} else {
|
|
200
|
+
params[key] = value;
|
|
201
|
+
}
|
|
202
|
+
} catch {
|
|
203
|
+
params[key] = value;
|
|
204
|
+
}
|
|
205
|
+
}
|
|
195
206
|
i++;
|
|
196
207
|
} else {
|
|
197
208
|
params[key] = true;
|
|
@@ -6535,8 +6546,48 @@ async function loadHooks() {
|
|
|
6535
6546
|
// src/executor.ts
|
|
6536
6547
|
import { homedir as homedir3 } from "os";
|
|
6537
6548
|
import { join as join3 } from "path";
|
|
6549
|
+
import { existsSync as existsSync6, readFileSync as readFileSync9, writeFileSync as writeFileSync4, mkdirSync as mkdirSync3 } from "fs";
|
|
6538
6550
|
var NAVIGATION_COMMANDS = /* @__PURE__ */ new Set(["goto", "back", "forward", "refresh"]);
|
|
6539
6551
|
var snapshotHintShown = /* @__PURE__ */ new WeakSet();
|
|
6552
|
+
var STORAGE_DIR = join3(homedir3(), ".xbrowser", "storage");
|
|
6553
|
+
var storageCache = /* @__PURE__ */ new Map();
|
|
6554
|
+
function getPluginStorage(pluginName) {
|
|
6555
|
+
if (!storageCache.has(pluginName)) {
|
|
6556
|
+
const filePath = join3(STORAGE_DIR, `${pluginName}.json`);
|
|
6557
|
+
let data = {};
|
|
6558
|
+
const load3 = () => {
|
|
6559
|
+
if (existsSync6(filePath)) {
|
|
6560
|
+
try {
|
|
6561
|
+
data = JSON.parse(readFileSync9(filePath, "utf-8"));
|
|
6562
|
+
} catch {
|
|
6563
|
+
data = {};
|
|
6564
|
+
}
|
|
6565
|
+
}
|
|
6566
|
+
};
|
|
6567
|
+
const save = () => {
|
|
6568
|
+
mkdirSync3(STORAGE_DIR, { recursive: true });
|
|
6569
|
+
writeFileSync4(filePath, JSON.stringify(data, null, 2), "utf-8");
|
|
6570
|
+
};
|
|
6571
|
+
load3();
|
|
6572
|
+
storageCache.set(pluginName, {
|
|
6573
|
+
get: async (key) => data[key] ?? null,
|
|
6574
|
+
set: async (key, value) => {
|
|
6575
|
+
data[key] = value;
|
|
6576
|
+
save();
|
|
6577
|
+
},
|
|
6578
|
+
delete: async (key) => {
|
|
6579
|
+
delete data[key];
|
|
6580
|
+
save();
|
|
6581
|
+
},
|
|
6582
|
+
clear: async () => {
|
|
6583
|
+
data = {};
|
|
6584
|
+
save();
|
|
6585
|
+
},
|
|
6586
|
+
keys: async () => Object.keys(data)
|
|
6587
|
+
});
|
|
6588
|
+
}
|
|
6589
|
+
return storageCache.get(pluginName);
|
|
6590
|
+
}
|
|
6540
6591
|
var archiveInitialized = false;
|
|
6541
6592
|
function ensureArchiveInit() {
|
|
6542
6593
|
if (!archiveInitialized) {
|
|
@@ -6647,16 +6698,7 @@ async function executeCommand(commandName, params, sessionName = "default", extr
|
|
|
6647
6698
|
args: [],
|
|
6648
6699
|
options: {},
|
|
6649
6700
|
cwd: process.cwd(),
|
|
6650
|
-
storage:
|
|
6651
|
-
get: async () => null,
|
|
6652
|
-
set: async () => {
|
|
6653
|
-
},
|
|
6654
|
-
delete: async () => {
|
|
6655
|
-
},
|
|
6656
|
-
clear: async () => {
|
|
6657
|
-
},
|
|
6658
|
-
keys: async () => []
|
|
6659
|
-
},
|
|
6701
|
+
storage: getPluginStorage(commandName),
|
|
6660
6702
|
output: {
|
|
6661
6703
|
mode: "text",
|
|
6662
6704
|
showTips: false,
|
|
@@ -6879,16 +6921,7 @@ async function executeChain(input, options) {
|
|
|
6879
6921
|
browser: session.context.browser(),
|
|
6880
6922
|
browserContext: session.context,
|
|
6881
6923
|
sessionId: session.id,
|
|
6882
|
-
storage:
|
|
6883
|
-
get: async (_key) => null,
|
|
6884
|
-
set: async (_key, _value) => {
|
|
6885
|
-
},
|
|
6886
|
-
delete: async (_key) => {
|
|
6887
|
-
},
|
|
6888
|
-
clear: async () => {
|
|
6889
|
-
},
|
|
6890
|
-
keys: async () => []
|
|
6891
|
-
},
|
|
6924
|
+
storage: getPluginStorage(cmdName),
|
|
6892
6925
|
output: { mode: "text", showTips: false, color: false, emoji: false },
|
|
6893
6926
|
error: (msg) => {
|
|
6894
6927
|
throw new Error(msg);
|
|
@@ -6910,7 +6943,7 @@ async function executeChain(input, options) {
|
|
|
6910
6943
|
const outputs = [];
|
|
6911
6944
|
for (const h of hooks) {
|
|
6912
6945
|
const output = await h.onAfterCommand?.({ page: session.page, command: `${cmdName} ${subCommand}`, params: pluginParams, result: raw, duration: duration2 });
|
|
6913
|
-
if (output) outputs.push(output);
|
|
6946
|
+
if (output) outputs.push({ _hook: h.name, ...output });
|
|
6914
6947
|
}
|
|
6915
6948
|
if (outputs.length > 0) hookOutputs = outputs;
|
|
6916
6949
|
}
|
|
@@ -7300,26 +7333,26 @@ var configBuiltin = {
|
|
|
7300
7333
|
|
|
7301
7334
|
// src/plugin/installer.ts
|
|
7302
7335
|
import {
|
|
7303
|
-
existsSync as
|
|
7336
|
+
existsSync as existsSync13,
|
|
7304
7337
|
readdirSync as readdirSync3,
|
|
7305
|
-
mkdirSync as
|
|
7338
|
+
mkdirSync as mkdirSync8,
|
|
7306
7339
|
rmSync as rmSync7
|
|
7307
7340
|
} from "fs";
|
|
7308
7341
|
import { resolve as resolve15, basename as basename2 } from "path";
|
|
7309
7342
|
import { homedir as homedir4 } from "os";
|
|
7310
7343
|
|
|
7311
7344
|
// src/plugin/install-sources/local.ts
|
|
7312
|
-
import { existsSync as
|
|
7345
|
+
import { existsSync as existsSync8, cpSync as cpSync2, rmSync as rmSync2 } from "fs";
|
|
7313
7346
|
import { resolve as resolve10 } from "path";
|
|
7314
7347
|
|
|
7315
7348
|
// src/plugin/install-utils.ts
|
|
7316
7349
|
import {
|
|
7317
|
-
existsSync as
|
|
7350
|
+
existsSync as existsSync7,
|
|
7318
7351
|
readdirSync as readdirSync2,
|
|
7319
7352
|
cpSync,
|
|
7320
7353
|
rmSync,
|
|
7321
|
-
mkdirSync as
|
|
7322
|
-
readFileSync as
|
|
7354
|
+
mkdirSync as mkdirSync4,
|
|
7355
|
+
readFileSync as readFileSync10,
|
|
7323
7356
|
createWriteStream
|
|
7324
7357
|
} from "fs";
|
|
7325
7358
|
import { resolve as resolve9 } from "path";
|
|
@@ -7390,7 +7423,7 @@ async function downloadToFile(url, destPath) {
|
|
|
7390
7423
|
await pipeline(nodeStream, createWriteStream(destPath));
|
|
7391
7424
|
}
|
|
7392
7425
|
function extractTarGz(tarballPath, targetDir) {
|
|
7393
|
-
|
|
7426
|
+
mkdirSync4(targetDir, { recursive: true });
|
|
7394
7427
|
execSync7(`tar -xzf "${tarballPath}" -C "${targetDir}"`, { stdio: "pipe" });
|
|
7395
7428
|
}
|
|
7396
7429
|
function flattenPackageRoot(targetDir) {
|
|
@@ -7411,18 +7444,18 @@ function flattenPackageRoot(targetDir) {
|
|
|
7411
7444
|
async function verifyPlugin(dir) {
|
|
7412
7445
|
const warnings = [];
|
|
7413
7446
|
const indexPath = resolve9(dir, "index.ts");
|
|
7414
|
-
if (!
|
|
7447
|
+
if (!existsSync7(indexPath)) {
|
|
7415
7448
|
const indexJs = resolve9(dir, "index.js");
|
|
7416
|
-
if (!
|
|
7449
|
+
if (!existsSync7(indexJs)) {
|
|
7417
7450
|
return { valid: false, error: "No index.ts or index.js entry point found", warnings };
|
|
7418
7451
|
}
|
|
7419
7452
|
}
|
|
7420
7453
|
const pkgPath = resolve9(dir, "package.json");
|
|
7421
|
-
if (!
|
|
7454
|
+
if (!existsSync7(pkgPath)) {
|
|
7422
7455
|
warnings.push("No package.json found");
|
|
7423
7456
|
} else {
|
|
7424
7457
|
try {
|
|
7425
|
-
const pkg2 = JSON.parse(
|
|
7458
|
+
const pkg2 = JSON.parse(readFileSync10(pkgPath, "utf-8"));
|
|
7426
7459
|
if (!pkg2.xbrowser) {
|
|
7427
7460
|
warnings.push("No xbrowser metadata in package.json");
|
|
7428
7461
|
}
|
|
@@ -7442,7 +7475,7 @@ function safeCleanup(dir) {
|
|
|
7442
7475
|
// src/plugin/install-sources/local.ts
|
|
7443
7476
|
async function installFromLocal(source, name, targetDir) {
|
|
7444
7477
|
const srcPath = resolve10(source);
|
|
7445
|
-
if (!
|
|
7478
|
+
if (!existsSync8(srcPath)) {
|
|
7446
7479
|
throw new Error(`Local path does not exist: ${srcPath}`);
|
|
7447
7480
|
}
|
|
7448
7481
|
const tmpTarget = `${targetDir}-tmp-${Date.now()}`;
|
|
@@ -7455,7 +7488,7 @@ async function installFromLocal(source, name, targetDir) {
|
|
|
7455
7488
|
safeCleanup(tmpTarget);
|
|
7456
7489
|
throw new Error(`Invalid plugin: ${verify.error}`);
|
|
7457
7490
|
}
|
|
7458
|
-
if (
|
|
7491
|
+
if (existsSync8(targetDir)) {
|
|
7459
7492
|
rmSync2(targetDir, { recursive: true, force: true });
|
|
7460
7493
|
}
|
|
7461
7494
|
cpSync2(tmpTarget, targetDir, { recursive: true, force: true });
|
|
@@ -7475,7 +7508,7 @@ async function installFromLocal(source, name, targetDir) {
|
|
|
7475
7508
|
}
|
|
7476
7509
|
|
|
7477
7510
|
// src/plugin/install-sources/npm.ts
|
|
7478
|
-
import { existsSync as
|
|
7511
|
+
import { existsSync as existsSync9, mkdirSync as mkdirSync5, readFileSync as readFileSync11, writeFileSync as writeFileSync5, rmSync as rmSync3, cpSync as cpSync3 } from "fs";
|
|
7479
7512
|
import { resolve as resolve11, join as join4 } from "path";
|
|
7480
7513
|
import { tmpdir } from "os";
|
|
7481
7514
|
async function installFromNpm(packageName, name, targetDir) {
|
|
@@ -7496,7 +7529,7 @@ async function installFromNpm(packageName, name, targetDir) {
|
|
|
7496
7529
|
}
|
|
7497
7530
|
const tarballUrl = versionMeta.dist.tarball;
|
|
7498
7531
|
const tmpDir = join4(tmpdir(), `xbrowser-npm-${Date.now()}`);
|
|
7499
|
-
|
|
7532
|
+
mkdirSync5(tmpDir, { recursive: true });
|
|
7500
7533
|
let warnings = [];
|
|
7501
7534
|
try {
|
|
7502
7535
|
const tarballPath = join4(tmpDir, `${name}.tgz`);
|
|
@@ -7509,16 +7542,16 @@ async function installFromNpm(packageName, name, targetDir) {
|
|
|
7509
7542
|
if (!verify.valid) {
|
|
7510
7543
|
throw new Error(`Invalid npm plugin: ${verify.error}`);
|
|
7511
7544
|
}
|
|
7512
|
-
if (
|
|
7545
|
+
if (existsSync9(targetDir)) {
|
|
7513
7546
|
rmSync3(targetDir, { recursive: true, force: true });
|
|
7514
7547
|
}
|
|
7515
7548
|
cpSync3(extractDir, targetDir, { recursive: true, force: true });
|
|
7516
7549
|
const pkgPath = resolve11(targetDir, "package.json");
|
|
7517
|
-
if (
|
|
7518
|
-
const pkg2 = JSON.parse(
|
|
7550
|
+
if (existsSync9(pkgPath)) {
|
|
7551
|
+
const pkg2 = JSON.parse(readFileSync11(pkgPath, "utf-8"));
|
|
7519
7552
|
if (!pkg2._npmSource) {
|
|
7520
7553
|
pkg2._npmSource = { name: packageName, version: latestVersion };
|
|
7521
|
-
|
|
7554
|
+
writeFileSync5(pkgPath, JSON.stringify(pkg2, null, 2));
|
|
7522
7555
|
}
|
|
7523
7556
|
}
|
|
7524
7557
|
} finally {
|
|
@@ -7535,7 +7568,7 @@ async function installFromNpm(packageName, name, targetDir) {
|
|
|
7535
7568
|
}
|
|
7536
7569
|
|
|
7537
7570
|
// src/plugin/install-sources/git.ts
|
|
7538
|
-
import { existsSync as
|
|
7571
|
+
import { existsSync as existsSync10, readFileSync as readFileSync12, writeFileSync as writeFileSync6, rmSync as rmSync4, cpSync as cpSync4 } from "fs";
|
|
7539
7572
|
import { resolve as resolve12, join as join5 } from "path";
|
|
7540
7573
|
import { tmpdir as tmpdir2 } from "os";
|
|
7541
7574
|
import { execSync as execSync8 } from "child_process";
|
|
@@ -7549,17 +7582,17 @@ async function installFromGit(gitUrl, name, targetDir) {
|
|
|
7549
7582
|
if (!verify.valid) {
|
|
7550
7583
|
throw new Error(`Invalid git plugin: ${verify.error}`);
|
|
7551
7584
|
}
|
|
7552
|
-
if (
|
|
7585
|
+
if (existsSync10(targetDir)) {
|
|
7553
7586
|
rmSync4(targetDir, { recursive: true, force: true });
|
|
7554
7587
|
}
|
|
7555
7588
|
cpSync4(tmpDir, targetDir, { recursive: true, force: true });
|
|
7556
7589
|
rmSync4(resolve12(targetDir, ".git"), { recursive: true, force: true });
|
|
7557
7590
|
const pkgPath = resolve12(targetDir, "package.json");
|
|
7558
|
-
if (
|
|
7559
|
-
const pkg2 = JSON.parse(
|
|
7591
|
+
if (existsSync10(pkgPath)) {
|
|
7592
|
+
const pkg2 = JSON.parse(readFileSync12(pkgPath, "utf-8"));
|
|
7560
7593
|
if (!pkg2._gitSource) {
|
|
7561
7594
|
pkg2._gitSource = { url: gitUrl };
|
|
7562
|
-
|
|
7595
|
+
writeFileSync6(pkgPath, JSON.stringify(pkg2, null, 2));
|
|
7563
7596
|
}
|
|
7564
7597
|
}
|
|
7565
7598
|
} finally {
|
|
@@ -7576,12 +7609,12 @@ async function installFromGit(gitUrl, name, targetDir) {
|
|
|
7576
7609
|
}
|
|
7577
7610
|
|
|
7578
7611
|
// src/plugin/install-sources/url.ts
|
|
7579
|
-
import { existsSync as
|
|
7612
|
+
import { existsSync as existsSync11, readFileSync as readFileSync13, writeFileSync as writeFileSync7, mkdirSync as mkdirSync6, rmSync as rmSync5, cpSync as cpSync5 } from "fs";
|
|
7580
7613
|
import { resolve as resolve13, join as join6, basename } from "path";
|
|
7581
7614
|
import { tmpdir as tmpdir3 } from "os";
|
|
7582
7615
|
async function installFromUrl(url, name, targetDir) {
|
|
7583
7616
|
const tmpDir = join6(tmpdir3(), `xbrowser-url-${Date.now()}`);
|
|
7584
|
-
|
|
7617
|
+
mkdirSync6(tmpDir, { recursive: true });
|
|
7585
7618
|
let warnings = [];
|
|
7586
7619
|
try {
|
|
7587
7620
|
const fileName = basename(new URL(url).pathname) || "plugin.tar.gz";
|
|
@@ -7595,16 +7628,16 @@ async function installFromUrl(url, name, targetDir) {
|
|
|
7595
7628
|
if (!verify.valid) {
|
|
7596
7629
|
throw new Error(`Invalid plugin from URL: ${verify.error}`);
|
|
7597
7630
|
}
|
|
7598
|
-
if (
|
|
7631
|
+
if (existsSync11(targetDir)) {
|
|
7599
7632
|
rmSync5(targetDir, { recursive: true, force: true });
|
|
7600
7633
|
}
|
|
7601
7634
|
cpSync5(extractDir, targetDir, { recursive: true, force: true });
|
|
7602
7635
|
const pkgPath = resolve13(targetDir, "package.json");
|
|
7603
|
-
if (
|
|
7604
|
-
const pkg2 = JSON.parse(
|
|
7636
|
+
if (existsSync11(pkgPath)) {
|
|
7637
|
+
const pkg2 = JSON.parse(readFileSync13(pkgPath, "utf-8"));
|
|
7605
7638
|
if (!pkg2._urlSource) {
|
|
7606
7639
|
pkg2._urlSource = { url };
|
|
7607
|
-
|
|
7640
|
+
writeFileSync7(pkgPath, JSON.stringify(pkg2, null, 2));
|
|
7608
7641
|
}
|
|
7609
7642
|
}
|
|
7610
7643
|
} finally {
|
|
@@ -7622,10 +7655,10 @@ async function installFromUrl(url, name, targetDir) {
|
|
|
7622
7655
|
|
|
7623
7656
|
// src/plugin/install-sources/marketplace.ts
|
|
7624
7657
|
import {
|
|
7625
|
-
existsSync as
|
|
7626
|
-
mkdirSync as
|
|
7627
|
-
writeFileSync as
|
|
7628
|
-
readFileSync as
|
|
7658
|
+
existsSync as existsSync12,
|
|
7659
|
+
mkdirSync as mkdirSync7,
|
|
7660
|
+
writeFileSync as writeFileSync8,
|
|
7661
|
+
readFileSync as readFileSync14,
|
|
7629
7662
|
rmSync as rmSync6,
|
|
7630
7663
|
cpSync as cpSync6
|
|
7631
7664
|
} from "fs";
|
|
@@ -7647,12 +7680,12 @@ async function installFromMarketplace(pluginsDir, slug, options) {
|
|
|
7647
7680
|
const plugin = detailData.data;
|
|
7648
7681
|
const name = options?.name || String(plugin.slug || slug);
|
|
7649
7682
|
const targetDir = resolve14(pluginsDir, name);
|
|
7650
|
-
if (
|
|
7683
|
+
if (existsSync12(targetDir) && !options?.force) {
|
|
7651
7684
|
throw new Error(`Plugin "${name}" already exists. Use --force to overwrite.`);
|
|
7652
7685
|
}
|
|
7653
|
-
|
|
7686
|
+
mkdirSync7(targetDir, { recursive: true });
|
|
7654
7687
|
const tmpDir = join7(tmpdir4(), `xbrowser-marketplace-${Date.now()}`);
|
|
7655
|
-
|
|
7688
|
+
mkdirSync7(tmpDir, { recursive: true });
|
|
7656
7689
|
const realSlug = String(plugin.slug || slug);
|
|
7657
7690
|
try {
|
|
7658
7691
|
await downloadAndExtractMarketplaceTarball(baseUrl, realSlug, tmpDir, targetDir);
|
|
@@ -7682,14 +7715,14 @@ function isManifestArray(data) {
|
|
|
7682
7715
|
return Array.isArray(data) && data.length > 0 && typeof data[0].path === "string" && typeof data[0].content === "string";
|
|
7683
7716
|
}
|
|
7684
7717
|
function extractManifestToDir(manifest, targetDir) {
|
|
7685
|
-
if (
|
|
7718
|
+
if (existsSync12(targetDir)) {
|
|
7686
7719
|
rmSync6(targetDir, { recursive: true, force: true });
|
|
7687
7720
|
}
|
|
7688
|
-
|
|
7721
|
+
mkdirSync7(targetDir, { recursive: true });
|
|
7689
7722
|
for (const file of manifest) {
|
|
7690
7723
|
const filePath = resolve14(targetDir, file.path);
|
|
7691
|
-
|
|
7692
|
-
|
|
7724
|
+
mkdirSync7(dirname2(filePath), { recursive: true });
|
|
7725
|
+
writeFileSync8(filePath, Buffer.from(file.content, "base64"));
|
|
7693
7726
|
}
|
|
7694
7727
|
}
|
|
7695
7728
|
function tryParseAsGzippedManifest(buffer) {
|
|
@@ -7716,7 +7749,7 @@ async function downloadAndExtractMarketplaceTarball(baseUrl, slug, tmpDir, targe
|
|
|
7716
7749
|
const redirectUrl = tarballRes.headers.get("location");
|
|
7717
7750
|
const tarballPath = join7(tmpDir, `${slug}.tar.gz`);
|
|
7718
7751
|
await downloadToFile(redirectUrl, tarballPath);
|
|
7719
|
-
const buffer =
|
|
7752
|
+
const buffer = readFileSync14(tarballPath);
|
|
7720
7753
|
const manifest = tryParseAsGzippedManifest(buffer);
|
|
7721
7754
|
if (manifest) {
|
|
7722
7755
|
extractManifestToDir(manifest, targetDir);
|
|
@@ -7725,7 +7758,7 @@ async function downloadAndExtractMarketplaceTarball(baseUrl, slug, tmpDir, targe
|
|
|
7725
7758
|
const extractDir = join7(tmpDir, "extracted");
|
|
7726
7759
|
extractTarGz(tarballPath, extractDir);
|
|
7727
7760
|
flattenPackageRoot(extractDir);
|
|
7728
|
-
if (
|
|
7761
|
+
if (existsSync12(targetDir)) {
|
|
7729
7762
|
rmSync6(targetDir, { recursive: true, force: true });
|
|
7730
7763
|
}
|
|
7731
7764
|
cpSync6(extractDir, targetDir, { recursive: true, force: true });
|
|
@@ -7737,12 +7770,12 @@ async function downloadAndExtractMarketplaceTarball(baseUrl, slug, tmpDir, targe
|
|
|
7737
7770
|
return;
|
|
7738
7771
|
}
|
|
7739
7772
|
const tarballPath = join7(tmpDir, `${slug}.tar.gz`);
|
|
7740
|
-
|
|
7773
|
+
writeFileSync8(tarballPath, buffer);
|
|
7741
7774
|
try {
|
|
7742
7775
|
const extractDir = join7(tmpDir, "extracted");
|
|
7743
7776
|
extractTarGz(tarballPath, extractDir);
|
|
7744
7777
|
flattenPackageRoot(extractDir);
|
|
7745
|
-
if (
|
|
7778
|
+
if (existsSync12(targetDir)) {
|
|
7746
7779
|
rmSync6(targetDir, { recursive: true, force: true });
|
|
7747
7780
|
}
|
|
7748
7781
|
cpSync6(extractDir, targetDir, { recursive: true, force: true });
|
|
@@ -7778,24 +7811,24 @@ function writeMarketplacePackageJson(plugin, slug, name, baseUrl, targetDir) {
|
|
|
7778
7811
|
}
|
|
7779
7812
|
};
|
|
7780
7813
|
const pkgPath = resolve14(targetDir, "package.json");
|
|
7781
|
-
if (!
|
|
7782
|
-
|
|
7814
|
+
if (!existsSync12(pkgPath)) {
|
|
7815
|
+
writeFileSync8(pkgPath, JSON.stringify(packageJson, null, 2));
|
|
7783
7816
|
} else {
|
|
7784
7817
|
try {
|
|
7785
|
-
const existing = JSON.parse(
|
|
7818
|
+
const existing = JSON.parse(readFileSync14(pkgPath, "utf-8"));
|
|
7786
7819
|
const merged = {
|
|
7787
7820
|
...existing,
|
|
7788
7821
|
xbrowser: { ...existing.xbrowser, ...packageJson.xbrowser },
|
|
7789
7822
|
_marketplace: packageJson._marketplace
|
|
7790
7823
|
};
|
|
7791
|
-
|
|
7824
|
+
writeFileSync8(pkgPath, JSON.stringify(merged, null, 2));
|
|
7792
7825
|
} catch {
|
|
7793
|
-
|
|
7826
|
+
writeFileSync8(pkgPath, JSON.stringify(packageJson, null, 2));
|
|
7794
7827
|
}
|
|
7795
7828
|
}
|
|
7796
7829
|
}
|
|
7797
7830
|
function ensureIndexFile(plugin, name, targetDir) {
|
|
7798
|
-
if (!
|
|
7831
|
+
if (!existsSync12(resolve14(targetDir, "index.ts")) && !existsSync12(resolve14(targetDir, "index.js"))) {
|
|
7799
7832
|
const commands = plugin.commands || [];
|
|
7800
7833
|
const commandHandlers = commands.length > 0 ? commands.map((cmd) => {
|
|
7801
7834
|
return [
|
|
@@ -7810,7 +7843,7 @@ function ensureIndexFile(plugin, name, targetDir) {
|
|
|
7810
7843
|
` handler: async () => ({ data: { message: 'Hello from ${name}!' }, tips: [] }),`,
|
|
7811
7844
|
` });`
|
|
7812
7845
|
].join("\n");
|
|
7813
|
-
|
|
7846
|
+
writeFileSync8(
|
|
7814
7847
|
resolve14(targetDir, "index.ts"),
|
|
7815
7848
|
[
|
|
7816
7849
|
`import type { XCLIAPI } from '@dyyz1993/xcli-core';`,
|
|
@@ -7849,10 +7882,10 @@ var PluginInstaller = class {
|
|
|
7849
7882
|
const type = this.detectSourceType(source);
|
|
7850
7883
|
const name = options?.name || this.deriveName(source, type);
|
|
7851
7884
|
const targetDir = resolve15(this.pluginsDir, name);
|
|
7852
|
-
if (
|
|
7885
|
+
if (existsSync13(targetDir) && !options?.force) {
|
|
7853
7886
|
throw new Error(`Plugin "${name}" already exists. Use --force to overwrite.`);
|
|
7854
7887
|
}
|
|
7855
|
-
|
|
7888
|
+
mkdirSync8(targetDir, { recursive: true });
|
|
7856
7889
|
const resolvedSource = type === "npm" ? await resolveNpmPackageWithFallback(source) : source;
|
|
7857
7890
|
switch (type) {
|
|
7858
7891
|
case "local":
|
|
@@ -7910,7 +7943,7 @@ var PluginInstaller = class {
|
|
|
7910
7943
|
*/
|
|
7911
7944
|
async uninstall(name) {
|
|
7912
7945
|
const targetDir = resolve15(this.pluginsDir, name);
|
|
7913
|
-
if (!
|
|
7946
|
+
if (!existsSync13(targetDir)) {
|
|
7914
7947
|
throw new Error(`Plugin "${name}" not found`);
|
|
7915
7948
|
}
|
|
7916
7949
|
rmSync7(targetDir, { recursive: true, force: true });
|
|
@@ -7921,7 +7954,7 @@ var PluginInstaller = class {
|
|
|
7921
7954
|
* @returns Array of installed plugin information.
|
|
7922
7955
|
*/
|
|
7923
7956
|
async list(_options) {
|
|
7924
|
-
if (!
|
|
7957
|
+
if (!existsSync13(this.pluginsDir)) return [];
|
|
7925
7958
|
const entries = readdirSync3(this.pluginsDir, { withFileTypes: true });
|
|
7926
7959
|
const plugins = [];
|
|
7927
7960
|
for (const entry of entries) {
|
|
@@ -7929,7 +7962,7 @@ var PluginInstaller = class {
|
|
|
7929
7962
|
const pluginPath = resolve15(this.pluginsDir, entry.name);
|
|
7930
7963
|
const indexPath = resolve15(pluginPath, "index.ts");
|
|
7931
7964
|
const indexJsPath = resolve15(pluginPath, "index.js");
|
|
7932
|
-
if (!
|
|
7965
|
+
if (!existsSync13(indexPath) && !existsSync13(indexJsPath)) continue;
|
|
7933
7966
|
const metadata = PluginMetadataParser.parseFromPackageJson(pluginPath);
|
|
7934
7967
|
let source = "local";
|
|
7935
7968
|
const pkg2 = readJsonFile(resolve15(pluginPath, "package.json"), {});
|
|
@@ -7956,10 +7989,10 @@ var PluginInstaller = class {
|
|
|
7956
7989
|
}
|
|
7957
7990
|
if (source.startsWith("file://")) {
|
|
7958
7991
|
const filePath = decodeURIComponent(new URL(source).pathname);
|
|
7959
|
-
if (
|
|
7992
|
+
if (existsSync13(filePath)) return "url";
|
|
7960
7993
|
}
|
|
7961
7994
|
if (source.endsWith(".git") || source.includes("github.com/")) return "git";
|
|
7962
|
-
if (
|
|
7995
|
+
if (existsSync13(resolve15(source))) return "local";
|
|
7963
7996
|
return "npm";
|
|
7964
7997
|
}
|
|
7965
7998
|
deriveName(source, type) {
|
|
@@ -9988,7 +10021,7 @@ async function handleFilter(args, _mode) {
|
|
|
9988
10021
|
|
|
9989
10022
|
// src/stdin.ts
|
|
9990
10023
|
import { createInterface } from "readline";
|
|
9991
|
-
import { readFileSync as
|
|
10024
|
+
import { readFileSync as readFileSync15 } from "fs";
|
|
9992
10025
|
async function readStdin2() {
|
|
9993
10026
|
if (process.stdin.isTTY) return [];
|
|
9994
10027
|
const lines = [];
|
|
@@ -10002,7 +10035,7 @@ async function readStdin2() {
|
|
|
10002
10035
|
return lines;
|
|
10003
10036
|
}
|
|
10004
10037
|
function readCommandFile(filePath) {
|
|
10005
|
-
const content =
|
|
10038
|
+
const content = readFileSync15(filePath, "utf-8");
|
|
10006
10039
|
return content.split("\n").map((line) => line.trim()).filter((line) => line && !line.startsWith("#"));
|
|
10007
10040
|
}
|
|
10008
10041
|
|
|
@@ -11270,11 +11303,14 @@ Run "xbrowser ${command} --help" to see available commands.`
|
|
|
11270
11303
|
showCommandHelp(command, cmdEntry, { description: site.config.description, name: site.name, url: site.url }, mode);
|
|
11271
11304
|
return;
|
|
11272
11305
|
}
|
|
11273
|
-
const
|
|
11306
|
+
const pluginNameIdx = argv.indexOf(command);
|
|
11307
|
+
const subCmdIdx = pluginNameIdx >= 0 ? argv.indexOf(subCommand, pluginNameIdx + 1) : -1;
|
|
11308
|
+
const rawPluginArgs = subCmdIdx >= 0 ? argv.slice(subCmdIdx + 1) : [];
|
|
11309
|
+
const params = parsePluginParams(rawPluginArgs, cmdEntry.parameters);
|
|
11274
11310
|
if (options.target && !params._target) {
|
|
11275
11311
|
params._target = options.target;
|
|
11276
11312
|
}
|
|
11277
|
-
const needsBrowser = cmdEntry.scope
|
|
11313
|
+
const needsBrowser = cmdEntry.scope === "page";
|
|
11278
11314
|
if (needsBrowser && !process.env.XBROWSER_DAEMON_WORKER) {
|
|
11279
11315
|
const { forwardExec } = await import("./daemon-client-3IJD6X4B.js");
|
|
11280
11316
|
const userTimeout = typeof params.timeout === "number" && params.timeout > 0 ? params.timeout * 1e3 + 3e4 : void 0;
|
|
@@ -11311,16 +11347,7 @@ Run "xbrowser ${command} --help" to see available commands.`
|
|
|
11311
11347
|
browser: needsBrowser ? session.context.browser() : null,
|
|
11312
11348
|
browserContext: needsBrowser ? session.context : null,
|
|
11313
11349
|
sessionId: needsBrowser ? session.id : "",
|
|
11314
|
-
storage:
|
|
11315
|
-
get: async (_key) => null,
|
|
11316
|
-
set: async (_key, _value) => {
|
|
11317
|
-
},
|
|
11318
|
-
delete: async (_key) => {
|
|
11319
|
-
},
|
|
11320
|
-
clear: async () => {
|
|
11321
|
-
},
|
|
11322
|
-
keys: async () => []
|
|
11323
|
-
},
|
|
11350
|
+
storage: getPluginStorage(command),
|
|
11324
11351
|
output: { mode, showTips: true, color: true, emoji: true },
|
|
11325
11352
|
error: (msg) => {
|
|
11326
11353
|
outputError(msg);
|
|
@@ -12575,10 +12602,10 @@ var WSServer = class extends EventEmitter {
|
|
|
12575
12602
|
}
|
|
12576
12603
|
case "file_download": {
|
|
12577
12604
|
try {
|
|
12578
|
-
const { readFileSync:
|
|
12605
|
+
const { readFileSync: readFileSync17 } = await import("fs");
|
|
12579
12606
|
const { resolve: resolve16, basename: basename3 } = await import("path");
|
|
12580
12607
|
const targetPath = resolve16(msg.path);
|
|
12581
|
-
const data =
|
|
12608
|
+
const data = readFileSync17(targetPath);
|
|
12582
12609
|
const base64 = data.toString("base64");
|
|
12583
12610
|
const ext = targetPath.split(".").pop()?.toLowerCase() || "";
|
|
12584
12611
|
const mimeMap = {
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@xbrowser/cli",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "
|
|
3
|
+
"version": "0.15.0",
|
|
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": {
|
|
7
7
|
"xbrowser": "dist/cli.js"
|
|
@@ -27,21 +27,37 @@
|
|
|
27
27
|
"record-replay",
|
|
28
28
|
"browser automation",
|
|
29
29
|
"web scraping",
|
|
30
|
+
"web-scraping",
|
|
30
31
|
"playwright alternative",
|
|
32
|
+
"playwright-alternative",
|
|
31
33
|
"puppeteer alternative",
|
|
34
|
+
"puppeteer-alternative",
|
|
32
35
|
"selenium alternative",
|
|
36
|
+
"selenium-alternative",
|
|
33
37
|
"web crawler",
|
|
38
|
+
"web-crawler",
|
|
34
39
|
"headless browser",
|
|
40
|
+
"headless-browser",
|
|
41
|
+
"headless-chrome",
|
|
35
42
|
"scrape",
|
|
36
43
|
"crawl",
|
|
44
|
+
"crawler",
|
|
45
|
+
"scraping",
|
|
37
46
|
"cli tool",
|
|
38
47
|
"command line",
|
|
48
|
+
"command-line",
|
|
39
49
|
"browser cli",
|
|
50
|
+
"browser-cli",
|
|
40
51
|
"anti-detection",
|
|
41
52
|
"record replay",
|
|
42
53
|
"seo tool",
|
|
54
|
+
"seo",
|
|
55
|
+
"search-engine",
|
|
43
56
|
"ai agent",
|
|
44
|
-
"
|
|
57
|
+
"ai-agent",
|
|
58
|
+
"browser plugin",
|
|
59
|
+
"browser-testing",
|
|
60
|
+
"chrome-devtools-protocol"
|
|
45
61
|
],
|
|
46
62
|
"author": "dyyz1993",
|
|
47
63
|
"license": "MIT",
|