@xbrowser/cli 1.0.8 → 1.0.9

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.
@@ -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-6WOSXSCQ.js";
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-3JOKX2L2.js");
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
  }
@@ -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-3JOKX2L2.js");
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;
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  startDaemonProcess
3
- } from "./chunk-WJRE55TN.js";
3
+ } from "./chunk-O3FLVCUU.js";
4
4
  import {
5
5
  errMsg
6
6
  } from "./chunk-GDKLH7ZY.js";
@@ -29,7 +29,7 @@ import {
29
29
  forwardSessionList,
30
30
  forwardViewerCheckSelector,
31
31
  isDaemonRunning
32
- } from "./chunk-6WOSXSCQ.js";
32
+ } from "./chunk-XYXCS7JW.js";
33
33
  import "./chunk-GDKLH7ZY.js";
34
34
  import "./chunk-KFQGP6VL.js";
35
35
  export {
@@ -27,14 +27,14 @@ import "./chunk-TNEN6VQ2.js";
27
27
  import {
28
28
  getDaemonConfig,
29
29
  getDaemonProcessStatus
30
- } from "./chunk-WJRE55TN.js";
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-DIEHGP5B.js");
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) => {
package/dist/index.js CHANGED
@@ -25,7 +25,7 @@ import {
25
25
  killAllDaemonProcesses,
26
26
  startDaemonProcess,
27
27
  stopDaemonProcess
28
- } from "./chunk-6WOSXSCQ.js";
28
+ } from "./chunk-XYXCS7JW.js";
29
29
  import {
30
30
  CaptchaDetector,
31
31
  HumanInteractionManager,
@@ -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-3JOKX2L2.js");
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
  }
@@ -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-3JOKX2L2.js");
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.8",
3
+ "version": "1.0.9",
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": {