@xbrowser/cli 0.15.0 → 0.16.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/dist/cli.js +160 -128
- package/dist/daemon-main.js +20 -47
- package/dist/index.js +158 -126
- package/package.json +2 -2
package/dist/cli.js
CHANGED
|
@@ -174,7 +174,8 @@ import {
|
|
|
174
174
|
isCommandResult,
|
|
175
175
|
configureArchiveStore,
|
|
176
176
|
appendCommandToArchive,
|
|
177
|
-
checkGuard
|
|
177
|
+
checkGuard,
|
|
178
|
+
PluginStorage
|
|
178
179
|
} from "@dyyz1993/xcli-core";
|
|
179
180
|
|
|
180
181
|
// src/commands/navigation.ts
|
|
@@ -5652,7 +5653,7 @@ import { join as join2 } from "path";
|
|
|
5652
5653
|
import { execSync as execSync6 } from "child_process";
|
|
5653
5654
|
var SHARED_PLUGIN_DEPENDENCIES = {
|
|
5654
5655
|
"zod": "^3.24.0",
|
|
5655
|
-
"@dyyz1993/xcli-core": "^0.
|
|
5656
|
+
"@dyyz1993/xcli-core": "^0.12.1"
|
|
5656
5657
|
};
|
|
5657
5658
|
function ensurePluginDependencies(pluginsDir) {
|
|
5658
5659
|
const zodPath = join2(pluginsDir, "node_modules", "zod");
|
|
@@ -6236,45 +6237,13 @@ async function loadHooks() {
|
|
|
6236
6237
|
// src/executor.ts
|
|
6237
6238
|
import { homedir as homedir3 } from "os";
|
|
6238
6239
|
import { join as join3 } from "path";
|
|
6239
|
-
import { existsSync as existsSync6, readFileSync as readFileSync10, writeFileSync as writeFileSync5, mkdirSync as mkdirSync3 } from "fs";
|
|
6240
6240
|
var NAVIGATION_COMMANDS = /* @__PURE__ */ new Set(["goto", "back", "forward", "refresh"]);
|
|
6241
6241
|
var snapshotHintShown = /* @__PURE__ */ new WeakSet();
|
|
6242
6242
|
var STORAGE_DIR = join3(homedir3(), ".xbrowser", "storage");
|
|
6243
6243
|
var storageCache = /* @__PURE__ */ new Map();
|
|
6244
6244
|
function getPluginStorage(pluginName) {
|
|
6245
6245
|
if (!storageCache.has(pluginName)) {
|
|
6246
|
-
|
|
6247
|
-
let data = {};
|
|
6248
|
-
const load3 = () => {
|
|
6249
|
-
if (existsSync6(filePath)) {
|
|
6250
|
-
try {
|
|
6251
|
-
data = JSON.parse(readFileSync10(filePath, "utf-8"));
|
|
6252
|
-
} catch {
|
|
6253
|
-
data = {};
|
|
6254
|
-
}
|
|
6255
|
-
}
|
|
6256
|
-
};
|
|
6257
|
-
const save = () => {
|
|
6258
|
-
mkdirSync3(STORAGE_DIR, { recursive: true });
|
|
6259
|
-
writeFileSync5(filePath, JSON.stringify(data, null, 2), "utf-8");
|
|
6260
|
-
};
|
|
6261
|
-
load3();
|
|
6262
|
-
storageCache.set(pluginName, {
|
|
6263
|
-
get: async (key) => data[key] ?? null,
|
|
6264
|
-
set: async (key, value) => {
|
|
6265
|
-
data[key] = value;
|
|
6266
|
-
save();
|
|
6267
|
-
},
|
|
6268
|
-
delete: async (key) => {
|
|
6269
|
-
delete data[key];
|
|
6270
|
-
save();
|
|
6271
|
-
},
|
|
6272
|
-
clear: async () => {
|
|
6273
|
-
data = {};
|
|
6274
|
-
save();
|
|
6275
|
-
},
|
|
6276
|
-
keys: async () => Object.keys(data)
|
|
6277
|
-
});
|
|
6246
|
+
storageCache.set(pluginName, new PluginStorage(pluginName, STORAGE_DIR));
|
|
6278
6247
|
}
|
|
6279
6248
|
return storageCache.get(pluginName);
|
|
6280
6249
|
}
|
|
@@ -6371,6 +6340,10 @@ async function executeCommand(commandName, params, sessionName = "default", extr
|
|
|
6371
6340
|
session = await createSession(sessionName, params.url, {
|
|
6372
6341
|
cdpEndpoint: extraOpts?.cdpEndpoint
|
|
6373
6342
|
});
|
|
6343
|
+
} else if (command.scope === "browser") {
|
|
6344
|
+
session = await createSession(sessionName, void 0, {
|
|
6345
|
+
cdpEndpoint: extraOpts?.cdpEndpoint
|
|
6346
|
+
});
|
|
6374
6347
|
} else if (command.scope !== "project") {
|
|
6375
6348
|
return errorResult(
|
|
6376
6349
|
`Session '${sessionName}' not found. Run "xbrowser session open <url>" first.`
|
|
@@ -6901,7 +6874,7 @@ var sessionKillBuiltin = {
|
|
|
6901
6874
|
};
|
|
6902
6875
|
|
|
6903
6876
|
// src/config.ts
|
|
6904
|
-
import { existsSync as
|
|
6877
|
+
import { existsSync as existsSync6, mkdirSync as mkdirSync3, writeFileSync as writeFileSync5 } from "fs";
|
|
6905
6878
|
import { join as join4 } from "path";
|
|
6906
6879
|
import { homedir as homedir4, tmpdir } from "os";
|
|
6907
6880
|
function getConfigFile() {
|
|
@@ -6909,14 +6882,14 @@ function getConfigFile() {
|
|
|
6909
6882
|
}
|
|
6910
6883
|
function loadConfig() {
|
|
6911
6884
|
const configFile = getConfigFile();
|
|
6912
|
-
if (!
|
|
6885
|
+
if (!existsSync6(configFile)) return {};
|
|
6913
6886
|
return readJsonFile(configFile, {});
|
|
6914
6887
|
}
|
|
6915
6888
|
function saveConfig(config) {
|
|
6916
6889
|
const dir = join4(homedir4() || tmpdir(), ".xbrowser");
|
|
6917
6890
|
const configFile = getConfigFile();
|
|
6918
|
-
if (!
|
|
6919
|
-
|
|
6891
|
+
if (!existsSync6(dir)) mkdirSync3(dir, { recursive: true });
|
|
6892
|
+
writeFileSync5(configFile, JSON.stringify(config, null, 2), "utf-8");
|
|
6920
6893
|
}
|
|
6921
6894
|
function getConfigValue(key) {
|
|
6922
6895
|
return loadConfig()[key];
|
|
@@ -7024,26 +6997,26 @@ var configBuiltin = {
|
|
|
7024
6997
|
|
|
7025
6998
|
// src/plugin/installer.ts
|
|
7026
6999
|
import {
|
|
7027
|
-
existsSync as
|
|
7000
|
+
existsSync as existsSync13,
|
|
7028
7001
|
readdirSync as readdirSync3,
|
|
7029
|
-
mkdirSync as
|
|
7002
|
+
mkdirSync as mkdirSync8,
|
|
7030
7003
|
rmSync as rmSync7
|
|
7031
7004
|
} from "fs";
|
|
7032
7005
|
import { resolve as resolve15, basename as basename2 } from "path";
|
|
7033
7006
|
import { homedir as homedir5 } from "os";
|
|
7034
7007
|
|
|
7035
7008
|
// src/plugin/install-sources/local.ts
|
|
7036
|
-
import { existsSync as
|
|
7009
|
+
import { existsSync as existsSync8, cpSync as cpSync2, rmSync as rmSync2 } from "fs";
|
|
7037
7010
|
import { resolve as resolve10 } from "path";
|
|
7038
7011
|
|
|
7039
7012
|
// src/plugin/install-utils.ts
|
|
7040
7013
|
import {
|
|
7041
|
-
existsSync as
|
|
7014
|
+
existsSync as existsSync7,
|
|
7042
7015
|
readdirSync as readdirSync2,
|
|
7043
7016
|
cpSync,
|
|
7044
7017
|
rmSync,
|
|
7045
|
-
mkdirSync as
|
|
7046
|
-
readFileSync as
|
|
7018
|
+
mkdirSync as mkdirSync4,
|
|
7019
|
+
readFileSync as readFileSync10,
|
|
7047
7020
|
createWriteStream
|
|
7048
7021
|
} from "fs";
|
|
7049
7022
|
import { resolve as resolve9 } from "path";
|
|
@@ -7114,7 +7087,7 @@ async function downloadToFile(url, destPath) {
|
|
|
7114
7087
|
await pipeline(nodeStream, createWriteStream(destPath));
|
|
7115
7088
|
}
|
|
7116
7089
|
function extractTarGz(tarballPath, targetDir) {
|
|
7117
|
-
|
|
7090
|
+
mkdirSync4(targetDir, { recursive: true });
|
|
7118
7091
|
execSync7(`tar -xzf "${tarballPath}" -C "${targetDir}"`, { stdio: "pipe" });
|
|
7119
7092
|
}
|
|
7120
7093
|
function flattenPackageRoot(targetDir) {
|
|
@@ -7135,18 +7108,18 @@ function flattenPackageRoot(targetDir) {
|
|
|
7135
7108
|
async function verifyPlugin(dir) {
|
|
7136
7109
|
const warnings = [];
|
|
7137
7110
|
const indexPath = resolve9(dir, "index.ts");
|
|
7138
|
-
if (!
|
|
7111
|
+
if (!existsSync7(indexPath)) {
|
|
7139
7112
|
const indexJs = resolve9(dir, "index.js");
|
|
7140
|
-
if (!
|
|
7113
|
+
if (!existsSync7(indexJs)) {
|
|
7141
7114
|
return { valid: false, error: "No index.ts or index.js entry point found", warnings };
|
|
7142
7115
|
}
|
|
7143
7116
|
}
|
|
7144
7117
|
const pkgPath = resolve9(dir, "package.json");
|
|
7145
|
-
if (!
|
|
7118
|
+
if (!existsSync7(pkgPath)) {
|
|
7146
7119
|
warnings.push("No package.json found");
|
|
7147
7120
|
} else {
|
|
7148
7121
|
try {
|
|
7149
|
-
const pkg2 = JSON.parse(
|
|
7122
|
+
const pkg2 = JSON.parse(readFileSync10(pkgPath, "utf-8"));
|
|
7150
7123
|
if (!pkg2.xbrowser) {
|
|
7151
7124
|
warnings.push("No xbrowser metadata in package.json");
|
|
7152
7125
|
}
|
|
@@ -7166,7 +7139,7 @@ function safeCleanup(dir) {
|
|
|
7166
7139
|
// src/plugin/install-sources/local.ts
|
|
7167
7140
|
async function installFromLocal(source, name, targetDir) {
|
|
7168
7141
|
const srcPath = resolve10(source);
|
|
7169
|
-
if (!
|
|
7142
|
+
if (!existsSync8(srcPath)) {
|
|
7170
7143
|
throw new Error(`Local path does not exist: ${srcPath}`);
|
|
7171
7144
|
}
|
|
7172
7145
|
const tmpTarget = `${targetDir}-tmp-${Date.now()}`;
|
|
@@ -7179,7 +7152,7 @@ async function installFromLocal(source, name, targetDir) {
|
|
|
7179
7152
|
safeCleanup(tmpTarget);
|
|
7180
7153
|
throw new Error(`Invalid plugin: ${verify.error}`);
|
|
7181
7154
|
}
|
|
7182
|
-
if (
|
|
7155
|
+
if (existsSync8(targetDir)) {
|
|
7183
7156
|
rmSync2(targetDir, { recursive: true, force: true });
|
|
7184
7157
|
}
|
|
7185
7158
|
cpSync2(tmpTarget, targetDir, { recursive: true, force: true });
|
|
@@ -7199,7 +7172,7 @@ async function installFromLocal(source, name, targetDir) {
|
|
|
7199
7172
|
}
|
|
7200
7173
|
|
|
7201
7174
|
// src/plugin/install-sources/npm.ts
|
|
7202
|
-
import { existsSync as
|
|
7175
|
+
import { existsSync as existsSync9, mkdirSync as mkdirSync5, readFileSync as readFileSync11, writeFileSync as writeFileSync6, rmSync as rmSync3, cpSync as cpSync3 } from "fs";
|
|
7203
7176
|
import { resolve as resolve11, join as join5 } from "path";
|
|
7204
7177
|
import { tmpdir as tmpdir2 } from "os";
|
|
7205
7178
|
async function installFromNpm(packageName, name, targetDir) {
|
|
@@ -7220,7 +7193,7 @@ async function installFromNpm(packageName, name, targetDir) {
|
|
|
7220
7193
|
}
|
|
7221
7194
|
const tarballUrl = versionMeta.dist.tarball;
|
|
7222
7195
|
const tmpDir = join5(tmpdir2(), `xbrowser-npm-${Date.now()}`);
|
|
7223
|
-
|
|
7196
|
+
mkdirSync5(tmpDir, { recursive: true });
|
|
7224
7197
|
let warnings = [];
|
|
7225
7198
|
try {
|
|
7226
7199
|
const tarballPath = join5(tmpDir, `${name}.tgz`);
|
|
@@ -7233,16 +7206,16 @@ async function installFromNpm(packageName, name, targetDir) {
|
|
|
7233
7206
|
if (!verify.valid) {
|
|
7234
7207
|
throw new Error(`Invalid npm plugin: ${verify.error}`);
|
|
7235
7208
|
}
|
|
7236
|
-
if (
|
|
7209
|
+
if (existsSync9(targetDir)) {
|
|
7237
7210
|
rmSync3(targetDir, { recursive: true, force: true });
|
|
7238
7211
|
}
|
|
7239
7212
|
cpSync3(extractDir, targetDir, { recursive: true, force: true });
|
|
7240
7213
|
const pkgPath = resolve11(targetDir, "package.json");
|
|
7241
|
-
if (
|
|
7242
|
-
const pkg2 = JSON.parse(
|
|
7214
|
+
if (existsSync9(pkgPath)) {
|
|
7215
|
+
const pkg2 = JSON.parse(readFileSync11(pkgPath, "utf-8"));
|
|
7243
7216
|
if (!pkg2._npmSource) {
|
|
7244
7217
|
pkg2._npmSource = { name: packageName, version: latestVersion };
|
|
7245
|
-
|
|
7218
|
+
writeFileSync6(pkgPath, JSON.stringify(pkg2, null, 2));
|
|
7246
7219
|
}
|
|
7247
7220
|
}
|
|
7248
7221
|
} finally {
|
|
@@ -7259,7 +7232,7 @@ async function installFromNpm(packageName, name, targetDir) {
|
|
|
7259
7232
|
}
|
|
7260
7233
|
|
|
7261
7234
|
// src/plugin/install-sources/git.ts
|
|
7262
|
-
import { existsSync as
|
|
7235
|
+
import { existsSync as existsSync10, readFileSync as readFileSync12, writeFileSync as writeFileSync7, rmSync as rmSync4, cpSync as cpSync4 } from "fs";
|
|
7263
7236
|
import { resolve as resolve12, join as join6 } from "path";
|
|
7264
7237
|
import { tmpdir as tmpdir3 } from "os";
|
|
7265
7238
|
import { execSync as execSync8 } from "child_process";
|
|
@@ -7273,17 +7246,17 @@ async function installFromGit(gitUrl, name, targetDir) {
|
|
|
7273
7246
|
if (!verify.valid) {
|
|
7274
7247
|
throw new Error(`Invalid git plugin: ${verify.error}`);
|
|
7275
7248
|
}
|
|
7276
|
-
if (
|
|
7249
|
+
if (existsSync10(targetDir)) {
|
|
7277
7250
|
rmSync4(targetDir, { recursive: true, force: true });
|
|
7278
7251
|
}
|
|
7279
7252
|
cpSync4(tmpDir, targetDir, { recursive: true, force: true });
|
|
7280
7253
|
rmSync4(resolve12(targetDir, ".git"), { recursive: true, force: true });
|
|
7281
7254
|
const pkgPath = resolve12(targetDir, "package.json");
|
|
7282
|
-
if (
|
|
7283
|
-
const pkg2 = JSON.parse(
|
|
7255
|
+
if (existsSync10(pkgPath)) {
|
|
7256
|
+
const pkg2 = JSON.parse(readFileSync12(pkgPath, "utf-8"));
|
|
7284
7257
|
if (!pkg2._gitSource) {
|
|
7285
7258
|
pkg2._gitSource = { url: gitUrl };
|
|
7286
|
-
|
|
7259
|
+
writeFileSync7(pkgPath, JSON.stringify(pkg2, null, 2));
|
|
7287
7260
|
}
|
|
7288
7261
|
}
|
|
7289
7262
|
} finally {
|
|
@@ -7300,12 +7273,12 @@ async function installFromGit(gitUrl, name, targetDir) {
|
|
|
7300
7273
|
}
|
|
7301
7274
|
|
|
7302
7275
|
// src/plugin/install-sources/url.ts
|
|
7303
|
-
import { existsSync as
|
|
7276
|
+
import { existsSync as existsSync11, readFileSync as readFileSync13, writeFileSync as writeFileSync8, mkdirSync as mkdirSync6, rmSync as rmSync5, cpSync as cpSync5 } from "fs";
|
|
7304
7277
|
import { resolve as resolve13, join as join7, basename } from "path";
|
|
7305
7278
|
import { tmpdir as tmpdir4 } from "os";
|
|
7306
7279
|
async function installFromUrl(url, name, targetDir) {
|
|
7307
7280
|
const tmpDir = join7(tmpdir4(), `xbrowser-url-${Date.now()}`);
|
|
7308
|
-
|
|
7281
|
+
mkdirSync6(tmpDir, { recursive: true });
|
|
7309
7282
|
let warnings = [];
|
|
7310
7283
|
try {
|
|
7311
7284
|
const fileName = basename(new URL(url).pathname) || "plugin.tar.gz";
|
|
@@ -7319,16 +7292,16 @@ async function installFromUrl(url, name, targetDir) {
|
|
|
7319
7292
|
if (!verify.valid) {
|
|
7320
7293
|
throw new Error(`Invalid plugin from URL: ${verify.error}`);
|
|
7321
7294
|
}
|
|
7322
|
-
if (
|
|
7295
|
+
if (existsSync11(targetDir)) {
|
|
7323
7296
|
rmSync5(targetDir, { recursive: true, force: true });
|
|
7324
7297
|
}
|
|
7325
7298
|
cpSync5(extractDir, targetDir, { recursive: true, force: true });
|
|
7326
7299
|
const pkgPath = resolve13(targetDir, "package.json");
|
|
7327
|
-
if (
|
|
7328
|
-
const pkg2 = JSON.parse(
|
|
7300
|
+
if (existsSync11(pkgPath)) {
|
|
7301
|
+
const pkg2 = JSON.parse(readFileSync13(pkgPath, "utf-8"));
|
|
7329
7302
|
if (!pkg2._urlSource) {
|
|
7330
7303
|
pkg2._urlSource = { url };
|
|
7331
|
-
|
|
7304
|
+
writeFileSync8(pkgPath, JSON.stringify(pkg2, null, 2));
|
|
7332
7305
|
}
|
|
7333
7306
|
}
|
|
7334
7307
|
} finally {
|
|
@@ -7346,10 +7319,10 @@ async function installFromUrl(url, name, targetDir) {
|
|
|
7346
7319
|
|
|
7347
7320
|
// src/plugin/install-sources/marketplace.ts
|
|
7348
7321
|
import {
|
|
7349
|
-
existsSync as
|
|
7350
|
-
mkdirSync as
|
|
7351
|
-
writeFileSync as
|
|
7352
|
-
readFileSync as
|
|
7322
|
+
existsSync as existsSync12,
|
|
7323
|
+
mkdirSync as mkdirSync7,
|
|
7324
|
+
writeFileSync as writeFileSync9,
|
|
7325
|
+
readFileSync as readFileSync14,
|
|
7353
7326
|
rmSync as rmSync6,
|
|
7354
7327
|
cpSync as cpSync6
|
|
7355
7328
|
} from "fs";
|
|
@@ -7371,12 +7344,12 @@ async function installFromMarketplace(pluginsDir, slug, options) {
|
|
|
7371
7344
|
const plugin = detailData.data;
|
|
7372
7345
|
const name = options?.name || String(plugin.slug || slug);
|
|
7373
7346
|
const targetDir = resolve14(pluginsDir, name);
|
|
7374
|
-
if (
|
|
7347
|
+
if (existsSync12(targetDir) && !options?.force) {
|
|
7375
7348
|
throw new Error(`Plugin "${name}" already exists. Use --force to overwrite.`);
|
|
7376
7349
|
}
|
|
7377
|
-
|
|
7350
|
+
mkdirSync7(targetDir, { recursive: true });
|
|
7378
7351
|
const tmpDir = join8(tmpdir5(), `xbrowser-marketplace-${Date.now()}`);
|
|
7379
|
-
|
|
7352
|
+
mkdirSync7(tmpDir, { recursive: true });
|
|
7380
7353
|
const realSlug = String(plugin.slug || slug);
|
|
7381
7354
|
try {
|
|
7382
7355
|
await downloadAndExtractMarketplaceTarball(baseUrl, realSlug, tmpDir, targetDir);
|
|
@@ -7406,14 +7379,14 @@ function isManifestArray(data) {
|
|
|
7406
7379
|
return Array.isArray(data) && data.length > 0 && typeof data[0].path === "string" && typeof data[0].content === "string";
|
|
7407
7380
|
}
|
|
7408
7381
|
function extractManifestToDir(manifest, targetDir) {
|
|
7409
|
-
if (
|
|
7382
|
+
if (existsSync12(targetDir)) {
|
|
7410
7383
|
rmSync6(targetDir, { recursive: true, force: true });
|
|
7411
7384
|
}
|
|
7412
|
-
|
|
7385
|
+
mkdirSync7(targetDir, { recursive: true });
|
|
7413
7386
|
for (const file of manifest) {
|
|
7414
7387
|
const filePath = resolve14(targetDir, file.path);
|
|
7415
|
-
|
|
7416
|
-
|
|
7388
|
+
mkdirSync7(dirname2(filePath), { recursive: true });
|
|
7389
|
+
writeFileSync9(filePath, Buffer.from(file.content, "base64"));
|
|
7417
7390
|
}
|
|
7418
7391
|
}
|
|
7419
7392
|
function tryParseAsGzippedManifest(buffer) {
|
|
@@ -7440,7 +7413,7 @@ async function downloadAndExtractMarketplaceTarball(baseUrl, slug, tmpDir, targe
|
|
|
7440
7413
|
const redirectUrl = tarballRes.headers.get("location");
|
|
7441
7414
|
const tarballPath = join8(tmpDir, `${slug}.tar.gz`);
|
|
7442
7415
|
await downloadToFile(redirectUrl, tarballPath);
|
|
7443
|
-
const buffer =
|
|
7416
|
+
const buffer = readFileSync14(tarballPath);
|
|
7444
7417
|
const manifest = tryParseAsGzippedManifest(buffer);
|
|
7445
7418
|
if (manifest) {
|
|
7446
7419
|
extractManifestToDir(manifest, targetDir);
|
|
@@ -7449,7 +7422,7 @@ async function downloadAndExtractMarketplaceTarball(baseUrl, slug, tmpDir, targe
|
|
|
7449
7422
|
const extractDir = join8(tmpDir, "extracted");
|
|
7450
7423
|
extractTarGz(tarballPath, extractDir);
|
|
7451
7424
|
flattenPackageRoot(extractDir);
|
|
7452
|
-
if (
|
|
7425
|
+
if (existsSync12(targetDir)) {
|
|
7453
7426
|
rmSync6(targetDir, { recursive: true, force: true });
|
|
7454
7427
|
}
|
|
7455
7428
|
cpSync6(extractDir, targetDir, { recursive: true, force: true });
|
|
@@ -7461,12 +7434,12 @@ async function downloadAndExtractMarketplaceTarball(baseUrl, slug, tmpDir, targe
|
|
|
7461
7434
|
return;
|
|
7462
7435
|
}
|
|
7463
7436
|
const tarballPath = join8(tmpDir, `${slug}.tar.gz`);
|
|
7464
|
-
|
|
7437
|
+
writeFileSync9(tarballPath, buffer);
|
|
7465
7438
|
try {
|
|
7466
7439
|
const extractDir = join8(tmpDir, "extracted");
|
|
7467
7440
|
extractTarGz(tarballPath, extractDir);
|
|
7468
7441
|
flattenPackageRoot(extractDir);
|
|
7469
|
-
if (
|
|
7442
|
+
if (existsSync12(targetDir)) {
|
|
7470
7443
|
rmSync6(targetDir, { recursive: true, force: true });
|
|
7471
7444
|
}
|
|
7472
7445
|
cpSync6(extractDir, targetDir, { recursive: true, force: true });
|
|
@@ -7502,24 +7475,24 @@ function writeMarketplacePackageJson(plugin, slug, name, baseUrl, targetDir) {
|
|
|
7502
7475
|
}
|
|
7503
7476
|
};
|
|
7504
7477
|
const pkgPath = resolve14(targetDir, "package.json");
|
|
7505
|
-
if (!
|
|
7506
|
-
|
|
7478
|
+
if (!existsSync12(pkgPath)) {
|
|
7479
|
+
writeFileSync9(pkgPath, JSON.stringify(packageJson, null, 2));
|
|
7507
7480
|
} else {
|
|
7508
7481
|
try {
|
|
7509
|
-
const existing = JSON.parse(
|
|
7482
|
+
const existing = JSON.parse(readFileSync14(pkgPath, "utf-8"));
|
|
7510
7483
|
const merged = {
|
|
7511
7484
|
...existing,
|
|
7512
7485
|
xbrowser: { ...existing.xbrowser, ...packageJson.xbrowser },
|
|
7513
7486
|
_marketplace: packageJson._marketplace
|
|
7514
7487
|
};
|
|
7515
|
-
|
|
7488
|
+
writeFileSync9(pkgPath, JSON.stringify(merged, null, 2));
|
|
7516
7489
|
} catch {
|
|
7517
|
-
|
|
7490
|
+
writeFileSync9(pkgPath, JSON.stringify(packageJson, null, 2));
|
|
7518
7491
|
}
|
|
7519
7492
|
}
|
|
7520
7493
|
}
|
|
7521
7494
|
function ensureIndexFile(plugin, name, targetDir) {
|
|
7522
|
-
if (!
|
|
7495
|
+
if (!existsSync12(resolve14(targetDir, "index.ts")) && !existsSync12(resolve14(targetDir, "index.js"))) {
|
|
7523
7496
|
const commands = plugin.commands || [];
|
|
7524
7497
|
const commandHandlers = commands.length > 0 ? commands.map((cmd) => {
|
|
7525
7498
|
return [
|
|
@@ -7534,7 +7507,7 @@ function ensureIndexFile(plugin, name, targetDir) {
|
|
|
7534
7507
|
` handler: async () => ({ data: { message: 'Hello from ${name}!' }, tips: [] }),`,
|
|
7535
7508
|
` });`
|
|
7536
7509
|
].join("\n");
|
|
7537
|
-
|
|
7510
|
+
writeFileSync9(
|
|
7538
7511
|
resolve14(targetDir, "index.ts"),
|
|
7539
7512
|
[
|
|
7540
7513
|
`import type { XCLIAPI } from '@dyyz1993/xcli-core';`,
|
|
@@ -7573,10 +7546,10 @@ var PluginInstaller = class {
|
|
|
7573
7546
|
const type = this.detectSourceType(source);
|
|
7574
7547
|
const name = options?.name || this.deriveName(source, type);
|
|
7575
7548
|
const targetDir = resolve15(this.pluginsDir, name);
|
|
7576
|
-
if (
|
|
7549
|
+
if (existsSync13(targetDir) && !options?.force) {
|
|
7577
7550
|
throw new Error(`Plugin "${name}" already exists. Use --force to overwrite.`);
|
|
7578
7551
|
}
|
|
7579
|
-
|
|
7552
|
+
mkdirSync8(targetDir, { recursive: true });
|
|
7580
7553
|
const resolvedSource = type === "npm" ? await resolveNpmPackageWithFallback(source) : source;
|
|
7581
7554
|
switch (type) {
|
|
7582
7555
|
case "local":
|
|
@@ -7634,7 +7607,7 @@ var PluginInstaller = class {
|
|
|
7634
7607
|
*/
|
|
7635
7608
|
async uninstall(name) {
|
|
7636
7609
|
const targetDir = resolve15(this.pluginsDir, name);
|
|
7637
|
-
if (!
|
|
7610
|
+
if (!existsSync13(targetDir)) {
|
|
7638
7611
|
throw new Error(`Plugin "${name}" not found`);
|
|
7639
7612
|
}
|
|
7640
7613
|
rmSync7(targetDir, { recursive: true, force: true });
|
|
@@ -7645,7 +7618,7 @@ var PluginInstaller = class {
|
|
|
7645
7618
|
* @returns Array of installed plugin information.
|
|
7646
7619
|
*/
|
|
7647
7620
|
async list(_options) {
|
|
7648
|
-
if (!
|
|
7621
|
+
if (!existsSync13(this.pluginsDir)) return [];
|
|
7649
7622
|
const entries = readdirSync3(this.pluginsDir, { withFileTypes: true });
|
|
7650
7623
|
const plugins = [];
|
|
7651
7624
|
for (const entry of entries) {
|
|
@@ -7653,7 +7626,7 @@ var PluginInstaller = class {
|
|
|
7653
7626
|
const pluginPath = resolve15(this.pluginsDir, entry.name);
|
|
7654
7627
|
const indexPath = resolve15(pluginPath, "index.ts");
|
|
7655
7628
|
const indexJsPath = resolve15(pluginPath, "index.js");
|
|
7656
|
-
if (!
|
|
7629
|
+
if (!existsSync13(indexPath) && !existsSync13(indexJsPath)) continue;
|
|
7657
7630
|
const metadata = PluginMetadataParser.parseFromPackageJson(pluginPath);
|
|
7658
7631
|
let source = "local";
|
|
7659
7632
|
const pkg2 = readJsonFile(resolve15(pluginPath, "package.json"), {});
|
|
@@ -7680,10 +7653,10 @@ var PluginInstaller = class {
|
|
|
7680
7653
|
}
|
|
7681
7654
|
if (source.startsWith("file://")) {
|
|
7682
7655
|
const filePath = decodeURIComponent(new URL(source).pathname);
|
|
7683
|
-
if (
|
|
7656
|
+
if (existsSync13(filePath)) return "url";
|
|
7684
7657
|
}
|
|
7685
7658
|
if (source.endsWith(".git") || source.includes("github.com/")) return "git";
|
|
7686
|
-
if (
|
|
7659
|
+
if (existsSync13(resolve15(source))) return "local";
|
|
7687
7660
|
return "npm";
|
|
7688
7661
|
}
|
|
7689
7662
|
deriveName(source, type) {
|
|
@@ -9707,7 +9680,7 @@ async function handleFilter(args, _mode) {
|
|
|
9707
9680
|
|
|
9708
9681
|
// src/stdin.ts
|
|
9709
9682
|
import { createInterface } from "readline";
|
|
9710
|
-
import { readFileSync as
|
|
9683
|
+
import { readFileSync as readFileSync15 } from "fs";
|
|
9711
9684
|
async function readStdin2() {
|
|
9712
9685
|
if (process.stdin.isTTY) return [];
|
|
9713
9686
|
const lines = [];
|
|
@@ -9721,7 +9694,7 @@ async function readStdin2() {
|
|
|
9721
9694
|
return lines;
|
|
9722
9695
|
}
|
|
9723
9696
|
function readCommandFile(filePath) {
|
|
9724
|
-
const content =
|
|
9697
|
+
const content = readFileSync15(filePath, "utf-8");
|
|
9725
9698
|
return content.split("\n").map((line) => line.trim()).filter((line) => line && !line.startsWith("#"));
|
|
9726
9699
|
}
|
|
9727
9700
|
|
|
@@ -10618,6 +10591,22 @@ var HTTPServer = class {
|
|
|
10618
10591
|
};
|
|
10619
10592
|
|
|
10620
10593
|
// src/router.ts
|
|
10594
|
+
var KNOWN_GLOBAL_OPTIONS = /* @__PURE__ */ new Set([
|
|
10595
|
+
"json",
|
|
10596
|
+
"yaml",
|
|
10597
|
+
"session",
|
|
10598
|
+
"cdp",
|
|
10599
|
+
"cdp-endpoint",
|
|
10600
|
+
"version",
|
|
10601
|
+
"v",
|
|
10602
|
+
"help",
|
|
10603
|
+
"h",
|
|
10604
|
+
"target",
|
|
10605
|
+
"port",
|
|
10606
|
+
"token",
|
|
10607
|
+
"timeout",
|
|
10608
|
+
"headless"
|
|
10609
|
+
]);
|
|
10621
10610
|
function showCommandHelp(siteName, cmd, siteConfig, mode) {
|
|
10622
10611
|
const c = cmd;
|
|
10623
10612
|
if (mode === "json") {
|
|
@@ -10742,8 +10731,23 @@ async function handleEvalMode(argv) {
|
|
|
10742
10731
|
}
|
|
10743
10732
|
async function handleChainInput(input, argv) {
|
|
10744
10733
|
const cdpEndpoint = argv ? extractCdpFromArgv(argv) : void 0;
|
|
10734
|
+
const jsonMode = argv ? argv.includes("--json") || argv.includes("-j") : false;
|
|
10745
10735
|
const chainResult = await executeChain(input, { cdpEndpoint });
|
|
10746
|
-
|
|
10736
|
+
if (jsonMode) {
|
|
10737
|
+
const output = {
|
|
10738
|
+
success: chainResult.success,
|
|
10739
|
+
steps: chainResult.steps.map((s) => ({
|
|
10740
|
+
command: s.raw,
|
|
10741
|
+
success: s.success,
|
|
10742
|
+
data: s.data,
|
|
10743
|
+
duration: s.duration,
|
|
10744
|
+
...s.hookOutputs?.length ? { hooks: s.hookOutputs } : {}
|
|
10745
|
+
}))
|
|
10746
|
+
};
|
|
10747
|
+
console.log(JSON.stringify(output, null, 2));
|
|
10748
|
+
} else {
|
|
10749
|
+
printChainResult(chainResult);
|
|
10750
|
+
}
|
|
10747
10751
|
if (!chainResult.success) throw new Error("Command failed");
|
|
10748
10752
|
}
|
|
10749
10753
|
async function routeCommand(argv, stdinCommands) {
|
|
@@ -10766,6 +10770,8 @@ async function routeCommand(argv, stdinCommands) {
|
|
|
10766
10770
|
}
|
|
10767
10771
|
const parsed = parseArgs(argv);
|
|
10768
10772
|
const { positional, options } = parsed;
|
|
10773
|
+
const command = positional[0];
|
|
10774
|
+
const cmdArgs = positional.slice(1);
|
|
10769
10775
|
const mode = options.json ? "json" : options.yaml ? "yaml" : "text";
|
|
10770
10776
|
const sessionName = options.session || process.env.XBROWSER_SESSION || "default";
|
|
10771
10777
|
const cdpEndpoint = options.cdp;
|
|
@@ -10777,8 +10783,6 @@ async function routeCommand(argv, stdinCommands) {
|
|
|
10777
10783
|
showMainHelp();
|
|
10778
10784
|
return;
|
|
10779
10785
|
}
|
|
10780
|
-
const command = positional[0];
|
|
10781
|
-
const cmdArgs = positional.slice(1);
|
|
10782
10786
|
if ((options.help || options.h) && positional.length > 0) {
|
|
10783
10787
|
const loader = await getPluginLoader();
|
|
10784
10788
|
const internalLoader = loader.getCore().loader;
|
|
@@ -10993,10 +10997,30 @@ Run "xbrowser ${command} --help" to see available commands.`
|
|
|
10993
10997
|
const subCmdIdx = pluginNameIdx >= 0 ? argv.indexOf(subCommand, pluginNameIdx + 1) : -1;
|
|
10994
10998
|
const rawPluginArgs = subCmdIdx >= 0 ? argv.slice(subCmdIdx + 1) : [];
|
|
10995
10999
|
const params = parsePluginParams(rawPluginArgs, cmdEntry.parameters);
|
|
11000
|
+
if (cmdEntry.parameters) {
|
|
11001
|
+
const schemaAny = cmdEntry.parameters;
|
|
11002
|
+
const def = schemaAny._def;
|
|
11003
|
+
const shapeOrFn = def?.shape ?? schemaAny.shape;
|
|
11004
|
+
const shapeObj = typeof shapeOrFn === "function" ? shapeOrFn() : shapeOrFn;
|
|
11005
|
+
if (shapeObj && typeof shapeObj === "object") {
|
|
11006
|
+
const knownKeys = new Set(Object.keys(shapeObj));
|
|
11007
|
+
knownKeys.add("_target");
|
|
11008
|
+
for (const gk of KNOWN_GLOBAL_OPTIONS) knownKeys.add(gk.replace(/-([a-z])/g, (_, c) => c.toUpperCase()));
|
|
11009
|
+
const unknownKeys = Object.keys(params).filter((k) => !knownKeys.has(k));
|
|
11010
|
+
if (unknownKeys.length > 0) {
|
|
11011
|
+
const unknown = unknownKeys.map((k) => `--${k.replace(/([A-Z])/g, "-$1").toLowerCase()}`).join(", ");
|
|
11012
|
+
outputError(
|
|
11013
|
+
`Unknown parameter: ${unknown}
|
|
11014
|
+
Run "xbrowser ${command} ${subCommand} --help" to see available parameters.`
|
|
11015
|
+
);
|
|
11016
|
+
return;
|
|
11017
|
+
}
|
|
11018
|
+
}
|
|
11019
|
+
}
|
|
10996
11020
|
if (options.target && !params._target) {
|
|
10997
11021
|
params._target = options.target;
|
|
10998
11022
|
}
|
|
10999
|
-
const needsBrowser = cmdEntry.scope === "page";
|
|
11023
|
+
const needsBrowser = cmdEntry.scope === "page" || cmdEntry.scope === "browser";
|
|
11000
11024
|
if (needsBrowser && !process.env.XBROWSER_DAEMON_WORKER) {
|
|
11001
11025
|
const { forwardExec } = await import("./daemon-client-XWSSQBEA.js");
|
|
11002
11026
|
const userTimeout = typeof params.timeout === "number" && params.timeout > 0 ? params.timeout * 1e3 + 3e4 : void 0;
|
|
@@ -11046,38 +11070,46 @@ Run "xbrowser ${command} --help" to see available commands.`
|
|
|
11046
11070
|
}
|
|
11047
11071
|
};
|
|
11048
11072
|
try {
|
|
11073
|
+
const cmdStart = Date.now();
|
|
11074
|
+
const cmdHooks = await loadHooks();
|
|
11075
|
+
if (cmdHooks.length > 0 && session?.page) {
|
|
11076
|
+
await Promise.all(cmdHooks.map((h) => h.onBeforeCommand?.({ page: session.page, command: `${command} ${subCommand}`, params })));
|
|
11077
|
+
}
|
|
11049
11078
|
const result = await cmdEntry.handler(params, ctx);
|
|
11079
|
+
const hookOutputs = [];
|
|
11080
|
+
if (cmdHooks.length > 0 && session?.page) {
|
|
11081
|
+
for (const h of cmdHooks) {
|
|
11082
|
+
const output = await h.onAfterCommand?.({ page: session.page, command: `${command} ${subCommand}`, params, result, duration: Date.now() - cmdStart });
|
|
11083
|
+
if (output) hookOutputs.push({ _hook: h.name, ...output });
|
|
11084
|
+
}
|
|
11085
|
+
}
|
|
11050
11086
|
if (session && result && result.data) {
|
|
11051
11087
|
const convUrl = result.data.conversationUrl;
|
|
11052
11088
|
if (convUrl) {
|
|
11053
11089
|
saveSessionDiskMeta(sessionName, { conversationUrl: convUrl, cdpEndpoint });
|
|
11054
11090
|
}
|
|
11055
11091
|
}
|
|
11056
|
-
|
|
11057
|
-
|
|
11058
|
-
|
|
11059
|
-
|
|
11060
|
-
|
|
11061
|
-
|
|
11062
|
-
|
|
11063
|
-
|
|
11064
|
-
if (result.tips?.length) {
|
|
11065
|
-
for (const tip of result.tips) console.log(` \u{1F4A1} ${tip}`);
|
|
11066
|
-
}
|
|
11092
|
+
const outputData = isCommandResult2(result) ? result.data : result && typeof result === "object" ? result.data ?? result : result;
|
|
11093
|
+
const tips = isCommandResult2(result) ? result.tips : result && typeof result === "object" ? result.tips : void 0;
|
|
11094
|
+
if (mode === "json" || mode === "yaml") {
|
|
11095
|
+
const finalOutput = {
|
|
11096
|
+
data: outputData
|
|
11097
|
+
};
|
|
11098
|
+
if (hookOutputs.length > 0) {
|
|
11099
|
+
finalOutput.hooks = hookOutputs;
|
|
11067
11100
|
}
|
|
11068
|
-
|
|
11069
|
-
|
|
11070
|
-
|
|
11071
|
-
|
|
11072
|
-
|
|
11073
|
-
|
|
11074
|
-
|
|
11075
|
-
}
|
|
11076
|
-
}
|
|
11077
|
-
|
|
11078
|
-
const
|
|
11079
|
-
|
|
11080
|
-
for (const tip of tips) console.log(` \u{1F4A1} ${tip}`);
|
|
11101
|
+
console.log(outputFormatter2.format(finalOutput, { mode, color: false, emoji: false }));
|
|
11102
|
+
if (tips?.length) {
|
|
11103
|
+
for (const tip of tips) console.error(`\u{1F4A1} ${tip}`);
|
|
11104
|
+
}
|
|
11105
|
+
} else {
|
|
11106
|
+
console.log(outputFormatter2.format(outputData, { mode: "text", color: true, emoji: true }));
|
|
11107
|
+
if (tips?.length) {
|
|
11108
|
+
for (const tip of tips) console.log(` \u{1F4A1} ${tip}`);
|
|
11109
|
+
}
|
|
11110
|
+
if (hookOutputs.length > 0) {
|
|
11111
|
+
for (const ho of hookOutputs) {
|
|
11112
|
+
console.log(` \u{1F4F8} screenshot: ${ho.screenshot?.url || "captured"}`);
|
|
11081
11113
|
}
|
|
11082
11114
|
}
|
|
11083
11115
|
}
|