@xbrowser/cli 1.0.8 → 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{chunk-OPRXFZVE.js → chunk-AT4PHAJY.js} +16 -2
- package/dist/{chunk-WJRE55TN.js → chunk-O3FLVCUU.js} +37 -0
- package/dist/{chunk-6WOSXSCQ.js → chunk-XYXCS7JW.js} +37 -0
- package/dist/cli.js +7 -7
- package/dist/{daemon-client-DIEHGP5B.js → daemon-client-R4QWHD7V.js} +1 -1
- package/dist/{daemon-client-3JOKX2L2.js → daemon-client-ZHO6NG36.js} +1 -1
- package/dist/daemon-main.js +15 -3
- package/dist/{filter-T7DSZ2X7.js → filter-3JQWBM5F.js} +1 -1
- package/dist/{filter-KCFO4RSV.js → filter-EDTFGLS5.js} +16 -2
- package/dist/index.js +8 -8
- package/package.json +1 -1
|
@@ -38,9 +38,23 @@ function filterRecording(inputPath, outputPath, excludeTypes) {
|
|
|
38
38
|
return { originalCount, filteredCount, removed, percentage };
|
|
39
39
|
}
|
|
40
40
|
function parseExcludeTypes(args) {
|
|
41
|
-
for (
|
|
41
|
+
for (let i = 0; i < args.length; i++) {
|
|
42
|
+
const arg = args[i];
|
|
42
43
|
if (arg.startsWith("--exclude-types=")) {
|
|
43
|
-
return arg.replace("--exclude-types=", "").split(",");
|
|
44
|
+
return arg.replace("--exclude-types=", "").split(",").map((s) => s.trim());
|
|
45
|
+
}
|
|
46
|
+
if (arg === "--exclude-types" && args[i + 1]) {
|
|
47
|
+
return args[i + 1].split(",").map((s) => s.trim());
|
|
48
|
+
}
|
|
49
|
+
if (arg.startsWith("--exclude=")) {
|
|
50
|
+
return arg.replace("--exclude=", "").split(",").map((s) => s.trim());
|
|
51
|
+
}
|
|
52
|
+
if (arg === "--exclude" && args[i + 1]) {
|
|
53
|
+
const types = [];
|
|
54
|
+
for (let j = i + 1; j < args.length && !args[j].startsWith("-"); j++) {
|
|
55
|
+
types.push(...args[j].split(",").map((s) => s.trim()));
|
|
56
|
+
}
|
|
57
|
+
if (types.length > 0) return types;
|
|
44
58
|
}
|
|
45
59
|
}
|
|
46
60
|
return void 0;
|
|
@@ -3,6 +3,7 @@ import { spawn } from "child_process";
|
|
|
3
3
|
import { join, dirname } from "path";
|
|
4
4
|
import { homedir } from "os";
|
|
5
5
|
import { fileURLToPath } from "url";
|
|
6
|
+
import { writeFileSync, unlinkSync, mkdirSync } from "fs";
|
|
6
7
|
import { stopDaemon as xcliStopDaemon, isDaemonRunning, getDaemonStatus, killAllDaemon } from "@dyyz1993/xcli-core";
|
|
7
8
|
var CONFIG_DIR = join(homedir(), ".xbrowser");
|
|
8
9
|
var __dirname = dirname(fileURLToPath(import.meta.url));
|
|
@@ -23,6 +24,30 @@ async function startDaemonProcess(port = 9224) {
|
|
|
23
24
|
}
|
|
24
25
|
await xcliStopDaemon(config);
|
|
25
26
|
}
|
|
27
|
+
const lockFile = join(CONFIG_DIR, "daemon.lock");
|
|
28
|
+
try {
|
|
29
|
+
mkdirSync(CONFIG_DIR, { recursive: true });
|
|
30
|
+
writeFileSync(lockFile, String(process.pid), { flag: "wx" });
|
|
31
|
+
} catch {
|
|
32
|
+
console.error("Another process is starting the daemon, waiting...");
|
|
33
|
+
for (let i = 0; i < 50; i++) {
|
|
34
|
+
await new Promise((r) => setTimeout(r, 200));
|
|
35
|
+
if (isDaemonRunning(config)) {
|
|
36
|
+
const s = getDaemonStatus(config);
|
|
37
|
+
if (s.port === port && s.pid) {
|
|
38
|
+
return { pid: s.pid, port: s.port, startedAt: (/* @__PURE__ */ new Date()).toISOString() };
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
try {
|
|
43
|
+
unlinkSync(lockFile);
|
|
44
|
+
} catch {
|
|
45
|
+
}
|
|
46
|
+
try {
|
|
47
|
+
writeFileSync(lockFile, String(process.pid), { flag: "wx" });
|
|
48
|
+
} catch {
|
|
49
|
+
}
|
|
50
|
+
}
|
|
26
51
|
const child = spawn("node", [WORKER_PATH], {
|
|
27
52
|
detached: true,
|
|
28
53
|
stdio: "ignore",
|
|
@@ -37,6 +62,10 @@ async function startDaemonProcess(port = 9224) {
|
|
|
37
62
|
const timeout = setTimeout(() => {
|
|
38
63
|
if (!resolved) {
|
|
39
64
|
resolved = true;
|
|
65
|
+
try {
|
|
66
|
+
unlinkSync(lockFile);
|
|
67
|
+
} catch {
|
|
68
|
+
}
|
|
40
69
|
reject(new Error("Daemon start timeout after 15s"));
|
|
41
70
|
}
|
|
42
71
|
}, 15e3);
|
|
@@ -47,6 +76,10 @@ async function startDaemonProcess(port = 9224) {
|
|
|
47
76
|
resolved = true;
|
|
48
77
|
clearTimeout(timeout);
|
|
49
78
|
clearInterval(checkInterval);
|
|
79
|
+
try {
|
|
80
|
+
unlinkSync(lockFile);
|
|
81
|
+
} catch {
|
|
82
|
+
}
|
|
50
83
|
resolve({ pid: s.pid, port: s.port, startedAt: (/* @__PURE__ */ new Date()).toISOString() });
|
|
51
84
|
}
|
|
52
85
|
}
|
|
@@ -56,6 +89,10 @@ async function startDaemonProcess(port = 9224) {
|
|
|
56
89
|
resolved = true;
|
|
57
90
|
clearTimeout(timeout);
|
|
58
91
|
clearInterval(checkInterval);
|
|
92
|
+
try {
|
|
93
|
+
unlinkSync(lockFile);
|
|
94
|
+
} catch {
|
|
95
|
+
}
|
|
59
96
|
reject(err);
|
|
60
97
|
}
|
|
61
98
|
});
|
|
@@ -7,6 +7,7 @@ import { spawn } from "child_process";
|
|
|
7
7
|
import { join, dirname } from "path";
|
|
8
8
|
import { homedir } from "os";
|
|
9
9
|
import { fileURLToPath } from "url";
|
|
10
|
+
import { writeFileSync, unlinkSync, mkdirSync } from "fs";
|
|
10
11
|
import { stopDaemon as xcliStopDaemon, isDaemonRunning, getDaemonStatus, killAllDaemon } from "@dyyz1993/xcli-core";
|
|
11
12
|
var CONFIG_DIR = join(homedir(), ".xbrowser");
|
|
12
13
|
var __dirname = dirname(fileURLToPath(import.meta.url));
|
|
@@ -27,6 +28,30 @@ async function startDaemonProcess(port = 9224) {
|
|
|
27
28
|
}
|
|
28
29
|
await xcliStopDaemon(config);
|
|
29
30
|
}
|
|
31
|
+
const lockFile = join(CONFIG_DIR, "daemon.lock");
|
|
32
|
+
try {
|
|
33
|
+
mkdirSync(CONFIG_DIR, { recursive: true });
|
|
34
|
+
writeFileSync(lockFile, String(process.pid), { flag: "wx" });
|
|
35
|
+
} catch {
|
|
36
|
+
console.error("Another process is starting the daemon, waiting...");
|
|
37
|
+
for (let i = 0; i < 50; i++) {
|
|
38
|
+
await new Promise((r) => setTimeout(r, 200));
|
|
39
|
+
if (isDaemonRunning(config)) {
|
|
40
|
+
const s = getDaemonStatus(config);
|
|
41
|
+
if (s.port === port && s.pid) {
|
|
42
|
+
return { pid: s.pid, port: s.port, startedAt: (/* @__PURE__ */ new Date()).toISOString() };
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
try {
|
|
47
|
+
unlinkSync(lockFile);
|
|
48
|
+
} catch {
|
|
49
|
+
}
|
|
50
|
+
try {
|
|
51
|
+
writeFileSync(lockFile, String(process.pid), { flag: "wx" });
|
|
52
|
+
} catch {
|
|
53
|
+
}
|
|
54
|
+
}
|
|
30
55
|
const child = spawn("node", [WORKER_PATH], {
|
|
31
56
|
detached: true,
|
|
32
57
|
stdio: "ignore",
|
|
@@ -41,6 +66,10 @@ async function startDaemonProcess(port = 9224) {
|
|
|
41
66
|
const timeout = setTimeout(() => {
|
|
42
67
|
if (!resolved) {
|
|
43
68
|
resolved = true;
|
|
69
|
+
try {
|
|
70
|
+
unlinkSync(lockFile);
|
|
71
|
+
} catch {
|
|
72
|
+
}
|
|
44
73
|
reject(new Error("Daemon start timeout after 15s"));
|
|
45
74
|
}
|
|
46
75
|
}, 15e3);
|
|
@@ -51,6 +80,10 @@ async function startDaemonProcess(port = 9224) {
|
|
|
51
80
|
resolved = true;
|
|
52
81
|
clearTimeout(timeout);
|
|
53
82
|
clearInterval(checkInterval);
|
|
83
|
+
try {
|
|
84
|
+
unlinkSync(lockFile);
|
|
85
|
+
} catch {
|
|
86
|
+
}
|
|
54
87
|
resolve({ pid: s.pid, port: s.port, startedAt: (/* @__PURE__ */ new Date()).toISOString() });
|
|
55
88
|
}
|
|
56
89
|
}
|
|
@@ -60,6 +93,10 @@ async function startDaemonProcess(port = 9224) {
|
|
|
60
93
|
resolved = true;
|
|
61
94
|
clearTimeout(timeout);
|
|
62
95
|
clearInterval(checkInterval);
|
|
96
|
+
try {
|
|
97
|
+
unlinkSync(lockFile);
|
|
98
|
+
} catch {
|
|
99
|
+
}
|
|
63
100
|
reject(err);
|
|
64
101
|
}
|
|
65
102
|
});
|
package/dist/cli.js
CHANGED
|
@@ -54,7 +54,7 @@ import {
|
|
|
54
54
|
killAllDaemonProcesses,
|
|
55
55
|
startDaemonProcess,
|
|
56
56
|
stopDaemonProcess
|
|
57
|
-
} from "./chunk-
|
|
57
|
+
} from "./chunk-XYXCS7JW.js";
|
|
58
58
|
import {
|
|
59
59
|
errMsg
|
|
60
60
|
} from "./chunk-GDKLH7ZY.js";
|
|
@@ -6984,7 +6984,7 @@ async function executeCommand(commandName, params, sessionName = "default", extr
|
|
|
6984
6984
|
params = result.data;
|
|
6985
6985
|
}
|
|
6986
6986
|
if (command.scope !== "cli" && !process.env.XBROWSER_DAEMON_WORKER) {
|
|
6987
|
-
const { forwardExec } = await import("./daemon-client-
|
|
6987
|
+
const { forwardExec } = await import("./daemon-client-ZHO6NG36.js");
|
|
6988
6988
|
const result = await forwardExec(commandName, params, sessionName, extraOpts?.cdpEndpoint);
|
|
6989
6989
|
if (result) return result;
|
|
6990
6990
|
}
|
|
@@ -10646,7 +10646,7 @@ async function handleFilter(args, _mode) {
|
|
|
10646
10646
|
console.error("Usage: xbrowser filter <input.yaml> <output.yaml> [--exclude-types=type1,type2]");
|
|
10647
10647
|
process.exit(1);
|
|
10648
10648
|
}
|
|
10649
|
-
const { filterRecording, parseExcludeTypes } = await import("./filter-
|
|
10649
|
+
const { filterRecording, parseExcludeTypes } = await import("./filter-EDTFGLS5.js");
|
|
10650
10650
|
const excludeTypes = parseExcludeTypes(args.slice(2));
|
|
10651
10651
|
const result = filterRecording(filePath, outputPath, excludeTypes);
|
|
10652
10652
|
console.log(`Filtered ${filePath} -> ${outputPath}`);
|
|
@@ -12272,13 +12272,13 @@ async function routeCommand(argvIn, stdinCommands) {
|
|
|
12272
12272
|
handleConfig(cmdArgs, options);
|
|
12273
12273
|
break;
|
|
12274
12274
|
case "convert":
|
|
12275
|
-
handleConvert(cmdArgs, mode);
|
|
12275
|
+
await handleConvert(cmdArgs, mode);
|
|
12276
12276
|
break;
|
|
12277
12277
|
case "extract":
|
|
12278
|
-
handleExtract(cmdArgs, mode);
|
|
12278
|
+
await handleExtract(cmdArgs, mode);
|
|
12279
12279
|
break;
|
|
12280
12280
|
case "filter":
|
|
12281
|
-
handleFilter(cmdArgs, mode);
|
|
12281
|
+
await handleFilter(cmdArgs, mode);
|
|
12282
12282
|
break;
|
|
12283
12283
|
case "run":
|
|
12284
12284
|
if (!cmdArgs[0]) {
|
|
@@ -12421,7 +12421,7 @@ Run "xbrowser ${command} ${subCommand} --help" to see available parameters.`
|
|
|
12421
12421
|
}
|
|
12422
12422
|
const needsBrowser = cmdEntry.scope === "page" || cmdEntry.scope === "browser";
|
|
12423
12423
|
if (needsBrowser && !process.env.XBROWSER_DAEMON_WORKER) {
|
|
12424
|
-
const { forwardExec } = await import("./daemon-client-
|
|
12424
|
+
const { forwardExec } = await import("./daemon-client-ZHO6NG36.js");
|
|
12425
12425
|
const userTimeout = typeof params.timeout === "number" && params.timeout > 0 ? params.timeout * 1e3 + 3e4 : void 0;
|
|
12426
12426
|
const result = await forwardExec(`${command}.${subCommand}`, params, sessionName, cdpEndpoint, userTimeout);
|
|
12427
12427
|
const resultData = result && typeof result === "object" && "data" in result ? result.data : void 0;
|
package/dist/daemon-main.js
CHANGED
|
@@ -27,14 +27,14 @@ import "./chunk-TNEN6VQ2.js";
|
|
|
27
27
|
import {
|
|
28
28
|
getDaemonConfig,
|
|
29
29
|
getDaemonProcessStatus
|
|
30
|
-
} from "./chunk-
|
|
30
|
+
} from "./chunk-O3FLVCUU.js";
|
|
31
31
|
import {
|
|
32
32
|
errMsg
|
|
33
33
|
} from "./chunk-GDKLH7ZY.js";
|
|
34
34
|
import "./chunk-KFQGP6VL.js";
|
|
35
35
|
|
|
36
36
|
// src/daemon/daemon-main.ts
|
|
37
|
-
import { writeFileSync as writeFileSync8, mkdirSync as mkdirSync7, appendFileSync } from "fs";
|
|
37
|
+
import { writeFileSync as writeFileSync8, mkdirSync as mkdirSync7, appendFileSync, unlinkSync } from "fs";
|
|
38
38
|
import { join as join9 } from "path";
|
|
39
39
|
import { homedir as homedir9 } from "os";
|
|
40
40
|
import { startHttpServer } from "@dyyz1993/xcli-core";
|
|
@@ -6942,7 +6942,7 @@ async function executeCommand(commandName, params, sessionName = "default", extr
|
|
|
6942
6942
|
params = result.data;
|
|
6943
6943
|
}
|
|
6944
6944
|
if (command.scope !== "cli" && !process.env.XBROWSER_DAEMON_WORKER) {
|
|
6945
|
-
const { forwardExec } = await import("./daemon-client-
|
|
6945
|
+
const { forwardExec } = await import("./daemon-client-R4QWHD7V.js");
|
|
6946
6946
|
const result = await forwardExec(commandName, params, sessionName, extraOpts?.cdpEndpoint);
|
|
6947
6947
|
if (result) return result;
|
|
6948
6948
|
}
|
|
@@ -11406,6 +11406,18 @@ async function main() {
|
|
|
11406
11406
|
}
|
|
11407
11407
|
]
|
|
11408
11408
|
});
|
|
11409
|
+
server.on("error", (err) => {
|
|
11410
|
+
if (err.code === "EADDRINUSE") {
|
|
11411
|
+
log(`Port ${daemonPort} already in use \u2014 another daemon instance likely won the startup race. Exiting gracefully.`);
|
|
11412
|
+
try {
|
|
11413
|
+
unlinkSync(join9(CONFIG_DIR4, "daemon.json"));
|
|
11414
|
+
} catch {
|
|
11415
|
+
}
|
|
11416
|
+
process.exit(0);
|
|
11417
|
+
}
|
|
11418
|
+
log(`Server error: ${err.message}`);
|
|
11419
|
+
process.exit(1);
|
|
11420
|
+
});
|
|
11409
11421
|
const originalListeners = server.listeners("request").slice();
|
|
11410
11422
|
server.removeAllListeners("request");
|
|
11411
11423
|
server.on("request", (req, res) => {
|
|
@@ -40,9 +40,23 @@ function filterRecording(inputPath, outputPath, excludeTypes) {
|
|
|
40
40
|
return { originalCount, filteredCount, removed, percentage };
|
|
41
41
|
}
|
|
42
42
|
function parseExcludeTypes(args) {
|
|
43
|
-
for (
|
|
43
|
+
for (let i = 0; i < args.length; i++) {
|
|
44
|
+
const arg = args[i];
|
|
44
45
|
if (arg.startsWith("--exclude-types=")) {
|
|
45
|
-
return arg.replace("--exclude-types=", "").split(",");
|
|
46
|
+
return arg.replace("--exclude-types=", "").split(",").map((s) => s.trim());
|
|
47
|
+
}
|
|
48
|
+
if (arg === "--exclude-types" && args[i + 1]) {
|
|
49
|
+
return args[i + 1].split(",").map((s) => s.trim());
|
|
50
|
+
}
|
|
51
|
+
if (arg.startsWith("--exclude=")) {
|
|
52
|
+
return arg.replace("--exclude=", "").split(",").map((s) => s.trim());
|
|
53
|
+
}
|
|
54
|
+
if (arg === "--exclude" && args[i + 1]) {
|
|
55
|
+
const types = [];
|
|
56
|
+
for (let j = i + 1; j < args.length && !args[j].startsWith("-"); j++) {
|
|
57
|
+
types.push(...args[j].split(",").map((s) => s.trim()));
|
|
58
|
+
}
|
|
59
|
+
if (types.length > 0) return types;
|
|
46
60
|
}
|
|
47
61
|
}
|
|
48
62
|
return void 0;
|
package/dist/index.js
CHANGED
|
@@ -25,7 +25,7 @@ import {
|
|
|
25
25
|
killAllDaemonProcesses,
|
|
26
26
|
startDaemonProcess,
|
|
27
27
|
stopDaemonProcess
|
|
28
|
-
} from "./chunk-
|
|
28
|
+
} from "./chunk-XYXCS7JW.js";
|
|
29
29
|
import {
|
|
30
30
|
CaptchaDetector,
|
|
31
31
|
HumanInteractionManager,
|
|
@@ -53,7 +53,7 @@ import {
|
|
|
53
53
|
import {
|
|
54
54
|
filterRecording,
|
|
55
55
|
parseExcludeTypes
|
|
56
|
-
} from "./chunk-
|
|
56
|
+
} from "./chunk-AT4PHAJY.js";
|
|
57
57
|
import {
|
|
58
58
|
SessionRecorder
|
|
59
59
|
} from "./chunk-ACFE6PKF.js";
|
|
@@ -7304,7 +7304,7 @@ async function executeCommand(commandName, params, sessionName = "default", extr
|
|
|
7304
7304
|
params = result.data;
|
|
7305
7305
|
}
|
|
7306
7306
|
if (command.scope !== "cli" && !process.env.XBROWSER_DAEMON_WORKER) {
|
|
7307
|
-
const { forwardExec } = await import("./daemon-client-
|
|
7307
|
+
const { forwardExec } = await import("./daemon-client-ZHO6NG36.js");
|
|
7308
7308
|
const result = await forwardExec(commandName, params, sessionName, extraOpts?.cdpEndpoint);
|
|
7309
7309
|
if (result) return result;
|
|
7310
7310
|
}
|
|
@@ -10986,7 +10986,7 @@ async function handleFilter(args, _mode) {
|
|
|
10986
10986
|
console.error("Usage: xbrowser filter <input.yaml> <output.yaml> [--exclude-types=type1,type2]");
|
|
10987
10987
|
process.exit(1);
|
|
10988
10988
|
}
|
|
10989
|
-
const { filterRecording: filterRecording2, parseExcludeTypes: parseExcludeTypes2 } = await import("./filter-
|
|
10989
|
+
const { filterRecording: filterRecording2, parseExcludeTypes: parseExcludeTypes2 } = await import("./filter-3JQWBM5F.js");
|
|
10990
10990
|
const excludeTypes = parseExcludeTypes2(args.slice(2));
|
|
10991
10991
|
const result = filterRecording2(filePath, outputPath, excludeTypes);
|
|
10992
10992
|
console.log(`Filtered ${filePath} -> ${outputPath}`);
|
|
@@ -12612,13 +12612,13 @@ async function routeCommand(argvIn, stdinCommands) {
|
|
|
12612
12612
|
handleConfig(cmdArgs, options);
|
|
12613
12613
|
break;
|
|
12614
12614
|
case "convert":
|
|
12615
|
-
handleConvert(cmdArgs, mode);
|
|
12615
|
+
await handleConvert(cmdArgs, mode);
|
|
12616
12616
|
break;
|
|
12617
12617
|
case "extract":
|
|
12618
|
-
handleExtract(cmdArgs, mode);
|
|
12618
|
+
await handleExtract(cmdArgs, mode);
|
|
12619
12619
|
break;
|
|
12620
12620
|
case "filter":
|
|
12621
|
-
handleFilter(cmdArgs, mode);
|
|
12621
|
+
await handleFilter(cmdArgs, mode);
|
|
12622
12622
|
break;
|
|
12623
12623
|
case "run":
|
|
12624
12624
|
if (!cmdArgs[0]) {
|
|
@@ -12761,7 +12761,7 @@ Run "xbrowser ${command} ${subCommand} --help" to see available parameters.`
|
|
|
12761
12761
|
}
|
|
12762
12762
|
const needsBrowser = cmdEntry.scope === "page" || cmdEntry.scope === "browser";
|
|
12763
12763
|
if (needsBrowser && !process.env.XBROWSER_DAEMON_WORKER) {
|
|
12764
|
-
const { forwardExec } = await import("./daemon-client-
|
|
12764
|
+
const { forwardExec } = await import("./daemon-client-ZHO6NG36.js");
|
|
12765
12765
|
const userTimeout = typeof params.timeout === "number" && params.timeout > 0 ? params.timeout * 1e3 + 3e4 : void 0;
|
|
12766
12766
|
const result = await forwardExec(`${command}.${subCommand}`, params, sessionName, cdpEndpoint, userTimeout);
|
|
12767
12767
|
const resultData = result && typeof result === "object" && "data" in result ? result.data : void 0;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@xbrowser/cli",
|
|
3
|
-
"version": "1.0
|
|
3
|
+
"version": "1.1.0",
|
|
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": {
|