@xbrowser/cli 1.2.2 → 1.3.1
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/{browser-CWI6BXYK.js → browser-ALV2PLW4.js} +2 -2
- package/dist/{browser-PZX7PO23.js → browser-VKZVOOVV.js} +1 -1
- package/dist/{browser-JP2LFPR2.js → browser-WMQRPYXX.js} +2 -2
- package/dist/{cdp-driver-S5STYUZZ.js → cdp-driver-72HOBP4C.js} +1 -1
- package/dist/{cdp-driver-RPUNQBGM.js → cdp-driver-JZPU5YXY.js} +49 -1
- package/dist/{chunk-PHBK3TRN.js → chunk-2QQDTXDL.js} +4 -2
- package/dist/{chunk-SLQR57XZ.js → chunk-7OGKQWXE.js} +1 -1
- package/dist/{chunk-AT4PHAJY.js → chunk-GJAV3QGG.js} +2 -2
- package/dist/{chunk-L53IDAWK.js → chunk-MJFYLKGL.js} +3 -2
- package/dist/{chunk-QFROODUU.js → chunk-N4PIGZDG.js} +49 -1
- package/dist/{chunk-MNFOCOL6.js → chunk-TLOHV3FP.js} +49 -1
- package/dist/{chunk-6V57JME6.js → chunk-UZQYMXR5.js} +1 -1
- package/dist/cli.js +178 -51
- package/dist/daemon-main.js +68 -43
- package/dist/{extract-BSYBM4MR.js → extract-O46CC533.js} +3 -2
- package/dist/{extract-2ZFW2MX7.js → extract-RM62AJXW.js} +1 -1
- package/dist/{filter-3JQWBM5F.js → filter-K6FGRJQU.js} +1 -1
- package/dist/{filter-EDTFGLS5.js → filter-TAAYMSYI.js} +2 -2
- package/dist/index.d.ts +10 -0
- package/dist/index.js +183 -56
- package/dist/{plugin-singleton-ZBVTWEYK.js → plugin-singleton-SYJF6BD6.js} +1 -1
- package/dist/{session-replayer-IXLSCF5U.js → session-replayer-JIVFXVUL.js} +1 -1
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -25,7 +25,7 @@ import {
|
|
|
25
25
|
resolveLaunchOpts,
|
|
26
26
|
saveSessionDiskMeta,
|
|
27
27
|
setActivePage
|
|
28
|
-
} from "./chunk-
|
|
28
|
+
} from "./chunk-TLOHV3FP.js";
|
|
29
29
|
import "./chunk-TNEN6VQ2.js";
|
|
30
30
|
import {
|
|
31
31
|
forwardCommandLog,
|
|
@@ -187,7 +187,7 @@ var version = pkg.version;
|
|
|
187
187
|
// src/executor.ts
|
|
188
188
|
import {
|
|
189
189
|
ok as ok25,
|
|
190
|
-
fail as
|
|
190
|
+
fail as fail8,
|
|
191
191
|
isCommandResult,
|
|
192
192
|
CompositeStorage as CompositeStorage2,
|
|
193
193
|
TipCollector as TipCollector2,
|
|
@@ -263,7 +263,7 @@ function createStubContext(pluginName) {
|
|
|
263
263
|
|
|
264
264
|
// src/commands/navigation.ts
|
|
265
265
|
import { z } from "zod";
|
|
266
|
-
import { ok } from "@dyyz1993/xcli-core";
|
|
266
|
+
import { ok, fail } from "@dyyz1993/xcli-core";
|
|
267
267
|
|
|
268
268
|
// src/commands/command-registry.ts
|
|
269
269
|
var registry = /* @__PURE__ */ new Map();
|
|
@@ -352,13 +352,19 @@ var gotoCommand = registerCommand({
|
|
|
352
352
|
if (/^[\w-]+(\.[\w-]+)+/.test(url) || url.startsWith("localhost")) {
|
|
353
353
|
url = "https://" + url;
|
|
354
354
|
} else {
|
|
355
|
-
|
|
355
|
+
return fail(`Invalid URL: "${url}". Expected http(s)://, file://, about:, data:, or a domain name.`);
|
|
356
356
|
}
|
|
357
357
|
}
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
358
|
+
let response;
|
|
359
|
+
try {
|
|
360
|
+
response = await ctx.page.goto(url, {
|
|
361
|
+
waitUntil: p.waitUntil || "domcontentloaded",
|
|
362
|
+
...p.timeout ? { timeout: p.timeout } : {}
|
|
363
|
+
});
|
|
364
|
+
} catch (err) {
|
|
365
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
366
|
+
return fail(`Navigation failed: ${msg}`);
|
|
367
|
+
}
|
|
362
368
|
const ssr = await detectSsr(ctx.page);
|
|
363
369
|
return ok({ url, status: response?.status(), ...ssr ? { ssr } : {} });
|
|
364
370
|
}
|
|
@@ -673,6 +679,22 @@ var checkCommand = registerCommand({
|
|
|
673
679
|
return ok2({ selector: p.selector });
|
|
674
680
|
}
|
|
675
681
|
});
|
|
682
|
+
var uncheckCommand = registerCommand({
|
|
683
|
+
name: "uncheck",
|
|
684
|
+
description: "Uncheck checkbox or radio",
|
|
685
|
+
scope: "element",
|
|
686
|
+
selectorParams: ["selector"],
|
|
687
|
+
parameters: z2.object({
|
|
688
|
+
selector: z2.string()
|
|
689
|
+
}),
|
|
690
|
+
result: z2.object({
|
|
691
|
+
selector: z2.string()
|
|
692
|
+
}),
|
|
693
|
+
handler: async (p, ctx) => {
|
|
694
|
+
await ctx.page.uncheck(p.selector, { timeout: 1e4 });
|
|
695
|
+
return ok2({ selector: p.selector });
|
|
696
|
+
}
|
|
697
|
+
});
|
|
676
698
|
var hoverCommand = registerCommand({
|
|
677
699
|
name: "hover",
|
|
678
700
|
description: "Hover over element",
|
|
@@ -1214,7 +1236,7 @@ var setViewportCommand = registerCommand({
|
|
|
1214
1236
|
|
|
1215
1237
|
// src/commands/frame.ts
|
|
1216
1238
|
import { z as z12 } from "zod";
|
|
1217
|
-
import { ok as ok12, fail } from "@dyyz1993/xcli-core";
|
|
1239
|
+
import { ok as ok12, fail as fail2 } from "@dyyz1993/xcli-core";
|
|
1218
1240
|
var framesCommand = registerCommand({
|
|
1219
1241
|
name: "frames",
|
|
1220
1242
|
description: "List all frames in the current page",
|
|
@@ -1227,7 +1249,9 @@ var framesCommand = registerCommand({
|
|
|
1227
1249
|
}))
|
|
1228
1250
|
}),
|
|
1229
1251
|
handler: async (_p, ctx) => {
|
|
1230
|
-
const
|
|
1252
|
+
const discover = ctx.page.discoverFrames;
|
|
1253
|
+
const rawFrames = discover ? await discover.call(ctx.page) : ctx.page.frames();
|
|
1254
|
+
const frameList = rawFrames.map((frame, index) => ({
|
|
1231
1255
|
index,
|
|
1232
1256
|
name: frame.name(),
|
|
1233
1257
|
url: frame.url()
|
|
@@ -1249,17 +1273,18 @@ var frameCommand = registerCommand({
|
|
|
1249
1273
|
error: z12.string().optional()
|
|
1250
1274
|
}),
|
|
1251
1275
|
handler: async (p, ctx) => {
|
|
1252
|
-
const
|
|
1276
|
+
const discover = ctx.page.discoverFrames;
|
|
1277
|
+
const rawFrames = discover ? await discover.call(ctx.page) : ctx.page.frames();
|
|
1253
1278
|
let targetFrame;
|
|
1254
1279
|
if (p.index !== void 0) {
|
|
1255
|
-
targetFrame =
|
|
1280
|
+
targetFrame = rawFrames[p.index];
|
|
1256
1281
|
} else if (p.name !== void 0) {
|
|
1257
|
-
targetFrame =
|
|
1282
|
+
targetFrame = rawFrames.find((f) => f.name() === p.name);
|
|
1258
1283
|
} else {
|
|
1259
|
-
return
|
|
1284
|
+
return fail2("Must provide index or name");
|
|
1260
1285
|
}
|
|
1261
1286
|
if (!targetFrame) {
|
|
1262
|
-
return
|
|
1287
|
+
return fail2("Frame not found");
|
|
1263
1288
|
}
|
|
1264
1289
|
return ok12({
|
|
1265
1290
|
name: targetFrame.name(),
|
|
@@ -1905,7 +1930,7 @@ var actionsCommand = registerCommand({
|
|
|
1905
1930
|
|
|
1906
1931
|
// src/commands/scrape.ts
|
|
1907
1932
|
import { z as z15 } from "zod";
|
|
1908
|
-
import { ok as ok15, fail as
|
|
1933
|
+
import { ok as ok15, fail as fail3 } from "@dyyz1993/xcli-core";
|
|
1909
1934
|
|
|
1910
1935
|
// src/lib/html-to-markdown.ts
|
|
1911
1936
|
import * as cheerio from "cheerio";
|
|
@@ -2421,7 +2446,7 @@ var scrapeCommand = registerCommand({
|
|
|
2421
2446
|
}
|
|
2422
2447
|
}
|
|
2423
2448
|
}
|
|
2424
|
-
return
|
|
2449
|
+
return fail3(`Scrape failed after ${maxAttempts} attempt(s): ${lastError?.message ?? "unknown error"}`);
|
|
2425
2450
|
} finally {
|
|
2426
2451
|
await closeEphemeralContext(context);
|
|
2427
2452
|
}
|
|
@@ -3485,7 +3510,7 @@ ${errors.map((e) => ` - ${e.engine}: ${e.error}`).join("\n")}`
|
|
|
3485
3510
|
|
|
3486
3511
|
// src/commands/network.ts
|
|
3487
3512
|
import { z as z19 } from "zod";
|
|
3488
|
-
import { ok as ok19, fail as
|
|
3513
|
+
import { ok as ok19, fail as fail4 } from "@dyyz1993/xcli-core";
|
|
3489
3514
|
function extractPath2(url) {
|
|
3490
3515
|
try {
|
|
3491
3516
|
const u = new URL(url);
|
|
@@ -3650,7 +3675,7 @@ var networkCommand = registerCommand({
|
|
|
3650
3675
|
};
|
|
3651
3676
|
if (p.listen) {
|
|
3652
3677
|
const page2 = ctx.page;
|
|
3653
|
-
if (!page2) return
|
|
3678
|
+
if (!page2) return fail4("No active page. Use --cdp to connect first.");
|
|
3654
3679
|
const captures = [];
|
|
3655
3680
|
const consoleMessages = [];
|
|
3656
3681
|
const wsCaptures = [];
|
|
@@ -4030,7 +4055,7 @@ var ENGINE_KEY_ENUM = z20.enum(ALL_ENGINE_KEYS);
|
|
|
4030
4055
|
|
|
4031
4056
|
// src/commands/snapshot.ts
|
|
4032
4057
|
import { z as z21 } from "zod";
|
|
4033
|
-
import { ok as ok20, fail as
|
|
4058
|
+
import { ok as ok20, fail as fail5, normalizeTips as normalizeTips3 } from "@dyyz1993/xcli-core";
|
|
4034
4059
|
|
|
4035
4060
|
// src/runtime/ref-store.ts
|
|
4036
4061
|
var sessions = /* @__PURE__ */ new Map();
|
|
@@ -4986,7 +5011,7 @@ var snapshotCommand = registerCommand({
|
|
|
4986
5011
|
persistSemantics(url, aria);
|
|
4987
5012
|
return ok20({ url, title, aria, text, dom }, normalizeTips3(tips));
|
|
4988
5013
|
}
|
|
4989
|
-
return
|
|
5014
|
+
return fail5(`Unknown snapshot type: ${p.type}`);
|
|
4990
5015
|
}
|
|
4991
5016
|
});
|
|
4992
5017
|
function persistSemantics(url, aria) {
|
|
@@ -5155,7 +5180,7 @@ var waitForCommand = registerCommand({
|
|
|
5155
5180
|
|
|
5156
5181
|
// src/commands/tab.ts
|
|
5157
5182
|
import { z as z23 } from "zod";
|
|
5158
|
-
import { ok as ok22, fail as
|
|
5183
|
+
import { ok as ok22, fail as fail6 } from "@dyyz1993/xcli-core";
|
|
5159
5184
|
var TabParams = z23.object({
|
|
5160
5185
|
subcommand: z23.enum(["list", "new", "close", "switch"]),
|
|
5161
5186
|
url: z23.string().optional(),
|
|
@@ -5182,7 +5207,7 @@ var tabCommand = registerCommand({
|
|
|
5182
5207
|
case "switch":
|
|
5183
5208
|
return handleSwitch(p, pages, ctx);
|
|
5184
5209
|
default:
|
|
5185
|
-
return
|
|
5210
|
+
return fail6(`Unknown subcommand: ${p.subcommand}`);
|
|
5186
5211
|
}
|
|
5187
5212
|
}
|
|
5188
5213
|
});
|
|
@@ -5239,11 +5264,11 @@ async function handleNew(p, _pages, ctx) {
|
|
|
5239
5264
|
}
|
|
5240
5265
|
async function handleClose(p, pages, ctx) {
|
|
5241
5266
|
if (pages.length <= 1) {
|
|
5242
|
-
return
|
|
5267
|
+
return fail6("Cannot close the last remaining tab");
|
|
5243
5268
|
}
|
|
5244
5269
|
const closeIndex = p.index ?? pages.indexOf(ctx.page);
|
|
5245
5270
|
if (closeIndex < 0 || closeIndex >= pages.length) {
|
|
5246
|
-
return
|
|
5271
|
+
return fail6(`Invalid tab index: ${closeIndex}. Valid range: 0-${pages.length - 1}`);
|
|
5247
5272
|
}
|
|
5248
5273
|
const pageToClose = pages[closeIndex];
|
|
5249
5274
|
const isActivePage = pageToClose === ctx.page;
|
|
@@ -5266,10 +5291,10 @@ async function handleClose(p, pages, ctx) {
|
|
|
5266
5291
|
}
|
|
5267
5292
|
async function handleSwitch(p, pages, ctx) {
|
|
5268
5293
|
if (p.index === void 0) {
|
|
5269
|
-
return
|
|
5294
|
+
return fail6("Parameter --index is required for switch subcommand");
|
|
5270
5295
|
}
|
|
5271
5296
|
if (p.index < 0 || p.index >= pages.length) {
|
|
5272
|
-
return
|
|
5297
|
+
return fail6(`Invalid tab index: ${p.index}. Valid range: 0-${pages.length - 1}`);
|
|
5273
5298
|
}
|
|
5274
5299
|
const targetPage = pages[p.index];
|
|
5275
5300
|
await targetPage.bringToFront().catch(() => {
|
|
@@ -5515,7 +5540,7 @@ registerCommandDefinition("addinitscript", ["script"]);
|
|
|
5515
5540
|
|
|
5516
5541
|
// src/commands/find.ts
|
|
5517
5542
|
import { z as z25 } from "zod";
|
|
5518
|
-
import { ok as ok24, fail as
|
|
5543
|
+
import { ok as ok24, fail as fail7, normalizeTips as normalizeTips5 } from "@dyyz1993/xcli-core";
|
|
5519
5544
|
var actionSchema2 = z25.enum(["click", "fill", "type", "select", "hover", "check"]);
|
|
5520
5545
|
var findCommand = registerCommand({
|
|
5521
5546
|
name: "find",
|
|
@@ -5556,7 +5581,7 @@ var findCommand = registerCommand({
|
|
|
5556
5581
|
});
|
|
5557
5582
|
const count = await locator.count();
|
|
5558
5583
|
if (count === 0) {
|
|
5559
|
-
return
|
|
5584
|
+
return fail7(`No element found with ${p.strategy}="${p.value}"`);
|
|
5560
5585
|
}
|
|
5561
5586
|
const tips = [];
|
|
5562
5587
|
const target = selectTarget(locator, p.strategy);
|
|
@@ -5568,15 +5593,15 @@ var findCommand = registerCommand({
|
|
|
5568
5593
|
await target.click({ timeout: p.timeout, force: true });
|
|
5569
5594
|
return okWithTips({ matched: count, selector, action: "click" }, tips);
|
|
5570
5595
|
} else if (actionName === "fill") {
|
|
5571
|
-
if (actionValue === void 0) return
|
|
5596
|
+
if (actionValue === void 0) return fail7("find fill requires a value");
|
|
5572
5597
|
await target.fill(actionValue, { timeout: p.timeout, force: true });
|
|
5573
5598
|
return okWithTips({ matched: count, selector, action: `fill("${actionValue}")` }, tips);
|
|
5574
5599
|
} else if (actionName === "type") {
|
|
5575
|
-
if (actionValue === void 0) return
|
|
5600
|
+
if (actionValue === void 0) return fail7("find type requires a value");
|
|
5576
5601
|
await target.type(actionValue, { delay: 10, timeout: p.timeout });
|
|
5577
5602
|
return okWithTips({ matched: count, selector, action: `type("${actionValue}")` }, tips);
|
|
5578
5603
|
} else if (actionName === "select") {
|
|
5579
|
-
if (actionValue === void 0) return
|
|
5604
|
+
if (actionValue === void 0) return fail7("find select requires a value");
|
|
5580
5605
|
await target.selectOption(actionValue);
|
|
5581
5606
|
return okWithTips({ matched: count, selector, action: `select("${actionValue}")` }, tips);
|
|
5582
5607
|
} else if (actionName === "hover") {
|
|
@@ -6331,8 +6356,10 @@ var XBrowserPluginLoader = class {
|
|
|
6331
6356
|
const instance = await this.loadPlugin(indexPath, entry.name);
|
|
6332
6357
|
loaded.push(instance);
|
|
6333
6358
|
} catch (err) {
|
|
6334
|
-
|
|
6335
|
-
|
|
6359
|
+
const errMsg2 = err instanceof Error ? err.message : String(err);
|
|
6360
|
+
console.warn(`\u26A0\uFE0F Plugin "${entry.name}" load failed: ${errMsg2}`);
|
|
6361
|
+
if (errMsg2.includes("Cannot find module") && errMsg2.includes("shared/")) {
|
|
6362
|
+
console.warn(` \u{1F4A1} This plugin needs shared/ dependencies. Try: xbrowser plugin install shared`);
|
|
6336
6363
|
}
|
|
6337
6364
|
}
|
|
6338
6365
|
}
|
|
@@ -6998,7 +7025,7 @@ async function guardCheck(commandName) {
|
|
|
6998
7025
|
}
|
|
6999
7026
|
}
|
|
7000
7027
|
function errorResult(message) {
|
|
7001
|
-
return { ...
|
|
7028
|
+
return { ...fail8(message), duration: 0 };
|
|
7002
7029
|
}
|
|
7003
7030
|
function tipsToMessages(tips) {
|
|
7004
7031
|
if (!tips || tips.length === 0) return [];
|
|
@@ -7031,7 +7058,7 @@ async function executeCommand(commandName, params, sessionName = "default", extr
|
|
|
7031
7058
|
}
|
|
7032
7059
|
let targetPageOverride = null;
|
|
7033
7060
|
if (_target && extraOpts?.cdpEndpoint) {
|
|
7034
|
-
const { findTargetPage } = await import("./browser-
|
|
7061
|
+
const { findTargetPage } = await import("./browser-VKZVOOVV.js");
|
|
7035
7062
|
targetPageOverride = await findTargetPage(extraOpts.cdpEndpoint, _target);
|
|
7036
7063
|
if (!targetPageOverride) {
|
|
7037
7064
|
return errorResult(`Target "${_target}" not found. Use 'xbrowser targets --cdp ${extraOpts.cdpEndpoint}' to list available pages.`);
|
|
@@ -7235,7 +7262,7 @@ async function executeCommand(commandName, params, sessionName = "default", extr
|
|
|
7235
7262
|
duration,
|
|
7236
7263
|
timestamp: start
|
|
7237
7264
|
});
|
|
7238
|
-
return { ...
|
|
7265
|
+
return { ...fail8(errorMessage), duration };
|
|
7239
7266
|
} finally {
|
|
7240
7267
|
}
|
|
7241
7268
|
}
|
|
@@ -7276,7 +7303,7 @@ async function executeChain(input, options) {
|
|
|
7276
7303
|
results.push({
|
|
7277
7304
|
command: cmdName,
|
|
7278
7305
|
raw: cmdStr,
|
|
7279
|
-
...
|
|
7306
|
+
...fail8(`Plugin "${cmdName}" requires a sub-command`),
|
|
7280
7307
|
duration: 0
|
|
7281
7308
|
});
|
|
7282
7309
|
if (type === "and") {
|
|
@@ -7295,7 +7322,7 @@ async function executeChain(input, options) {
|
|
|
7295
7322
|
results.push({
|
|
7296
7323
|
command: cmdName,
|
|
7297
7324
|
raw: cmdStr,
|
|
7298
|
-
...
|
|
7325
|
+
...fail8(`Unknown command "${subCommand}" for plugin "${cmdName}"`),
|
|
7299
7326
|
duration: 0
|
|
7300
7327
|
});
|
|
7301
7328
|
if (type === "and") {
|
|
@@ -7427,7 +7454,7 @@ async function executeChain(input, options) {
|
|
|
7427
7454
|
results.push({
|
|
7428
7455
|
command: `${cmdName} ${subCommand}`,
|
|
7429
7456
|
raw: cmdStr,
|
|
7430
|
-
...
|
|
7457
|
+
...fail8(errorMessage),
|
|
7431
7458
|
duration: duration2
|
|
7432
7459
|
});
|
|
7433
7460
|
if (type === "and") {
|
|
@@ -7499,7 +7526,7 @@ async function executeChain(input, options) {
|
|
|
7499
7526
|
}
|
|
7500
7527
|
}
|
|
7501
7528
|
function isChainInput(input) {
|
|
7502
|
-
return /\s&&\s|\s;\s|\s,\s|\s\+\s|\s->\s/.test(input);
|
|
7529
|
+
return /\s&&\s|\|\|\s|\s;\s|\s,\s|\s\+\s|\s->\s/.test(input);
|
|
7503
7530
|
}
|
|
7504
7531
|
|
|
7505
7532
|
// src/session/session-client.ts
|
|
@@ -7734,9 +7761,12 @@ import {
|
|
|
7734
7761
|
existsSync as existsSync10,
|
|
7735
7762
|
readdirSync as readdirSync2,
|
|
7736
7763
|
mkdirSync as mkdirSync8,
|
|
7737
|
-
rmSync as rmSync6
|
|
7764
|
+
rmSync as rmSync6,
|
|
7765
|
+
copyFileSync,
|
|
7766
|
+
cpSync as cpSync6,
|
|
7767
|
+
readFileSync as readFileSync8
|
|
7738
7768
|
} from "fs";
|
|
7739
|
-
import { resolve as resolve8, basename as basename2 } from "path";
|
|
7769
|
+
import { resolve as resolve8, basename as basename2, dirname as dirname3 } from "path";
|
|
7740
7770
|
import { homedir as homedir8 } from "os";
|
|
7741
7771
|
|
|
7742
7772
|
// src/plugin/install-sources/local.ts
|
|
@@ -8229,28 +8259,103 @@ var PluginInstaller = class {
|
|
|
8229
8259
|
switch (type) {
|
|
8230
8260
|
case "local":
|
|
8231
8261
|
return await installFromLocal(source, name, targetDir).then((r) => {
|
|
8262
|
+
this.fixSharedDeps(targetDir);
|
|
8232
8263
|
ensurePluginDependencies(this.pluginsDir);
|
|
8233
8264
|
return r;
|
|
8234
8265
|
});
|
|
8235
8266
|
case "npm":
|
|
8236
8267
|
return await installFromNpm(resolvedSource, name, targetDir).then((r) => {
|
|
8268
|
+
this.fixSharedDeps(targetDir);
|
|
8237
8269
|
ensurePluginDependencies(this.pluginsDir);
|
|
8238
8270
|
return r;
|
|
8239
8271
|
});
|
|
8240
8272
|
case "git":
|
|
8241
8273
|
return await installFromGit(source, name, targetDir).then((r) => {
|
|
8274
|
+
this.fixSharedDeps(targetDir);
|
|
8242
8275
|
ensurePluginDependencies(this.pluginsDir);
|
|
8243
8276
|
return r;
|
|
8244
8277
|
});
|
|
8245
8278
|
case "url":
|
|
8246
8279
|
return await installFromUrl(source, name, targetDir).then((r) => {
|
|
8280
|
+
this.fixSharedDeps(targetDir);
|
|
8247
8281
|
ensurePluginDependencies(this.pluginsDir);
|
|
8248
8282
|
return r;
|
|
8249
8283
|
});
|
|
8250
8284
|
}
|
|
8251
8285
|
}
|
|
8286
|
+
/**
|
|
8287
|
+
* Fix missing `../shared/` dependencies after installation.
|
|
8288
|
+
*
|
|
8289
|
+
* Some marketplace/npm packages import from `../shared/` (e.g. ssr-detect.js,
|
|
8290
|
+
* ai-chat-base.ts) but the `shared/` directory is not included in the package.
|
|
8291
|
+
* This method scans the installed plugin's index.ts for such imports and
|
|
8292
|
+
* copies the missing files from the local repository's `.xcli/plugins/shared/`
|
|
8293
|
+
* directory (if available).
|
|
8294
|
+
*/
|
|
8295
|
+
fixSharedDeps(pluginDir) {
|
|
8296
|
+
const indexPath = resolve8(pluginDir, "index.ts");
|
|
8297
|
+
if (!existsSync10(indexPath)) return;
|
|
8298
|
+
let content;
|
|
8299
|
+
try {
|
|
8300
|
+
content = readFileSync8(indexPath, "utf8");
|
|
8301
|
+
} catch {
|
|
8302
|
+
return;
|
|
8303
|
+
}
|
|
8304
|
+
const sharedImportRegex = /from\s+['"]\.\.\/shared\/([^'"]+)['"]/g;
|
|
8305
|
+
const missingFiles = [];
|
|
8306
|
+
let match;
|
|
8307
|
+
while ((match = sharedImportRegex.exec(content)) !== null) {
|
|
8308
|
+
missingFiles.push(match[1]);
|
|
8309
|
+
}
|
|
8310
|
+
if (missingFiles.length === 0) return;
|
|
8311
|
+
const sharedDir = resolve8(pluginDir, "..", "shared");
|
|
8312
|
+
const toCopy = [];
|
|
8313
|
+
for (const file of missingFiles) {
|
|
8314
|
+
const targetPath = resolve8(sharedDir, file);
|
|
8315
|
+
if (!existsSync10(targetPath)) {
|
|
8316
|
+
toCopy.push(file);
|
|
8317
|
+
}
|
|
8318
|
+
}
|
|
8319
|
+
if (toCopy.length === 0) return;
|
|
8320
|
+
const repoSharedDirs = [
|
|
8321
|
+
resolve8(process.cwd(), ".xcli/plugins/shared"),
|
|
8322
|
+
resolve8(homedir8(), ".xbrowser/plugins/shared")
|
|
8323
|
+
];
|
|
8324
|
+
let sourceSharedDir = null;
|
|
8325
|
+
for (const dir of repoSharedDirs) {
|
|
8326
|
+
if (existsSync10(dir)) {
|
|
8327
|
+
sourceSharedDir = dir;
|
|
8328
|
+
break;
|
|
8329
|
+
}
|
|
8330
|
+
}
|
|
8331
|
+
if (!sourceSharedDir) {
|
|
8332
|
+
console.warn(`\u26A0\uFE0F Plugin "${basename2(pluginDir)}" imports shared files but they are missing: ${toCopy.join(", ")}`);
|
|
8333
|
+
console.warn(` To fix: install the "shared" plugin or copy .xcli/plugins/shared/ to ~/.xbrowser/plugins/shared/`);
|
|
8334
|
+
return;
|
|
8335
|
+
}
|
|
8336
|
+
mkdirSync8(sharedDir, { recursive: true });
|
|
8337
|
+
for (const file of toCopy) {
|
|
8338
|
+
const src = resolve8(sourceSharedDir, file);
|
|
8339
|
+
const dst = resolve8(sharedDir, file);
|
|
8340
|
+
if (existsSync10(src)) {
|
|
8341
|
+
try {
|
|
8342
|
+
cpSync6(dirname3(src), dirname3(dst), { recursive: true });
|
|
8343
|
+
console.log(`\u2705 Copied shared/${file} for plugin "${basename2(pluginDir)}"`);
|
|
8344
|
+
} catch {
|
|
8345
|
+
try {
|
|
8346
|
+
copyFileSync(src, dst);
|
|
8347
|
+
console.log(`\u2705 Copied shared/${file} for plugin "${basename2(pluginDir)}"`);
|
|
8348
|
+
} catch {
|
|
8349
|
+
console.warn(`\u26A0\uFE0F Could not copy shared/${file}`);
|
|
8350
|
+
}
|
|
8351
|
+
}
|
|
8352
|
+
}
|
|
8353
|
+
}
|
|
8354
|
+
}
|
|
8252
8355
|
async installFromMarketplace(slug, options) {
|
|
8253
8356
|
const result = await installFromMarketplace(this.pluginsDir, slug, options);
|
|
8357
|
+
const targetDir = resolve8(this.pluginsDir, result.name);
|
|
8358
|
+
this.fixSharedDeps(targetDir);
|
|
8254
8359
|
ensurePluginDependencies(this.pluginsDir);
|
|
8255
8360
|
return result;
|
|
8256
8361
|
}
|
|
@@ -9893,6 +9998,17 @@ async function handleBrowserCommand(command, args, options, sessionName, mode, c
|
|
|
9893
9998
|
};
|
|
9894
9999
|
break;
|
|
9895
10000
|
}
|
|
10001
|
+
case "tab": {
|
|
10002
|
+
const tabSub = args[0];
|
|
10003
|
+
const validSubs = ["list", "new", "close", "switch"];
|
|
10004
|
+
cmdName = "tab";
|
|
10005
|
+
params = {
|
|
10006
|
+
subcommand: validSubs.includes(tabSub) ? tabSub : options.subcommand,
|
|
10007
|
+
url: args[1] || options.url,
|
|
10008
|
+
index: options.index ? Number(options.index) : void 0
|
|
10009
|
+
};
|
|
10010
|
+
break;
|
|
10011
|
+
}
|
|
9896
10012
|
default:
|
|
9897
10013
|
cmdName = command;
|
|
9898
10014
|
params = { ...options };
|
|
@@ -10715,6 +10831,7 @@ async function handleConvert(args, _mode) {
|
|
|
10715
10831
|
const { generateJSScript, generatePythonScript, generateBashScript } = await import("./convert-LB3GJTLR.js");
|
|
10716
10832
|
const content = fs3.readFileSync(filePath, "utf-8");
|
|
10717
10833
|
const recording = yaml.parse(content);
|
|
10834
|
+
if (recording.actions && !recording.events) recording.events = recording.actions;
|
|
10718
10835
|
const ext = path3.extname(outputPath).toLowerCase();
|
|
10719
10836
|
let script;
|
|
10720
10837
|
if (ext === ".py") {
|
|
@@ -10726,7 +10843,7 @@ async function handleConvert(args, _mode) {
|
|
|
10726
10843
|
}
|
|
10727
10844
|
fs3.writeFileSync(outputPath, script);
|
|
10728
10845
|
fs3.chmodSync(outputPath, 493);
|
|
10729
|
-
const eventCount = (recording.events || []).length;
|
|
10846
|
+
const eventCount = (recording.events || recording.actions || []).length;
|
|
10730
10847
|
console.log(`Converted ${filePath} -> ${outputPath}`);
|
|
10731
10848
|
console.log(` Events: ${eventCount}, Start URL: ${recording.startUrl}`);
|
|
10732
10849
|
console.log(` Run: ${ext === ".py" ? "python" : ext === ".sh" ? "./" : "node"} ${outputPath}`);
|
|
@@ -10737,7 +10854,7 @@ async function handleExtract(args, _mode) {
|
|
|
10737
10854
|
console.error("Usage: xbrowser extract <recording.yaml>");
|
|
10738
10855
|
process.exit(1);
|
|
10739
10856
|
}
|
|
10740
|
-
const { extractAndSave, printExtractSummary } = await import("./extract-
|
|
10857
|
+
const { extractAndSave, printExtractSummary } = await import("./extract-O46CC533.js");
|
|
10741
10858
|
const { summary, outputPath } = extractAndSave(filePath);
|
|
10742
10859
|
printExtractSummary(summary);
|
|
10743
10860
|
console.log(`
|
|
@@ -10750,7 +10867,7 @@ async function handleFilter(args, _mode, options) {
|
|
|
10750
10867
|
console.error("Usage: xbrowser filter <input.yaml> <output.yaml> [--exclude type1,type2]");
|
|
10751
10868
|
process.exit(1);
|
|
10752
10869
|
}
|
|
10753
|
-
const { filterRecording, parseExcludeTypes } = await import("./filter-
|
|
10870
|
+
const { filterRecording, parseExcludeTypes } = await import("./filter-TAAYMSYI.js");
|
|
10754
10871
|
const excludeArgs = args.slice(2).concat(
|
|
10755
10872
|
Object.entries(options || {}).flatMap(
|
|
10756
10873
|
([k, v]) => k.startsWith("exclude") ? [`--${k}${typeof v === "string" ? "=" + v : ""}`] : []
|
|
@@ -11313,7 +11430,7 @@ async function handleNetCommand(args, options, mode, sessionName) {
|
|
|
11313
11430
|
|
|
11314
11431
|
// src/cli/test-routes.ts
|
|
11315
11432
|
import { execSync as execSync3 } from "child_process";
|
|
11316
|
-
import { readFileSync as
|
|
11433
|
+
import { readFileSync as readFileSync9 } from "fs";
|
|
11317
11434
|
import { resolve as resolve9 } from "path";
|
|
11318
11435
|
function findPluginPath(plugin) {
|
|
11319
11436
|
const candidates = [
|
|
@@ -11322,7 +11439,7 @@ function findPluginPath(plugin) {
|
|
|
11322
11439
|
];
|
|
11323
11440
|
for (const p of candidates) {
|
|
11324
11441
|
try {
|
|
11325
|
-
|
|
11442
|
+
readFileSync9(p, "utf-8");
|
|
11326
11443
|
return p;
|
|
11327
11444
|
} catch {
|
|
11328
11445
|
}
|
|
@@ -11333,7 +11450,7 @@ function extractSchema(plugin, command) {
|
|
|
11333
11450
|
const pluginPath = findPluginPath(plugin);
|
|
11334
11451
|
let src;
|
|
11335
11452
|
try {
|
|
11336
|
-
src =
|
|
11453
|
+
src = readFileSync9(pluginPath, "utf-8");
|
|
11337
11454
|
} catch {
|
|
11338
11455
|
return null;
|
|
11339
11456
|
}
|
|
@@ -12205,7 +12322,7 @@ function extractCdpFromArgv(argv) {
|
|
|
12205
12322
|
return process.env.XBROWSER_CDP;
|
|
12206
12323
|
}
|
|
12207
12324
|
async function handleStdinMode(stdinCommands, argv) {
|
|
12208
|
-
const chain = stdinCommands.join("
|
|
12325
|
+
const chain = stdinCommands.join(" ; ");
|
|
12209
12326
|
const cdpEndpoint = argv ? extractCdpFromArgv(argv) : void 0;
|
|
12210
12327
|
const sessionName = argv ? extractSessionNameFromArgv(argv) : "default";
|
|
12211
12328
|
const chainResult = await executeChain(chain, { fileMode: true, cdpEndpoint, sessionName });
|
|
@@ -12468,6 +12585,13 @@ async function routeCommand(argvIn, stdinCommands) {
|
|
|
12468
12585
|
for (const step of chainResult.steps) {
|
|
12469
12586
|
if (step.success) {
|
|
12470
12587
|
console.log(`[OK] ${step.raw}`);
|
|
12588
|
+
if (step.data && typeof step.data === "object") {
|
|
12589
|
+
const d = step.data;
|
|
12590
|
+
for (const [k, v] of Object.entries(d)) {
|
|
12591
|
+
if (k !== "ok" && k !== "success")
|
|
12592
|
+
console.log(` ${k}: ${typeof v === "string" ? v : JSON.stringify(v)}`);
|
|
12593
|
+
}
|
|
12594
|
+
}
|
|
12471
12595
|
if (step.tips?.length) {
|
|
12472
12596
|
for (const tip of step.tips) {
|
|
12473
12597
|
console.log(` \u{1F4A1} ${tip}`);
|
|
@@ -12477,6 +12601,9 @@ async function routeCommand(argvIn, stdinCommands) {
|
|
|
12477
12601
|
console.error(`[FAIL] ${step.raw}: ${step.message}`);
|
|
12478
12602
|
}
|
|
12479
12603
|
}
|
|
12604
|
+
if (chainResult.stoppedReason) {
|
|
12605
|
+
console.error(`Stopped: ${chainResult.stoppedReason}`);
|
|
12606
|
+
}
|
|
12480
12607
|
if (!chainResult.success) throw new Error("Command failed");
|
|
12481
12608
|
return;
|
|
12482
12609
|
}
|
|
@@ -12869,7 +12996,7 @@ async function main() {
|
|
|
12869
12996
|
const command = process.argv[2];
|
|
12870
12997
|
const isLongRunning = command === "preview" || command === "serve";
|
|
12871
12998
|
if (!isLongRunning) {
|
|
12872
|
-
const { ensureProcessCanExit } = await import("./browser-
|
|
12999
|
+
const { ensureProcessCanExit } = await import("./browser-VKZVOOVV.js");
|
|
12873
13000
|
await ensureProcessCanExit().catch(() => {
|
|
12874
13001
|
});
|
|
12875
13002
|
process.exit(exitCode);
|