@xbrowser/cli 1.8.5 → 1.8.7
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-NSSCH4MJ.js → browser-LW2MDJE4.js} +1 -1
- package/dist/{browser-PTELW3WS.js → browser-TLIDFFEG.js} +1 -1
- package/dist/{browser-PUAJ3AHG.js → browser-XPKM344Y.js} +1 -1
- package/dist/{chunk-7EOQV6ZW.js → chunk-CJJ564VK.js} +1 -1
- package/dist/{chunk-BALOM2HW.js → chunk-FL6DOSWV.js} +36 -8
- package/dist/{chunk-TAHJCCME.js → chunk-HXLMMSU3.js} +1 -1
- package/dist/{chunk-XU5WOJIV.js → chunk-RMYEHTLS.js} +36 -8
- package/dist/{chunk-U25ZKXBJ.js → chunk-SJLRCE6N.js} +1 -1
- package/dist/cli.js +213 -103
- package/dist/daemon-main.js +65 -32
- package/dist/index.d.ts +1 -0
- package/dist/index.js +212 -102
- package/dist/{session-recorder-H2WPBCSW.js → session-recorder-33UKWCIR.js} +1 -1
- package/dist/{session-recorder-CV5EJSDY.js → session-recorder-BMIJ3ZJM.js} +1 -1
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -57,7 +57,7 @@ import {
|
|
|
57
57
|
} from "./chunk-GJAV3QGG.js";
|
|
58
58
|
import {
|
|
59
59
|
SessionRecorder
|
|
60
|
-
} from "./chunk-
|
|
60
|
+
} from "./chunk-RMYEHTLS.js";
|
|
61
61
|
import {
|
|
62
62
|
addKnownIssue,
|
|
63
63
|
getKnowledgePath,
|
|
@@ -82,7 +82,7 @@ import {
|
|
|
82
82
|
resolveLaunchOpts,
|
|
83
83
|
saveSessionDiskMeta,
|
|
84
84
|
setActivePage
|
|
85
|
-
} from "./chunk-
|
|
85
|
+
} from "./chunk-CJJ564VK.js";
|
|
86
86
|
import "./chunk-VJNMAWPZ.js";
|
|
87
87
|
import "./chunk-TNEN6VQ2.js";
|
|
88
88
|
import {
|
|
@@ -109,7 +109,7 @@ import {
|
|
|
109
109
|
// src/executor.ts
|
|
110
110
|
import {
|
|
111
111
|
ok as ok25,
|
|
112
|
-
fail as
|
|
112
|
+
fail as fail9,
|
|
113
113
|
isCommandResult,
|
|
114
114
|
CompositeStorage as CompositeStorage2,
|
|
115
115
|
TipCollector as TipCollector2,
|
|
@@ -2356,7 +2356,7 @@ var scrapeCommand = registerCommand({
|
|
|
2356
2356
|
scope: "project",
|
|
2357
2357
|
selectorParams: ["selector"],
|
|
2358
2358
|
parameters: z15.object({
|
|
2359
|
-
url: z15.string(),
|
|
2359
|
+
url: z15.string().optional(),
|
|
2360
2360
|
selector: z15.string().optional(),
|
|
2361
2361
|
timeout: z15.number().default(3e4),
|
|
2362
2362
|
format: z15.enum(["markdown", "html", "text"]).default("markdown"),
|
|
@@ -2369,10 +2369,14 @@ var scrapeCommand = registerCommand({
|
|
|
2369
2369
|
const { context, page } = await createEphemeralContext(resolveLaunchOpts(ctx));
|
|
2370
2370
|
const maxAttempts = p.retries + 1;
|
|
2371
2371
|
try {
|
|
2372
|
+
const targetUrl = p.url || page.url();
|
|
2373
|
+
if (!targetUrl || targetUrl === "about:blank") {
|
|
2374
|
+
return fail3("URL is required. Provide a URL or connect to a browser (--cdp) with a non-blank page.");
|
|
2375
|
+
}
|
|
2372
2376
|
let lastError;
|
|
2373
2377
|
for (let attempt = 1; attempt <= maxAttempts; attempt++) {
|
|
2374
2378
|
try {
|
|
2375
|
-
await page.goto(
|
|
2379
|
+
await page.goto(targetUrl, { waitUntil: "commit", timeout: p.timeout });
|
|
2376
2380
|
await page.waitForSelector("body", { timeout: p.timeout }).catch(() => {
|
|
2377
2381
|
});
|
|
2378
2382
|
await page.waitForLoadState("networkidle", Math.min(p.timeout, 8e3)).catch(() => {
|
|
@@ -2433,7 +2437,7 @@ var scrapeCommand = registerCommand({
|
|
|
2433
2437
|
return { url: location.href, title: document.title, navigation, tables, forms: forms.slice(0, 20), links: links.slice(0, 30), mainText };
|
|
2434
2438
|
});
|
|
2435
2439
|
try {
|
|
2436
|
-
persistFromScrape(
|
|
2440
|
+
persistFromScrape(targetUrl, structured);
|
|
2437
2441
|
} catch {
|
|
2438
2442
|
}
|
|
2439
2443
|
if (p.mode === "smart") {
|
|
@@ -2534,7 +2538,7 @@ var scrapeCommand = registerCommand({
|
|
|
2534
2538
|
|
|
2535
2539
|
// src/commands/map.ts
|
|
2536
2540
|
import { z as z16 } from "zod";
|
|
2537
|
-
import { ok as ok16 } from "@dyyz1993/xcli-core";
|
|
2541
|
+
import { ok as ok16, fail as fail4 } from "@dyyz1993/xcli-core";
|
|
2538
2542
|
|
|
2539
2543
|
// src/utils/url.ts
|
|
2540
2544
|
var SKIP_EXTENSIONS = /* @__PURE__ */ new Set([
|
|
@@ -2770,7 +2774,7 @@ var mapCommand = registerCommand({
|
|
|
2770
2774
|
description: "Discover all URLs on a website via sitemap and page link extraction",
|
|
2771
2775
|
scope: "project",
|
|
2772
2776
|
parameters: z16.object({
|
|
2773
|
-
url: z16.string(),
|
|
2777
|
+
url: z16.string().optional(),
|
|
2774
2778
|
search: z16.string().optional(),
|
|
2775
2779
|
sitemap: z16.enum(["include", "only"]).optional(),
|
|
2776
2780
|
includeSubdomains: z16.boolean().optional(),
|
|
@@ -2781,7 +2785,11 @@ var mapCommand = registerCommand({
|
|
|
2781
2785
|
handler: async (p, ctx) => {
|
|
2782
2786
|
const { context, page } = await createEphemeralContext(resolveLaunchOpts(ctx));
|
|
2783
2787
|
try {
|
|
2784
|
-
const
|
|
2788
|
+
const targetUrl = p.url || page.url();
|
|
2789
|
+
if (!targetUrl || targetUrl === "about:blank") {
|
|
2790
|
+
return fail4("URL is required. Provide a URL or connect to a browser (--cdp) with a non-blank page.");
|
|
2791
|
+
}
|
|
2792
|
+
const links = await discoverUrls(page, targetUrl, {
|
|
2785
2793
|
sitemap: p.sitemap,
|
|
2786
2794
|
includeSubdomains: p.includeSubdomains,
|
|
2787
2795
|
allowExternalLinks: p.allowExternalLinks,
|
|
@@ -3624,7 +3632,7 @@ ${errors.map((e) => ` - ${e.engine}: ${e.error}`).join("\n")}`
|
|
|
3624
3632
|
|
|
3625
3633
|
// src/commands/network.ts
|
|
3626
3634
|
import { z as z19 } from "zod";
|
|
3627
|
-
import { ok as ok19, fail as
|
|
3635
|
+
import { ok as ok19, fail as fail5 } from "@dyyz1993/xcli-core";
|
|
3628
3636
|
function extractPath2(url) {
|
|
3629
3637
|
try {
|
|
3630
3638
|
const u = new URL(url);
|
|
@@ -3789,7 +3797,7 @@ var networkCommand = registerCommand({
|
|
|
3789
3797
|
};
|
|
3790
3798
|
if (p.listen) {
|
|
3791
3799
|
const page2 = ctx.page;
|
|
3792
|
-
if (!page2) return
|
|
3800
|
+
if (!page2) return fail5("No active page. Use --cdp to connect first.");
|
|
3793
3801
|
const captures = [];
|
|
3794
3802
|
const consoleMessages = [];
|
|
3795
3803
|
const wsCaptures = [];
|
|
@@ -4446,7 +4454,7 @@ function parseMarkdownResults(rawText) {
|
|
|
4446
4454
|
|
|
4447
4455
|
// src/commands/snapshot.ts
|
|
4448
4456
|
import { z as z21 } from "zod";
|
|
4449
|
-
import { ok as ok20, fail as
|
|
4457
|
+
import { ok as ok20, fail as fail6, normalizeTips as normalizeTips3 } from "@dyyz1993/xcli-core";
|
|
4450
4458
|
|
|
4451
4459
|
// src/runtime/ref-store.ts
|
|
4452
4460
|
var sessions = /* @__PURE__ */ new Map();
|
|
@@ -5417,7 +5425,7 @@ var snapshotCommand = registerCommand({
|
|
|
5417
5425
|
persistSemantics(url, aria);
|
|
5418
5426
|
return ok20({ url, title, aria, text, dom }, normalizeTips3(tips));
|
|
5419
5427
|
}
|
|
5420
|
-
return
|
|
5428
|
+
return fail6(`Unknown snapshot type: ${p.type}`);
|
|
5421
5429
|
}
|
|
5422
5430
|
});
|
|
5423
5431
|
function persistSemantics(url, aria) {
|
|
@@ -5586,7 +5594,7 @@ var waitForCommand = registerCommand({
|
|
|
5586
5594
|
|
|
5587
5595
|
// src/commands/tab.ts
|
|
5588
5596
|
import { z as z23 } from "zod";
|
|
5589
|
-
import { ok as ok22, fail as
|
|
5597
|
+
import { ok as ok22, fail as fail7 } from "@dyyz1993/xcli-core";
|
|
5590
5598
|
var TabParams = z23.object({
|
|
5591
5599
|
subcommand: z23.enum(["list", "new", "close", "switch"]),
|
|
5592
5600
|
url: z23.string().optional(),
|
|
@@ -5603,7 +5611,7 @@ var tabCommand = registerCommand({
|
|
|
5603
5611
|
}),
|
|
5604
5612
|
handler: async (p, ctx) => {
|
|
5605
5613
|
if (!ctx.browserContext) {
|
|
5606
|
-
return
|
|
5614
|
+
return fail7("No browser context available. Use --cdp to connect to a browser first.");
|
|
5607
5615
|
}
|
|
5608
5616
|
const pages = ctx.browserContext.pages();
|
|
5609
5617
|
switch (p.subcommand) {
|
|
@@ -5616,7 +5624,7 @@ var tabCommand = registerCommand({
|
|
|
5616
5624
|
case "switch":
|
|
5617
5625
|
return handleSwitch(p, pages, ctx);
|
|
5618
5626
|
default:
|
|
5619
|
-
return
|
|
5627
|
+
return fail7(`Unknown subcommand: ${p.subcommand}`);
|
|
5620
5628
|
}
|
|
5621
5629
|
}
|
|
5622
5630
|
});
|
|
@@ -5673,11 +5681,11 @@ async function handleNew(p, _pages, ctx) {
|
|
|
5673
5681
|
}
|
|
5674
5682
|
async function handleClose(p, pages, ctx) {
|
|
5675
5683
|
if (pages.length <= 1) {
|
|
5676
|
-
return
|
|
5684
|
+
return fail7("Cannot close the last remaining tab");
|
|
5677
5685
|
}
|
|
5678
5686
|
const closeIndex = p.index ?? pages.indexOf(ctx.page);
|
|
5679
5687
|
if (closeIndex < 0 || closeIndex >= pages.length) {
|
|
5680
|
-
return
|
|
5688
|
+
return fail7(`Invalid tab index: ${closeIndex}. Valid range: 0-${pages.length - 1}`);
|
|
5681
5689
|
}
|
|
5682
5690
|
const pageToClose = pages[closeIndex];
|
|
5683
5691
|
const isActivePage = pageToClose === ctx.page;
|
|
@@ -5700,10 +5708,10 @@ async function handleClose(p, pages, ctx) {
|
|
|
5700
5708
|
}
|
|
5701
5709
|
async function handleSwitch(p, pages, ctx) {
|
|
5702
5710
|
if (p.index === void 0) {
|
|
5703
|
-
return
|
|
5711
|
+
return fail7("Parameter --index is required for switch subcommand");
|
|
5704
5712
|
}
|
|
5705
5713
|
if (p.index < 0 || p.index >= pages.length) {
|
|
5706
|
-
return
|
|
5714
|
+
return fail7(`Invalid tab index: ${p.index}. Valid range: 0-${pages.length - 1}`);
|
|
5707
5715
|
}
|
|
5708
5716
|
const targetPage = pages[p.index];
|
|
5709
5717
|
await targetPage.bringToFront().catch(() => {
|
|
@@ -5955,7 +5963,7 @@ registerCommandDefinition("addinitscript", ["script"]);
|
|
|
5955
5963
|
|
|
5956
5964
|
// src/commands/find.ts
|
|
5957
5965
|
import { z as z25 } from "zod";
|
|
5958
|
-
import { ok as ok24, fail as
|
|
5966
|
+
import { ok as ok24, fail as fail8, normalizeTips as normalizeTips5 } from "@dyyz1993/xcli-core";
|
|
5959
5967
|
var actionSchema2 = z25.enum(["click", "fill", "type", "select", "hover", "check"]);
|
|
5960
5968
|
var findCommand = registerCommand({
|
|
5961
5969
|
name: "find",
|
|
@@ -5996,7 +6004,7 @@ var findCommand = registerCommand({
|
|
|
5996
6004
|
});
|
|
5997
6005
|
const count = await locator.count();
|
|
5998
6006
|
if (count === 0) {
|
|
5999
|
-
return
|
|
6007
|
+
return fail8(`No element found with ${p.strategy}="${p.value}"`);
|
|
6000
6008
|
}
|
|
6001
6009
|
const tips = [];
|
|
6002
6010
|
const target = selectTarget(locator, p.strategy);
|
|
@@ -6008,15 +6016,15 @@ var findCommand = registerCommand({
|
|
|
6008
6016
|
await target.click({ timeout: p.timeout, force: true });
|
|
6009
6017
|
return okWithTips({ matched: count, selector, action: "click" }, tips);
|
|
6010
6018
|
} else if (actionName === "fill") {
|
|
6011
|
-
if (actionValue === void 0) return
|
|
6019
|
+
if (actionValue === void 0) return fail8("find fill requires a value");
|
|
6012
6020
|
await target.fill(actionValue, { timeout: p.timeout, force: true });
|
|
6013
6021
|
return okWithTips({ matched: count, selector, action: `fill("${actionValue}")` }, tips);
|
|
6014
6022
|
} else if (actionName === "type") {
|
|
6015
|
-
if (actionValue === void 0) return
|
|
6023
|
+
if (actionValue === void 0) return fail8("find type requires a value");
|
|
6016
6024
|
await target.type(actionValue, { delay: 10, timeout: p.timeout });
|
|
6017
6025
|
return okWithTips({ matched: count, selector, action: `type("${actionValue}")` }, tips);
|
|
6018
6026
|
} else if (actionName === "select") {
|
|
6019
|
-
if (actionValue === void 0) return
|
|
6027
|
+
if (actionValue === void 0) return fail8("find select requires a value");
|
|
6020
6028
|
await target.selectOption(actionValue);
|
|
6021
6029
|
return okWithTips({ matched: count, selector, action: `select("${actionValue}")` }, tips);
|
|
6022
6030
|
} else if (actionName === "hover") {
|
|
@@ -7452,7 +7460,7 @@ async function guardCheck(commandName) {
|
|
|
7452
7460
|
}
|
|
7453
7461
|
}
|
|
7454
7462
|
function errorResult(message) {
|
|
7455
|
-
return { ...
|
|
7463
|
+
return { ...fail9(message), duration: 0 };
|
|
7456
7464
|
}
|
|
7457
7465
|
function tipsToMessages(tips) {
|
|
7458
7466
|
if (!tips || tips.length === 0) return [];
|
|
@@ -7525,9 +7533,14 @@ async function executeCommand(commandName, params, sessionName = "default", extr
|
|
|
7525
7533
|
const { _target: _u, ...rest } = params;
|
|
7526
7534
|
params = rest;
|
|
7527
7535
|
}
|
|
7536
|
+
const _tabIndex = params._tabIndex;
|
|
7537
|
+
if (_tabIndex !== void 0) {
|
|
7538
|
+
const { _tabIndex: _u, ...rest } = params;
|
|
7539
|
+
params = rest;
|
|
7540
|
+
}
|
|
7528
7541
|
let targetPageOverride = null;
|
|
7529
7542
|
if (_target && extraOpts?.cdpEndpoint) {
|
|
7530
|
-
const { findTargetPage } = await import("./browser-
|
|
7543
|
+
const { findTargetPage } = await import("./browser-TLIDFFEG.js");
|
|
7531
7544
|
targetPageOverride = await findTargetPage(extraOpts.cdpEndpoint, _target);
|
|
7532
7545
|
if (!targetPageOverride) {
|
|
7533
7546
|
return errorResult(`Target "${_target}" not found. Use 'xbrowser targets --cdp ${extraOpts.cdpEndpoint}' to list available pages.`);
|
|
@@ -7599,6 +7612,16 @@ async function executeCommand(commandName, params, sessionName = "default", extr
|
|
|
7599
7612
|
cliName: "xbrowser",
|
|
7600
7613
|
tips: new TipCollector2()
|
|
7601
7614
|
};
|
|
7615
|
+
if (_tabIndex !== void 0 && session?.context) {
|
|
7616
|
+
const pages = session.context.pages();
|
|
7617
|
+
if (_tabIndex >= 0 && _tabIndex < pages.length) {
|
|
7618
|
+
const targetPage = pages[_tabIndex];
|
|
7619
|
+
await targetPage.bringToFront().catch(() => {
|
|
7620
|
+
});
|
|
7621
|
+
setActivePage(session, targetPage);
|
|
7622
|
+
ctx.page = targetPage;
|
|
7623
|
+
}
|
|
7624
|
+
}
|
|
7602
7625
|
const start = Date.now();
|
|
7603
7626
|
if (session) {
|
|
7604
7627
|
streamCommandEvent(session.id, {
|
|
@@ -7627,7 +7650,17 @@ async function executeCommand(commandName, params, sessionName = "default", extr
|
|
|
7627
7650
|
if (hooks.length > 0 && session?.page) {
|
|
7628
7651
|
await Promise.all(hooks.map((h) => h.onBeforeCommand?.({ page: session.page, command: commandName, params })));
|
|
7629
7652
|
}
|
|
7630
|
-
|
|
7653
|
+
let raw;
|
|
7654
|
+
const handlerPromise = command.handler(params, ctx);
|
|
7655
|
+
if (extraOpts?.timeout && extraOpts.timeout > 0) {
|
|
7656
|
+
const timeoutMs = extraOpts.timeout;
|
|
7657
|
+
const timeoutPromise = new Promise(
|
|
7658
|
+
(_, reject) => setTimeout(() => reject(new Error(`Command timed out after ${timeoutMs}ms`)), timeoutMs)
|
|
7659
|
+
);
|
|
7660
|
+
raw = await Promise.race([handlerPromise, timeoutPromise]);
|
|
7661
|
+
} else {
|
|
7662
|
+
raw = await handlerPromise;
|
|
7663
|
+
}
|
|
7631
7664
|
const end = Date.now();
|
|
7632
7665
|
const duration = end - start;
|
|
7633
7666
|
let hookOutputs;
|
|
@@ -7731,7 +7764,7 @@ async function executeCommand(commandName, params, sessionName = "default", extr
|
|
|
7731
7764
|
duration,
|
|
7732
7765
|
timestamp: start
|
|
7733
7766
|
});
|
|
7734
|
-
return { ...
|
|
7767
|
+
return { ...fail9(errorMessage), duration };
|
|
7735
7768
|
} finally {
|
|
7736
7769
|
}
|
|
7737
7770
|
}
|
|
@@ -7772,7 +7805,7 @@ async function executeChain(input, options) {
|
|
|
7772
7805
|
results.push({
|
|
7773
7806
|
command: cmdName,
|
|
7774
7807
|
raw: cmdStr,
|
|
7775
|
-
...
|
|
7808
|
+
...fail9(`Plugin "${cmdName}" requires a sub-command`),
|
|
7776
7809
|
duration: 0
|
|
7777
7810
|
});
|
|
7778
7811
|
if (type === "and") {
|
|
@@ -7791,7 +7824,7 @@ async function executeChain(input, options) {
|
|
|
7791
7824
|
results.push({
|
|
7792
7825
|
command: cmdName,
|
|
7793
7826
|
raw: cmdStr,
|
|
7794
|
-
...
|
|
7827
|
+
...fail9(`Unknown command "${subCommand}" for plugin "${cmdName}"`),
|
|
7795
7828
|
duration: 0
|
|
7796
7829
|
});
|
|
7797
7830
|
if (type === "and") {
|
|
@@ -7923,7 +7956,7 @@ async function executeChain(input, options) {
|
|
|
7923
7956
|
results.push({
|
|
7924
7957
|
command: `${cmdName} ${subCommand}`,
|
|
7925
7958
|
raw: cmdStr,
|
|
7926
|
-
...
|
|
7959
|
+
...fail9(errorMessage),
|
|
7927
7960
|
duration: duration2
|
|
7928
7961
|
});
|
|
7929
7962
|
if (type === "and") {
|
|
@@ -8201,16 +8234,29 @@ var configBuiltin = {
|
|
|
8201
8234
|
execute: async (args, _options, _ctx) => {
|
|
8202
8235
|
const [subcommand, ...rest] = args;
|
|
8203
8236
|
if (!subcommand || subcommand === "list") {
|
|
8237
|
+
let flatten2 = function(obj, prefix = "") {
|
|
8238
|
+
const entries2 = [];
|
|
8239
|
+
for (const [k, v] of Object.entries(obj)) {
|
|
8240
|
+
const fullKey = prefix ? `${prefix}.${k}` : k;
|
|
8241
|
+
if (v && typeof v === "object" && !Array.isArray(v)) {
|
|
8242
|
+
entries2.push(...flatten2(v, fullKey));
|
|
8243
|
+
} else {
|
|
8244
|
+
entries2.push({ key: fullKey, value: v });
|
|
8245
|
+
}
|
|
8246
|
+
}
|
|
8247
|
+
return entries2;
|
|
8248
|
+
};
|
|
8249
|
+
var flatten = flatten2;
|
|
8204
8250
|
const config = loadConfig();
|
|
8205
|
-
const
|
|
8206
|
-
if (
|
|
8251
|
+
const entries = flatten2(config);
|
|
8252
|
+
if (entries.length === 0) {
|
|
8207
8253
|
console.log("Configuration is empty");
|
|
8208
8254
|
return;
|
|
8209
8255
|
}
|
|
8210
8256
|
console.log("Configuration:");
|
|
8211
8257
|
console.log("");
|
|
8212
|
-
for (const
|
|
8213
|
-
console.log(` ${
|
|
8258
|
+
for (const { key, value } of entries) {
|
|
8259
|
+
console.log(` ${key} = ${value}`);
|
|
8214
8260
|
}
|
|
8215
8261
|
return;
|
|
8216
8262
|
}
|
|
@@ -9009,6 +9055,39 @@ function outputError(message) {
|
|
|
9009
9055
|
console.error(formatted);
|
|
9010
9056
|
process.exit(1);
|
|
9011
9057
|
}
|
|
9058
|
+
function outputEnvelope(result, meta, mode) {
|
|
9059
|
+
if (mode !== "json" && mode !== "yaml") {
|
|
9060
|
+
if (!result.success) {
|
|
9061
|
+
outputError(result.message || "Unknown error");
|
|
9062
|
+
return;
|
|
9063
|
+
}
|
|
9064
|
+
outputResult(result.data, mode);
|
|
9065
|
+
return;
|
|
9066
|
+
}
|
|
9067
|
+
const { command, ...extraMeta } = meta;
|
|
9068
|
+
const commandResult = {
|
|
9069
|
+
success: result.success,
|
|
9070
|
+
data: result.data,
|
|
9071
|
+
message: result.message,
|
|
9072
|
+
tips: [],
|
|
9073
|
+
meta: {
|
|
9074
|
+
duration: result.duration ?? 0,
|
|
9075
|
+
...extraMeta
|
|
9076
|
+
}
|
|
9077
|
+
};
|
|
9078
|
+
const formatted = outputFormatter.formatEnvelope(commandResult, {
|
|
9079
|
+
command,
|
|
9080
|
+
extraMeta,
|
|
9081
|
+
mode
|
|
9082
|
+
});
|
|
9083
|
+
console.log(formatted);
|
|
9084
|
+
if (result.tips?.length) {
|
|
9085
|
+
for (const tip of result.tips) {
|
|
9086
|
+
const text = typeof tip === "string" ? tip : tip.message;
|
|
9087
|
+
if (text) console.error(` \u{1F4A1} ${text}`);
|
|
9088
|
+
}
|
|
9089
|
+
}
|
|
9090
|
+
}
|
|
9012
9091
|
|
|
9013
9092
|
// src/builtins/plugin.ts
|
|
9014
9093
|
var pluginLoader2 = null;
|
|
@@ -10573,9 +10652,13 @@ async function handleBrowserCommand(command, args, options, sessionName, mode, c
|
|
|
10573
10652
|
if (target) {
|
|
10574
10653
|
params = { ...params, _target: target };
|
|
10575
10654
|
}
|
|
10655
|
+
const tabIndex = options.tab;
|
|
10656
|
+
if (tabIndex !== void 0) {
|
|
10657
|
+
params = { ...params, _tabIndex: Number(tabIndex) };
|
|
10658
|
+
}
|
|
10576
10659
|
const result = cdpEndpoint ? await executeCommand(cmdName, params, sessionName, { cdpEndpoint }) : await executeCommand(cmdName, params, sessionName);
|
|
10577
10660
|
if (mode === "json" || mode === "yaml") {
|
|
10578
|
-
|
|
10661
|
+
outputEnvelope(result, { command: cmdName }, mode);
|
|
10579
10662
|
} else if (!result.success) {
|
|
10580
10663
|
outputError(result.message || "Command failed");
|
|
10581
10664
|
} else {
|
|
@@ -10635,7 +10718,7 @@ async function handleSession(args, options, mode, _cdpEndpoint) {
|
|
|
10635
10718
|
}
|
|
10636
10719
|
} catch {
|
|
10637
10720
|
}
|
|
10638
|
-
|
|
10721
|
+
outputEnvelope({ success: true, data: { closed: count, all: true } }, { command: "session close" }, mode);
|
|
10639
10722
|
} else {
|
|
10640
10723
|
const name = options.session || options.name || process.env.XBROWSER_SESSION || "default";
|
|
10641
10724
|
try {
|
|
@@ -10643,7 +10726,7 @@ async function handleSession(args, options, mode, _cdpEndpoint) {
|
|
|
10643
10726
|
} catch {
|
|
10644
10727
|
}
|
|
10645
10728
|
await closeSession(name);
|
|
10646
|
-
|
|
10729
|
+
outputEnvelope({ success: true, data: { name } }, { command: "session close" }, mode);
|
|
10647
10730
|
}
|
|
10648
10731
|
break;
|
|
10649
10732
|
}
|
|
@@ -10651,10 +10734,10 @@ async function handleSession(args, options, mode, _cdpEndpoint) {
|
|
|
10651
10734
|
case "ls": {
|
|
10652
10735
|
try {
|
|
10653
10736
|
const sessions2 = await forwardSessionList();
|
|
10654
|
-
|
|
10737
|
+
outputEnvelope({ success: true, data: { sessions: sessions2 } }, { command: "session list" }, mode);
|
|
10655
10738
|
} catch {
|
|
10656
10739
|
const sessions2 = await listSessions();
|
|
10657
|
-
|
|
10740
|
+
outputEnvelope({ success: true, data: { sessions: sessions2 } }, { command: "session list" }, mode);
|
|
10658
10741
|
}
|
|
10659
10742
|
break;
|
|
10660
10743
|
}
|
|
@@ -10669,7 +10752,7 @@ async function handleSession(args, options, mode, _cdpEndpoint) {
|
|
|
10669
10752
|
await stopDaemonProcess();
|
|
10670
10753
|
} catch {
|
|
10671
10754
|
}
|
|
10672
|
-
|
|
10755
|
+
outputEnvelope({ success: true, data: { name, killed: true, daemon: "stopped" } }, { command: "session kill" }, mode);
|
|
10673
10756
|
break;
|
|
10674
10757
|
}
|
|
10675
10758
|
case "kill-all": {
|
|
@@ -10688,7 +10771,7 @@ async function handleSession(args, options, mode, _cdpEndpoint) {
|
|
|
10688
10771
|
} catch {
|
|
10689
10772
|
}
|
|
10690
10773
|
const cleaned = cleanSessionFiles();
|
|
10691
|
-
|
|
10774
|
+
outputEnvelope({ success: true, data: { sessionsCleaned: cleaned, daemon: "killed" } }, { command: "session kill-all" }, mode);
|
|
10692
10775
|
break;
|
|
10693
10776
|
}
|
|
10694
10777
|
default:
|
|
@@ -10808,7 +10891,7 @@ async function handleSearch(args, options, mode) {
|
|
|
10808
10891
|
}
|
|
10809
10892
|
}
|
|
10810
10893
|
if (mode === "json") {
|
|
10811
|
-
|
|
10894
|
+
outputEnvelope({ success: true, data: { results, total: results.length } }, { command: "plugin search" }, mode);
|
|
10812
10895
|
} else {
|
|
10813
10896
|
if (results.length === 0) {
|
|
10814
10897
|
console.log("No plugins found");
|
|
@@ -10837,7 +10920,7 @@ async function handlePluginInfo(args, options, mode) {
|
|
|
10837
10920
|
if (pluginInfo) {
|
|
10838
10921
|
const d = pluginInfo;
|
|
10839
10922
|
if (mode === "json") {
|
|
10840
|
-
|
|
10923
|
+
outputEnvelope({ success: true, data: { source: "marketplace", ...d } }, { command: "plugin info" }, mode);
|
|
10841
10924
|
return;
|
|
10842
10925
|
}
|
|
10843
10926
|
console.log(`\u540D\u79F0: ${d.name || ""}`);
|
|
@@ -10863,7 +10946,7 @@ async function handlePluginInfo(args, options, mode) {
|
|
|
10863
10946
|
const pkg = latest && versions?.[latest];
|
|
10864
10947
|
if (pkg) {
|
|
10865
10948
|
if (mode === "json") {
|
|
10866
|
-
|
|
10949
|
+
outputEnvelope({ success: true, data: { source: "npm", name: pkg.name, version: latest, description: pkg.description } }, { command: "plugin info" }, mode);
|
|
10867
10950
|
return;
|
|
10868
10951
|
}
|
|
10869
10952
|
console.log(`\u540D\u79F0: ${pkg.name || ""}`);
|
|
@@ -10892,7 +10975,7 @@ async function handlePluginSchema(args, mode) {
|
|
|
10892
10975
|
return;
|
|
10893
10976
|
}
|
|
10894
10977
|
if (mode === "json") {
|
|
10895
|
-
|
|
10978
|
+
outputEnvelope({ success: true, data: contract }, { command: "plugin schema" }, mode);
|
|
10896
10979
|
return;
|
|
10897
10980
|
}
|
|
10898
10981
|
if ("commands" in contract) {
|
|
@@ -10970,8 +11053,9 @@ async function handlePlugin(args, options, mode) {
|
|
|
10970
11053
|
}
|
|
10971
11054
|
} catch {
|
|
10972
11055
|
}
|
|
10973
|
-
|
|
10974
|
-
{
|
|
11056
|
+
outputEnvelope(
|
|
11057
|
+
{ success: true, data: { name: result.name, source: result.source, path: result.path } },
|
|
11058
|
+
{ command: "plugin install" },
|
|
10975
11059
|
mode
|
|
10976
11060
|
);
|
|
10977
11061
|
break;
|
|
@@ -10990,7 +11074,7 @@ async function handlePlugin(args, options, mode) {
|
|
|
10990
11074
|
await loader.reloadPlugin(name);
|
|
10991
11075
|
} catch {
|
|
10992
11076
|
}
|
|
10993
|
-
|
|
11077
|
+
outputEnvelope({ success: true, data: { name } }, { command: "plugin uninstall" }, mode);
|
|
10994
11078
|
break;
|
|
10995
11079
|
}
|
|
10996
11080
|
case "list": {
|
|
@@ -11012,7 +11096,7 @@ async function handlePlugin(args, options, mode) {
|
|
|
11012
11096
|
};
|
|
11013
11097
|
});
|
|
11014
11098
|
if (mode === "json") {
|
|
11015
|
-
|
|
11099
|
+
outputEnvelope({ success: true, data: { plugins: enrichedPlugins } }, { command: "plugin list" }, mode);
|
|
11016
11100
|
} else {
|
|
11017
11101
|
if (enrichedPlugins.length === 0) {
|
|
11018
11102
|
console.log("No plugins installed");
|
|
@@ -11048,7 +11132,7 @@ Total: ${enrichedPlugins.length} plugins`);
|
|
|
11048
11132
|
} catch {
|
|
11049
11133
|
outputError(`Plugin "${name}" not found. Use 'xbrowser plugin list' to see installed plugins.`);
|
|
11050
11134
|
}
|
|
11051
|
-
|
|
11135
|
+
outputEnvelope({ success: true, data: { name } }, { command: "plugin reload" }, mode);
|
|
11052
11136
|
break;
|
|
11053
11137
|
}
|
|
11054
11138
|
case "search":
|
|
@@ -11080,24 +11164,22 @@ function handleDaemon(args, options, mode) {
|
|
|
11080
11164
|
case "start": {
|
|
11081
11165
|
const port = options.port ? Number(options.port) : 9224;
|
|
11082
11166
|
startDaemonProcess(port).then(
|
|
11083
|
-
(config) =>
|
|
11167
|
+
(config) => outputEnvelope({ success: true, data: { pid: config.pid, port: config.port } }, { command: "daemon start" }, mode)
|
|
11084
11168
|
).catch(
|
|
11085
11169
|
(e) => outputError(e instanceof Error ? e.message : String(e))
|
|
11086
11170
|
);
|
|
11087
11171
|
break;
|
|
11088
11172
|
}
|
|
11089
11173
|
case "stop": {
|
|
11090
|
-
stopDaemonProcess().then(() =>
|
|
11174
|
+
stopDaemonProcess().then(() => outputEnvelope({ success: true, data: {} }, { command: "daemon stop" }, mode)).catch(
|
|
11091
11175
|
(e) => outputError(e instanceof Error ? e.message : String(e))
|
|
11092
11176
|
);
|
|
11093
11177
|
break;
|
|
11094
11178
|
}
|
|
11095
11179
|
case "status": {
|
|
11096
11180
|
const status = getDaemonProcessStatus();
|
|
11097
|
-
|
|
11098
|
-
|
|
11099
|
-
mode
|
|
11100
|
-
);
|
|
11181
|
+
const statusData = status.running ? { running: true, pid: status.pid, port: status.port } : { running: false };
|
|
11182
|
+
outputEnvelope({ success: true, data: statusData }, { command: "daemon status" }, mode);
|
|
11101
11183
|
break;
|
|
11102
11184
|
}
|
|
11103
11185
|
default:
|
|
@@ -11475,7 +11557,7 @@ async function handleFilter(args, _mode, options) {
|
|
|
11475
11557
|
console.log(` Original: ${result.originalCount}, After: ${result.filteredCount}, Removed: ${result.removed} (${result.percentage}%)`);
|
|
11476
11558
|
}
|
|
11477
11559
|
async function handleGeneratePlugin(sessionName, pluginName, outputDir) {
|
|
11478
|
-
const { SessionRecorder: SessionRecorder2 } = await import("./session-recorder-
|
|
11560
|
+
const { SessionRecorder: SessionRecorder2 } = await import("./session-recorder-33UKWCIR.js");
|
|
11479
11561
|
const { readSiteKnowledge: readSiteKnowledge2, toMarkdown } = await import("./site-knowledge-SYC6VCDB.js");
|
|
11480
11562
|
const { mkdirSync: mkdirSync11, writeFileSync: writeFileSync13 } = await import("fs");
|
|
11481
11563
|
const { join: join14 } = await import("path");
|
|
@@ -12822,7 +12904,8 @@ var KNOWN_GLOBAL_OPTIONS = /* @__PURE__ */ new Set([
|
|
|
12822
12904
|
"port",
|
|
12823
12905
|
"token",
|
|
12824
12906
|
"timeout",
|
|
12825
|
-
"headless"
|
|
12907
|
+
"headless",
|
|
12908
|
+
"tab"
|
|
12826
12909
|
]);
|
|
12827
12910
|
function showCommandHelp(siteName, cmd, siteConfig, mode) {
|
|
12828
12911
|
const c = cmd;
|
|
@@ -12976,20 +13059,28 @@ async function handleEvalMode(argv) {
|
|
|
12976
13059
|
}
|
|
12977
13060
|
async function handleChainInput(input, argv) {
|
|
12978
13061
|
const cdpEndpoint = argv ? extractCdpFromArgv(argv) : void 0;
|
|
12979
|
-
const
|
|
13062
|
+
const hasJson = argv ? argv.some((a) => a === "--json" || a.startsWith("--json=") || a.includes(" --json") || a.startsWith("--json")) || argv.includes("-j") : false;
|
|
13063
|
+
const hasYaml = argv ? argv.some((a) => a === "--yaml" || a.startsWith("--yaml=")) : false;
|
|
13064
|
+
const mode = hasJson ? "json" : hasYaml ? "yaml" : "text";
|
|
12980
13065
|
const chainResult = await executeChain(input, { cdpEndpoint });
|
|
12981
|
-
if (
|
|
12982
|
-
|
|
12983
|
-
|
|
12984
|
-
|
|
12985
|
-
|
|
12986
|
-
|
|
12987
|
-
|
|
12988
|
-
|
|
12989
|
-
|
|
12990
|
-
|
|
12991
|
-
|
|
12992
|
-
|
|
13066
|
+
if (mode === "json" || mode === "yaml") {
|
|
13067
|
+
outputEnvelope(
|
|
13068
|
+
{
|
|
13069
|
+
success: chainResult.success,
|
|
13070
|
+
data: {
|
|
13071
|
+
steps: chainResult.steps.map((s) => ({
|
|
13072
|
+
command: s.raw,
|
|
13073
|
+
success: s.success,
|
|
13074
|
+
data: s.data,
|
|
13075
|
+
duration: s.duration,
|
|
13076
|
+
...s.hookOutputs?.length ? { hooks: s.hookOutputs } : {}
|
|
13077
|
+
}))
|
|
13078
|
+
},
|
|
13079
|
+
duration: chainResult.totalDuration
|
|
13080
|
+
},
|
|
13081
|
+
{ command: "chain", totalSteps: chainResult.steps.length },
|
|
13082
|
+
mode
|
|
13083
|
+
);
|
|
12993
13084
|
} else {
|
|
12994
13085
|
printChainResult(chainResult);
|
|
12995
13086
|
}
|
|
@@ -13056,7 +13147,15 @@ async function routeCommand(argvIn, stdinCommands) {
|
|
|
13056
13147
|
const sessionName = options.session || process.env.XBROWSER_SESSION || "default";
|
|
13057
13148
|
const cdpEndpoint = options.cdp || process.env.XBROWSER_CDP;
|
|
13058
13149
|
if (options.version || options.v && positional.length === 0) {
|
|
13059
|
-
|
|
13150
|
+
if (mode === "json") {
|
|
13151
|
+
outputEnvelope(
|
|
13152
|
+
{ success: true, data: { version, name: "@xbrowser/cli" } },
|
|
13153
|
+
{ command: "version" },
|
|
13154
|
+
mode
|
|
13155
|
+
);
|
|
13156
|
+
} else {
|
|
13157
|
+
console.log(`xbrowser v${version}`);
|
|
13158
|
+
}
|
|
13060
13159
|
return;
|
|
13061
13160
|
}
|
|
13062
13161
|
if (positional.length === 0) {
|
|
@@ -13252,18 +13351,23 @@ async function routeCommand(argvIn, stdinCommands) {
|
|
|
13252
13351
|
if (isChainInput(fullInput)) {
|
|
13253
13352
|
const chainResult = await executeChain(fullInput, { cdpEndpoint, sessionName });
|
|
13254
13353
|
if (mode === "json" || mode === "yaml") {
|
|
13255
|
-
|
|
13256
|
-
|
|
13257
|
-
|
|
13258
|
-
|
|
13259
|
-
|
|
13260
|
-
|
|
13261
|
-
|
|
13262
|
-
|
|
13263
|
-
|
|
13264
|
-
|
|
13265
|
-
|
|
13266
|
-
|
|
13354
|
+
outputEnvelope(
|
|
13355
|
+
{
|
|
13356
|
+
success: chainResult.success,
|
|
13357
|
+
data: {
|
|
13358
|
+
steps: chainResult.steps.map((s) => ({
|
|
13359
|
+
command: s.raw,
|
|
13360
|
+
success: s.success,
|
|
13361
|
+
data: s.data,
|
|
13362
|
+
duration: s.duration
|
|
13363
|
+
})),
|
|
13364
|
+
...chainResult.stoppedReason ? { stoppedReason: chainResult.stoppedReason } : {}
|
|
13365
|
+
},
|
|
13366
|
+
duration: chainResult.totalDuration
|
|
13367
|
+
},
|
|
13368
|
+
{ command: "chain", totalSteps: chainResult.steps.length },
|
|
13369
|
+
mode
|
|
13370
|
+
);
|
|
13267
13371
|
if (!chainResult.success) throw new Error("Command failed");
|
|
13268
13372
|
return;
|
|
13269
13373
|
}
|
|
@@ -13408,6 +13512,17 @@ Run "xbrowser ${command} ${subCommand} --help" to see available parameters.`
|
|
|
13408
13512
|
session = await createSession(sessionName, void 0, cdpEndpoint ? { cdpEndpoint } : {});
|
|
13409
13513
|
}
|
|
13410
13514
|
}
|
|
13515
|
+
const cmdTabIndex = options.tab !== void 0 ? Number(options.tab) : void 0;
|
|
13516
|
+
if (cmdTabIndex !== void 0 && session?.context) {
|
|
13517
|
+
const pages = session.context.pages();
|
|
13518
|
+
if (cmdTabIndex >= 0 && cmdTabIndex < pages.length) {
|
|
13519
|
+
const targetPage = pages[cmdTabIndex];
|
|
13520
|
+
await targetPage.bringToFront().catch(() => {
|
|
13521
|
+
});
|
|
13522
|
+
const { setActivePage: setActivePage2 } = await import("./browser-TLIDFFEG.js");
|
|
13523
|
+
setActivePage2(session, targetPage);
|
|
13524
|
+
}
|
|
13525
|
+
}
|
|
13411
13526
|
const ctx = {
|
|
13412
13527
|
args: cmdArgsForPlugin,
|
|
13413
13528
|
options,
|
|
@@ -13485,22 +13600,17 @@ Run "xbrowser ${command} ${subCommand} --help" to see available parameters.`
|
|
|
13485
13600
|
const outputData = isCommandResult2(result) ? result.data : result && typeof result === "object" ? result.data ?? result : result;
|
|
13486
13601
|
const tips = isCommandResult2(result) ? result.tips : result && typeof result === "object" ? result.tips : void 0;
|
|
13487
13602
|
if (mode === "json" || mode === "yaml") {
|
|
13488
|
-
const
|
|
13489
|
-
|
|
13490
|
-
|
|
13491
|
-
|
|
13492
|
-
|
|
13493
|
-
|
|
13494
|
-
|
|
13495
|
-
|
|
13496
|
-
|
|
13497
|
-
|
|
13498
|
-
|
|
13499
|
-
}
|
|
13500
|
-
console.log(outputFormatter2.format(finalOutput, { mode, color: false, emoji: false }));
|
|
13501
|
-
if (tips?.length) {
|
|
13502
|
-
for (const tip of tips) console.error(`\u{1F4A1} ${typeof tip === "string" ? tip : tip.message}`);
|
|
13503
|
-
}
|
|
13603
|
+
const resultSuccess = isCommandResult2(result) ? result.success !== false : true;
|
|
13604
|
+
const resultMsg = isCommandResult2(result) ? result.message : void 0;
|
|
13605
|
+
const duration = Date.now() - cmdStart;
|
|
13606
|
+
const envelopeMeta = { command: `${command} ${subCommand}` };
|
|
13607
|
+
if (injectedViewerUrl) envelopeMeta.viewerUrl = injectedViewerUrl;
|
|
13608
|
+
if (hookOutputs.length > 0) envelopeMeta.hooks = hookOutputs;
|
|
13609
|
+
outputEnvelope(
|
|
13610
|
+
{ success: resultSuccess, data: outputData, message: resultMsg, tips, duration },
|
|
13611
|
+
envelopeMeta,
|
|
13612
|
+
mode
|
|
13613
|
+
);
|
|
13504
13614
|
} else {
|
|
13505
13615
|
console.log(outputFormatter2.format(outputData, { mode: "text", color: true, emoji: true }));
|
|
13506
13616
|
if (tips?.length) {
|