@xbrowser/cli 1.8.5 → 1.8.6
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 +177 -75
- package/dist/daemon-main.js +29 -4
- package/dist/index.d.ts +1 -0
- package/dist/index.js +176 -74
- 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
|
@@ -656,7 +656,7 @@ async function closeSessionByName(name) {
|
|
|
656
656
|
} catch {
|
|
657
657
|
}
|
|
658
658
|
try {
|
|
659
|
-
const { SessionRecorder } = await import("./session-recorder-
|
|
659
|
+
const { SessionRecorder } = await import("./session-recorder-33UKWCIR.js");
|
|
660
660
|
SessionRecorder.cleanup(session.name);
|
|
661
661
|
} catch {
|
|
662
662
|
}
|
|
@@ -1891,15 +1891,37 @@ var SessionRecorder = class _SessionRecorder {
|
|
|
1891
1891
|
}
|
|
1892
1892
|
// ==================== Private ====================
|
|
1893
1893
|
async injectActionScript(page) {
|
|
1894
|
-
|
|
1895
|
-
|
|
1896
|
-
|
|
1897
|
-
|
|
1898
|
-
|
|
1894
|
+
let success = false;
|
|
1895
|
+
const maxAttempts = 3;
|
|
1896
|
+
for (let attempt = 1; attempt <= maxAttempts; attempt++) {
|
|
1897
|
+
try {
|
|
1898
|
+
await page.evaluate(getSelectorGeneratorScript());
|
|
1899
|
+
await page.evaluate(ACTION_SIGNAL_SCRIPT);
|
|
1900
|
+
await page.evaluate(`window.__xb_action_script_src = ${JSON.stringify(ACTION_SIGNAL_SCRIPT)};`);
|
|
1901
|
+
const injected = await page.evaluate(`(function() {
|
|
1902
|
+
try { return !!window.__xb_action_signal; } catch(e) { return false; }
|
|
1903
|
+
})()`).catch(() => false);
|
|
1904
|
+
if (injected) {
|
|
1905
|
+
success = true;
|
|
1906
|
+
break;
|
|
1907
|
+
}
|
|
1908
|
+
console.error(`[recorder] Action signal injection verification failed (attempt ${attempt}/${maxAttempts})`);
|
|
1909
|
+
} catch (e) {
|
|
1910
|
+
const msg = e instanceof Error ? e.message : String(e);
|
|
1911
|
+
console.error(`[recorder] Action signal injection error (attempt ${attempt}/${maxAttempts}): ${msg}`);
|
|
1912
|
+
}
|
|
1913
|
+
if (attempt < maxAttempts) {
|
|
1914
|
+
await new Promise((r) => setTimeout(r, 1e3));
|
|
1915
|
+
}
|
|
1916
|
+
}
|
|
1917
|
+
if (!success) {
|
|
1918
|
+
console.error(`[recorder] WARNING: Action signal injection FAILED after ${maxAttempts} attempts. User actions will NOT be recorded. Check that the page supports Runtime.evaluate.`);
|
|
1899
1919
|
}
|
|
1900
1920
|
try {
|
|
1901
1921
|
await page.evaluate(CHECKPOINT_OVERLAY_SCRIPT);
|
|
1902
|
-
} catch {
|
|
1922
|
+
} catch (e) {
|
|
1923
|
+
const msg = e instanceof Error ? e.message : String(e);
|
|
1924
|
+
console.error(`[recorder] Checkpoint overlay injection failed (non-fatal): ${msg}`);
|
|
1903
1925
|
}
|
|
1904
1926
|
try {
|
|
1905
1927
|
await page.evaluate(`
|
|
@@ -2051,7 +2073,11 @@ var SessionRecorder = class _SessionRecorder {
|
|
|
2051
2073
|
await this.injectActionScript(page);
|
|
2052
2074
|
return;
|
|
2053
2075
|
}
|
|
2054
|
-
} catch {
|
|
2076
|
+
} catch (e) {
|
|
2077
|
+
const msg = e instanceof Error ? e.message : String(e);
|
|
2078
|
+
if (attempt < 4) {
|
|
2079
|
+
console.error(`[recorder] injectActionScript retry ${attempt + 1}/5 failed: ${msg}`);
|
|
2080
|
+
}
|
|
2055
2081
|
}
|
|
2056
2082
|
await new Promise((r) => setTimeout(r, 1e3));
|
|
2057
2083
|
}
|
|
@@ -2071,7 +2097,9 @@ var SessionRecorder = class _SessionRecorder {
|
|
|
2071
2097
|
if (url && url !== "about:blank" && !url.startsWith("chrome")) {
|
|
2072
2098
|
try {
|
|
2073
2099
|
await this.injectActionScript(page);
|
|
2074
|
-
} catch {
|
|
2100
|
+
} catch (e) {
|
|
2101
|
+
const msg = e instanceof Error ? e.message : String(e);
|
|
2102
|
+
console.error(`[recorder] injectActionScript after navigation failed: ${msg}`);
|
|
2075
2103
|
}
|
|
2076
2104
|
}
|
|
2077
2105
|
});
|
|
@@ -2021,7 +2021,7 @@ async function closeSessionByName(name) {
|
|
|
2021
2021
|
} catch {
|
|
2022
2022
|
}
|
|
2023
2023
|
try {
|
|
2024
|
-
const { SessionRecorder } = await import("./session-recorder-
|
|
2024
|
+
const { SessionRecorder } = await import("./session-recorder-BMIJ3ZJM.js");
|
|
2025
2025
|
SessionRecorder.cleanup(session.name);
|
|
2026
2026
|
} catch {
|
|
2027
2027
|
}
|
|
@@ -1494,15 +1494,37 @@ var SessionRecorder = class _SessionRecorder {
|
|
|
1494
1494
|
}
|
|
1495
1495
|
// ==================== Private ====================
|
|
1496
1496
|
async injectActionScript(page) {
|
|
1497
|
-
|
|
1498
|
-
|
|
1499
|
-
|
|
1500
|
-
|
|
1501
|
-
|
|
1497
|
+
let success = false;
|
|
1498
|
+
const maxAttempts = 3;
|
|
1499
|
+
for (let attempt = 1; attempt <= maxAttempts; attempt++) {
|
|
1500
|
+
try {
|
|
1501
|
+
await page.evaluate(getSelectorGeneratorScript());
|
|
1502
|
+
await page.evaluate(ACTION_SIGNAL_SCRIPT);
|
|
1503
|
+
await page.evaluate(`window.__xb_action_script_src = ${JSON.stringify(ACTION_SIGNAL_SCRIPT)};`);
|
|
1504
|
+
const injected = await page.evaluate(`(function() {
|
|
1505
|
+
try { return !!window.__xb_action_signal; } catch(e) { return false; }
|
|
1506
|
+
})()`).catch(() => false);
|
|
1507
|
+
if (injected) {
|
|
1508
|
+
success = true;
|
|
1509
|
+
break;
|
|
1510
|
+
}
|
|
1511
|
+
console.error(`[recorder] Action signal injection verification failed (attempt ${attempt}/${maxAttempts})`);
|
|
1512
|
+
} catch (e) {
|
|
1513
|
+
const msg = e instanceof Error ? e.message : String(e);
|
|
1514
|
+
console.error(`[recorder] Action signal injection error (attempt ${attempt}/${maxAttempts}): ${msg}`);
|
|
1515
|
+
}
|
|
1516
|
+
if (attempt < maxAttempts) {
|
|
1517
|
+
await new Promise((r) => setTimeout(r, 1e3));
|
|
1518
|
+
}
|
|
1519
|
+
}
|
|
1520
|
+
if (!success) {
|
|
1521
|
+
console.error(`[recorder] WARNING: Action signal injection FAILED after ${maxAttempts} attempts. User actions will NOT be recorded. Check that the page supports Runtime.evaluate.`);
|
|
1502
1522
|
}
|
|
1503
1523
|
try {
|
|
1504
1524
|
await page.evaluate(CHECKPOINT_OVERLAY_SCRIPT);
|
|
1505
|
-
} catch {
|
|
1525
|
+
} catch (e) {
|
|
1526
|
+
const msg = e instanceof Error ? e.message : String(e);
|
|
1527
|
+
console.error(`[recorder] Checkpoint overlay injection failed (non-fatal): ${msg}`);
|
|
1506
1528
|
}
|
|
1507
1529
|
try {
|
|
1508
1530
|
await page.evaluate(`
|
|
@@ -1654,7 +1676,11 @@ var SessionRecorder = class _SessionRecorder {
|
|
|
1654
1676
|
await this.injectActionScript(page);
|
|
1655
1677
|
return;
|
|
1656
1678
|
}
|
|
1657
|
-
} catch {
|
|
1679
|
+
} catch (e) {
|
|
1680
|
+
const msg = e instanceof Error ? e.message : String(e);
|
|
1681
|
+
if (attempt < 4) {
|
|
1682
|
+
console.error(`[recorder] injectActionScript retry ${attempt + 1}/5 failed: ${msg}`);
|
|
1683
|
+
}
|
|
1658
1684
|
}
|
|
1659
1685
|
await new Promise((r) => setTimeout(r, 1e3));
|
|
1660
1686
|
}
|
|
@@ -1674,7 +1700,9 @@ var SessionRecorder = class _SessionRecorder {
|
|
|
1674
1700
|
if (url && url !== "about:blank" && !url.startsWith("chrome")) {
|
|
1675
1701
|
try {
|
|
1676
1702
|
await this.injectActionScript(page);
|
|
1677
|
-
} catch {
|
|
1703
|
+
} catch (e) {
|
|
1704
|
+
const msg = e instanceof Error ? e.message : String(e);
|
|
1705
|
+
console.error(`[recorder] injectActionScript after navigation failed: ${msg}`);
|
|
1678
1706
|
}
|
|
1679
1707
|
}
|
|
1680
1708
|
});
|
|
@@ -4965,7 +4965,7 @@ async function closeSessionByName(name) {
|
|
|
4965
4965
|
} catch {
|
|
4966
4966
|
}
|
|
4967
4967
|
try {
|
|
4968
|
-
const { SessionRecorder } = await import("./session-recorder-
|
|
4968
|
+
const { SessionRecorder } = await import("./session-recorder-33UKWCIR.js");
|
|
4969
4969
|
SessionRecorder.cleanup(session.name);
|
|
4970
4970
|
} catch {
|
|
4971
4971
|
}
|
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,
|
|
@@ -7205,9 +7205,14 @@ async function executeCommand(commandName, params, sessionName = "default", extr
|
|
|
7205
7205
|
const { _target: _u, ...rest } = params;
|
|
7206
7206
|
params = rest;
|
|
7207
7207
|
}
|
|
7208
|
+
const _tabIndex = params._tabIndex;
|
|
7209
|
+
if (_tabIndex !== void 0) {
|
|
7210
|
+
const { _tabIndex: _u, ...rest } = params;
|
|
7211
|
+
params = rest;
|
|
7212
|
+
}
|
|
7208
7213
|
let targetPageOverride = null;
|
|
7209
7214
|
if (_target && extraOpts?.cdpEndpoint) {
|
|
7210
|
-
const { findTargetPage } = await import("./browser-
|
|
7215
|
+
const { findTargetPage } = await import("./browser-XPKM344Y.js");
|
|
7211
7216
|
targetPageOverride = await findTargetPage(extraOpts.cdpEndpoint, _target);
|
|
7212
7217
|
if (!targetPageOverride) {
|
|
7213
7218
|
return errorResult(`Target "${_target}" not found. Use 'xbrowser targets --cdp ${extraOpts.cdpEndpoint}' to list available pages.`);
|
|
@@ -7279,6 +7284,16 @@ async function executeCommand(commandName, params, sessionName = "default", extr
|
|
|
7279
7284
|
cliName: "xbrowser",
|
|
7280
7285
|
tips: new TipCollector2()
|
|
7281
7286
|
};
|
|
7287
|
+
if (_tabIndex !== void 0 && session?.context) {
|
|
7288
|
+
const pages = session.context.pages();
|
|
7289
|
+
if (_tabIndex >= 0 && _tabIndex < pages.length) {
|
|
7290
|
+
const targetPage = pages[_tabIndex];
|
|
7291
|
+
await targetPage.bringToFront().catch(() => {
|
|
7292
|
+
});
|
|
7293
|
+
setActivePage(session, targetPage);
|
|
7294
|
+
ctx.page = targetPage;
|
|
7295
|
+
}
|
|
7296
|
+
}
|
|
7282
7297
|
const start = Date.now();
|
|
7283
7298
|
if (session) {
|
|
7284
7299
|
streamCommandEvent(session.id, {
|
|
@@ -7307,7 +7322,17 @@ async function executeCommand(commandName, params, sessionName = "default", extr
|
|
|
7307
7322
|
if (hooks.length > 0 && session?.page) {
|
|
7308
7323
|
await Promise.all(hooks.map((h) => h.onBeforeCommand?.({ page: session.page, command: commandName, params })));
|
|
7309
7324
|
}
|
|
7310
|
-
|
|
7325
|
+
let raw;
|
|
7326
|
+
const handlerPromise = command.handler(params, ctx);
|
|
7327
|
+
if (extraOpts?.timeout && extraOpts.timeout > 0) {
|
|
7328
|
+
const timeoutMs = extraOpts.timeout;
|
|
7329
|
+
const timeoutPromise = new Promise(
|
|
7330
|
+
(_, reject) => setTimeout(() => reject(new Error(`Command timed out after ${timeoutMs}ms`)), timeoutMs)
|
|
7331
|
+
);
|
|
7332
|
+
raw = await Promise.race([handlerPromise, timeoutPromise]);
|
|
7333
|
+
} else {
|
|
7334
|
+
raw = await handlerPromise;
|
|
7335
|
+
}
|
|
7311
7336
|
const end = Date.now();
|
|
7312
7337
|
const duration = end - start;
|
|
7313
7338
|
let hookOutputs;
|
|
@@ -7883,16 +7908,29 @@ var configBuiltin = {
|
|
|
7883
7908
|
execute: async (args, _options, _ctx) => {
|
|
7884
7909
|
const [subcommand, ...rest] = args;
|
|
7885
7910
|
if (!subcommand || subcommand === "list") {
|
|
7911
|
+
let flatten2 = function(obj, prefix = "") {
|
|
7912
|
+
const entries2 = [];
|
|
7913
|
+
for (const [k, v] of Object.entries(obj)) {
|
|
7914
|
+
const fullKey = prefix ? `${prefix}.${k}` : k;
|
|
7915
|
+
if (v && typeof v === "object" && !Array.isArray(v)) {
|
|
7916
|
+
entries2.push(...flatten2(v, fullKey));
|
|
7917
|
+
} else {
|
|
7918
|
+
entries2.push({ key: fullKey, value: v });
|
|
7919
|
+
}
|
|
7920
|
+
}
|
|
7921
|
+
return entries2;
|
|
7922
|
+
};
|
|
7923
|
+
var flatten = flatten2;
|
|
7886
7924
|
const config = loadConfig();
|
|
7887
|
-
const
|
|
7888
|
-
if (
|
|
7925
|
+
const entries = flatten2(config);
|
|
7926
|
+
if (entries.length === 0) {
|
|
7889
7927
|
console.log("Configuration is empty");
|
|
7890
7928
|
return;
|
|
7891
7929
|
}
|
|
7892
7930
|
console.log("Configuration:");
|
|
7893
7931
|
console.log("");
|
|
7894
|
-
for (const
|
|
7895
|
-
console.log(` ${
|
|
7932
|
+
for (const { key, value } of entries) {
|
|
7933
|
+
console.log(` ${key} = ${value}`);
|
|
7896
7934
|
}
|
|
7897
7935
|
return;
|
|
7898
7936
|
}
|
|
@@ -8691,6 +8729,39 @@ function outputError(message) {
|
|
|
8691
8729
|
console.error(formatted);
|
|
8692
8730
|
process.exit(1);
|
|
8693
8731
|
}
|
|
8732
|
+
function outputEnvelope(result, meta, mode) {
|
|
8733
|
+
if (mode !== "json" && mode !== "yaml") {
|
|
8734
|
+
if (!result.success) {
|
|
8735
|
+
outputError(result.message || "Unknown error");
|
|
8736
|
+
return;
|
|
8737
|
+
}
|
|
8738
|
+
outputResult(result.data, mode);
|
|
8739
|
+
return;
|
|
8740
|
+
}
|
|
8741
|
+
const { command, ...extraMeta } = meta;
|
|
8742
|
+
const commandResult = {
|
|
8743
|
+
success: result.success,
|
|
8744
|
+
data: result.data,
|
|
8745
|
+
message: result.message,
|
|
8746
|
+
tips: [],
|
|
8747
|
+
meta: {
|
|
8748
|
+
duration: result.duration ?? 0,
|
|
8749
|
+
...extraMeta
|
|
8750
|
+
}
|
|
8751
|
+
};
|
|
8752
|
+
const formatted = outputFormatter.formatEnvelope(commandResult, {
|
|
8753
|
+
command,
|
|
8754
|
+
extraMeta,
|
|
8755
|
+
mode
|
|
8756
|
+
});
|
|
8757
|
+
console.log(formatted);
|
|
8758
|
+
if (result.tips?.length) {
|
|
8759
|
+
for (const tip of result.tips) {
|
|
8760
|
+
const text = typeof tip === "string" ? tip : tip.message;
|
|
8761
|
+
if (text) console.error(` \u{1F4A1} ${text}`);
|
|
8762
|
+
}
|
|
8763
|
+
}
|
|
8764
|
+
}
|
|
8694
8765
|
|
|
8695
8766
|
// src/builtins/plugin.ts
|
|
8696
8767
|
var pluginLoader2 = null;
|
|
@@ -10250,9 +10321,13 @@ async function handleBrowserCommand(command, args, options, sessionName, mode, c
|
|
|
10250
10321
|
if (target) {
|
|
10251
10322
|
params = { ...params, _target: target };
|
|
10252
10323
|
}
|
|
10324
|
+
const tabIndex = options.tab;
|
|
10325
|
+
if (tabIndex !== void 0) {
|
|
10326
|
+
params = { ...params, _tabIndex: Number(tabIndex) };
|
|
10327
|
+
}
|
|
10253
10328
|
const result = cdpEndpoint ? await executeCommand(cmdName, params, sessionName, { cdpEndpoint }) : await executeCommand(cmdName, params, sessionName);
|
|
10254
10329
|
if (mode === "json" || mode === "yaml") {
|
|
10255
|
-
|
|
10330
|
+
outputEnvelope(result, { command: cmdName }, mode);
|
|
10256
10331
|
} else if (!result.success) {
|
|
10257
10332
|
outputError(result.message || "Command failed");
|
|
10258
10333
|
} else {
|
|
@@ -10312,7 +10387,7 @@ async function handleSession(args, options, mode, _cdpEndpoint) {
|
|
|
10312
10387
|
}
|
|
10313
10388
|
} catch {
|
|
10314
10389
|
}
|
|
10315
|
-
|
|
10390
|
+
outputEnvelope({ success: true, data: { closed: count, all: true } }, { command: "session close" }, mode);
|
|
10316
10391
|
} else {
|
|
10317
10392
|
const name = options.session || options.name || process.env.XBROWSER_SESSION || "default";
|
|
10318
10393
|
try {
|
|
@@ -10320,7 +10395,7 @@ async function handleSession(args, options, mode, _cdpEndpoint) {
|
|
|
10320
10395
|
} catch {
|
|
10321
10396
|
}
|
|
10322
10397
|
await closeSession(name);
|
|
10323
|
-
|
|
10398
|
+
outputEnvelope({ success: true, data: { name } }, { command: "session close" }, mode);
|
|
10324
10399
|
}
|
|
10325
10400
|
break;
|
|
10326
10401
|
}
|
|
@@ -10328,10 +10403,10 @@ async function handleSession(args, options, mode, _cdpEndpoint) {
|
|
|
10328
10403
|
case "ls": {
|
|
10329
10404
|
try {
|
|
10330
10405
|
const sessions2 = await forwardSessionList();
|
|
10331
|
-
|
|
10406
|
+
outputEnvelope({ success: true, data: { sessions: sessions2 } }, { command: "session list" }, mode);
|
|
10332
10407
|
} catch {
|
|
10333
10408
|
const sessions2 = await listSessions();
|
|
10334
|
-
|
|
10409
|
+
outputEnvelope({ success: true, data: { sessions: sessions2 } }, { command: "session list" }, mode);
|
|
10335
10410
|
}
|
|
10336
10411
|
break;
|
|
10337
10412
|
}
|
|
@@ -10346,7 +10421,7 @@ async function handleSession(args, options, mode, _cdpEndpoint) {
|
|
|
10346
10421
|
await stopDaemonProcess();
|
|
10347
10422
|
} catch {
|
|
10348
10423
|
}
|
|
10349
|
-
|
|
10424
|
+
outputEnvelope({ success: true, data: { name, killed: true, daemon: "stopped" } }, { command: "session kill" }, mode);
|
|
10350
10425
|
break;
|
|
10351
10426
|
}
|
|
10352
10427
|
case "kill-all": {
|
|
@@ -10365,7 +10440,7 @@ async function handleSession(args, options, mode, _cdpEndpoint) {
|
|
|
10365
10440
|
} catch {
|
|
10366
10441
|
}
|
|
10367
10442
|
const cleaned = cleanSessionFiles();
|
|
10368
|
-
|
|
10443
|
+
outputEnvelope({ success: true, data: { sessionsCleaned: cleaned, daemon: "killed" } }, { command: "session kill-all" }, mode);
|
|
10369
10444
|
break;
|
|
10370
10445
|
}
|
|
10371
10446
|
default:
|
|
@@ -10485,7 +10560,7 @@ async function handleSearch(args, options, mode) {
|
|
|
10485
10560
|
}
|
|
10486
10561
|
}
|
|
10487
10562
|
if (mode === "json") {
|
|
10488
|
-
|
|
10563
|
+
outputEnvelope({ success: true, data: { results, total: results.length } }, { command: "plugin search" }, mode);
|
|
10489
10564
|
} else {
|
|
10490
10565
|
if (results.length === 0) {
|
|
10491
10566
|
console.log("No plugins found");
|
|
@@ -10514,7 +10589,7 @@ async function handlePluginInfo(args, options, mode) {
|
|
|
10514
10589
|
if (pluginInfo) {
|
|
10515
10590
|
const d = pluginInfo;
|
|
10516
10591
|
if (mode === "json") {
|
|
10517
|
-
|
|
10592
|
+
outputEnvelope({ success: true, data: { source: "marketplace", ...d } }, { command: "plugin info" }, mode);
|
|
10518
10593
|
return;
|
|
10519
10594
|
}
|
|
10520
10595
|
console.log(`\u540D\u79F0: ${d.name || ""}`);
|
|
@@ -10540,7 +10615,7 @@ async function handlePluginInfo(args, options, mode) {
|
|
|
10540
10615
|
const pkg = latest && versions?.[latest];
|
|
10541
10616
|
if (pkg) {
|
|
10542
10617
|
if (mode === "json") {
|
|
10543
|
-
|
|
10618
|
+
outputEnvelope({ success: true, data: { source: "npm", name: pkg.name, version: latest, description: pkg.description } }, { command: "plugin info" }, mode);
|
|
10544
10619
|
return;
|
|
10545
10620
|
}
|
|
10546
10621
|
console.log(`\u540D\u79F0: ${pkg.name || ""}`);
|
|
@@ -10569,7 +10644,7 @@ async function handlePluginSchema(args, mode) {
|
|
|
10569
10644
|
return;
|
|
10570
10645
|
}
|
|
10571
10646
|
if (mode === "json") {
|
|
10572
|
-
|
|
10647
|
+
outputEnvelope({ success: true, data: contract }, { command: "plugin schema" }, mode);
|
|
10573
10648
|
return;
|
|
10574
10649
|
}
|
|
10575
10650
|
if ("commands" in contract) {
|
|
@@ -10647,8 +10722,9 @@ async function handlePlugin(args, options, mode) {
|
|
|
10647
10722
|
}
|
|
10648
10723
|
} catch {
|
|
10649
10724
|
}
|
|
10650
|
-
|
|
10651
|
-
{
|
|
10725
|
+
outputEnvelope(
|
|
10726
|
+
{ success: true, data: { name: result.name, source: result.source, path: result.path } },
|
|
10727
|
+
{ command: "plugin install" },
|
|
10652
10728
|
mode
|
|
10653
10729
|
);
|
|
10654
10730
|
break;
|
|
@@ -10667,7 +10743,7 @@ async function handlePlugin(args, options, mode) {
|
|
|
10667
10743
|
await loader.reloadPlugin(name);
|
|
10668
10744
|
} catch {
|
|
10669
10745
|
}
|
|
10670
|
-
|
|
10746
|
+
outputEnvelope({ success: true, data: { name } }, { command: "plugin uninstall" }, mode);
|
|
10671
10747
|
break;
|
|
10672
10748
|
}
|
|
10673
10749
|
case "list": {
|
|
@@ -10689,7 +10765,7 @@ async function handlePlugin(args, options, mode) {
|
|
|
10689
10765
|
};
|
|
10690
10766
|
});
|
|
10691
10767
|
if (mode === "json") {
|
|
10692
|
-
|
|
10768
|
+
outputEnvelope({ success: true, data: { plugins: enrichedPlugins } }, { command: "plugin list" }, mode);
|
|
10693
10769
|
} else {
|
|
10694
10770
|
if (enrichedPlugins.length === 0) {
|
|
10695
10771
|
console.log("No plugins installed");
|
|
@@ -10725,7 +10801,7 @@ Total: ${enrichedPlugins.length} plugins`);
|
|
|
10725
10801
|
} catch {
|
|
10726
10802
|
outputError(`Plugin "${name}" not found. Use 'xbrowser plugin list' to see installed plugins.`);
|
|
10727
10803
|
}
|
|
10728
|
-
|
|
10804
|
+
outputEnvelope({ success: true, data: { name } }, { command: "plugin reload" }, mode);
|
|
10729
10805
|
break;
|
|
10730
10806
|
}
|
|
10731
10807
|
case "search":
|
|
@@ -10757,24 +10833,22 @@ function handleDaemon(args, options, mode) {
|
|
|
10757
10833
|
case "start": {
|
|
10758
10834
|
const port = options.port ? Number(options.port) : 9224;
|
|
10759
10835
|
startDaemonProcess(port).then(
|
|
10760
|
-
(config) =>
|
|
10836
|
+
(config) => outputEnvelope({ success: true, data: { pid: config.pid, port: config.port } }, { command: "daemon start" }, mode)
|
|
10761
10837
|
).catch(
|
|
10762
10838
|
(e) => outputError(e instanceof Error ? e.message : String(e))
|
|
10763
10839
|
);
|
|
10764
10840
|
break;
|
|
10765
10841
|
}
|
|
10766
10842
|
case "stop": {
|
|
10767
|
-
stopDaemonProcess().then(() =>
|
|
10843
|
+
stopDaemonProcess().then(() => outputEnvelope({ success: true, data: {} }, { command: "daemon stop" }, mode)).catch(
|
|
10768
10844
|
(e) => outputError(e instanceof Error ? e.message : String(e))
|
|
10769
10845
|
);
|
|
10770
10846
|
break;
|
|
10771
10847
|
}
|
|
10772
10848
|
case "status": {
|
|
10773
10849
|
const status = getDaemonProcessStatus();
|
|
10774
|
-
|
|
10775
|
-
|
|
10776
|
-
mode
|
|
10777
|
-
);
|
|
10850
|
+
const statusData = status.running ? { running: true, pid: status.pid, port: status.port } : { running: false };
|
|
10851
|
+
outputEnvelope({ success: true, data: statusData }, { command: "daemon status" }, mode);
|
|
10778
10852
|
break;
|
|
10779
10853
|
}
|
|
10780
10854
|
default:
|
|
@@ -11152,7 +11226,7 @@ async function handleFilter(args, _mode, options) {
|
|
|
11152
11226
|
console.log(` Original: ${result.originalCount}, After: ${result.filteredCount}, Removed: ${result.removed} (${result.percentage}%)`);
|
|
11153
11227
|
}
|
|
11154
11228
|
async function handleGeneratePlugin(sessionName, pluginName, outputDir) {
|
|
11155
|
-
const { SessionRecorder: SessionRecorder2 } = await import("./session-recorder-
|
|
11229
|
+
const { SessionRecorder: SessionRecorder2 } = await import("./session-recorder-33UKWCIR.js");
|
|
11156
11230
|
const { readSiteKnowledge: readSiteKnowledge2, toMarkdown } = await import("./site-knowledge-SYC6VCDB.js");
|
|
11157
11231
|
const { mkdirSync: mkdirSync10, writeFileSync: writeFileSync12 } = await import("fs");
|
|
11158
11232
|
const { join: join14 } = await import("path");
|
|
@@ -12499,7 +12573,8 @@ var KNOWN_GLOBAL_OPTIONS = /* @__PURE__ */ new Set([
|
|
|
12499
12573
|
"port",
|
|
12500
12574
|
"token",
|
|
12501
12575
|
"timeout",
|
|
12502
|
-
"headless"
|
|
12576
|
+
"headless",
|
|
12577
|
+
"tab"
|
|
12503
12578
|
]);
|
|
12504
12579
|
function showCommandHelp(siteName, cmd, siteConfig, mode) {
|
|
12505
12580
|
const c = cmd;
|
|
@@ -12653,20 +12728,28 @@ async function handleEvalMode(argv) {
|
|
|
12653
12728
|
}
|
|
12654
12729
|
async function handleChainInput(input, argv) {
|
|
12655
12730
|
const cdpEndpoint = argv ? extractCdpFromArgv(argv) : void 0;
|
|
12656
|
-
const
|
|
12731
|
+
const hasJson = argv ? argv.some((a) => a === "--json" || a.startsWith("--json=") || a.includes(" --json") || a.startsWith("--json")) || argv.includes("-j") : false;
|
|
12732
|
+
const hasYaml = argv ? argv.some((a) => a === "--yaml" || a.startsWith("--yaml=")) : false;
|
|
12733
|
+
const mode = hasJson ? "json" : hasYaml ? "yaml" : "text";
|
|
12657
12734
|
const chainResult = await executeChain(input, { cdpEndpoint });
|
|
12658
|
-
if (
|
|
12659
|
-
|
|
12660
|
-
|
|
12661
|
-
|
|
12662
|
-
|
|
12663
|
-
|
|
12664
|
-
|
|
12665
|
-
|
|
12666
|
-
|
|
12667
|
-
|
|
12668
|
-
|
|
12669
|
-
|
|
12735
|
+
if (mode === "json" || mode === "yaml") {
|
|
12736
|
+
outputEnvelope(
|
|
12737
|
+
{
|
|
12738
|
+
success: chainResult.success,
|
|
12739
|
+
data: {
|
|
12740
|
+
steps: chainResult.steps.map((s) => ({
|
|
12741
|
+
command: s.raw,
|
|
12742
|
+
success: s.success,
|
|
12743
|
+
data: s.data,
|
|
12744
|
+
duration: s.duration,
|
|
12745
|
+
...s.hookOutputs?.length ? { hooks: s.hookOutputs } : {}
|
|
12746
|
+
}))
|
|
12747
|
+
},
|
|
12748
|
+
duration: chainResult.totalDuration
|
|
12749
|
+
},
|
|
12750
|
+
{ command: "chain", totalSteps: chainResult.steps.length },
|
|
12751
|
+
mode
|
|
12752
|
+
);
|
|
12670
12753
|
} else {
|
|
12671
12754
|
printChainResult(chainResult);
|
|
12672
12755
|
}
|
|
@@ -12733,7 +12816,15 @@ async function routeCommand(argvIn, stdinCommands) {
|
|
|
12733
12816
|
const sessionName = options.session || process.env.XBROWSER_SESSION || "default";
|
|
12734
12817
|
const cdpEndpoint = options.cdp || process.env.XBROWSER_CDP;
|
|
12735
12818
|
if (options.version || options.v && positional.length === 0) {
|
|
12736
|
-
|
|
12819
|
+
if (mode === "json") {
|
|
12820
|
+
outputEnvelope(
|
|
12821
|
+
{ success: true, data: { version, name: "@xbrowser/cli" } },
|
|
12822
|
+
{ command: "version" },
|
|
12823
|
+
mode
|
|
12824
|
+
);
|
|
12825
|
+
} else {
|
|
12826
|
+
console.log(`xbrowser v${version}`);
|
|
12827
|
+
}
|
|
12737
12828
|
return;
|
|
12738
12829
|
}
|
|
12739
12830
|
if (positional.length === 0) {
|
|
@@ -12929,18 +13020,23 @@ async function routeCommand(argvIn, stdinCommands) {
|
|
|
12929
13020
|
if (isChainInput(fullInput)) {
|
|
12930
13021
|
const chainResult = await executeChain(fullInput, { cdpEndpoint, sessionName });
|
|
12931
13022
|
if (mode === "json" || mode === "yaml") {
|
|
12932
|
-
|
|
12933
|
-
|
|
12934
|
-
|
|
12935
|
-
|
|
12936
|
-
|
|
12937
|
-
|
|
12938
|
-
|
|
12939
|
-
|
|
12940
|
-
|
|
12941
|
-
|
|
12942
|
-
|
|
12943
|
-
|
|
13023
|
+
outputEnvelope(
|
|
13024
|
+
{
|
|
13025
|
+
success: chainResult.success,
|
|
13026
|
+
data: {
|
|
13027
|
+
steps: chainResult.steps.map((s) => ({
|
|
13028
|
+
command: s.raw,
|
|
13029
|
+
success: s.success,
|
|
13030
|
+
data: s.data,
|
|
13031
|
+
duration: s.duration
|
|
13032
|
+
})),
|
|
13033
|
+
...chainResult.stoppedReason ? { stoppedReason: chainResult.stoppedReason } : {}
|
|
13034
|
+
},
|
|
13035
|
+
duration: chainResult.totalDuration
|
|
13036
|
+
},
|
|
13037
|
+
{ command: "chain", totalSteps: chainResult.steps.length },
|
|
13038
|
+
mode
|
|
13039
|
+
);
|
|
12944
13040
|
if (!chainResult.success) throw new Error("Command failed");
|
|
12945
13041
|
return;
|
|
12946
13042
|
}
|
|
@@ -13085,6 +13181,17 @@ Run "xbrowser ${command} ${subCommand} --help" to see available parameters.`
|
|
|
13085
13181
|
session = await createSession(sessionName, void 0, cdpEndpoint ? { cdpEndpoint } : {});
|
|
13086
13182
|
}
|
|
13087
13183
|
}
|
|
13184
|
+
const cmdTabIndex = options.tab !== void 0 ? Number(options.tab) : void 0;
|
|
13185
|
+
if (cmdTabIndex !== void 0 && session?.context) {
|
|
13186
|
+
const pages = session.context.pages();
|
|
13187
|
+
if (cmdTabIndex >= 0 && cmdTabIndex < pages.length) {
|
|
13188
|
+
const targetPage = pages[cmdTabIndex];
|
|
13189
|
+
await targetPage.bringToFront().catch(() => {
|
|
13190
|
+
});
|
|
13191
|
+
const { setActivePage: setActivePage2 } = await import("./browser-XPKM344Y.js");
|
|
13192
|
+
setActivePage2(session, targetPage);
|
|
13193
|
+
}
|
|
13194
|
+
}
|
|
13088
13195
|
const ctx = {
|
|
13089
13196
|
args: cmdArgsForPlugin,
|
|
13090
13197
|
options,
|
|
@@ -13162,22 +13269,17 @@ Run "xbrowser ${command} ${subCommand} --help" to see available parameters.`
|
|
|
13162
13269
|
const outputData = isCommandResult2(result) ? result.data : result && typeof result === "object" ? result.data ?? result : result;
|
|
13163
13270
|
const tips = isCommandResult2(result) ? result.tips : result && typeof result === "object" ? result.tips : void 0;
|
|
13164
13271
|
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
|
-
}
|
|
13272
|
+
const resultSuccess = isCommandResult2(result) ? result.success !== false : true;
|
|
13273
|
+
const resultMsg = isCommandResult2(result) ? result.message : void 0;
|
|
13274
|
+
const duration = Date.now() - cmdStart;
|
|
13275
|
+
const envelopeMeta = { command: `${command} ${subCommand}` };
|
|
13276
|
+
if (injectedViewerUrl) envelopeMeta.viewerUrl = injectedViewerUrl;
|
|
13277
|
+
if (hookOutputs.length > 0) envelopeMeta.hooks = hookOutputs;
|
|
13278
|
+
outputEnvelope(
|
|
13279
|
+
{ success: resultSuccess, data: outputData, message: resultMsg, tips, duration },
|
|
13280
|
+
envelopeMeta,
|
|
13281
|
+
mode
|
|
13282
|
+
);
|
|
13181
13283
|
} else {
|
|
13182
13284
|
console.log(outputFormatter2.format(outputData, { mode: "text", color: true, emoji: true }));
|
|
13183
13285
|
if (tips?.length) {
|
|
@@ -13359,7 +13461,7 @@ async function main() {
|
|
|
13359
13461
|
const command = process.argv[2];
|
|
13360
13462
|
const isLongRunning = command === "preview" || command === "serve";
|
|
13361
13463
|
if (!isLongRunning) {
|
|
13362
|
-
const { ensureProcessCanExit } = await import("./browser-
|
|
13464
|
+
const { ensureProcessCanExit } = await import("./browser-XPKM344Y.js");
|
|
13363
13465
|
await ensureProcessCanExit().catch(() => {
|
|
13364
13466
|
});
|
|
13365
13467
|
process.exit(exitCode);
|
package/dist/daemon-main.js
CHANGED
|
@@ -5,7 +5,7 @@ import {
|
|
|
5
5
|
} from "./chunk-VEDJ5XSQ.js";
|
|
6
6
|
import {
|
|
7
7
|
SessionRecorder
|
|
8
|
-
} from "./chunk-
|
|
8
|
+
} from "./chunk-FL6DOSWV.js";
|
|
9
9
|
import {
|
|
10
10
|
closeEphemeralContext,
|
|
11
11
|
closeSessionByName,
|
|
@@ -21,7 +21,7 @@ import {
|
|
|
21
21
|
resolveLaunchOpts,
|
|
22
22
|
saveSessionDiskMeta,
|
|
23
23
|
setActivePage
|
|
24
|
-
} from "./chunk-
|
|
24
|
+
} from "./chunk-HXLMMSU3.js";
|
|
25
25
|
import "./chunk-VJNMAWPZ.js";
|
|
26
26
|
import "./chunk-TNEN6VQ2.js";
|
|
27
27
|
import {
|
|
@@ -6742,9 +6742,14 @@ async function executeCommand(commandName, params, sessionName = "default", extr
|
|
|
6742
6742
|
const { _target: _u, ...rest } = params;
|
|
6743
6743
|
params = rest;
|
|
6744
6744
|
}
|
|
6745
|
+
const _tabIndex = params._tabIndex;
|
|
6746
|
+
if (_tabIndex !== void 0) {
|
|
6747
|
+
const { _tabIndex: _u, ...rest } = params;
|
|
6748
|
+
params = rest;
|
|
6749
|
+
}
|
|
6745
6750
|
let targetPageOverride = null;
|
|
6746
6751
|
if (_target && extraOpts?.cdpEndpoint) {
|
|
6747
|
-
const { findTargetPage } = await import("./browser-
|
|
6752
|
+
const { findTargetPage } = await import("./browser-LW2MDJE4.js");
|
|
6748
6753
|
targetPageOverride = await findTargetPage(extraOpts.cdpEndpoint, _target);
|
|
6749
6754
|
if (!targetPageOverride) {
|
|
6750
6755
|
return errorResult(`Target "${_target}" not found. Use 'xbrowser targets --cdp ${extraOpts.cdpEndpoint}' to list available pages.`);
|
|
@@ -6816,6 +6821,16 @@ async function executeCommand(commandName, params, sessionName = "default", extr
|
|
|
6816
6821
|
cliName: "xbrowser",
|
|
6817
6822
|
tips: new TipCollector2()
|
|
6818
6823
|
};
|
|
6824
|
+
if (_tabIndex !== void 0 && session?.context) {
|
|
6825
|
+
const pages = session.context.pages();
|
|
6826
|
+
if (_tabIndex >= 0 && _tabIndex < pages.length) {
|
|
6827
|
+
const targetPage = pages[_tabIndex];
|
|
6828
|
+
await targetPage.bringToFront().catch(() => {
|
|
6829
|
+
});
|
|
6830
|
+
setActivePage(session, targetPage);
|
|
6831
|
+
ctx.page = targetPage;
|
|
6832
|
+
}
|
|
6833
|
+
}
|
|
6819
6834
|
const start = Date.now();
|
|
6820
6835
|
if (session) {
|
|
6821
6836
|
streamCommandEvent(session.id, {
|
|
@@ -6844,7 +6859,17 @@ async function executeCommand(commandName, params, sessionName = "default", extr
|
|
|
6844
6859
|
if (hooks.length > 0 && session?.page) {
|
|
6845
6860
|
await Promise.all(hooks.map((h) => h.onBeforeCommand?.({ page: session.page, command: commandName, params })));
|
|
6846
6861
|
}
|
|
6847
|
-
|
|
6862
|
+
let raw;
|
|
6863
|
+
const handlerPromise = command.handler(params, ctx);
|
|
6864
|
+
if (extraOpts?.timeout && extraOpts.timeout > 0) {
|
|
6865
|
+
const timeoutMs = extraOpts.timeout;
|
|
6866
|
+
const timeoutPromise = new Promise(
|
|
6867
|
+
(_, reject) => setTimeout(() => reject(new Error(`Command timed out after ${timeoutMs}ms`)), timeoutMs)
|
|
6868
|
+
);
|
|
6869
|
+
raw = await Promise.race([handlerPromise, timeoutPromise]);
|
|
6870
|
+
} else {
|
|
6871
|
+
raw = await handlerPromise;
|
|
6872
|
+
}
|
|
6848
6873
|
const end = Date.now();
|
|
6849
6874
|
const duration = end - start;
|
|
6850
6875
|
let hookOutputs;
|
package/dist/index.d.ts
CHANGED
|
@@ -737,6 +737,7 @@ declare function setWSServer(server: WSServer | null): void;
|
|
|
737
737
|
declare function executeCommand(commandName: string, params: Record<string, unknown>, sessionName?: string, extraOpts?: {
|
|
738
738
|
cdpEndpoint?: string;
|
|
739
739
|
skipCleanup?: boolean;
|
|
740
|
+
timeout?: number;
|
|
740
741
|
}): Promise<ExecutionResult>;
|
|
741
742
|
/**
|
|
742
743
|
* Execute a chain of browser commands parsed from a string expression.
|
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 {
|
|
@@ -7525,9 +7525,14 @@ async function executeCommand(commandName, params, sessionName = "default", extr
|
|
|
7525
7525
|
const { _target: _u, ...rest } = params;
|
|
7526
7526
|
params = rest;
|
|
7527
7527
|
}
|
|
7528
|
+
const _tabIndex = params._tabIndex;
|
|
7529
|
+
if (_tabIndex !== void 0) {
|
|
7530
|
+
const { _tabIndex: _u, ...rest } = params;
|
|
7531
|
+
params = rest;
|
|
7532
|
+
}
|
|
7528
7533
|
let targetPageOverride = null;
|
|
7529
7534
|
if (_target && extraOpts?.cdpEndpoint) {
|
|
7530
|
-
const { findTargetPage } = await import("./browser-
|
|
7535
|
+
const { findTargetPage } = await import("./browser-TLIDFFEG.js");
|
|
7531
7536
|
targetPageOverride = await findTargetPage(extraOpts.cdpEndpoint, _target);
|
|
7532
7537
|
if (!targetPageOverride) {
|
|
7533
7538
|
return errorResult(`Target "${_target}" not found. Use 'xbrowser targets --cdp ${extraOpts.cdpEndpoint}' to list available pages.`);
|
|
@@ -7599,6 +7604,16 @@ async function executeCommand(commandName, params, sessionName = "default", extr
|
|
|
7599
7604
|
cliName: "xbrowser",
|
|
7600
7605
|
tips: new TipCollector2()
|
|
7601
7606
|
};
|
|
7607
|
+
if (_tabIndex !== void 0 && session?.context) {
|
|
7608
|
+
const pages = session.context.pages();
|
|
7609
|
+
if (_tabIndex >= 0 && _tabIndex < pages.length) {
|
|
7610
|
+
const targetPage = pages[_tabIndex];
|
|
7611
|
+
await targetPage.bringToFront().catch(() => {
|
|
7612
|
+
});
|
|
7613
|
+
setActivePage(session, targetPage);
|
|
7614
|
+
ctx.page = targetPage;
|
|
7615
|
+
}
|
|
7616
|
+
}
|
|
7602
7617
|
const start = Date.now();
|
|
7603
7618
|
if (session) {
|
|
7604
7619
|
streamCommandEvent(session.id, {
|
|
@@ -7627,7 +7642,17 @@ async function executeCommand(commandName, params, sessionName = "default", extr
|
|
|
7627
7642
|
if (hooks.length > 0 && session?.page) {
|
|
7628
7643
|
await Promise.all(hooks.map((h) => h.onBeforeCommand?.({ page: session.page, command: commandName, params })));
|
|
7629
7644
|
}
|
|
7630
|
-
|
|
7645
|
+
let raw;
|
|
7646
|
+
const handlerPromise = command.handler(params, ctx);
|
|
7647
|
+
if (extraOpts?.timeout && extraOpts.timeout > 0) {
|
|
7648
|
+
const timeoutMs = extraOpts.timeout;
|
|
7649
|
+
const timeoutPromise = new Promise(
|
|
7650
|
+
(_, reject) => setTimeout(() => reject(new Error(`Command timed out after ${timeoutMs}ms`)), timeoutMs)
|
|
7651
|
+
);
|
|
7652
|
+
raw = await Promise.race([handlerPromise, timeoutPromise]);
|
|
7653
|
+
} else {
|
|
7654
|
+
raw = await handlerPromise;
|
|
7655
|
+
}
|
|
7631
7656
|
const end = Date.now();
|
|
7632
7657
|
const duration = end - start;
|
|
7633
7658
|
let hookOutputs;
|
|
@@ -8201,16 +8226,29 @@ var configBuiltin = {
|
|
|
8201
8226
|
execute: async (args, _options, _ctx) => {
|
|
8202
8227
|
const [subcommand, ...rest] = args;
|
|
8203
8228
|
if (!subcommand || subcommand === "list") {
|
|
8229
|
+
let flatten2 = function(obj, prefix = "") {
|
|
8230
|
+
const entries2 = [];
|
|
8231
|
+
for (const [k, v] of Object.entries(obj)) {
|
|
8232
|
+
const fullKey = prefix ? `${prefix}.${k}` : k;
|
|
8233
|
+
if (v && typeof v === "object" && !Array.isArray(v)) {
|
|
8234
|
+
entries2.push(...flatten2(v, fullKey));
|
|
8235
|
+
} else {
|
|
8236
|
+
entries2.push({ key: fullKey, value: v });
|
|
8237
|
+
}
|
|
8238
|
+
}
|
|
8239
|
+
return entries2;
|
|
8240
|
+
};
|
|
8241
|
+
var flatten = flatten2;
|
|
8204
8242
|
const config = loadConfig();
|
|
8205
|
-
const
|
|
8206
|
-
if (
|
|
8243
|
+
const entries = flatten2(config);
|
|
8244
|
+
if (entries.length === 0) {
|
|
8207
8245
|
console.log("Configuration is empty");
|
|
8208
8246
|
return;
|
|
8209
8247
|
}
|
|
8210
8248
|
console.log("Configuration:");
|
|
8211
8249
|
console.log("");
|
|
8212
|
-
for (const
|
|
8213
|
-
console.log(` ${
|
|
8250
|
+
for (const { key, value } of entries) {
|
|
8251
|
+
console.log(` ${key} = ${value}`);
|
|
8214
8252
|
}
|
|
8215
8253
|
return;
|
|
8216
8254
|
}
|
|
@@ -9009,6 +9047,39 @@ function outputError(message) {
|
|
|
9009
9047
|
console.error(formatted);
|
|
9010
9048
|
process.exit(1);
|
|
9011
9049
|
}
|
|
9050
|
+
function outputEnvelope(result, meta, mode) {
|
|
9051
|
+
if (mode !== "json" && mode !== "yaml") {
|
|
9052
|
+
if (!result.success) {
|
|
9053
|
+
outputError(result.message || "Unknown error");
|
|
9054
|
+
return;
|
|
9055
|
+
}
|
|
9056
|
+
outputResult(result.data, mode);
|
|
9057
|
+
return;
|
|
9058
|
+
}
|
|
9059
|
+
const { command, ...extraMeta } = meta;
|
|
9060
|
+
const commandResult = {
|
|
9061
|
+
success: result.success,
|
|
9062
|
+
data: result.data,
|
|
9063
|
+
message: result.message,
|
|
9064
|
+
tips: [],
|
|
9065
|
+
meta: {
|
|
9066
|
+
duration: result.duration ?? 0,
|
|
9067
|
+
...extraMeta
|
|
9068
|
+
}
|
|
9069
|
+
};
|
|
9070
|
+
const formatted = outputFormatter.formatEnvelope(commandResult, {
|
|
9071
|
+
command,
|
|
9072
|
+
extraMeta,
|
|
9073
|
+
mode
|
|
9074
|
+
});
|
|
9075
|
+
console.log(formatted);
|
|
9076
|
+
if (result.tips?.length) {
|
|
9077
|
+
for (const tip of result.tips) {
|
|
9078
|
+
const text = typeof tip === "string" ? tip : tip.message;
|
|
9079
|
+
if (text) console.error(` \u{1F4A1} ${text}`);
|
|
9080
|
+
}
|
|
9081
|
+
}
|
|
9082
|
+
}
|
|
9012
9083
|
|
|
9013
9084
|
// src/builtins/plugin.ts
|
|
9014
9085
|
var pluginLoader2 = null;
|
|
@@ -10573,9 +10644,13 @@ async function handleBrowserCommand(command, args, options, sessionName, mode, c
|
|
|
10573
10644
|
if (target) {
|
|
10574
10645
|
params = { ...params, _target: target };
|
|
10575
10646
|
}
|
|
10647
|
+
const tabIndex = options.tab;
|
|
10648
|
+
if (tabIndex !== void 0) {
|
|
10649
|
+
params = { ...params, _tabIndex: Number(tabIndex) };
|
|
10650
|
+
}
|
|
10576
10651
|
const result = cdpEndpoint ? await executeCommand(cmdName, params, sessionName, { cdpEndpoint }) : await executeCommand(cmdName, params, sessionName);
|
|
10577
10652
|
if (mode === "json" || mode === "yaml") {
|
|
10578
|
-
|
|
10653
|
+
outputEnvelope(result, { command: cmdName }, mode);
|
|
10579
10654
|
} else if (!result.success) {
|
|
10580
10655
|
outputError(result.message || "Command failed");
|
|
10581
10656
|
} else {
|
|
@@ -10635,7 +10710,7 @@ async function handleSession(args, options, mode, _cdpEndpoint) {
|
|
|
10635
10710
|
}
|
|
10636
10711
|
} catch {
|
|
10637
10712
|
}
|
|
10638
|
-
|
|
10713
|
+
outputEnvelope({ success: true, data: { closed: count, all: true } }, { command: "session close" }, mode);
|
|
10639
10714
|
} else {
|
|
10640
10715
|
const name = options.session || options.name || process.env.XBROWSER_SESSION || "default";
|
|
10641
10716
|
try {
|
|
@@ -10643,7 +10718,7 @@ async function handleSession(args, options, mode, _cdpEndpoint) {
|
|
|
10643
10718
|
} catch {
|
|
10644
10719
|
}
|
|
10645
10720
|
await closeSession(name);
|
|
10646
|
-
|
|
10721
|
+
outputEnvelope({ success: true, data: { name } }, { command: "session close" }, mode);
|
|
10647
10722
|
}
|
|
10648
10723
|
break;
|
|
10649
10724
|
}
|
|
@@ -10651,10 +10726,10 @@ async function handleSession(args, options, mode, _cdpEndpoint) {
|
|
|
10651
10726
|
case "ls": {
|
|
10652
10727
|
try {
|
|
10653
10728
|
const sessions2 = await forwardSessionList();
|
|
10654
|
-
|
|
10729
|
+
outputEnvelope({ success: true, data: { sessions: sessions2 } }, { command: "session list" }, mode);
|
|
10655
10730
|
} catch {
|
|
10656
10731
|
const sessions2 = await listSessions();
|
|
10657
|
-
|
|
10732
|
+
outputEnvelope({ success: true, data: { sessions: sessions2 } }, { command: "session list" }, mode);
|
|
10658
10733
|
}
|
|
10659
10734
|
break;
|
|
10660
10735
|
}
|
|
@@ -10669,7 +10744,7 @@ async function handleSession(args, options, mode, _cdpEndpoint) {
|
|
|
10669
10744
|
await stopDaemonProcess();
|
|
10670
10745
|
} catch {
|
|
10671
10746
|
}
|
|
10672
|
-
|
|
10747
|
+
outputEnvelope({ success: true, data: { name, killed: true, daemon: "stopped" } }, { command: "session kill" }, mode);
|
|
10673
10748
|
break;
|
|
10674
10749
|
}
|
|
10675
10750
|
case "kill-all": {
|
|
@@ -10688,7 +10763,7 @@ async function handleSession(args, options, mode, _cdpEndpoint) {
|
|
|
10688
10763
|
} catch {
|
|
10689
10764
|
}
|
|
10690
10765
|
const cleaned = cleanSessionFiles();
|
|
10691
|
-
|
|
10766
|
+
outputEnvelope({ success: true, data: { sessionsCleaned: cleaned, daemon: "killed" } }, { command: "session kill-all" }, mode);
|
|
10692
10767
|
break;
|
|
10693
10768
|
}
|
|
10694
10769
|
default:
|
|
@@ -10808,7 +10883,7 @@ async function handleSearch(args, options, mode) {
|
|
|
10808
10883
|
}
|
|
10809
10884
|
}
|
|
10810
10885
|
if (mode === "json") {
|
|
10811
|
-
|
|
10886
|
+
outputEnvelope({ success: true, data: { results, total: results.length } }, { command: "plugin search" }, mode);
|
|
10812
10887
|
} else {
|
|
10813
10888
|
if (results.length === 0) {
|
|
10814
10889
|
console.log("No plugins found");
|
|
@@ -10837,7 +10912,7 @@ async function handlePluginInfo(args, options, mode) {
|
|
|
10837
10912
|
if (pluginInfo) {
|
|
10838
10913
|
const d = pluginInfo;
|
|
10839
10914
|
if (mode === "json") {
|
|
10840
|
-
|
|
10915
|
+
outputEnvelope({ success: true, data: { source: "marketplace", ...d } }, { command: "plugin info" }, mode);
|
|
10841
10916
|
return;
|
|
10842
10917
|
}
|
|
10843
10918
|
console.log(`\u540D\u79F0: ${d.name || ""}`);
|
|
@@ -10863,7 +10938,7 @@ async function handlePluginInfo(args, options, mode) {
|
|
|
10863
10938
|
const pkg = latest && versions?.[latest];
|
|
10864
10939
|
if (pkg) {
|
|
10865
10940
|
if (mode === "json") {
|
|
10866
|
-
|
|
10941
|
+
outputEnvelope({ success: true, data: { source: "npm", name: pkg.name, version: latest, description: pkg.description } }, { command: "plugin info" }, mode);
|
|
10867
10942
|
return;
|
|
10868
10943
|
}
|
|
10869
10944
|
console.log(`\u540D\u79F0: ${pkg.name || ""}`);
|
|
@@ -10892,7 +10967,7 @@ async function handlePluginSchema(args, mode) {
|
|
|
10892
10967
|
return;
|
|
10893
10968
|
}
|
|
10894
10969
|
if (mode === "json") {
|
|
10895
|
-
|
|
10970
|
+
outputEnvelope({ success: true, data: contract }, { command: "plugin schema" }, mode);
|
|
10896
10971
|
return;
|
|
10897
10972
|
}
|
|
10898
10973
|
if ("commands" in contract) {
|
|
@@ -10970,8 +11045,9 @@ async function handlePlugin(args, options, mode) {
|
|
|
10970
11045
|
}
|
|
10971
11046
|
} catch {
|
|
10972
11047
|
}
|
|
10973
|
-
|
|
10974
|
-
{
|
|
11048
|
+
outputEnvelope(
|
|
11049
|
+
{ success: true, data: { name: result.name, source: result.source, path: result.path } },
|
|
11050
|
+
{ command: "plugin install" },
|
|
10975
11051
|
mode
|
|
10976
11052
|
);
|
|
10977
11053
|
break;
|
|
@@ -10990,7 +11066,7 @@ async function handlePlugin(args, options, mode) {
|
|
|
10990
11066
|
await loader.reloadPlugin(name);
|
|
10991
11067
|
} catch {
|
|
10992
11068
|
}
|
|
10993
|
-
|
|
11069
|
+
outputEnvelope({ success: true, data: { name } }, { command: "plugin uninstall" }, mode);
|
|
10994
11070
|
break;
|
|
10995
11071
|
}
|
|
10996
11072
|
case "list": {
|
|
@@ -11012,7 +11088,7 @@ async function handlePlugin(args, options, mode) {
|
|
|
11012
11088
|
};
|
|
11013
11089
|
});
|
|
11014
11090
|
if (mode === "json") {
|
|
11015
|
-
|
|
11091
|
+
outputEnvelope({ success: true, data: { plugins: enrichedPlugins } }, { command: "plugin list" }, mode);
|
|
11016
11092
|
} else {
|
|
11017
11093
|
if (enrichedPlugins.length === 0) {
|
|
11018
11094
|
console.log("No plugins installed");
|
|
@@ -11048,7 +11124,7 @@ Total: ${enrichedPlugins.length} plugins`);
|
|
|
11048
11124
|
} catch {
|
|
11049
11125
|
outputError(`Plugin "${name}" not found. Use 'xbrowser plugin list' to see installed plugins.`);
|
|
11050
11126
|
}
|
|
11051
|
-
|
|
11127
|
+
outputEnvelope({ success: true, data: { name } }, { command: "plugin reload" }, mode);
|
|
11052
11128
|
break;
|
|
11053
11129
|
}
|
|
11054
11130
|
case "search":
|
|
@@ -11080,24 +11156,22 @@ function handleDaemon(args, options, mode) {
|
|
|
11080
11156
|
case "start": {
|
|
11081
11157
|
const port = options.port ? Number(options.port) : 9224;
|
|
11082
11158
|
startDaemonProcess(port).then(
|
|
11083
|
-
(config) =>
|
|
11159
|
+
(config) => outputEnvelope({ success: true, data: { pid: config.pid, port: config.port } }, { command: "daemon start" }, mode)
|
|
11084
11160
|
).catch(
|
|
11085
11161
|
(e) => outputError(e instanceof Error ? e.message : String(e))
|
|
11086
11162
|
);
|
|
11087
11163
|
break;
|
|
11088
11164
|
}
|
|
11089
11165
|
case "stop": {
|
|
11090
|
-
stopDaemonProcess().then(() =>
|
|
11166
|
+
stopDaemonProcess().then(() => outputEnvelope({ success: true, data: {} }, { command: "daemon stop" }, mode)).catch(
|
|
11091
11167
|
(e) => outputError(e instanceof Error ? e.message : String(e))
|
|
11092
11168
|
);
|
|
11093
11169
|
break;
|
|
11094
11170
|
}
|
|
11095
11171
|
case "status": {
|
|
11096
11172
|
const status = getDaemonProcessStatus();
|
|
11097
|
-
|
|
11098
|
-
|
|
11099
|
-
mode
|
|
11100
|
-
);
|
|
11173
|
+
const statusData = status.running ? { running: true, pid: status.pid, port: status.port } : { running: false };
|
|
11174
|
+
outputEnvelope({ success: true, data: statusData }, { command: "daemon status" }, mode);
|
|
11101
11175
|
break;
|
|
11102
11176
|
}
|
|
11103
11177
|
default:
|
|
@@ -11475,7 +11549,7 @@ async function handleFilter(args, _mode, options) {
|
|
|
11475
11549
|
console.log(` Original: ${result.originalCount}, After: ${result.filteredCount}, Removed: ${result.removed} (${result.percentage}%)`);
|
|
11476
11550
|
}
|
|
11477
11551
|
async function handleGeneratePlugin(sessionName, pluginName, outputDir) {
|
|
11478
|
-
const { SessionRecorder: SessionRecorder2 } = await import("./session-recorder-
|
|
11552
|
+
const { SessionRecorder: SessionRecorder2 } = await import("./session-recorder-33UKWCIR.js");
|
|
11479
11553
|
const { readSiteKnowledge: readSiteKnowledge2, toMarkdown } = await import("./site-knowledge-SYC6VCDB.js");
|
|
11480
11554
|
const { mkdirSync: mkdirSync11, writeFileSync: writeFileSync13 } = await import("fs");
|
|
11481
11555
|
const { join: join14 } = await import("path");
|
|
@@ -12822,7 +12896,8 @@ var KNOWN_GLOBAL_OPTIONS = /* @__PURE__ */ new Set([
|
|
|
12822
12896
|
"port",
|
|
12823
12897
|
"token",
|
|
12824
12898
|
"timeout",
|
|
12825
|
-
"headless"
|
|
12899
|
+
"headless",
|
|
12900
|
+
"tab"
|
|
12826
12901
|
]);
|
|
12827
12902
|
function showCommandHelp(siteName, cmd, siteConfig, mode) {
|
|
12828
12903
|
const c = cmd;
|
|
@@ -12976,20 +13051,28 @@ async function handleEvalMode(argv) {
|
|
|
12976
13051
|
}
|
|
12977
13052
|
async function handleChainInput(input, argv) {
|
|
12978
13053
|
const cdpEndpoint = argv ? extractCdpFromArgv(argv) : void 0;
|
|
12979
|
-
const
|
|
13054
|
+
const hasJson = argv ? argv.some((a) => a === "--json" || a.startsWith("--json=") || a.includes(" --json") || a.startsWith("--json")) || argv.includes("-j") : false;
|
|
13055
|
+
const hasYaml = argv ? argv.some((a) => a === "--yaml" || a.startsWith("--yaml=")) : false;
|
|
13056
|
+
const mode = hasJson ? "json" : hasYaml ? "yaml" : "text";
|
|
12980
13057
|
const chainResult = await executeChain(input, { cdpEndpoint });
|
|
12981
|
-
if (
|
|
12982
|
-
|
|
12983
|
-
|
|
12984
|
-
|
|
12985
|
-
|
|
12986
|
-
|
|
12987
|
-
|
|
12988
|
-
|
|
12989
|
-
|
|
12990
|
-
|
|
12991
|
-
|
|
12992
|
-
|
|
13058
|
+
if (mode === "json" || mode === "yaml") {
|
|
13059
|
+
outputEnvelope(
|
|
13060
|
+
{
|
|
13061
|
+
success: chainResult.success,
|
|
13062
|
+
data: {
|
|
13063
|
+
steps: chainResult.steps.map((s) => ({
|
|
13064
|
+
command: s.raw,
|
|
13065
|
+
success: s.success,
|
|
13066
|
+
data: s.data,
|
|
13067
|
+
duration: s.duration,
|
|
13068
|
+
...s.hookOutputs?.length ? { hooks: s.hookOutputs } : {}
|
|
13069
|
+
}))
|
|
13070
|
+
},
|
|
13071
|
+
duration: chainResult.totalDuration
|
|
13072
|
+
},
|
|
13073
|
+
{ command: "chain", totalSteps: chainResult.steps.length },
|
|
13074
|
+
mode
|
|
13075
|
+
);
|
|
12993
13076
|
} else {
|
|
12994
13077
|
printChainResult(chainResult);
|
|
12995
13078
|
}
|
|
@@ -13056,7 +13139,15 @@ async function routeCommand(argvIn, stdinCommands) {
|
|
|
13056
13139
|
const sessionName = options.session || process.env.XBROWSER_SESSION || "default";
|
|
13057
13140
|
const cdpEndpoint = options.cdp || process.env.XBROWSER_CDP;
|
|
13058
13141
|
if (options.version || options.v && positional.length === 0) {
|
|
13059
|
-
|
|
13142
|
+
if (mode === "json") {
|
|
13143
|
+
outputEnvelope(
|
|
13144
|
+
{ success: true, data: { version, name: "@xbrowser/cli" } },
|
|
13145
|
+
{ command: "version" },
|
|
13146
|
+
mode
|
|
13147
|
+
);
|
|
13148
|
+
} else {
|
|
13149
|
+
console.log(`xbrowser v${version}`);
|
|
13150
|
+
}
|
|
13060
13151
|
return;
|
|
13061
13152
|
}
|
|
13062
13153
|
if (positional.length === 0) {
|
|
@@ -13252,18 +13343,23 @@ async function routeCommand(argvIn, stdinCommands) {
|
|
|
13252
13343
|
if (isChainInput(fullInput)) {
|
|
13253
13344
|
const chainResult = await executeChain(fullInput, { cdpEndpoint, sessionName });
|
|
13254
13345
|
if (mode === "json" || mode === "yaml") {
|
|
13255
|
-
|
|
13256
|
-
|
|
13257
|
-
|
|
13258
|
-
|
|
13259
|
-
|
|
13260
|
-
|
|
13261
|
-
|
|
13262
|
-
|
|
13263
|
-
|
|
13264
|
-
|
|
13265
|
-
|
|
13266
|
-
|
|
13346
|
+
outputEnvelope(
|
|
13347
|
+
{
|
|
13348
|
+
success: chainResult.success,
|
|
13349
|
+
data: {
|
|
13350
|
+
steps: chainResult.steps.map((s) => ({
|
|
13351
|
+
command: s.raw,
|
|
13352
|
+
success: s.success,
|
|
13353
|
+
data: s.data,
|
|
13354
|
+
duration: s.duration
|
|
13355
|
+
})),
|
|
13356
|
+
...chainResult.stoppedReason ? { stoppedReason: chainResult.stoppedReason } : {}
|
|
13357
|
+
},
|
|
13358
|
+
duration: chainResult.totalDuration
|
|
13359
|
+
},
|
|
13360
|
+
{ command: "chain", totalSteps: chainResult.steps.length },
|
|
13361
|
+
mode
|
|
13362
|
+
);
|
|
13267
13363
|
if (!chainResult.success) throw new Error("Command failed");
|
|
13268
13364
|
return;
|
|
13269
13365
|
}
|
|
@@ -13408,6 +13504,17 @@ Run "xbrowser ${command} ${subCommand} --help" to see available parameters.`
|
|
|
13408
13504
|
session = await createSession(sessionName, void 0, cdpEndpoint ? { cdpEndpoint } : {});
|
|
13409
13505
|
}
|
|
13410
13506
|
}
|
|
13507
|
+
const cmdTabIndex = options.tab !== void 0 ? Number(options.tab) : void 0;
|
|
13508
|
+
if (cmdTabIndex !== void 0 && session?.context) {
|
|
13509
|
+
const pages = session.context.pages();
|
|
13510
|
+
if (cmdTabIndex >= 0 && cmdTabIndex < pages.length) {
|
|
13511
|
+
const targetPage = pages[cmdTabIndex];
|
|
13512
|
+
await targetPage.bringToFront().catch(() => {
|
|
13513
|
+
});
|
|
13514
|
+
const { setActivePage: setActivePage2 } = await import("./browser-TLIDFFEG.js");
|
|
13515
|
+
setActivePage2(session, targetPage);
|
|
13516
|
+
}
|
|
13517
|
+
}
|
|
13411
13518
|
const ctx = {
|
|
13412
13519
|
args: cmdArgsForPlugin,
|
|
13413
13520
|
options,
|
|
@@ -13485,22 +13592,17 @@ Run "xbrowser ${command} ${subCommand} --help" to see available parameters.`
|
|
|
13485
13592
|
const outputData = isCommandResult2(result) ? result.data : result && typeof result === "object" ? result.data ?? result : result;
|
|
13486
13593
|
const tips = isCommandResult2(result) ? result.tips : result && typeof result === "object" ? result.tips : void 0;
|
|
13487
13594
|
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
|
-
}
|
|
13595
|
+
const resultSuccess = isCommandResult2(result) ? result.success !== false : true;
|
|
13596
|
+
const resultMsg = isCommandResult2(result) ? result.message : void 0;
|
|
13597
|
+
const duration = Date.now() - cmdStart;
|
|
13598
|
+
const envelopeMeta = { command: `${command} ${subCommand}` };
|
|
13599
|
+
if (injectedViewerUrl) envelopeMeta.viewerUrl = injectedViewerUrl;
|
|
13600
|
+
if (hookOutputs.length > 0) envelopeMeta.hooks = hookOutputs;
|
|
13601
|
+
outputEnvelope(
|
|
13602
|
+
{ success: resultSuccess, data: outputData, message: resultMsg, tips, duration },
|
|
13603
|
+
envelopeMeta,
|
|
13604
|
+
mode
|
|
13605
|
+
);
|
|
13504
13606
|
} else {
|
|
13505
13607
|
console.log(outputFormatter2.format(outputData, { mode: "text", color: true, emoji: true }));
|
|
13506
13608
|
if (tips?.length) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@xbrowser/cli",
|
|
3
|
-
"version": "1.8.
|
|
3
|
+
"version": "1.8.6",
|
|
4
4
|
"description": "Browser automation CLI for web scraping, headless browsing, SEO analysis, and AI agent workflows. A command-line alternative to Playwright, Puppeteer, and Selenium.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -84,7 +84,7 @@
|
|
|
84
84
|
"prepare": "husky"
|
|
85
85
|
},
|
|
86
86
|
"dependencies": {
|
|
87
|
-
"@dyyz1993/xcli-core": "^0.
|
|
87
|
+
"@dyyz1993/xcli-core": "^0.19.0",
|
|
88
88
|
"@types/react-syntax-highlighter": "^15.5.13",
|
|
89
89
|
"@types/turndown": "^5.0.6",
|
|
90
90
|
"cheerio": "^1.2.0",
|