@tunnelbox/core 0.1.17 → 0.1.18

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/index.js CHANGED
@@ -1804,6 +1804,52 @@ var MessagesCache = class {
1804
1804
  }
1805
1805
  };
1806
1806
  var messagesCache = new MessagesCache();
1807
+
1808
+ // src/cli.ts
1809
+ import { spawnSync } from "child_process";
1810
+ import { existsSync as existsSync2 } from "fs";
1811
+ import { join as join2 } from "path";
1812
+ function needsCmdQuote(s) {
1813
+ return s === "" || /[ \t&|<>^"%]/.test(s);
1814
+ }
1815
+ function cmdLineFor(shimPath, args) {
1816
+ const parts = [`"${shimPath}"`, ...args.map((a) => needsCmdQuote(a) ? `"${a}"` : a)];
1817
+ return parts.join(" ");
1818
+ }
1819
+ function findWinShim(name) {
1820
+ if (name.includes("/") || name.includes("\\")) return null;
1821
+ const dirs = (process.env.PATH || "").split(";").filter(Boolean);
1822
+ for (const dir of dirs) {
1823
+ for (const ext of [".cmd", ".bat"]) {
1824
+ const p = join2(dir, name + ext);
1825
+ if (existsSync2(p)) return p;
1826
+ }
1827
+ }
1828
+ return null;
1829
+ }
1830
+ function killCliTree(child) {
1831
+ if (!child || child.exitCode !== null) return;
1832
+ if (process.platform === "win32") {
1833
+ const pid = child.pid;
1834
+ if (pid) {
1835
+ try {
1836
+ spawnSync("taskkill", ["/PID", String(pid), "/T", "/F"], { stdio: "ignore", windowsHide: true });
1837
+ } catch {
1838
+ }
1839
+ }
1840
+ return;
1841
+ }
1842
+ try {
1843
+ child.kill("SIGTERM");
1844
+ } catch {
1845
+ }
1846
+ setTimeout(() => {
1847
+ try {
1848
+ if (child.exitCode === null) child.kill("SIGKILL");
1849
+ } catch {
1850
+ }
1851
+ }, 1500);
1852
+ }
1807
1853
  export {
1808
1854
  DEFAULT_LANG,
1809
1855
  DEFAULT_PAGE_SIZE,
@@ -1815,12 +1861,16 @@ export {
1815
1861
  RelayClient,
1816
1862
  capMessage,
1817
1863
  capMessages,
1864
+ cmdLineFor,
1818
1865
  detectSystemLang,
1819
1866
  envelope,
1867
+ findWinShim,
1820
1868
  injectedRelayUrl,
1869
+ killCliTree,
1821
1870
  loadState,
1822
1871
  makeT,
1823
1872
  messagesCache,
1873
+ needsCmdQuote,
1824
1874
  normalizeLang,
1825
1875
  printPairing,
1826
1876
  renderPairingQrText,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tunnelbox/core",
3
- "version": "0.1.17",
3
+ "version": "0.1.18",
4
4
  "description": "tunnelbox 共享核心:协议类型、中继客户端、状态持久化、二维码配对",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
package/src/cli.ts ADDED
@@ -0,0 +1,63 @@
1
+ /**
2
+ * CLI 子进程辅助:Windows `.cmd/.bat` shim 解析与进程树终止。
3
+ * 供各适配器驱动本机 CLI 时复用(Linux/macOS 直接 spawn 可执行文件)。
4
+ */
5
+ import { spawnSync, type ChildProcess } from "node:child_process";
6
+ import { existsSync } from "node:fs";
7
+ import { join } from "node:path";
8
+
9
+ /** 参数是否需要 cmd 引号(含空格或 cmd 元字符)。 */
10
+ export function needsCmdQuote(s: string): boolean {
11
+ return s === "" || /[ \t&|<>^"%]/.test(s);
12
+ }
13
+
14
+ /** 拼接一条 `cmd /c` 命令行:路径恒引号,参数按需引号。 */
15
+ export function cmdLineFor(shimPath: string, args: string[]): string {
16
+ const parts = [`"${shimPath}"`, ...args.map((a) => (needsCmdQuote(a) ? `"${a}"` : a))];
17
+ return parts.join(" ");
18
+ }
19
+
20
+ /** 在 PATH 中查找 `<name>.cmd/.bat`(Windows shim);name 含路径分隔符时返回 null。 */
21
+ export function findWinShim(name: string): string | null {
22
+ if (name.includes("/") || name.includes("\\")) return null;
23
+ const dirs = (process.env.PATH || "").split(";").filter(Boolean);
24
+ for (const dir of dirs) {
25
+ for (const ext of [".cmd", ".bat"]) {
26
+ const p = join(dir, name + ext);
27
+ if (existsSync(p)) return p;
28
+ }
29
+ }
30
+ return null;
31
+ }
32
+
33
+ /**
34
+ * 终止子进程:
35
+ * - Windows:`taskkill /PID <pid> /T /F` 杀整棵进程树(经 shell 启动时只杀 cmd.exe 不够);
36
+ * - 其余平台:SIGTERM,1.5s 后仍存活再 SIGKILL。
37
+ */
38
+ export function killCliTree(child: ChildProcess | null | undefined): void {
39
+ if (!child || child.exitCode !== null) return;
40
+ if (process.platform === "win32") {
41
+ const pid = child.pid;
42
+ if (pid) {
43
+ try {
44
+ spawnSync("taskkill", ["/PID", String(pid), "/T", "/F"], { stdio: "ignore", windowsHide: true });
45
+ } catch {
46
+ /* ignore */
47
+ }
48
+ }
49
+ return;
50
+ }
51
+ try {
52
+ child.kill("SIGTERM");
53
+ } catch {
54
+ /* ignore */
55
+ }
56
+ setTimeout(() => {
57
+ try {
58
+ if (child.exitCode === null) child.kill("SIGKILL");
59
+ } catch {
60
+ /* ignore */
61
+ }
62
+ }, 1500);
63
+ }
package/src/index.ts CHANGED
@@ -10,3 +10,4 @@ export * from "./env";
10
10
  export * from "./qr";
11
11
  export * from "./i18n";
12
12
  export * from "./messages";
13
+ export * from "./cli";