xshell 1.0.202 → 1.0.204

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/net.d.ts CHANGED
@@ -54,6 +54,10 @@ export interface RequestOptions {
54
54
  cookies?: Record<string, string>;
55
55
  redirect?: 'follow' | 'manual';
56
56
  decode?: boolean;
57
+ print?: {
58
+ retry: boolean;
59
+ timeout: boolean;
60
+ };
57
61
  }
58
62
  export interface RequestFullOptions extends RequestOptions {
59
63
  full: true;
@@ -92,7 +96,10 @@ export interface RequestError extends Error {
92
96
  - cookies?: 需要额外添加到请求的 cookies, 默认情况下携带了 MemoryCookieStore 中保存的之前 http 响应中的 cookies
93
97
  - raw?: `false` 传入后返回整个 response (RawResponse),body 为 Readable
94
98
  - full?: `false` 传入后返回整个 response (FullResponse),body 根据 encoding 对应为 string 或 Buffer
95
- - decode?: 根据 content-encoding: br 等解码压缩后的 response.body */
99
+ - decode?: 根据 content-encoding: br 等解码压缩后的 response.body
100
+ - print?:
101
+ - retry: `true` 是否打印 "等待 1 秒后重试 request" 提示信息
102
+ - timeout: `true` 是否打印最后一次超时重试失败时的错误 */
96
103
  export declare function request(url: string | URL): Promise<string>;
97
104
  export declare function request(url: string | URL, options: RequestRawOptions): Promise<RawResponse>;
98
105
  export declare function request(url: string | URL, options: RequestFullOptions & {
package/net.js CHANGED
@@ -38,7 +38,7 @@ const drop_request_headers = new Set([
38
38
  'upgrade',
39
39
  ]);
40
40
  let agents = {};
41
- async function request_retry(url, options, _timeout, retries = 0, count = 0) {
41
+ async function request_retry(url, options, _timeout, retries = 0, count = 0, print) {
42
42
  let { default: undici, request: undici_request } = await import('undici');
43
43
  undici_request ??= undici.request;
44
44
  try {
@@ -46,7 +46,7 @@ async function request_retry(url, options, _timeout, retries = 0, count = 0) {
46
46
  // 设置给 undici 设置 timeout, signal 不一定管用,还是得自己兜底
47
47
  options.signal = AbortSignal.timeout(_timeout);
48
48
  return await timeout(_timeout + 300, // 为 undici 兜底
49
- async () => undici.request(url, options), undefined, count >= retries // 只打印最后一次超时的错误,避免太多冗余输出
49
+ async () => undici.request(url, options), undefined, print.timeout && count >= retries // 只打印最后一次超时的错误,避免太多冗余输出
50
50
  );
51
51
  }
52
52
  else
@@ -56,9 +56,10 @@ async function request_retry(url, options, _timeout, retries = 0, count = 0) {
56
56
  if (error.name === 'TimeoutError')
57
57
  if (count < retries) {
58
58
  const duration = 2 ** count;
59
- console.log(`${t('等待 {{duration}} 秒后重试 request (已尝试 {{_count}} 次) …', { duration, _count: count + 1 }).yellow} ${url.toString().blue.underline}`);
59
+ if (print.retry)
60
+ console.log(`${t('等待 {{duration}} 秒后重试 request (已尝试 {{_count}} 次) …', { duration, _count: count + 1 }).yellow} ${url.toString().blue.underline}`);
60
61
  await delay(1000 * duration);
61
- return request_retry(url, options, _timeout, retries, count + 1);
62
+ return request_retry(url, options, _timeout, retries, count + 1, print);
62
63
  }
63
64
  else
64
65
  throw Object.assign(new Error(`request 超时: ${url.toString()}`), { name: 'TimeoutError' });
@@ -72,7 +73,10 @@ export async function request(url, options = {}) {
72
73
  FormData ??= undici.FormData;
73
74
  const { Cookie } = await import('tough-cookie');
74
75
  await cookies.init();
75
- const { queries, headers: _headers, body, type = 'application/json', timeout = 5 * 1000, auth, cookies: _cookies, raw = false, full = false, redirect = 'follow', decode = true, } = options;
76
+ const { queries, headers: _headers, body, type = 'application/json', timeout = 5 * 1000, auth, cookies: _cookies, raw = false, full = false, redirect = 'follow', decode = true, print = {
77
+ timeout: true,
78
+ retry: true
79
+ } } = options;
76
80
  let { method, retries, encoding, proxy, } = options;
77
81
  url = new URL(url);
78
82
  if (queries)
@@ -179,7 +183,7 @@ export async function request(url, options = {}) {
179
183
  };
180
184
  let response;
181
185
  try {
182
- const { statusCode: status, headers: _headers, body: _body } = await request_retry(url, undici_options, timeout, retries);
186
+ const { statusCode: status, headers: _headers, body: _body } = await request_retry(url, undici_options, timeout, retries, 0, print);
183
187
  // 处理 cookie,自动保存到 cookie jar
184
188
  let _cookies = _headers['set-cookie'] || [];
185
189
  if (typeof _cookies === 'string')
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "xshell",
3
- "version": "1.0.202",
3
+ "version": "1.0.204",
4
4
  "type": "module",
5
5
  "main": "./index.js",
6
6
  "bin": {
@@ -105,7 +105,7 @@
105
105
  "tslib": "^2.8.1",
106
106
  "typescript": "^5.7.2",
107
107
  "ua-parser-js": "^2.0.0",
108
- "undici": "^7.0.0-alpha.7",
108
+ "undici": "^7.0.0",
109
109
  "vinyl": "^3.0.0",
110
110
  "vinyl-fs": "^4.0.0",
111
111
  "webpack": "^5.96.1",
@@ -126,7 +126,7 @@
126
126
  "@types/koa-compress": "^4.0.6",
127
127
  "@types/lodash": "^4.17.13",
128
128
  "@types/mime-types": "^2.1.4",
129
- "@types/node": "^22.10.0",
129
+ "@types/node": "^22.10.1",
130
130
  "@types/react": "^18.3.12",
131
131
  "@types/through2": "^2.0.41",
132
132
  "@types/tough-cookie": "^4.0.5",
package/process.d.ts CHANGED
@@ -2,7 +2,6 @@ import { type ChildProcess } from 'child_process';
2
2
  import './prototype.ts';
3
3
  import type { Encoding } from './file.ts';
4
4
  import type { MyProxy } from './net.ts';
5
- import { inspect } from './utils.ts';
6
5
  export declare const exe_nodejs: string;
7
6
  export declare const platform: NodeJS.Platform;
8
7
  export declare const username: string;
@@ -18,35 +17,25 @@ export declare const print_no_command: {
18
17
  };
19
18
  };
20
19
  type StdioType = 'pipe' | 'ignore' | 'inherit' | number;
21
- interface StartOptions {
22
- /** `继承当前工作目录 process.cwd()` 子进程的工作目录 `inherit the cwd` cwd of the child process. */
20
+ export interface FullPrintOptions {
21
+ stdout: boolean;
22
+ stderr: boolean;
23
+ command: boolean;
24
+ /** 进程执行成功的消息 */
25
+ code: boolean;
26
+ }
27
+ interface BaseOptions {
23
28
  cwd?: string;
24
29
  /** `process.env` 覆盖/添加到 process.env 的环境变量 */
25
30
  envs?: Record<string, string>;
26
31
  /** 创建子进程时添加 http_proxy, https_proxy, no_proxy 环境变量以启用代理 */
27
32
  proxy?: MyProxy | true;
28
- /** `'utf-8'` 子进程输出编码 child output encoding */
29
- encoding?: Encoding | 'binary';
30
- /** `true` print 选项,支持设置细项 print option (with details) */
31
- print?: boolean | {
32
- stdout: boolean;
33
- stderr: boolean;
34
- command: boolean;
35
- /** 进程执行成功的消息 */
36
- code: boolean;
37
- };
38
- /** `'pipe'` 设置为 'ignore' 时忽略 stdio 处理 */
39
- stdio?: 'pipe' | 'ignore' | [StdioType, StdioType, StdioType];
40
- /** 启动子进程之后写入到子进程 stdin 中的内容,写完后关闭子进程 stdin (pty 不关闭) */
41
- input?: string;
42
33
  /** 使用文件作为标准输入 */
43
34
  fp_stdin?: string;
44
35
  /** 使用文件作为标准输出 */
45
36
  fp_stdout?: string;
46
37
  /** 使用文件作为标准错误 */
47
38
  fp_stderr?: string;
48
- /** `false` 是否断开和 child 的关系 (ignore stdio, unref) whether to break the connection with child (ignore stdio, unref) */
49
- detached?: boolean;
50
39
  /** 为 true 时会设置 UV_PROCESS_WINDOWS_HIDE
51
40
  然后设置启动进程的参数 CREATE_NO_WINDOW, 和 SW_HIDE
52
41
  D:/0/libuv/src/win/process.c
@@ -59,29 +48,47 @@ interface StartOptions {
59
48
  具体有什么用还不清楚 */
60
49
  window?: boolean;
61
50
  }
62
- /** start process
63
- - exe: .exe 路径或文件名 (建议使用完整路径,跳过 path 搜索,性能更高) path or filename (full path is recommanded to skip path searching for better perf)
64
- - args: `[]` 参数列表 arguments list
65
- - options
66
- - cwd?: `继承当前工作目录 process.cwd()` 子进程的工作目录 `inherit the cwd` cwd of the child process.
51
+ export interface StartOptions extends BaseOptions {
52
+ /** `true` 是否打印启动命令行 */
53
+ print?: boolean;
54
+ /** 使用文件作为标准输入 */
55
+ fp_stdin?: string;
56
+ /** 使用文件作为标准输出 */
57
+ fp_stdout?: string;
58
+ /** 使用文件作为标准错误 */
59
+ fp_stderr?: string;
60
+ }
61
+ /** 启动独立的进程,不受当前 node.js 进程退出的影响
62
+ - exe: .exe 路径或文件名 (建议使用完整路径,跳过 path 搜索,性能更高)
63
+ - args?: `[ ]` 参数列表
64
+ - options?:
65
+ - cwd?
67
66
  - envs?: `process.env` 覆盖/添加到 process.env 的环境变量,传 null 时可以取消设置该变量
68
- - encoding?: `'utf-8'` 子进程输出编码 child output encoding
69
- - print?: `true` print 选项,支持设置细项 print option (with details)
70
- - stdio?: `'pipe'` 设置为 'ignore' 时忽略 stdio 处理 when 'ignore' then ignore stdio processing
67
+ - encoding?: `'utf-8'` 子进程输出编码
68
+ - print?: `true` 是否打印启动命令行
69
+ - stdio?: `'pipe'` 设置为 'ignore' 时忽略 stdio 处理
71
70
  - input?: string, 启动子进程之后写入到子进程 stdin 中的内容,写完后关闭子进程 stdin (pty 不关闭)
72
- - fp_stdin?: 使用文件作为标准输入,设置 stdio 中选项为对应的值
73
- - fp_stdout?: 使用文件作为标准输出,设置 stdio 中选项为对应的值
74
- - fp_stderr?: 使用文件作为标准错误,设置 stdio 中选项为对应的值
75
- - detached?: `false` 是否断开和 child 的关系 (ignore stdio, unref) whether to break the connection with child (ignore stdio, unref) */
71
+ - fp_stdin?: 使用文件作为标准输入,设置 stdio 中对应的值
72
+ - fp_stdout?: 使用文件作为标准输出,设置 stdio 中对应的值
73
+ - fp_stderr?: 使用文件作为标准错误,设置 stdio 中对应的值 */
76
74
  export declare function start(exe: string, args?: string[], options?: StartOptions): Promise<ChildProcess>;
77
- export declare function start_nodejs(js: string, args?: string[], options?: StartOptions): Promise<ChildProcess>;
78
- export interface CallOptions extends StartOptions {
75
+ export interface CallOptions extends BaseOptions {
76
+ /** `true` print 选项,支持设置细项 */
77
+ print?: boolean | FullPrintOptions;
78
+ /** `true` code 不为 0 时是否抛出异常 */
79
79
  throw_code?: boolean;
80
+ /** `'utf-8'` 子进程输出编码 */
81
+ encoding?: 'binary' | Encoding;
82
+ /** `'pipe'` 设置为 'ignore' 时忽略 stdio 处理 */
83
+ stdio?: 'pipe' | 'ignore' | [StdioType, StdioType, StdioType];
84
+ /** 启动子进程之后写入到子进程 stdin 中的内容,写完后关闭子进程 stdin */
80
85
  input?: string;
86
+ /** 实时处理 stdout 和 stderr 的每个 chunk,启用后子进程输出不会自动 print */
81
87
  printers?: {
82
88
  stdout?: (chunk: string) => void;
83
89
  stderr?: (chunk: string) => void;
84
90
  };
91
+ /** 可以传入回调函数及时获取通过 start 创建的子进程,便于执行 kill、获得 pid 等操作 */
85
92
  on_child?: (child: ChildProcess) => void;
86
93
  }
87
94
  export interface CallResult<TOutput extends string | Buffer = string> {
@@ -91,83 +98,63 @@ export interface CallResult<TOutput extends string | Buffer = string> {
91
98
  code: number | null;
92
99
  signal: NodeJS.Signals | null;
93
100
  child: ChildProcess;
94
- [inspect.custom](): string;
95
101
  }
96
- export interface CallError {
102
+ export interface CallError<TOutput extends string | Buffer = string> {
97
103
  result: {
98
104
  pid: number;
99
- stdout: string;
100
- stderr: string;
105
+ stdout: TOutput;
106
+ stderr: TOutput;
101
107
  code: number;
102
- signal: number | NodeJS.Signals;
108
+ signal: NodeJS.Signals;
103
109
  child: ChildProcess;
104
110
  };
105
111
  }
106
- /** call process for result
107
- - exe: .exe 路径或文件名 (建议使用路径,跳过 path 搜索,性能更高) path or filename (full path is recommanded to skip path searching for better perf)
108
- - args: `[]` 参数列表 arguments list
112
+ /** 调用可执行文件,获取返回结果
113
+ - exe: .exe 路径或文件名 (建议使用路径,跳过 path 搜索,性能更高)
114
+ - args: `[ ]` 参数列表
109
115
  - options?:
110
- - cwd?: `process.cwd()`
116
+ - cwd?
117
+ - print?: `true` print 选项,支持设置细项
118
+ - throw_code?: `true` code 不为 0 时是否抛出异常
111
119
  - envs?: `process.env` 覆盖/添加到 process.env 的环境变量,传 null 时可以取消设置该变量
112
120
  - encoding?: `'utf-8'` 子进程输出编码, 设置为 binary 时返回 stdout, stderr 类型为 Buffer; 否则是 string
113
- child output encoding. When set to binary, return stdout, stderr is of type Buffer; otherwise it is string
114
- - print?: `true` print 选项,支持设置细项 print option (with details)
115
- - printers?: 实时处理 stdout stderr 的每个 chunk
116
- - stdio?: `'pipe'` 设置为 'ignore' 时忽略 stdio 处理 when 'ignore' then ignore stdio processing
117
- - input?: string, 启动子进程之后写入到子进程 stdin 中的内容,写完后关闭子进程 stdin (pty 不关闭)
118
- - detached?: `false` 是否断开和 child 的关系 (ignore stdio, unref) whether to break the connection with child (ignore stdio, unref)
119
- - throw_code?: `true` code 不为 0 时是否抛出异常 whether to throw Error when code is not 0
120
- - on_child: 可以传入回调函数及时获取通过 start 创建的子进程,便于执行 kill、获得 pid 等操作 */
121
- export declare function call(exe: string, args?: string[]): Promise<CallResult<string>>;
122
- export declare function call(exe: string, args?: string[], options?: CallOptions & {
123
- encoding: 'binary';
124
- }): Promise<CallResult<Buffer>>;
121
+ - printers?: 实时处理 stdout stderr 的每个 chunk,启用后子进程输出不会自动 print,且对应的 stdout, stderr 为空
122
+ - stdio?: `'pipe'` 设置为 'ignore' 时忽略 stdio 处理
123
+ - input?: string, 启动子进程之后写入到子进程 stdin 中的内容,写完后关闭子进程 stdin
124
+ - on_child?: 可以传入回调函数及时获取通过 start 创建的子进程,便于执行 kill、获得 pid 等操作 */
125
125
  export declare function call(exe: string, args?: string[], options?: CallOptions): Promise<CallResult<string>>;
126
126
  export interface CallNodeJsOptions extends CallOptions {
127
- inspect?: number;
127
+ inspect?: number | true;
128
128
  break?: boolean;
129
129
  }
130
- /** call node <js> for result
131
- - js: .js 路径 (相对路径根据 cwd 解析) path (relative path will resolve based on cwd)
132
- - args: `[]` 参数列表 arguments list
133
- - options
134
- - cwd?: `process.cwd()`
135
- - envs?: `process.env` 覆盖/添加到 process.env 的环境变量 overwrite/add to process.env
136
- - encoding?: `'utf-8'` 子进程输出编码 child process output encoding
137
- - print?: `true` print 选项,支持设置细项 print option (with details)
138
- - stdio?: `'pipe'` 设置为 'ignore' 时忽略 stdio 处理 when 'ignore' then ignore stdio processing
139
- - detached?: `false` 是否断开和 child 的关系 (ignore stdio, unref) whether to break the connection with child (ignore stdio, unref)
130
+ /** 调用 node <js> 并等待结果
131
+ - js: .js 路径 (相对路径根据 cwd 解析)
132
+ - args?: `[ ]` 参数列表
133
+ - options?:
134
+ - cwd?: `'T:/'`
135
+ - envs?: `process.env` 覆盖/添加到 process.env 的环境变量
136
+ - encoding?: `'utf-8'` 子进程输出编码
137
+ - print?: `true` print 选项,支持设置细项
138
+ - stdio?: `'pipe'` 设置为 'ignore' 时忽略 stdio 处理
140
139
  - throw_code?: `true` code 不为 0 时是否抛出异常
141
- - inspect?: nodejs debugger port
140
+ - inspect?: nodejs debugger port, 填 9229 端口 (或者传 true) 可以用临时配置来调试
142
141
  - break?: break at first line */
143
142
  export declare function call_nodejs(js: string, args?: string[], { inspect, break: _break, ...options }?: CallNodeJsOptions): Promise<CallResult<string>>;
144
- export interface TermOptions {
145
- /** `process.cwd()` */
146
- cwd?: string;
147
- /** `true` 打印参数 */
148
- print?: boolean;
149
- title?: string;
150
- /** `process.env` 覆盖/添加到 process.env 的环境变量 */
151
- envs?: Record<string, string>;
152
- }
153
- export declare const exe_winterm: string;
154
- /** 新建 terminal 窗口执行进程 New Terminal window execution process
155
- - exe: exe 文件路径 exe file path
156
- - args: 调用参数 call parameter
157
- - options?: WinTermOptions */
158
- export declare function term(exe: string, args?: string[], { cwd, print, title, envs }?: TermOptions): Promise<ChildProcess>;
159
- export interface TermNodeOptions extends TermOptions {
160
- /** nodejs debugger port */
161
- inspect?: number;
162
- /** break at first line */
143
+ export interface StartNodeJsOptions extends StartOptions {
144
+ inspect?: number | true;
163
145
  break?: boolean;
164
- /** 使用 ts-node 直接运行 use ts-node to run directly */
165
- tsnode?: boolean;
166
- /** `false` --experimental-specifier-resolution=node */
167
- resolve?: boolean;
168
- /** `false` --trace-warnings */
169
- trace_warnings?: boolean;
170
146
  }
171
- /** term tab 中创建 node.exe 进程 */
172
- export declare function term_nodejs(fp_js: string, args?: string[], { title, inspect, tsnode, break: _break, resolve, trace_warnings, ...options }?: TermNodeOptions): Promise<ChildProcess>;
147
+ /** 启动 node <js>
148
+ - js: .js 路径 (相对路径根据 cwd 解析)
149
+ - args: `[]` 参数列表
150
+ - options
151
+ - cwd?: `'T:/'`
152
+ - envs?: `process.env` 覆盖/添加到 process.env 的环境变量
153
+ - encoding?: `'utf-8'` 子进程输出编码
154
+ - print?: `true` print 选项,支持设置细项
155
+ - stdio?: `'pipe'` 设置为 'ignore' 时忽略 stdio 处理
156
+ - detached?: `false` 是否断开和 child 的关系 (ignore stdio, unref)
157
+ - inspect?: nodejs debugger port, 填 9229 端口 (或者传 true) 可以用临时配置来调试
158
+ - break?: break at first line */
159
+ export declare function start_nodejs(js: string, args?: string[], { inspect, break: _break, ...options }?: StartNodeJsOptions): Promise<ChildProcess>;
173
160
  export {};
package/process.js CHANGED
@@ -1,42 +1,50 @@
1
1
  import { spawn } from 'child_process';
2
2
  import os from 'os';
3
- import { t } from "./i18n/instance.js";
4
3
  import "./prototype.js";
5
- import { inspect, DecoderStream, filter_values, assert, check } from "./utils.js";
4
+ import { inspect, DecoderStream, filter_values, check } from "./utils.js";
6
5
  export const exe_nodejs = process.execPath.fp;
7
6
  export const platform = os.platform();
8
7
  export const username = os.userInfo().username;
9
8
  export const noprint = { print: false };
10
9
  export const print_no_command = { print: { command: false, code: false, stdout: true, stderr: true } };
11
- /** start process
12
- - exe: .exe 路径或文件名 (建议使用完整路径,跳过 path 搜索,性能更高) path or filename (full path is recommanded to skip path searching for better perf)
13
- - args: `[]` 参数列表 arguments list
14
- - options
15
- - cwd?: `继承当前工作目录 process.cwd()` 子进程的工作目录 `inherit the cwd` cwd of the child process.
16
- - envs?: `process.env` 覆盖/添加到 process.env 的环境变量,传 null 时可以取消设置该变量
17
- - encoding?: `'utf-8'` 子进程输出编码 child output encoding
18
- - print?: `true` print 选项,支持设置细项 print option (with details)
19
- - stdio?: `'pipe'` 设置为 'ignore' 时忽略 stdio 处理 when 'ignore' then ignore stdio processing
20
- - input?: string, 启动子进程之后写入到子进程 stdin 中的内容,写完后关闭子进程 stdin (pty 不关闭)
21
- - fp_stdin?: 使用文件作为标准输入,设置 stdio 中选项为对应的值
22
- - fp_stdout?: 使用文件作为标准输出,设置 stdio 中选项为对应的值
23
- - fp_stderr?: 使用文件作为标准错误,设置 stdio 中选项为对应的值
24
- - detached?: `false` 是否断开和 child 的关系 (ignore stdio, unref) whether to break the connection with child (ignore stdio, unref) */
25
- export async function start(exe, args = [], options = {}) {
26
- const { cwd, encoding = 'utf-8', detached = false, window: _window = true, envs, input, fp_stdin, fp_stdout, fp_stderr } = options;
27
- let { print = true, stdio = detached ? 'ignore' : 'pipe', proxy } = options;
10
+ async function prepare_spawn(detached, exe, args, { cwd, window: _window = true, envs,
11
+ // @ts-ignore
12
+ input, fp_stdin, fp_stdout, fp_stderr, print = true, proxy,
13
+ // @ts-ignore
14
+ stdio }) {
15
+ // --- 处理 proxy, envs
28
16
  if (proxy === true) {
29
17
  const { MyProxy } = await import("./net.js");
30
18
  proxy = MyProxy.socks5;
31
19
  }
32
- if (typeof stdio === 'string')
33
- stdio = [stdio, stdio, stdio];
34
- if (input)
35
- assert(!fp_stdin, 'input 和 fp_stdin 不能同时设置');
20
+ let envs_;
21
+ if (envs || proxy)
22
+ envs_ = filter_values({
23
+ ...process.env,
24
+ ...proxy ? {
25
+ http_proxy: proxy,
26
+ https_proxy: proxy,
27
+ no_proxy: '127.0.0.1,::1,localhost,192.168.0.0/20,192.168.100.0/24'
28
+ } : {},
29
+ ...envs
30
+ });
31
+ // --- 处理 stdio
32
+ if (input && fp_stdin)
33
+ throw new Error('input 和 fp_stdin 不能同时设置');
36
34
  let opened_handles = [];
37
35
  async function close_all_handles() {
38
36
  await Promise.all(opened_handles.map(async (handle) => handle.close()));
39
37
  }
38
+ if (Array.isArray(stdio)) {
39
+ if (input)
40
+ check(stdio[0] === 'pipe', '传入 input 时 stdio[0] 应该是 pipe');
41
+ }
42
+ else if (typeof stdio === 'string')
43
+ stdio = [stdio, stdio, stdio];
44
+ else if (detached)
45
+ stdio = ['ignore', 'ignore', 'ignore'];
46
+ else
47
+ stdio = [input ? 'pipe' : 'ignore', 'pipe', 'pipe'];
40
48
  if (fp_stdin || fp_stdout || fp_stderr) {
41
49
  const { fopen } = await import("./file.js");
42
50
  async function open(fp, flags) {
@@ -59,168 +67,145 @@ export async function start(exe, args = [], options = {}) {
59
67
  ? stdio[1]
60
68
  : await open(fp_stderr, 'w');
61
69
  }
62
- const options_ = {
63
- cwd,
64
- shell: false,
65
- windowsHide: !_window,
66
- detached,
67
- stdio,
68
- ...envs || proxy ? {
69
- env: filter_values({
70
- ...process.env,
71
- ...proxy ? {
72
- http_proxy: proxy,
73
- https_proxy: proxy,
74
- no_proxy: '127.0.0.1,::1,localhost,192.168.0.0/20,192.168.100.0/24'
75
- } : {},
76
- ...envs
77
- })
78
- } : {},
79
- };
70
+ if (detached)
71
+ check(stdio.every((x) => x === 'ignore' || typeof x === 'number'), '调用 start 时 stdio 只能是 fd 或者 ignore');
80
72
  if (typeof print === 'boolean')
81
73
  print = {
82
- stdout: print,
83
- stderr: print,
84
74
  command: print,
85
75
  code: print,
76
+ stdout: print,
77
+ stderr: print
86
78
  };
79
+ let command;
87
80
  if (print.command)
88
- console.log(((short_exe_names[exe] || exe.quote_if_space()) +
89
- (args.length ?
90
- ' ' + args.filter(arg => arg !== '--suppressApplicationTitle')
91
- .map(arg => arg.quote_if_space())
92
- .join(' ')
93
- :
94
- '')).blue);
95
- if (detached) {
96
- check(stdio.every(x => x === 'ignore' || typeof x === 'number'), '调用 start({ detached: true }) 时 stdio 只能是 fd 或者 ignore');
97
- try {
98
- let child = spawn(exe, args, options_);
99
- child.unref();
100
- return child;
101
- }
102
- finally {
103
- if (opened_handles.length)
104
- await close_all_handles();
105
- }
81
+ console.log((command =
82
+ (short_exe_names[exe] || exe.quote_if_space()) +
83
+ (args.length
84
+ ? ' ' + args
85
+ .map(arg => arg.quote_if_space())
86
+ .join(' ')
87
+ : '')).blue);
88
+ return {
89
+ print,
90
+ command,
91
+ spawn_options: {
92
+ cwd,
93
+ shell: false,
94
+ // processhacker 在 windowsHide 为 true 时不显示窗口
95
+ windowsHide: !_window,
96
+ detached,
97
+ stdio,
98
+ ...envs_ ? { env: envs_ } : {}
99
+ },
100
+ close_all_handles: opened_handles.length ? close_all_handles : undefined
101
+ };
102
+ }
103
+ /** 启动独立的进程,不受当前 node.js 进程退出的影响
104
+ - exe: .exe 路径或文件名 (建议使用完整路径,跳过 path 搜索,性能更高)
105
+ - args?: `[ ]` 参数列表
106
+ - options?:
107
+ - cwd?
108
+ - envs?: `process.env` 覆盖/添加到 process.env 的环境变量,传 null 时可以取消设置该变量
109
+ - encoding?: `'utf-8'` 子进程输出编码
110
+ - print?: `true` 是否打印启动命令行
111
+ - stdio?: `'pipe'` 设置为 'ignore' 时忽略 stdio 处理
112
+ - input?: string, 启动子进程之后写入到子进程 stdin 中的内容,写完后关闭子进程 stdin (pty 不关闭)
113
+ - fp_stdin?: 使用文件作为标准输入,设置 stdio 中对应的值
114
+ - fp_stdout?: 使用文件作为标准输出,设置 stdio 中对应的值
115
+ - fp_stderr?: 使用文件作为标准错误,设置 stdio 中对应的值 */
116
+ export async function start(exe, args = [], options = {}) {
117
+ const { spawn_options, close_all_handles } = await prepare_spawn(true, exe, args, options);
118
+ try {
119
+ let child = spawn(exe, args, spawn_options);
120
+ child.unref();
121
+ return child;
122
+ }
123
+ finally {
124
+ if (close_all_handles)
125
+ await close_all_handles();
106
126
  }
127
+ }
128
+ export async function call(exe, args = [], options = {}) {
129
+ const { print, command, spawn_options, close_all_handles } = await prepare_spawn(false, exe, args, options);
107
130
  let child;
108
131
  try {
109
- child = spawn(exe, args, options_);
132
+ child = spawn(exe, args, spawn_options);
110
133
  }
111
- catch (error) {
112
- if (opened_handles.length)
134
+ finally {
135
+ if (close_all_handles)
113
136
  await close_all_handles();
114
- throw error;
115
137
  }
138
+ const { stdio } = spawn_options;
139
+ const { encoding = 'utf-8', throw_code = true, input, printers, on_child } = options;
116
140
  // 防止 child spawn 失败时 crash nodejs 进程
117
141
  child.on('error', error => {
118
142
  console.error(error);
119
143
  });
120
- if (stdio[0] === 'pipe')
121
- child.stdin.setDefaultEncoding('utf8');
122
- if (encoding !== 'binary') {
123
- if (stdio[1] === 'pipe') {
124
- if (encoding === 'utf-8')
125
- child.stdout.setEncoding('utf-8');
126
- else
127
- child.stdout = child.stdout.pipe(new DecoderStream(encoding));
128
- if (print.stdout)
129
- child.stdout.pipe(process.stdout, { end: false });
130
- }
131
- if (stdio[2] === 'pipe') {
132
- if (encoding === 'utf-8')
133
- child.stderr.setEncoding('utf-8');
134
- else
135
- child.stderr = child.stderr.pipe(new DecoderStream(encoding));
136
- if (print.stderr)
137
- child.stderr.pipe(process.stderr, { end: false });
138
- }
144
+ if (stdio[0] === 'pipe') {
145
+ child.stdin.setDefaultEncoding('utf-8');
146
+ if (input)
147
+ child.stdin.end(input);
139
148
  }
140
- if (input)
141
- child.stdin.end(input);
142
- if (opened_handles.length)
143
- await close_all_handles();
144
- return child;
145
- }
146
- export async function start_nodejs(js, args = [], options) {
147
- return start(exe_nodejs, ['--enable-source-maps', js, ...args], options);
148
- }
149
- export async function call(exe, args = [], options = {}) {
150
- const { encoding = 'utf-8', throw_code = true, printers, on_child } = options;
151
- let { stdio = 'pipe', print = true } = options;
152
- if (typeof print === 'boolean')
153
- print = {
154
- command: print,
155
- stdout: print,
156
- stderr: print,
157
- code: print,
158
- };
159
- if (typeof stdio === 'string')
160
- stdio = [stdio, stdio, stdio];
161
- const cmd = (short_exe_names[exe] || exe.quote_if_space()) +
162
- (args.length ? (' ' + args.map(arg => arg.quote_if_space())
163
- .join(' '))
164
- :
165
- '');
166
- if (print.command)
167
- console.log(cmd.blue);
168
- let child = await start(exe, args, {
169
- ...options,
170
- print: false,
171
- });
172
- on_child?.(child);
173
- // --- collect output
149
+ // --- 收集进程输出
174
150
  let stdouts = [];
175
151
  let stderrs = [];
176
- let code, signal;
177
- await Promise.all([
178
- new Promise(resolve => {
179
- child.once('exit', (_code, _signal) => {
180
- code = _code;
181
- signal = _signal;
182
- resolve();
183
- });
184
- }),
185
- (async () => {
186
- if (stdio[1] === 'pipe')
187
- for await (const chunk of child.stdout) {
188
- if (encoding !== 'binary' && print.stdout)
189
- if (printers?.stdout)
190
- printers.stdout(chunk);
191
- else
192
- process.stdout.write(chunk);
152
+ if (stdio[1] === 'pipe') {
153
+ if (encoding === 'utf-8')
154
+ child.stdout.setEncoding('utf-8');
155
+ else if (encoding !== 'binary')
156
+ child.stdout = child.stdout.pipe(new DecoderStream(encoding));
157
+ child.stdout.on('data', printers?.stdout
158
+ ? printers.stdout
159
+ : print.stdout
160
+ ? (chunk) => {
193
161
  stdouts.push(chunk);
162
+ process.stdout.write(chunk);
194
163
  }
195
- })(),
196
- (async () => {
197
- if (stdio[2] === 'pipe')
198
- for await (const chunk of child.stderr) {
199
- if (encoding !== 'binary' && print.stderr)
200
- if (printers?.stderr)
201
- printers.stderr(chunk);
202
- else
203
- process.stderr.write(chunk);
164
+ : (chunk) => {
165
+ stdouts.push(chunk);
166
+ });
167
+ }
168
+ if (stdio[2] === 'pipe') {
169
+ if (encoding === 'utf-8')
170
+ child.stderr.setEncoding('utf-8');
171
+ else if (encoding !== 'binary')
172
+ child.stderr = child.stderr.pipe(new DecoderStream(encoding));
173
+ child.stderr.on('data', printers?.stderr
174
+ ? printers.stderr
175
+ : print.stderr
176
+ ? (chunk) => {
204
177
  stderrs.push(chunk);
178
+ process.stderr.write(chunk);
205
179
  }
206
- })()
207
- ]);
208
- const message = `${t('进程')} ${cmd} ` + (code ?
209
- `(pid: ${child.pid}) ${throw_code ? t('异常结束') : t('结束')}, code: ${code}${signal ? `, signal: ${signal}` : ''}`
210
- :
211
- t('正常结束'));
212
- if (print.code || (throw_code && (code || signal)))
213
- console.log(message[(throw_code && (code || signal)) ? 'red' : 'blue']);
180
+ : (chunk) => {
181
+ stderrs.push(chunk);
182
+ });
183
+ }
184
+ on_child?.(child);
185
+ let code, signal;
186
+ await new Promise(resolve => {
187
+ child.once('close', (_code, _signal) => {
188
+ code = _code;
189
+ signal = _signal;
190
+ resolve();
191
+ });
192
+ });
193
+ let message;
194
+ const code_error = throw_code && (code || signal);
195
+ if (print.code || code_error) {
196
+ message = `进程 ${command} ` + (code
197
+ ? `${throw_code ? '异常' : ''}结束,退出码: ${code}${signal ? `,信号: ${signal}` : ''}`
198
+ : '正常结束');
199
+ console.log(message[code_error ? 'red' : 'blue']);
200
+ }
214
201
  const result = {
215
202
  pid: child.pid,
216
- stdout: encoding === 'binary' ?
217
- Buffer.concat(stdouts)
218
- :
219
- stdouts.join(''),
220
- stderr: encoding === 'binary' ?
221
- Buffer.concat(stderrs)
222
- :
223
- stderrs.join(''),
203
+ stdout: encoding === 'binary'
204
+ ? Buffer.concat(stdouts)
205
+ : stdouts.join(''),
206
+ stderr: encoding === 'binary'
207
+ ? Buffer.concat(stderrs)
208
+ : stderrs.join(''),
224
209
  code,
225
210
  signal,
226
211
  child,
@@ -228,71 +213,54 @@ export async function call(exe, args = [], options = {}) {
228
213
  return inspect(this, { omit: ['child'] });
229
214
  }
230
215
  };
231
- if (code && throw_code)
232
- throw Object.assign(new Error(message), { result });
216
+ if (code_error) {
217
+ let error = new Error(message);
218
+ error.result = result;
219
+ throw error;
220
+ }
233
221
  return result;
234
222
  }
235
- /** call node <js> for result
236
- - js: .js 路径 (相对路径根据 cwd 解析) path (relative path will resolve based on cwd)
237
- - args: `[]` 参数列表 arguments list
238
- - options
239
- - cwd?: `process.cwd()`
240
- - envs?: `process.env` 覆盖/添加到 process.env 的环境变量 overwrite/add to process.env
241
- - encoding?: `'utf-8'` 子进程输出编码 child process output encoding
242
- - print?: `true` print 选项,支持设置细项 print option (with details)
243
- - stdio?: `'pipe'` 设置为 'ignore' 时忽略 stdio 处理 when 'ignore' then ignore stdio processing
244
- - detached?: `false` 是否断开和 child 的关系 (ignore stdio, unref) whether to break the connection with child (ignore stdio, unref)
223
+ /** 调用 node <js> 并等待结果
224
+ - js: .js 路径 (相对路径根据 cwd 解析)
225
+ - args?: `[ ]` 参数列表
226
+ - options?:
227
+ - cwd?: `'T:/'`
228
+ - envs?: `process.env` 覆盖/添加到 process.env 的环境变量
229
+ - encoding?: `'utf-8'` 子进程输出编码
230
+ - print?: `true` print 选项,支持设置细项
231
+ - stdio?: `'pipe'` 设置为 'ignore' 时忽略 stdio 处理
245
232
  - throw_code?: `true` code 不为 0 时是否抛出异常
246
- - inspect?: nodejs debugger port
233
+ - inspect?: nodejs debugger port, 填 9229 端口 (或者传 true) 可以用临时配置来调试
247
234
  - break?: break at first line */
248
235
  export async function call_nodejs(js, args = [], { inspect, break: _break, ...options } = {}) {
249
236
  return call(exe_nodejs, [
250
237
  '--enable-source-maps',
251
- ...inspect ? [`--inspect${_break ? '-brk' : ''}=localhost:${inspect}`] : [],
238
+ ...inspect ? [`--inspect${_break ? '-brk' : ''}=localhost:${inspect === true ? 9229 : inspect}`] : [],
252
239
  js,
253
240
  ...args
254
241
  ], options);
255
242
  }
256
- export const exe_winterm = `C:/Users/${username}/AppData/Local/Microsoft/WindowsApps/wt.exe`;
257
- /** 新建 terminal 窗口执行进程 New Terminal window execution process
258
- - exe: exe 文件路径 exe file path
259
- - args: 调用参数 call parameter
260
- - options?: WinTermOptions */
261
- export async function term(exe, args = [], { cwd = process.cwd().fpd, print = true, title, envs } = {}) {
262
- return start(exe_winterm, [
263
- 'new-tab',
264
- '-d', cwd,
265
- ...title ? ['--suppressApplicationTitle', '--title', title] : [],
266
- exe,
267
- ...args.map(arg => arg.replaceAll(';', '\\;')),
268
- ], {
269
- print,
270
- detached: true,
271
- cwd,
272
- envs
273
- });
274
- }
275
- /** 在 term tab 中创建 node.exe 进程 */
276
- export async function term_nodejs(fp_js, args = [], { title, inspect, tsnode = false, break: _break, resolve = false, trace_warnings, ...options } = {}) {
277
- return term(exe_nodejs, [
243
+ /** 启动 node <js>
244
+ - js: .js 路径 (相对路径根据 cwd 解析)
245
+ - args: `[]` 参数列表
246
+ - options
247
+ - cwd?: `'T:/'`
248
+ - envs?: `process.env` 覆盖/添加到 process.env 的环境变量
249
+ - encoding?: `'utf-8'` 子进程输出编码
250
+ - print?: `true` print 选项,支持设置细项
251
+ - stdio?: `'pipe'` 设置为 'ignore' 时忽略 stdio 处理
252
+ - detached?: `false` 是否断开和 child 的关系 (ignore stdio, unref)
253
+ - inspect?: nodejs debugger port, 填 9229 端口 (或者传 true) 可以用临时配置来调试
254
+ - break?: break at first line */
255
+ export async function start_nodejs(js, args = [], { inspect, break: _break, ...options } = {}) {
256
+ return start(exe_nodejs, [
278
257
  '--enable-source-maps',
279
- ...trace_warnings ?? inspect ? ['--trace-warnings'] : [],
280
- ...resolve ? ['--experimental-specifier-resolution=node'] : [],
281
- ...title ? [`--title=${title}`] : [],
282
- ...inspect ? [`--inspect${_break ? '-brk' : ''}=localhost:${inspect}`] : [],
283
- ...tsnode ? [
284
- '--loader=ts-node/esm',
285
- '--experimental-specifier-resolution=node'
286
- ] : [],
287
- fp_js,
258
+ ...inspect ? [`--inspect${_break ? '-brk' : ''}=localhost:${inspect === true ? 9229 : inspect}`] : [],
259
+ js,
288
260
  ...args
289
- ], {
290
- title,
291
- ...options,
292
- });
261
+ ], options);
293
262
  }
294
263
  const short_exe_names = {
295
- [exe_winterm]: 'term',
296
264
  [exe_nodejs]: 'node',
297
265
  };
298
266
  //# sourceMappingURL=process.js.map