@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/cli.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
3
|
SessionRecorder
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-RMYEHTLS.js";
|
|
5
5
|
import {
|
|
6
6
|
addKnownIssue,
|
|
7
7
|
getKnowledgePath,
|
|
@@ -25,7 +25,7 @@ import {
|
|
|
25
25
|
resolveLaunchOpts,
|
|
26
26
|
saveSessionDiskMeta,
|
|
27
27
|
setActivePage
|
|
28
|
-
} from "./chunk-
|
|
28
|
+
} from "./chunk-SJLRCE6N.js";
|
|
29
29
|
import "./chunk-TNEN6VQ2.js";
|
|
30
30
|
import {
|
|
31
31
|
forwardCommandLog,
|
|
@@ -182,7 +182,7 @@ function asZodSchema(value) {
|
|
|
182
182
|
// src/executor.ts
|
|
183
183
|
import {
|
|
184
184
|
ok as ok25,
|
|
185
|
-
fail as
|
|
185
|
+
fail as fail9,
|
|
186
186
|
isCommandResult,
|
|
187
187
|
CompositeStorage as CompositeStorage2,
|
|
188
188
|
TipCollector as TipCollector2,
|
|
@@ -2316,7 +2316,7 @@ var scrapeCommand = registerCommand({
|
|
|
2316
2316
|
scope: "project",
|
|
2317
2317
|
selectorParams: ["selector"],
|
|
2318
2318
|
parameters: z15.object({
|
|
2319
|
-
url: z15.string(),
|
|
2319
|
+
url: z15.string().optional(),
|
|
2320
2320
|
selector: z15.string().optional(),
|
|
2321
2321
|
timeout: z15.number().default(3e4),
|
|
2322
2322
|
format: z15.enum(["markdown", "html", "text"]).default("markdown"),
|
|
@@ -2329,10 +2329,14 @@ var scrapeCommand = registerCommand({
|
|
|
2329
2329
|
const { context, page } = await createEphemeralContext(resolveLaunchOpts(ctx));
|
|
2330
2330
|
const maxAttempts = p.retries + 1;
|
|
2331
2331
|
try {
|
|
2332
|
+
const targetUrl = p.url || page.url();
|
|
2333
|
+
if (!targetUrl || targetUrl === "about:blank") {
|
|
2334
|
+
return fail3("URL is required. Provide a URL or connect to a browser (--cdp) with a non-blank page.");
|
|
2335
|
+
}
|
|
2332
2336
|
let lastError;
|
|
2333
2337
|
for (let attempt = 1; attempt <= maxAttempts; attempt++) {
|
|
2334
2338
|
try {
|
|
2335
|
-
await page.goto(
|
|
2339
|
+
await page.goto(targetUrl, { waitUntil: "commit", timeout: p.timeout });
|
|
2336
2340
|
await page.waitForSelector("body", { timeout: p.timeout }).catch(() => {
|
|
2337
2341
|
});
|
|
2338
2342
|
await page.waitForLoadState("networkidle", Math.min(p.timeout, 8e3)).catch(() => {
|
|
@@ -2393,7 +2397,7 @@ var scrapeCommand = registerCommand({
|
|
|
2393
2397
|
return { url: location.href, title: document.title, navigation, tables, forms: forms.slice(0, 20), links: links.slice(0, 30), mainText };
|
|
2394
2398
|
});
|
|
2395
2399
|
try {
|
|
2396
|
-
persistFromScrape(
|
|
2400
|
+
persistFromScrape(targetUrl, structured);
|
|
2397
2401
|
} catch {
|
|
2398
2402
|
}
|
|
2399
2403
|
if (p.mode === "smart") {
|
|
@@ -2494,7 +2498,7 @@ var scrapeCommand = registerCommand({
|
|
|
2494
2498
|
|
|
2495
2499
|
// src/commands/map.ts
|
|
2496
2500
|
import { z as z16 } from "zod";
|
|
2497
|
-
import { ok as ok16 } from "@dyyz1993/xcli-core";
|
|
2501
|
+
import { ok as ok16, fail as fail4 } from "@dyyz1993/xcli-core";
|
|
2498
2502
|
|
|
2499
2503
|
// src/utils/url.ts
|
|
2500
2504
|
var SKIP_EXTENSIONS = /* @__PURE__ */ new Set([
|
|
@@ -2730,7 +2734,7 @@ var mapCommand = registerCommand({
|
|
|
2730
2734
|
description: "Discover all URLs on a website via sitemap and page link extraction",
|
|
2731
2735
|
scope: "project",
|
|
2732
2736
|
parameters: z16.object({
|
|
2733
|
-
url: z16.string(),
|
|
2737
|
+
url: z16.string().optional(),
|
|
2734
2738
|
search: z16.string().optional(),
|
|
2735
2739
|
sitemap: z16.enum(["include", "only"]).optional(),
|
|
2736
2740
|
includeSubdomains: z16.boolean().optional(),
|
|
@@ -2741,7 +2745,11 @@ var mapCommand = registerCommand({
|
|
|
2741
2745
|
handler: async (p, ctx) => {
|
|
2742
2746
|
const { context, page } = await createEphemeralContext(resolveLaunchOpts(ctx));
|
|
2743
2747
|
try {
|
|
2744
|
-
const
|
|
2748
|
+
const targetUrl = p.url || page.url();
|
|
2749
|
+
if (!targetUrl || targetUrl === "about:blank") {
|
|
2750
|
+
return fail4("URL is required. Provide a URL or connect to a browser (--cdp) with a non-blank page.");
|
|
2751
|
+
}
|
|
2752
|
+
const links = await discoverUrls(page, targetUrl, {
|
|
2745
2753
|
sitemap: p.sitemap,
|
|
2746
2754
|
includeSubdomains: p.includeSubdomains,
|
|
2747
2755
|
allowExternalLinks: p.allowExternalLinks,
|
|
@@ -3584,7 +3592,7 @@ ${errors.map((e) => ` - ${e.engine}: ${e.error}`).join("\n")}`
|
|
|
3584
3592
|
|
|
3585
3593
|
// src/commands/network.ts
|
|
3586
3594
|
import { z as z19 } from "zod";
|
|
3587
|
-
import { ok as ok19, fail as
|
|
3595
|
+
import { ok as ok19, fail as fail5 } from "@dyyz1993/xcli-core";
|
|
3588
3596
|
function extractPath2(url) {
|
|
3589
3597
|
try {
|
|
3590
3598
|
const u = new URL(url);
|
|
@@ -3749,7 +3757,7 @@ var networkCommand = registerCommand({
|
|
|
3749
3757
|
};
|
|
3750
3758
|
if (p.listen) {
|
|
3751
3759
|
const page2 = ctx.page;
|
|
3752
|
-
if (!page2) return
|
|
3760
|
+
if (!page2) return fail5("No active page. Use --cdp to connect first.");
|
|
3753
3761
|
const captures = [];
|
|
3754
3762
|
const consoleMessages = [];
|
|
3755
3763
|
const wsCaptures = [];
|
|
@@ -4129,7 +4137,7 @@ var ENGINE_KEY_ENUM = z20.enum(ALL_ENGINE_KEYS);
|
|
|
4129
4137
|
|
|
4130
4138
|
// src/commands/snapshot.ts
|
|
4131
4139
|
import { z as z21 } from "zod";
|
|
4132
|
-
import { ok as ok20, fail as
|
|
4140
|
+
import { ok as ok20, fail as fail6, normalizeTips as normalizeTips3 } from "@dyyz1993/xcli-core";
|
|
4133
4141
|
|
|
4134
4142
|
// src/runtime/ref-store.ts
|
|
4135
4143
|
var sessions = /* @__PURE__ */ new Map();
|
|
@@ -5100,7 +5108,7 @@ var snapshotCommand = registerCommand({
|
|
|
5100
5108
|
persistSemantics(url, aria);
|
|
5101
5109
|
return ok20({ url, title, aria, text, dom }, normalizeTips3(tips));
|
|
5102
5110
|
}
|
|
5103
|
-
return
|
|
5111
|
+
return fail6(`Unknown snapshot type: ${p.type}`);
|
|
5104
5112
|
}
|
|
5105
5113
|
});
|
|
5106
5114
|
function persistSemantics(url, aria) {
|
|
@@ -5269,7 +5277,7 @@ var waitForCommand = registerCommand({
|
|
|
5269
5277
|
|
|
5270
5278
|
// src/commands/tab.ts
|
|
5271
5279
|
import { z as z23 } from "zod";
|
|
5272
|
-
import { ok as ok22, fail as
|
|
5280
|
+
import { ok as ok22, fail as fail7 } from "@dyyz1993/xcli-core";
|
|
5273
5281
|
var TabParams = z23.object({
|
|
5274
5282
|
subcommand: z23.enum(["list", "new", "close", "switch"]),
|
|
5275
5283
|
url: z23.string().optional(),
|
|
@@ -5286,7 +5294,7 @@ var tabCommand = registerCommand({
|
|
|
5286
5294
|
}),
|
|
5287
5295
|
handler: async (p, ctx) => {
|
|
5288
5296
|
if (!ctx.browserContext) {
|
|
5289
|
-
return
|
|
5297
|
+
return fail7("No browser context available. Use --cdp to connect to a browser first.");
|
|
5290
5298
|
}
|
|
5291
5299
|
const pages = ctx.browserContext.pages();
|
|
5292
5300
|
switch (p.subcommand) {
|
|
@@ -5299,7 +5307,7 @@ var tabCommand = registerCommand({
|
|
|
5299
5307
|
case "switch":
|
|
5300
5308
|
return handleSwitch(p, pages, ctx);
|
|
5301
5309
|
default:
|
|
5302
|
-
return
|
|
5310
|
+
return fail7(`Unknown subcommand: ${p.subcommand}`);
|
|
5303
5311
|
}
|
|
5304
5312
|
}
|
|
5305
5313
|
});
|
|
@@ -5356,11 +5364,11 @@ async function handleNew(p, _pages, ctx) {
|
|
|
5356
5364
|
}
|
|
5357
5365
|
async function handleClose(p, pages, ctx) {
|
|
5358
5366
|
if (pages.length <= 1) {
|
|
5359
|
-
return
|
|
5367
|
+
return fail7("Cannot close the last remaining tab");
|
|
5360
5368
|
}
|
|
5361
5369
|
const closeIndex = p.index ?? pages.indexOf(ctx.page);
|
|
5362
5370
|
if (closeIndex < 0 || closeIndex >= pages.length) {
|
|
5363
|
-
return
|
|
5371
|
+
return fail7(`Invalid tab index: ${closeIndex}. Valid range: 0-${pages.length - 1}`);
|
|
5364
5372
|
}
|
|
5365
5373
|
const pageToClose = pages[closeIndex];
|
|
5366
5374
|
const isActivePage = pageToClose === ctx.page;
|
|
@@ -5383,10 +5391,10 @@ async function handleClose(p, pages, ctx) {
|
|
|
5383
5391
|
}
|
|
5384
5392
|
async function handleSwitch(p, pages, ctx) {
|
|
5385
5393
|
if (p.index === void 0) {
|
|
5386
|
-
return
|
|
5394
|
+
return fail7("Parameter --index is required for switch subcommand");
|
|
5387
5395
|
}
|
|
5388
5396
|
if (p.index < 0 || p.index >= pages.length) {
|
|
5389
|
-
return
|
|
5397
|
+
return fail7(`Invalid tab index: ${p.index}. Valid range: 0-${pages.length - 1}`);
|
|
5390
5398
|
}
|
|
5391
5399
|
const targetPage = pages[p.index];
|
|
5392
5400
|
await targetPage.bringToFront().catch(() => {
|
|
@@ -5638,7 +5646,7 @@ registerCommandDefinition("addinitscript", ["script"]);
|
|
|
5638
5646
|
|
|
5639
5647
|
// src/commands/find.ts
|
|
5640
5648
|
import { z as z25 } from "zod";
|
|
5641
|
-
import { ok as ok24, fail as
|
|
5649
|
+
import { ok as ok24, fail as fail8, normalizeTips as normalizeTips5 } from "@dyyz1993/xcli-core";
|
|
5642
5650
|
var actionSchema2 = z25.enum(["click", "fill", "type", "select", "hover", "check"]);
|
|
5643
5651
|
var findCommand = registerCommand({
|
|
5644
5652
|
name: "find",
|
|
@@ -5679,7 +5687,7 @@ var findCommand = registerCommand({
|
|
|
5679
5687
|
});
|
|
5680
5688
|
const count = await locator.count();
|
|
5681
5689
|
if (count === 0) {
|
|
5682
|
-
return
|
|
5690
|
+
return fail8(`No element found with ${p.strategy}="${p.value}"`);
|
|
5683
5691
|
}
|
|
5684
5692
|
const tips = [];
|
|
5685
5693
|
const target = selectTarget(locator, p.strategy);
|
|
@@ -5691,15 +5699,15 @@ var findCommand = registerCommand({
|
|
|
5691
5699
|
await target.click({ timeout: p.timeout, force: true });
|
|
5692
5700
|
return okWithTips({ matched: count, selector, action: "click" }, tips);
|
|
5693
5701
|
} else if (actionName === "fill") {
|
|
5694
|
-
if (actionValue === void 0) return
|
|
5702
|
+
if (actionValue === void 0) return fail8("find fill requires a value");
|
|
5695
5703
|
await target.fill(actionValue, { timeout: p.timeout, force: true });
|
|
5696
5704
|
return okWithTips({ matched: count, selector, action: `fill("${actionValue}")` }, tips);
|
|
5697
5705
|
} else if (actionName === "type") {
|
|
5698
|
-
if (actionValue === void 0) return
|
|
5706
|
+
if (actionValue === void 0) return fail8("find type requires a value");
|
|
5699
5707
|
await target.type(actionValue, { delay: 10, timeout: p.timeout });
|
|
5700
5708
|
return okWithTips({ matched: count, selector, action: `type("${actionValue}")` }, tips);
|
|
5701
5709
|
} else if (actionName === "select") {
|
|
5702
|
-
if (actionValue === void 0) return
|
|
5710
|
+
if (actionValue === void 0) return fail8("find select requires a value");
|
|
5703
5711
|
await target.selectOption(actionValue);
|
|
5704
5712
|
return okWithTips({ matched: count, selector, action: `select("${actionValue}")` }, tips);
|
|
5705
5713
|
} else if (actionName === "hover") {
|
|
@@ -7135,7 +7143,7 @@ async function guardCheck(commandName) {
|
|
|
7135
7143
|
}
|
|
7136
7144
|
}
|
|
7137
7145
|
function errorResult(message) {
|
|
7138
|
-
return { ...
|
|
7146
|
+
return { ...fail9(message), duration: 0 };
|
|
7139
7147
|
}
|
|
7140
7148
|
function tipsToMessages(tips) {
|
|
7141
7149
|
if (!tips || tips.length === 0) return [];
|
|
@@ -7205,9 +7213,14 @@ async function executeCommand(commandName, params, sessionName = "default", extr
|
|
|
7205
7213
|
const { _target: _u, ...rest } = params;
|
|
7206
7214
|
params = rest;
|
|
7207
7215
|
}
|
|
7216
|
+
const _tabIndex = params._tabIndex;
|
|
7217
|
+
if (_tabIndex !== void 0) {
|
|
7218
|
+
const { _tabIndex: _u, ...rest } = params;
|
|
7219
|
+
params = rest;
|
|
7220
|
+
}
|
|
7208
7221
|
let targetPageOverride = null;
|
|
7209
7222
|
if (_target && extraOpts?.cdpEndpoint) {
|
|
7210
|
-
const { findTargetPage } = await import("./browser-
|
|
7223
|
+
const { findTargetPage } = await import("./browser-XPKM344Y.js");
|
|
7211
7224
|
targetPageOverride = await findTargetPage(extraOpts.cdpEndpoint, _target);
|
|
7212
7225
|
if (!targetPageOverride) {
|
|
7213
7226
|
return errorResult(`Target "${_target}" not found. Use 'xbrowser targets --cdp ${extraOpts.cdpEndpoint}' to list available pages.`);
|
|
@@ -7279,6 +7292,16 @@ async function executeCommand(commandName, params, sessionName = "default", extr
|
|
|
7279
7292
|
cliName: "xbrowser",
|
|
7280
7293
|
tips: new TipCollector2()
|
|
7281
7294
|
};
|
|
7295
|
+
if (_tabIndex !== void 0 && session?.context) {
|
|
7296
|
+
const pages = session.context.pages();
|
|
7297
|
+
if (_tabIndex >= 0 && _tabIndex < pages.length) {
|
|
7298
|
+
const targetPage = pages[_tabIndex];
|
|
7299
|
+
await targetPage.bringToFront().catch(() => {
|
|
7300
|
+
});
|
|
7301
|
+
setActivePage(session, targetPage);
|
|
7302
|
+
ctx.page = targetPage;
|
|
7303
|
+
}
|
|
7304
|
+
}
|
|
7282
7305
|
const start = Date.now();
|
|
7283
7306
|
if (session) {
|
|
7284
7307
|
streamCommandEvent(session.id, {
|
|
@@ -7307,7 +7330,17 @@ async function executeCommand(commandName, params, sessionName = "default", extr
|
|
|
7307
7330
|
if (hooks.length > 0 && session?.page) {
|
|
7308
7331
|
await Promise.all(hooks.map((h) => h.onBeforeCommand?.({ page: session.page, command: commandName, params })));
|
|
7309
7332
|
}
|
|
7310
|
-
|
|
7333
|
+
let raw;
|
|
7334
|
+
const handlerPromise = command.handler(params, ctx);
|
|
7335
|
+
if (extraOpts?.timeout && extraOpts.timeout > 0) {
|
|
7336
|
+
const timeoutMs = extraOpts.timeout;
|
|
7337
|
+
const timeoutPromise = new Promise(
|
|
7338
|
+
(_, reject) => setTimeout(() => reject(new Error(`Command timed out after ${timeoutMs}ms`)), timeoutMs)
|
|
7339
|
+
);
|
|
7340
|
+
raw = await Promise.race([handlerPromise, timeoutPromise]);
|
|
7341
|
+
} else {
|
|
7342
|
+
raw = await handlerPromise;
|
|
7343
|
+
}
|
|
7311
7344
|
const end = Date.now();
|
|
7312
7345
|
const duration = end - start;
|
|
7313
7346
|
let hookOutputs;
|
|
@@ -7411,7 +7444,7 @@ async function executeCommand(commandName, params, sessionName = "default", extr
|
|
|
7411
7444
|
duration,
|
|
7412
7445
|
timestamp: start
|
|
7413
7446
|
});
|
|
7414
|
-
return { ...
|
|
7447
|
+
return { ...fail9(errorMessage), duration };
|
|
7415
7448
|
} finally {
|
|
7416
7449
|
}
|
|
7417
7450
|
}
|
|
@@ -7452,7 +7485,7 @@ async function executeChain(input, options) {
|
|
|
7452
7485
|
results.push({
|
|
7453
7486
|
command: cmdName,
|
|
7454
7487
|
raw: cmdStr,
|
|
7455
|
-
...
|
|
7488
|
+
...fail9(`Plugin "${cmdName}" requires a sub-command`),
|
|
7456
7489
|
duration: 0
|
|
7457
7490
|
});
|
|
7458
7491
|
if (type === "and") {
|
|
@@ -7471,7 +7504,7 @@ async function executeChain(input, options) {
|
|
|
7471
7504
|
results.push({
|
|
7472
7505
|
command: cmdName,
|
|
7473
7506
|
raw: cmdStr,
|
|
7474
|
-
...
|
|
7507
|
+
...fail9(`Unknown command "${subCommand}" for plugin "${cmdName}"`),
|
|
7475
7508
|
duration: 0
|
|
7476
7509
|
});
|
|
7477
7510
|
if (type === "and") {
|
|
@@ -7603,7 +7636,7 @@ async function executeChain(input, options) {
|
|
|
7603
7636
|
results.push({
|
|
7604
7637
|
command: `${cmdName} ${subCommand}`,
|
|
7605
7638
|
raw: cmdStr,
|
|
7606
|
-
...
|
|
7639
|
+
...fail9(errorMessage),
|
|
7607
7640
|
duration: duration2
|
|
7608
7641
|
});
|
|
7609
7642
|
if (type === "and") {
|
|
@@ -7883,16 +7916,29 @@ var configBuiltin = {
|
|
|
7883
7916
|
execute: async (args, _options, _ctx) => {
|
|
7884
7917
|
const [subcommand, ...rest] = args;
|
|
7885
7918
|
if (!subcommand || subcommand === "list") {
|
|
7919
|
+
let flatten2 = function(obj, prefix = "") {
|
|
7920
|
+
const entries2 = [];
|
|
7921
|
+
for (const [k, v] of Object.entries(obj)) {
|
|
7922
|
+
const fullKey = prefix ? `${prefix}.${k}` : k;
|
|
7923
|
+
if (v && typeof v === "object" && !Array.isArray(v)) {
|
|
7924
|
+
entries2.push(...flatten2(v, fullKey));
|
|
7925
|
+
} else {
|
|
7926
|
+
entries2.push({ key: fullKey, value: v });
|
|
7927
|
+
}
|
|
7928
|
+
}
|
|
7929
|
+
return entries2;
|
|
7930
|
+
};
|
|
7931
|
+
var flatten = flatten2;
|
|
7886
7932
|
const config = loadConfig();
|
|
7887
|
-
const
|
|
7888
|
-
if (
|
|
7933
|
+
const entries = flatten2(config);
|
|
7934
|
+
if (entries.length === 0) {
|
|
7889
7935
|
console.log("Configuration is empty");
|
|
7890
7936
|
return;
|
|
7891
7937
|
}
|
|
7892
7938
|
console.log("Configuration:");
|
|
7893
7939
|
console.log("");
|
|
7894
|
-
for (const
|
|
7895
|
-
console.log(` ${
|
|
7940
|
+
for (const { key, value } of entries) {
|
|
7941
|
+
console.log(` ${key} = ${value}`);
|
|
7896
7942
|
}
|
|
7897
7943
|
return;
|
|
7898
7944
|
}
|
|
@@ -8691,6 +8737,39 @@ function outputError(message) {
|
|
|
8691
8737
|
console.error(formatted);
|
|
8692
8738
|
process.exit(1);
|
|
8693
8739
|
}
|
|
8740
|
+
function outputEnvelope(result, meta, mode) {
|
|
8741
|
+
if (mode !== "json" && mode !== "yaml") {
|
|
8742
|
+
if (!result.success) {
|
|
8743
|
+
outputError(result.message || "Unknown error");
|
|
8744
|
+
return;
|
|
8745
|
+
}
|
|
8746
|
+
outputResult(result.data, mode);
|
|
8747
|
+
return;
|
|
8748
|
+
}
|
|
8749
|
+
const { command, ...extraMeta } = meta;
|
|
8750
|
+
const commandResult = {
|
|
8751
|
+
success: result.success,
|
|
8752
|
+
data: result.data,
|
|
8753
|
+
message: result.message,
|
|
8754
|
+
tips: [],
|
|
8755
|
+
meta: {
|
|
8756
|
+
duration: result.duration ?? 0,
|
|
8757
|
+
...extraMeta
|
|
8758
|
+
}
|
|
8759
|
+
};
|
|
8760
|
+
const formatted = outputFormatter.formatEnvelope(commandResult, {
|
|
8761
|
+
command,
|
|
8762
|
+
extraMeta,
|
|
8763
|
+
mode
|
|
8764
|
+
});
|
|
8765
|
+
console.log(formatted);
|
|
8766
|
+
if (result.tips?.length) {
|
|
8767
|
+
for (const tip of result.tips) {
|
|
8768
|
+
const text = typeof tip === "string" ? tip : tip.message;
|
|
8769
|
+
if (text) console.error(` \u{1F4A1} ${text}`);
|
|
8770
|
+
}
|
|
8771
|
+
}
|
|
8772
|
+
}
|
|
8694
8773
|
|
|
8695
8774
|
// src/builtins/plugin.ts
|
|
8696
8775
|
var pluginLoader2 = null;
|
|
@@ -10250,9 +10329,13 @@ async function handleBrowserCommand(command, args, options, sessionName, mode, c
|
|
|
10250
10329
|
if (target) {
|
|
10251
10330
|
params = { ...params, _target: target };
|
|
10252
10331
|
}
|
|
10332
|
+
const tabIndex = options.tab;
|
|
10333
|
+
if (tabIndex !== void 0) {
|
|
10334
|
+
params = { ...params, _tabIndex: Number(tabIndex) };
|
|
10335
|
+
}
|
|
10253
10336
|
const result = cdpEndpoint ? await executeCommand(cmdName, params, sessionName, { cdpEndpoint }) : await executeCommand(cmdName, params, sessionName);
|
|
10254
10337
|
if (mode === "json" || mode === "yaml") {
|
|
10255
|
-
|
|
10338
|
+
outputEnvelope(result, { command: cmdName }, mode);
|
|
10256
10339
|
} else if (!result.success) {
|
|
10257
10340
|
outputError(result.message || "Command failed");
|
|
10258
10341
|
} else {
|
|
@@ -10312,7 +10395,7 @@ async function handleSession(args, options, mode, _cdpEndpoint) {
|
|
|
10312
10395
|
}
|
|
10313
10396
|
} catch {
|
|
10314
10397
|
}
|
|
10315
|
-
|
|
10398
|
+
outputEnvelope({ success: true, data: { closed: count, all: true } }, { command: "session close" }, mode);
|
|
10316
10399
|
} else {
|
|
10317
10400
|
const name = options.session || options.name || process.env.XBROWSER_SESSION || "default";
|
|
10318
10401
|
try {
|
|
@@ -10320,7 +10403,7 @@ async function handleSession(args, options, mode, _cdpEndpoint) {
|
|
|
10320
10403
|
} catch {
|
|
10321
10404
|
}
|
|
10322
10405
|
await closeSession(name);
|
|
10323
|
-
|
|
10406
|
+
outputEnvelope({ success: true, data: { name } }, { command: "session close" }, mode);
|
|
10324
10407
|
}
|
|
10325
10408
|
break;
|
|
10326
10409
|
}
|
|
@@ -10328,10 +10411,10 @@ async function handleSession(args, options, mode, _cdpEndpoint) {
|
|
|
10328
10411
|
case "ls": {
|
|
10329
10412
|
try {
|
|
10330
10413
|
const sessions2 = await forwardSessionList();
|
|
10331
|
-
|
|
10414
|
+
outputEnvelope({ success: true, data: { sessions: sessions2 } }, { command: "session list" }, mode);
|
|
10332
10415
|
} catch {
|
|
10333
10416
|
const sessions2 = await listSessions();
|
|
10334
|
-
|
|
10417
|
+
outputEnvelope({ success: true, data: { sessions: sessions2 } }, { command: "session list" }, mode);
|
|
10335
10418
|
}
|
|
10336
10419
|
break;
|
|
10337
10420
|
}
|
|
@@ -10346,7 +10429,7 @@ async function handleSession(args, options, mode, _cdpEndpoint) {
|
|
|
10346
10429
|
await stopDaemonProcess();
|
|
10347
10430
|
} catch {
|
|
10348
10431
|
}
|
|
10349
|
-
|
|
10432
|
+
outputEnvelope({ success: true, data: { name, killed: true, daemon: "stopped" } }, { command: "session kill" }, mode);
|
|
10350
10433
|
break;
|
|
10351
10434
|
}
|
|
10352
10435
|
case "kill-all": {
|
|
@@ -10365,7 +10448,7 @@ async function handleSession(args, options, mode, _cdpEndpoint) {
|
|
|
10365
10448
|
} catch {
|
|
10366
10449
|
}
|
|
10367
10450
|
const cleaned = cleanSessionFiles();
|
|
10368
|
-
|
|
10451
|
+
outputEnvelope({ success: true, data: { sessionsCleaned: cleaned, daemon: "killed" } }, { command: "session kill-all" }, mode);
|
|
10369
10452
|
break;
|
|
10370
10453
|
}
|
|
10371
10454
|
default:
|
|
@@ -10485,7 +10568,7 @@ async function handleSearch(args, options, mode) {
|
|
|
10485
10568
|
}
|
|
10486
10569
|
}
|
|
10487
10570
|
if (mode === "json") {
|
|
10488
|
-
|
|
10571
|
+
outputEnvelope({ success: true, data: { results, total: results.length } }, { command: "plugin search" }, mode);
|
|
10489
10572
|
} else {
|
|
10490
10573
|
if (results.length === 0) {
|
|
10491
10574
|
console.log("No plugins found");
|
|
@@ -10514,7 +10597,7 @@ async function handlePluginInfo(args, options, mode) {
|
|
|
10514
10597
|
if (pluginInfo) {
|
|
10515
10598
|
const d = pluginInfo;
|
|
10516
10599
|
if (mode === "json") {
|
|
10517
|
-
|
|
10600
|
+
outputEnvelope({ success: true, data: { source: "marketplace", ...d } }, { command: "plugin info" }, mode);
|
|
10518
10601
|
return;
|
|
10519
10602
|
}
|
|
10520
10603
|
console.log(`\u540D\u79F0: ${d.name || ""}`);
|
|
@@ -10540,7 +10623,7 @@ async function handlePluginInfo(args, options, mode) {
|
|
|
10540
10623
|
const pkg = latest && versions?.[latest];
|
|
10541
10624
|
if (pkg) {
|
|
10542
10625
|
if (mode === "json") {
|
|
10543
|
-
|
|
10626
|
+
outputEnvelope({ success: true, data: { source: "npm", name: pkg.name, version: latest, description: pkg.description } }, { command: "plugin info" }, mode);
|
|
10544
10627
|
return;
|
|
10545
10628
|
}
|
|
10546
10629
|
console.log(`\u540D\u79F0: ${pkg.name || ""}`);
|
|
@@ -10569,7 +10652,7 @@ async function handlePluginSchema(args, mode) {
|
|
|
10569
10652
|
return;
|
|
10570
10653
|
}
|
|
10571
10654
|
if (mode === "json") {
|
|
10572
|
-
|
|
10655
|
+
outputEnvelope({ success: true, data: contract }, { command: "plugin schema" }, mode);
|
|
10573
10656
|
return;
|
|
10574
10657
|
}
|
|
10575
10658
|
if ("commands" in contract) {
|
|
@@ -10647,8 +10730,9 @@ async function handlePlugin(args, options, mode) {
|
|
|
10647
10730
|
}
|
|
10648
10731
|
} catch {
|
|
10649
10732
|
}
|
|
10650
|
-
|
|
10651
|
-
{
|
|
10733
|
+
outputEnvelope(
|
|
10734
|
+
{ success: true, data: { name: result.name, source: result.source, path: result.path } },
|
|
10735
|
+
{ command: "plugin install" },
|
|
10652
10736
|
mode
|
|
10653
10737
|
);
|
|
10654
10738
|
break;
|
|
@@ -10667,7 +10751,7 @@ async function handlePlugin(args, options, mode) {
|
|
|
10667
10751
|
await loader.reloadPlugin(name);
|
|
10668
10752
|
} catch {
|
|
10669
10753
|
}
|
|
10670
|
-
|
|
10754
|
+
outputEnvelope({ success: true, data: { name } }, { command: "plugin uninstall" }, mode);
|
|
10671
10755
|
break;
|
|
10672
10756
|
}
|
|
10673
10757
|
case "list": {
|
|
@@ -10689,7 +10773,7 @@ async function handlePlugin(args, options, mode) {
|
|
|
10689
10773
|
};
|
|
10690
10774
|
});
|
|
10691
10775
|
if (mode === "json") {
|
|
10692
|
-
|
|
10776
|
+
outputEnvelope({ success: true, data: { plugins: enrichedPlugins } }, { command: "plugin list" }, mode);
|
|
10693
10777
|
} else {
|
|
10694
10778
|
if (enrichedPlugins.length === 0) {
|
|
10695
10779
|
console.log("No plugins installed");
|
|
@@ -10725,7 +10809,7 @@ Total: ${enrichedPlugins.length} plugins`);
|
|
|
10725
10809
|
} catch {
|
|
10726
10810
|
outputError(`Plugin "${name}" not found. Use 'xbrowser plugin list' to see installed plugins.`);
|
|
10727
10811
|
}
|
|
10728
|
-
|
|
10812
|
+
outputEnvelope({ success: true, data: { name } }, { command: "plugin reload" }, mode);
|
|
10729
10813
|
break;
|
|
10730
10814
|
}
|
|
10731
10815
|
case "search":
|
|
@@ -10757,24 +10841,22 @@ function handleDaemon(args, options, mode) {
|
|
|
10757
10841
|
case "start": {
|
|
10758
10842
|
const port = options.port ? Number(options.port) : 9224;
|
|
10759
10843
|
startDaemonProcess(port).then(
|
|
10760
|
-
(config) =>
|
|
10844
|
+
(config) => outputEnvelope({ success: true, data: { pid: config.pid, port: config.port } }, { command: "daemon start" }, mode)
|
|
10761
10845
|
).catch(
|
|
10762
10846
|
(e) => outputError(e instanceof Error ? e.message : String(e))
|
|
10763
10847
|
);
|
|
10764
10848
|
break;
|
|
10765
10849
|
}
|
|
10766
10850
|
case "stop": {
|
|
10767
|
-
stopDaemonProcess().then(() =>
|
|
10851
|
+
stopDaemonProcess().then(() => outputEnvelope({ success: true, data: {} }, { command: "daemon stop" }, mode)).catch(
|
|
10768
10852
|
(e) => outputError(e instanceof Error ? e.message : String(e))
|
|
10769
10853
|
);
|
|
10770
10854
|
break;
|
|
10771
10855
|
}
|
|
10772
10856
|
case "status": {
|
|
10773
10857
|
const status = getDaemonProcessStatus();
|
|
10774
|
-
|
|
10775
|
-
|
|
10776
|
-
mode
|
|
10777
|
-
);
|
|
10858
|
+
const statusData = status.running ? { running: true, pid: status.pid, port: status.port } : { running: false };
|
|
10859
|
+
outputEnvelope({ success: true, data: statusData }, { command: "daemon status" }, mode);
|
|
10778
10860
|
break;
|
|
10779
10861
|
}
|
|
10780
10862
|
default:
|
|
@@ -11152,7 +11234,7 @@ async function handleFilter(args, _mode, options) {
|
|
|
11152
11234
|
console.log(` Original: ${result.originalCount}, After: ${result.filteredCount}, Removed: ${result.removed} (${result.percentage}%)`);
|
|
11153
11235
|
}
|
|
11154
11236
|
async function handleGeneratePlugin(sessionName, pluginName, outputDir) {
|
|
11155
|
-
const { SessionRecorder: SessionRecorder2 } = await import("./session-recorder-
|
|
11237
|
+
const { SessionRecorder: SessionRecorder2 } = await import("./session-recorder-33UKWCIR.js");
|
|
11156
11238
|
const { readSiteKnowledge: readSiteKnowledge2, toMarkdown } = await import("./site-knowledge-SYC6VCDB.js");
|
|
11157
11239
|
const { mkdirSync: mkdirSync10, writeFileSync: writeFileSync12 } = await import("fs");
|
|
11158
11240
|
const { join: join14 } = await import("path");
|
|
@@ -12499,7 +12581,8 @@ var KNOWN_GLOBAL_OPTIONS = /* @__PURE__ */ new Set([
|
|
|
12499
12581
|
"port",
|
|
12500
12582
|
"token",
|
|
12501
12583
|
"timeout",
|
|
12502
|
-
"headless"
|
|
12584
|
+
"headless",
|
|
12585
|
+
"tab"
|
|
12503
12586
|
]);
|
|
12504
12587
|
function showCommandHelp(siteName, cmd, siteConfig, mode) {
|
|
12505
12588
|
const c = cmd;
|
|
@@ -12653,20 +12736,28 @@ async function handleEvalMode(argv) {
|
|
|
12653
12736
|
}
|
|
12654
12737
|
async function handleChainInput(input, argv) {
|
|
12655
12738
|
const cdpEndpoint = argv ? extractCdpFromArgv(argv) : void 0;
|
|
12656
|
-
const
|
|
12739
|
+
const hasJson = argv ? argv.some((a) => a === "--json" || a.startsWith("--json=") || a.includes(" --json") || a.startsWith("--json")) || argv.includes("-j") : false;
|
|
12740
|
+
const hasYaml = argv ? argv.some((a) => a === "--yaml" || a.startsWith("--yaml=")) : false;
|
|
12741
|
+
const mode = hasJson ? "json" : hasYaml ? "yaml" : "text";
|
|
12657
12742
|
const chainResult = await executeChain(input, { cdpEndpoint });
|
|
12658
|
-
if (
|
|
12659
|
-
|
|
12660
|
-
|
|
12661
|
-
|
|
12662
|
-
|
|
12663
|
-
|
|
12664
|
-
|
|
12665
|
-
|
|
12666
|
-
|
|
12667
|
-
|
|
12668
|
-
|
|
12669
|
-
|
|
12743
|
+
if (mode === "json" || mode === "yaml") {
|
|
12744
|
+
outputEnvelope(
|
|
12745
|
+
{
|
|
12746
|
+
success: chainResult.success,
|
|
12747
|
+
data: {
|
|
12748
|
+
steps: chainResult.steps.map((s) => ({
|
|
12749
|
+
command: s.raw,
|
|
12750
|
+
success: s.success,
|
|
12751
|
+
data: s.data,
|
|
12752
|
+
duration: s.duration,
|
|
12753
|
+
...s.hookOutputs?.length ? { hooks: s.hookOutputs } : {}
|
|
12754
|
+
}))
|
|
12755
|
+
},
|
|
12756
|
+
duration: chainResult.totalDuration
|
|
12757
|
+
},
|
|
12758
|
+
{ command: "chain", totalSteps: chainResult.steps.length },
|
|
12759
|
+
mode
|
|
12760
|
+
);
|
|
12670
12761
|
} else {
|
|
12671
12762
|
printChainResult(chainResult);
|
|
12672
12763
|
}
|
|
@@ -12733,7 +12824,15 @@ async function routeCommand(argvIn, stdinCommands) {
|
|
|
12733
12824
|
const sessionName = options.session || process.env.XBROWSER_SESSION || "default";
|
|
12734
12825
|
const cdpEndpoint = options.cdp || process.env.XBROWSER_CDP;
|
|
12735
12826
|
if (options.version || options.v && positional.length === 0) {
|
|
12736
|
-
|
|
12827
|
+
if (mode === "json") {
|
|
12828
|
+
outputEnvelope(
|
|
12829
|
+
{ success: true, data: { version, name: "@xbrowser/cli" } },
|
|
12830
|
+
{ command: "version" },
|
|
12831
|
+
mode
|
|
12832
|
+
);
|
|
12833
|
+
} else {
|
|
12834
|
+
console.log(`xbrowser v${version}`);
|
|
12835
|
+
}
|
|
12737
12836
|
return;
|
|
12738
12837
|
}
|
|
12739
12838
|
if (positional.length === 0) {
|
|
@@ -12929,18 +13028,23 @@ async function routeCommand(argvIn, stdinCommands) {
|
|
|
12929
13028
|
if (isChainInput(fullInput)) {
|
|
12930
13029
|
const chainResult = await executeChain(fullInput, { cdpEndpoint, sessionName });
|
|
12931
13030
|
if (mode === "json" || mode === "yaml") {
|
|
12932
|
-
|
|
12933
|
-
|
|
12934
|
-
|
|
12935
|
-
|
|
12936
|
-
|
|
12937
|
-
|
|
12938
|
-
|
|
12939
|
-
|
|
12940
|
-
|
|
12941
|
-
|
|
12942
|
-
|
|
12943
|
-
|
|
13031
|
+
outputEnvelope(
|
|
13032
|
+
{
|
|
13033
|
+
success: chainResult.success,
|
|
13034
|
+
data: {
|
|
13035
|
+
steps: chainResult.steps.map((s) => ({
|
|
13036
|
+
command: s.raw,
|
|
13037
|
+
success: s.success,
|
|
13038
|
+
data: s.data,
|
|
13039
|
+
duration: s.duration
|
|
13040
|
+
})),
|
|
13041
|
+
...chainResult.stoppedReason ? { stoppedReason: chainResult.stoppedReason } : {}
|
|
13042
|
+
},
|
|
13043
|
+
duration: chainResult.totalDuration
|
|
13044
|
+
},
|
|
13045
|
+
{ command: "chain", totalSteps: chainResult.steps.length },
|
|
13046
|
+
mode
|
|
13047
|
+
);
|
|
12944
13048
|
if (!chainResult.success) throw new Error("Command failed");
|
|
12945
13049
|
return;
|
|
12946
13050
|
}
|
|
@@ -13085,6 +13189,17 @@ Run "xbrowser ${command} ${subCommand} --help" to see available parameters.`
|
|
|
13085
13189
|
session = await createSession(sessionName, void 0, cdpEndpoint ? { cdpEndpoint } : {});
|
|
13086
13190
|
}
|
|
13087
13191
|
}
|
|
13192
|
+
const cmdTabIndex = options.tab !== void 0 ? Number(options.tab) : void 0;
|
|
13193
|
+
if (cmdTabIndex !== void 0 && session?.context) {
|
|
13194
|
+
const pages = session.context.pages();
|
|
13195
|
+
if (cmdTabIndex >= 0 && cmdTabIndex < pages.length) {
|
|
13196
|
+
const targetPage = pages[cmdTabIndex];
|
|
13197
|
+
await targetPage.bringToFront().catch(() => {
|
|
13198
|
+
});
|
|
13199
|
+
const { setActivePage: setActivePage2 } = await import("./browser-XPKM344Y.js");
|
|
13200
|
+
setActivePage2(session, targetPage);
|
|
13201
|
+
}
|
|
13202
|
+
}
|
|
13088
13203
|
const ctx = {
|
|
13089
13204
|
args: cmdArgsForPlugin,
|
|
13090
13205
|
options,
|
|
@@ -13162,22 +13277,17 @@ Run "xbrowser ${command} ${subCommand} --help" to see available parameters.`
|
|
|
13162
13277
|
const outputData = isCommandResult2(result) ? result.data : result && typeof result === "object" ? result.data ?? result : result;
|
|
13163
13278
|
const tips = isCommandResult2(result) ? result.tips : result && typeof result === "object" ? result.tips : void 0;
|
|
13164
13279
|
if (mode === "json" || mode === "yaml") {
|
|
13165
|
-
const
|
|
13166
|
-
|
|
13167
|
-
|
|
13168
|
-
|
|
13169
|
-
|
|
13170
|
-
|
|
13171
|
-
|
|
13172
|
-
|
|
13173
|
-
|
|
13174
|
-
|
|
13175
|
-
|
|
13176
|
-
}
|
|
13177
|
-
console.log(outputFormatter2.format(finalOutput, { mode, color: false, emoji: false }));
|
|
13178
|
-
if (tips?.length) {
|
|
13179
|
-
for (const tip of tips) console.error(`\u{1F4A1} ${typeof tip === "string" ? tip : tip.message}`);
|
|
13180
|
-
}
|
|
13280
|
+
const resultSuccess = isCommandResult2(result) ? result.success !== false : true;
|
|
13281
|
+
const resultMsg = isCommandResult2(result) ? result.message : void 0;
|
|
13282
|
+
const duration = Date.now() - cmdStart;
|
|
13283
|
+
const envelopeMeta = { command: `${command} ${subCommand}` };
|
|
13284
|
+
if (injectedViewerUrl) envelopeMeta.viewerUrl = injectedViewerUrl;
|
|
13285
|
+
if (hookOutputs.length > 0) envelopeMeta.hooks = hookOutputs;
|
|
13286
|
+
outputEnvelope(
|
|
13287
|
+
{ success: resultSuccess, data: outputData, message: resultMsg, tips, duration },
|
|
13288
|
+
envelopeMeta,
|
|
13289
|
+
mode
|
|
13290
|
+
);
|
|
13181
13291
|
} else {
|
|
13182
13292
|
console.log(outputFormatter2.format(outputData, { mode: "text", color: true, emoji: true }));
|
|
13183
13293
|
if (tips?.length) {
|
|
@@ -13359,7 +13469,7 @@ async function main() {
|
|
|
13359
13469
|
const command = process.argv[2];
|
|
13360
13470
|
const isLongRunning = command === "preview" || command === "serve";
|
|
13361
13471
|
if (!isLongRunning) {
|
|
13362
|
-
const { ensureProcessCanExit } = await import("./browser-
|
|
13472
|
+
const { ensureProcessCanExit } = await import("./browser-XPKM344Y.js");
|
|
13363
13473
|
await ensureProcessCanExit().catch(() => {
|
|
13364
13474
|
});
|
|
13365
13475
|
process.exit(exitCode);
|