@actiondock/core 2.7.0 → 2.8.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/README.md +61 -68
- package/dist/catalog/action-catalog.d.ts +56 -0
- package/dist/catalog/action-catalog.js +202 -0
- package/dist/catalog/discovery.d.ts +60 -0
- package/dist/catalog/discovery.js +119 -0
- package/dist/catalog/graph.d.ts +190 -0
- package/dist/catalog/graph.js +589 -0
- package/dist/catalog/index.d.ts +5 -5
- package/dist/catalog/index.js +5 -5
- package/dist/catalog/resolve-action.d.ts +43 -0
- package/dist/catalog/resolve-action.js +119 -0
- package/dist/catalog/resolve-playbook.d.ts +26 -0
- package/dist/catalog/resolve-playbook.js +114 -0
- package/dist/doctor/checks/project.js +27 -8
- package/dist/doctor/checks/registry.js +2 -2
- package/dist/doctor/checks/runtime.js +34 -1
- package/dist/errors.d.ts +102 -10
- package/dist/errors.js +103 -10
- package/dist/execution/service.d.ts +18 -16
- package/dist/execution/service.js +183 -252
- package/dist/execution/types.d.ts +25 -69
- package/dist/execution/types.js +2 -1
- package/dist/filter/intent.d.ts +8 -9
- package/dist/filter/intent.js +49 -10
- package/dist/graph/index.d.ts +4 -0
- package/dist/graph/index.js +4 -0
- package/dist/host/host.d.ts +74 -32
- package/dist/host/host.js +585 -336
- package/dist/host/routing.d.ts +15 -48
- package/dist/host/routing.js +90 -153
- package/dist/host/types.d.ts +50 -17
- package/dist/index.d.ts +21 -24
- package/dist/index.js +19 -23
- package/dist/input/advice.d.ts +5 -1
- package/dist/input/advice.js +163 -214
- package/dist/input/describe.d.ts +1 -1
- package/dist/input/flat-errors.d.ts +5 -6
- package/dist/input/flat-errors.js +6 -6
- package/dist/input/flat-materializer.js +42 -44
- package/dist/invocation/index.d.ts +2 -0
- package/dist/invocation/index.js +2 -0
- package/dist/invocation/policy.d.ts +157 -0
- package/dist/invocation/policy.js +231 -0
- package/dist/invocation/types.d.ts +172 -0
- package/dist/invocation/types.js +97 -0
- package/dist/ipc/diagnostic.d.ts +0 -12
- package/dist/ipc/diagnostic.js +0 -21
- package/dist/ipc/host.d.ts +4 -4
- package/dist/ipc/host.js +44 -47
- package/dist/ipc/index.d.ts +1 -1
- package/dist/ipc/index.js +1 -1
- package/dist/ipc/service.d.ts +40 -0
- package/dist/ipc/service.js +349 -0
- package/dist/ipc/types.d.ts +21 -15
- package/dist/node/index.d.ts +1 -0
- package/dist/node/index.js +1 -0
- package/dist/node/module-loader.d.ts +63 -0
- package/dist/node/module-loader.js +112 -0
- package/dist/package/index.d.ts +23 -0
- package/dist/package/index.js +18 -0
- package/dist/{app/app.d.ts → package/runtime.d.ts} +41 -20
- package/dist/{app/app.js → package/runtime.js} +140 -95
- package/dist/{app → package}/static-index.js +58 -41
- package/dist/package/storage-view.d.ts +13 -0
- package/dist/package/storage-view.js +22 -0
- package/dist/{app → package}/types.d.ts +76 -57
- package/dist/package/types.js +22 -0
- package/dist/platform/index.d.ts +1 -1
- package/dist/platform/index.js +1 -1
- package/dist/platform/node.d.ts +48 -0
- package/dist/platform/node.js +96 -0
- package/dist/platform/types.d.ts +0 -9
- package/dist/process/control-arbiter.d.ts +2 -1
- package/dist/process/control-arbiter.js +1 -2
- package/dist/process/driver.d.ts +9 -8
- package/dist/process/driver.js +11 -22
- package/dist/process/index.d.ts +2 -0
- package/dist/process/index.js +2 -0
- package/dist/process/managed-record.d.ts +2 -2
- package/dist/process/process-driver.d.ts +109 -0
- package/dist/process/process-driver.js +650 -0
- package/dist/process/process-executor.d.ts +47 -0
- package/dist/process/process-executor.js +296 -0
- package/dist/process/process-manager.js +48 -26
- package/dist/process/run-executor.js +12 -12
- package/dist/profile/client-actions.js +2 -2
- package/dist/profile/client-health.js +2 -2
- package/dist/profile/client-query.js +5 -6
- package/dist/profile/client-transport.d.ts +19 -17
- package/dist/profile/client-transport.js +47 -80
- package/dist/profile/client.d.ts +2 -2
- package/dist/profile/client.js +1 -1
- package/dist/profile/index.d.ts +1 -0
- package/dist/profile/index.js +1 -0
- package/dist/profile/manager.d.ts +5 -0
- package/dist/profile/manager.js +41 -6
- package/dist/project/closure.js +2 -2
- package/dist/project/index.d.ts +8 -1
- package/dist/project/index.js +10 -1
- package/dist/project/init.js +2 -2
- package/dist/project/loader.d.ts +1 -1
- package/dist/project/loader.js +26 -29
- package/dist/project/transactions.js +5 -10
- package/dist/registry/index.d.ts +3 -1
- package/dist/registry/index.js +2 -1
- package/dist/registry/lock.d.ts +28 -7
- package/dist/registry/lock.js +136 -16
- package/dist/registry/registry.d.ts +1 -5
- package/dist/registry/registry.js +1 -53
- package/dist/registry/scan.d.ts +0 -15
- package/dist/registry/scan.js +0 -59
- package/dist/registry/store.d.ts +42 -0
- package/dist/registry/store.js +43 -0
- package/dist/registry/types.d.ts +0 -24
- package/dist/runtime/action-collection.d.ts +1 -1
- package/dist/runtime/action-registry.d.ts +0 -4
- package/dist/runtime/action-registry.js +0 -7
- package/dist/runtime/context.js +5 -11
- package/dist/runtime/events.js +3 -6
- package/dist/runtime/identity.d.ts +22 -0
- package/dist/runtime/identity.js +10 -0
- package/dist/runtime/index.d.ts +1 -2
- package/dist/runtime/index.js +1 -2
- package/dist/runtime/module-loader.d.ts +2 -34
- package/dist/runtime/module-loader.js +1 -16
- package/dist/runtime/process.d.ts +6 -24
- package/dist/runtime/process.js +1 -118
- package/dist/runtime/run-persistence.js +2 -5
- package/dist/runtime/runner.d.ts +33 -93
- package/dist/runtime/runner.js +132 -364
- package/dist/runtime/standalone.d.ts +23 -8
- package/dist/runtime/standalone.js +100 -147
- package/dist/server/body.d.ts +16 -8
- package/dist/server/body.js +33 -16
- package/dist/server/dispatcher.d.ts +6 -10
- package/dist/server/dispatcher.js +24 -32
- package/dist/server/http-server.d.ts +87 -0
- package/dist/server/http-server.js +304 -0
- package/dist/server/index.d.ts +11 -0
- package/dist/server/index.js +10 -0
- package/dist/server/mcp-endpoint.d.ts +61 -0
- package/dist/server/mcp-endpoint.js +118 -0
- package/dist/server/routes/actions.js +34 -28
- package/dist/server/routes/common.d.ts +10 -14
- package/dist/server/routes/common.js +32 -56
- package/dist/server/routes/config.js +54 -64
- package/dist/server/routes/doctor.d.ts +1 -1
- package/dist/server/routes/doctor.js +10 -18
- package/dist/server/routes/health.d.ts +1 -1
- package/dist/server/routes/health.js +2 -3
- package/dist/server/routes/info.d.ts +2 -2
- package/dist/server/routes/info.js +12 -13
- package/dist/server/routes/playbooks.js +16 -29
- package/dist/server/routes/runs.js +95 -117
- package/dist/server/routes/state.js +63 -62
- package/dist/server/server.d.ts +2 -2
- package/dist/server/server.js +43 -227
- package/dist/server/types.d.ts +8 -19
- package/dist/service/factory.d.ts +12 -0
- package/dist/service/factory.js +85 -0
- package/dist/{target → service}/index.d.ts +1 -1
- package/dist/{target → service}/index.js +1 -1
- package/dist/service/local.d.ts +27 -0
- package/dist/service/local.js +138 -0
- package/dist/{target → service}/remote-errors.d.ts +3 -6
- package/dist/service/remote-errors.js +38 -0
- package/dist/{target → service}/remote-polling.d.ts +2 -2
- package/dist/{target → service}/remote-polling.js +8 -8
- package/dist/service/remote.d.ts +34 -0
- package/dist/service/remote.js +634 -0
- package/dist/service/sse-stream.d.ts +24 -0
- package/dist/service/sse-stream.js +139 -0
- package/dist/service/types.d.ts +272 -0
- package/dist/service/types.js +32 -0
- package/dist/storage/data-dir-lock.js +10 -5
- package/dist/storage/driver.d.ts +2 -1
- package/dist/storage/driver.js +3 -52
- package/dist/storage/index.d.ts +1 -0
- package/dist/storage/index.js +1 -0
- package/dist/storage/lock-core.d.ts +2 -6
- package/dist/storage/lock-core.js +4 -17
- package/dist/storage/params.d.ts +2 -8
- package/dist/storage/params.js +2 -8
- package/dist/storage/sqlite-driver.d.ts +40 -0
- package/dist/storage/sqlite-driver.js +116 -0
- package/dist/storage/sqlite.js +21 -6
- package/dist/storage/types.d.ts +4 -4
- package/dist/storage/types.js +2 -2
- package/dist/utils/index.d.ts +53 -0
- package/dist/utils/index.js +99 -4
- package/dist/utils/process.d.ts +10 -0
- package/dist/utils/process.js +21 -0
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +41 -3
- package/dist/app/index.d.ts +0 -2
- package/dist/app/index.js +0 -2
- package/dist/app/types.js +0 -1
- package/dist/catalog/action-index.d.ts +0 -9
- package/dist/catalog/action-index.js +0 -95
- package/dist/catalog/action-resolver.d.ts +0 -20
- package/dist/catalog/action-resolver.js +0 -95
- package/dist/catalog/location-registry.d.ts +0 -15
- package/dist/catalog/location-registry.js +0 -138
- package/dist/catalog/package-catalog.d.ts +0 -7
- package/dist/catalog/package-catalog.js +0 -77
- package/dist/catalog/types.d.ts +0 -68
- package/dist/catalog/types.js +0 -1
- package/dist/export/index.d.ts +0 -1
- package/dist/export/index.js +0 -1
- package/dist/export/templates.d.ts +0 -71
- package/dist/export/templates.js +0 -635
- package/dist/ipc/target.d.ts +0 -74
- package/dist/ipc/target.js +0 -365
- package/dist/platform/default.d.ts +0 -38
- package/dist/platform/default.js +0 -78
- package/dist/project/resolver.d.ts +0 -116
- package/dist/project/resolver.js +0 -376
- package/dist/registry/resolve.d.ts +0 -62
- package/dist/registry/resolve.js +0 -195
- package/dist/runtime/execution-manager.d.ts +0 -48
- package/dist/runtime/execution-manager.js +0 -66
- package/dist/runtime/package-runner-factory.d.ts +0 -82
- package/dist/runtime/package-runner-factory.js +0 -186
- package/dist/target/local.d.ts +0 -53
- package/dist/target/local.js +0 -349
- package/dist/target/remote-errors.js +0 -51
- package/dist/target/remote.d.ts +0 -86
- package/dist/target/remote.js +0 -818
- package/dist/target/target.d.ts +0 -6
- package/dist/target/target.js +0 -37
- package/dist/target/types.d.ts +0 -261
- package/dist/target/types.js +0 -35
- /package/dist/{app → package}/static-index.d.ts +0 -0
- /package/dist/{target → service}/sse-parser.d.ts +0 -0
- /package/dist/{target → service}/sse-parser.js +0 -0
|
@@ -0,0 +1,650 @@
|
|
|
1
|
+
import childProcess from "node:child_process";
|
|
2
|
+
import { createRequire } from "node:module";
|
|
3
|
+
import { INPUT_CLOSED, UNSUPPORTED_CAPABILITY, ProcessError, } from "../errors.js";
|
|
4
|
+
import { DEFAULT_ENV_ALLOWLIST, resolveProcessEnv, } from "./driver.js";
|
|
5
|
+
export { DEFAULT_ENV_ALLOWLIST, resolveProcessEnv };
|
|
6
|
+
/**
|
|
7
|
+
* 跨平台终止进程组,确保不会遗留孤儿进程。
|
|
8
|
+
*
|
|
9
|
+
* - 在 POSIX 环境下通过负数进程标识终止整个进程组
|
|
10
|
+
* - 在 Windows 环境下优先通过 taskkill 递归终止整棵进程树,等待其完成后将 process.kill 作为失败或超时 fallback
|
|
11
|
+
*
|
|
12
|
+
* @param pid 目标子进程标识
|
|
13
|
+
* @param signal 发送的系统信号
|
|
14
|
+
* @param spawnFn 进程启动函数,默认为 childProcess.spawn
|
|
15
|
+
*/
|
|
16
|
+
export function killProcessGroup(pid, signal = "SIGTERM", spawnFn = childProcess.spawn) {
|
|
17
|
+
if (process.platform === "win32") {
|
|
18
|
+
return new Promise((resolve) => {
|
|
19
|
+
let settled = false;
|
|
20
|
+
const finish = () => {
|
|
21
|
+
if (!settled) {
|
|
22
|
+
settled = true;
|
|
23
|
+
resolve();
|
|
24
|
+
}
|
|
25
|
+
};
|
|
26
|
+
const fallbackToProcessKill = () => {
|
|
27
|
+
try {
|
|
28
|
+
process.kill(pid, signal);
|
|
29
|
+
}
|
|
30
|
+
catch {
|
|
31
|
+
// 忽略已退出状态
|
|
32
|
+
}
|
|
33
|
+
finish();
|
|
34
|
+
};
|
|
35
|
+
try {
|
|
36
|
+
const killer = spawnFn("taskkill", ["/pid", String(pid), "/T", "/F"], { stdio: "ignore" });
|
|
37
|
+
// 超时保底 fallback:若 taskkill 超过 2000ms 仍未退出,执行 process.kill 强行兜底
|
|
38
|
+
const timer = setTimeout(() => {
|
|
39
|
+
try {
|
|
40
|
+
killer.kill?.();
|
|
41
|
+
}
|
|
42
|
+
catch {
|
|
43
|
+
// 忽略终止失败异常
|
|
44
|
+
}
|
|
45
|
+
fallbackToProcessKill();
|
|
46
|
+
}, 2000);
|
|
47
|
+
timer.unref?.();
|
|
48
|
+
killer.on?.("error", () => {
|
|
49
|
+
clearTimeout(timer);
|
|
50
|
+
fallbackToProcessKill();
|
|
51
|
+
});
|
|
52
|
+
killer.on?.("close", (code) => {
|
|
53
|
+
clearTimeout(timer);
|
|
54
|
+
if (code !== 0) {
|
|
55
|
+
fallbackToProcessKill();
|
|
56
|
+
}
|
|
57
|
+
else {
|
|
58
|
+
finish();
|
|
59
|
+
}
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
catch {
|
|
63
|
+
fallbackToProcessKill();
|
|
64
|
+
}
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
else {
|
|
68
|
+
try {
|
|
69
|
+
process.kill(-pid, signal);
|
|
70
|
+
}
|
|
71
|
+
catch {
|
|
72
|
+
try {
|
|
73
|
+
process.kill(pid, signal);
|
|
74
|
+
}
|
|
75
|
+
catch {
|
|
76
|
+
// 忽略已退出状态
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
return Promise.resolve();
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* node-pty 探测结果模块级缓存:getCapabilities 处于 spawn 热路径,
|
|
84
|
+
* createRequire 与 require 探测开销只需在首次调用时执行一次。
|
|
85
|
+
*/
|
|
86
|
+
let cachedCapabilities;
|
|
87
|
+
/**
|
|
88
|
+
* POSIX 标准信号编号到名称的映射表(1-31,对齐 Linux 信号集)。
|
|
89
|
+
* pipe 模式下 Node 的 exit 事件直接给出 "SIGTERM" 等字符串信号名;
|
|
90
|
+
* node-pty 的 onExit 回调只给数字,必须经此表转换才能与 pipe 模式及
|
|
91
|
+
* FakeProcessDriver 的 signal 契约保持一致,杜绝 "15" 这类原始数字漂移。
|
|
92
|
+
*/
|
|
93
|
+
const POSIX_SIGNAL_NAMES = [
|
|
94
|
+
undefined, // 0:无信号
|
|
95
|
+
"SIGHUP", // 1
|
|
96
|
+
"SIGINT", // 2
|
|
97
|
+
"SIGQUIT", // 3
|
|
98
|
+
"SIGILL", // 4
|
|
99
|
+
"SIGTRAP", // 5
|
|
100
|
+
"SIGABRT", // 6
|
|
101
|
+
"SIGBUS", // 7
|
|
102
|
+
"SIGFPE", // 8
|
|
103
|
+
"SIGKILL", // 9
|
|
104
|
+
"SIGUSR1", // 10
|
|
105
|
+
"SIGSEGV", // 11
|
|
106
|
+
"SIGUSR2", // 12
|
|
107
|
+
"SIGPIPE", // 13
|
|
108
|
+
"SIGALRM", // 14
|
|
109
|
+
"SIGTERM", // 15
|
|
110
|
+
"SIGSTKFLT", // 16
|
|
111
|
+
"SIGCHLD", // 17
|
|
112
|
+
"SIGCONT", // 18
|
|
113
|
+
"SIGSTOP", // 19
|
|
114
|
+
"SIGTSTP", // 20
|
|
115
|
+
"SIGTTIN", // 21
|
|
116
|
+
"SIGTTOU", // 22
|
|
117
|
+
"SIGURG", // 23
|
|
118
|
+
"SIGXCPU", // 24
|
|
119
|
+
"SIGXFSZ", // 25
|
|
120
|
+
"SIGVTALRM", // 26
|
|
121
|
+
"SIGPROF", // 27
|
|
122
|
+
"SIGWINCH", // 28
|
|
123
|
+
"SIGIO", // 29
|
|
124
|
+
"SIGPWR", // 30
|
|
125
|
+
"SIGSYS", // 31
|
|
126
|
+
];
|
|
127
|
+
/**
|
|
128
|
+
* 将 PTY 退出回调给出的信号数字转换为标准信号名称。
|
|
129
|
+
* 0、负数与非整数视为无信号(对齐 pipe 模式的 null 语义);
|
|
130
|
+
* 表内已知编号返回 POSIX 名称,未知编号回退 SIG<num> 形式,绝不返回原始数字字符串。
|
|
131
|
+
*/
|
|
132
|
+
function ptySignalToName(signal) {
|
|
133
|
+
if (typeof signal !== "number" || !Number.isInteger(signal) || signal <= 0) {
|
|
134
|
+
return null;
|
|
135
|
+
}
|
|
136
|
+
return POSIX_SIGNAL_NAMES[signal] ?? `SIG${signal}`;
|
|
137
|
+
}
|
|
138
|
+
/**
|
|
139
|
+
* 基于 Node.js 标准子进程实现的平台驱动。
|
|
140
|
+
* 遵循《ActionDock Managed Process 设计 v2》规范:
|
|
141
|
+
* - pipe 模式采用 child_process.spawn,支持进程组隔离与跨平台 killProcessGroup
|
|
142
|
+
* - 输出与生命周期监听在 spawn 返回前完成绑定,杜绝竞态丢失
|
|
143
|
+
* - 环境变量按 allowlisted 白名单与 none 策略严格继承,叠加 set 与 unset 变更
|
|
144
|
+
* - 写入支持背压流控与管道提早关闭异常捕获
|
|
145
|
+
* - 输入流支持 inputEOF 干净终止
|
|
146
|
+
* - 支持 5s 优雅输出排空 deadline 与 outputClosed 状态上报
|
|
147
|
+
* - PTY 模式在无 node-pty 环境明确拒绝并报告 UNSUPPORTED_CAPABILITY
|
|
148
|
+
*/
|
|
149
|
+
export class NodeProcessDriver {
|
|
150
|
+
drainDeadlineMs;
|
|
151
|
+
spawnFn;
|
|
152
|
+
instances = new Map();
|
|
153
|
+
constructor(options = {}) {
|
|
154
|
+
this.drainDeadlineMs = options.drainDeadlineMs ?? 5000;
|
|
155
|
+
this.spawnFn = options.spawnFn ?? childProcess.spawn;
|
|
156
|
+
}
|
|
157
|
+
/**
|
|
158
|
+
* 运行时能力集属性访问器。
|
|
159
|
+
*/
|
|
160
|
+
get capabilities() {
|
|
161
|
+
return this.getCapabilities();
|
|
162
|
+
}
|
|
163
|
+
/**
|
|
164
|
+
* 获取驱动支持的运行时能力集。
|
|
165
|
+
*/
|
|
166
|
+
getCapabilities() {
|
|
167
|
+
if (cachedCapabilities) {
|
|
168
|
+
return { ...cachedCapabilities };
|
|
169
|
+
}
|
|
170
|
+
let ptySupported = false;
|
|
171
|
+
try {
|
|
172
|
+
const cjsRequire = createRequire(import.meta.url);
|
|
173
|
+
cjsRequire("node-pty");
|
|
174
|
+
ptySupported = true;
|
|
175
|
+
}
|
|
176
|
+
catch {
|
|
177
|
+
ptySupported = false;
|
|
178
|
+
}
|
|
179
|
+
cachedCapabilities = {
|
|
180
|
+
pty: ptySupported,
|
|
181
|
+
resize: ptySupported,
|
|
182
|
+
inputEOF: true,
|
|
183
|
+
interruptForeground: process.platform !== "win32",
|
|
184
|
+
terminationScope: "process-tree",
|
|
185
|
+
};
|
|
186
|
+
return { ...cachedCapabilities };
|
|
187
|
+
}
|
|
188
|
+
/**
|
|
189
|
+
* 依据《Managed Process 设计 v2》标准契约启动受管进程。
|
|
190
|
+
*/
|
|
191
|
+
async spawn(spec, observer) {
|
|
192
|
+
return this.spawnStandard(spec, observer, observer.processId);
|
|
193
|
+
}
|
|
194
|
+
/**
|
|
195
|
+
* 标准接口派生受管进程实现。
|
|
196
|
+
*/
|
|
197
|
+
async spawnStandard(spec, observer, customId) {
|
|
198
|
+
if (spec.io.mode === "pty") {
|
|
199
|
+
return this.spawnPty(spec, observer, customId);
|
|
200
|
+
}
|
|
201
|
+
return this.spawnPipe(spec, observer, customId);
|
|
202
|
+
}
|
|
203
|
+
/**
|
|
204
|
+
* PTY 模式派生:检查运行环境能力,若缺失 node-pty 则明确抛出异常。
|
|
205
|
+
*/
|
|
206
|
+
async spawnPty(spec, observer, customId) {
|
|
207
|
+
let ptyModule;
|
|
208
|
+
try {
|
|
209
|
+
const cjsRequire = createRequire(import.meta.url);
|
|
210
|
+
ptyModule = cjsRequire("node-pty");
|
|
211
|
+
}
|
|
212
|
+
catch (err) {
|
|
213
|
+
throw new ProcessError(UNSUPPORTED_CAPABILITY, `PTY mode is not supported because node-pty is unavailable: ${err?.message || String(err)}`);
|
|
214
|
+
}
|
|
215
|
+
const handleId = customId ?? crypto.randomUUID();
|
|
216
|
+
const env = resolveProcessEnv(spec.env);
|
|
217
|
+
const cols = spec.io.cols ?? 80;
|
|
218
|
+
const rows = spec.io.rows ?? 24;
|
|
219
|
+
const name = spec.io.term ?? "xterm-256color";
|
|
220
|
+
let ptyProcess;
|
|
221
|
+
try {
|
|
222
|
+
ptyProcess = ptyModule.spawn(spec.executable, spec.args, {
|
|
223
|
+
name,
|
|
224
|
+
cols,
|
|
225
|
+
rows,
|
|
226
|
+
cwd: spec.cwd,
|
|
227
|
+
env,
|
|
228
|
+
});
|
|
229
|
+
}
|
|
230
|
+
catch (err) {
|
|
231
|
+
const faultError = err instanceof Error ? err : new Error(String(err));
|
|
232
|
+
observer.fault?.(faultError);
|
|
233
|
+
observer.exited({ code: null, signal: null });
|
|
234
|
+
observer.outputClosed("natural");
|
|
235
|
+
throw faultError;
|
|
236
|
+
}
|
|
237
|
+
const exitListeners = [];
|
|
238
|
+
const instance = {
|
|
239
|
+
id: handleId,
|
|
240
|
+
pid: ptyProcess.pid,
|
|
241
|
+
child: ptyProcess,
|
|
242
|
+
observer,
|
|
243
|
+
mode: "pty",
|
|
244
|
+
ptyProcess,
|
|
245
|
+
exited: false,
|
|
246
|
+
outputClosed: false,
|
|
247
|
+
exitListeners,
|
|
248
|
+
onExit(cb) {
|
|
249
|
+
if (instance.exited) {
|
|
250
|
+
cb();
|
|
251
|
+
}
|
|
252
|
+
else {
|
|
253
|
+
exitListeners.push(cb);
|
|
254
|
+
}
|
|
255
|
+
},
|
|
256
|
+
cleanup() {
|
|
257
|
+
if (instance.drainTimer) {
|
|
258
|
+
clearTimeout(instance.drainTimer);
|
|
259
|
+
instance.drainTimer = undefined;
|
|
260
|
+
}
|
|
261
|
+
exitListeners.length = 0;
|
|
262
|
+
},
|
|
263
|
+
selfRelease: () => {
|
|
264
|
+
// 终态收敛后自移除:按实例身份判断,dispose 先行移除或表内已换新实例时不重复删除
|
|
265
|
+
if (this.instances.get(handleId) === instance) {
|
|
266
|
+
this.instances.delete(handleId);
|
|
267
|
+
}
|
|
268
|
+
},
|
|
269
|
+
};
|
|
270
|
+
const markExited = (code, signal) => {
|
|
271
|
+
if (!instance.exited) {
|
|
272
|
+
instance.exited = true;
|
|
273
|
+
instance.exitResult = { code, signal };
|
|
274
|
+
observer.exited({ code, signal });
|
|
275
|
+
for (const listener of exitListeners) {
|
|
276
|
+
listener();
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
};
|
|
280
|
+
const markOutputClosed = (reason) => {
|
|
281
|
+
if (instance.drainTimer) {
|
|
282
|
+
clearTimeout(instance.drainTimer);
|
|
283
|
+
instance.drainTimer = undefined;
|
|
284
|
+
}
|
|
285
|
+
if (!instance.outputClosed) {
|
|
286
|
+
instance.outputClosed = true;
|
|
287
|
+
observer.outputClosed(reason);
|
|
288
|
+
}
|
|
289
|
+
instance.selfRelease();
|
|
290
|
+
};
|
|
291
|
+
// 绑定 PTY 数据输出
|
|
292
|
+
ptyProcess.onData((data) => {
|
|
293
|
+
observer.output("pty", new TextEncoder().encode(data));
|
|
294
|
+
});
|
|
295
|
+
ptyProcess.onExit((e) => {
|
|
296
|
+
// node-pty 只回传信号数字,必须经映射表转为标准信号名与 pipe 模式对齐
|
|
297
|
+
const signalStr = ptySignalToName(e.signal);
|
|
298
|
+
markExited(e.exitCode, signalStr);
|
|
299
|
+
markOutputClosed("natural");
|
|
300
|
+
});
|
|
301
|
+
this.instances.set(handleId, instance);
|
|
302
|
+
return this.createHandleObject(instance);
|
|
303
|
+
}
|
|
304
|
+
/**
|
|
305
|
+
* pipe 模式派生:使用 child_process.spawn,同步完成监听绑定杜绝竞态。
|
|
306
|
+
*/
|
|
307
|
+
async spawnPipe(spec, observer, customId) {
|
|
308
|
+
const handleId = customId ?? crypto.randomUUID();
|
|
309
|
+
const env = resolveProcessEnv(spec.env);
|
|
310
|
+
let child;
|
|
311
|
+
try {
|
|
312
|
+
child = this.spawnFn(spec.executable, spec.args, {
|
|
313
|
+
cwd: spec.cwd,
|
|
314
|
+
env,
|
|
315
|
+
stdio: ["pipe", "pipe", "pipe"],
|
|
316
|
+
detached: process.platform !== "win32",
|
|
317
|
+
});
|
|
318
|
+
}
|
|
319
|
+
catch (err) {
|
|
320
|
+
const faultError = err instanceof Error ? err : new Error(String(err));
|
|
321
|
+
observer.fault?.(faultError);
|
|
322
|
+
observer.exited({ code: null, signal: null });
|
|
323
|
+
observer.outputClosed("natural");
|
|
324
|
+
throw faultError;
|
|
325
|
+
}
|
|
326
|
+
const exitListeners = [];
|
|
327
|
+
const instance = {
|
|
328
|
+
id: handleId,
|
|
329
|
+
pid: child.pid,
|
|
330
|
+
child,
|
|
331
|
+
observer,
|
|
332
|
+
mode: "pipe",
|
|
333
|
+
exited: false,
|
|
334
|
+
outputClosed: false,
|
|
335
|
+
exitListeners,
|
|
336
|
+
onExit(cb) {
|
|
337
|
+
if (instance.exited) {
|
|
338
|
+
cb();
|
|
339
|
+
}
|
|
340
|
+
else {
|
|
341
|
+
exitListeners.push(cb);
|
|
342
|
+
}
|
|
343
|
+
},
|
|
344
|
+
cleanup() {
|
|
345
|
+
if (instance.drainTimer) {
|
|
346
|
+
clearTimeout(instance.drainTimer);
|
|
347
|
+
instance.drainTimer = undefined;
|
|
348
|
+
}
|
|
349
|
+
exitListeners.length = 0;
|
|
350
|
+
},
|
|
351
|
+
selfRelease: () => {
|
|
352
|
+
// 终态收敛后自移除:按实例身份判断,dispose 先行移除或表内已换新实例时不重复删除
|
|
353
|
+
if (this.instances.get(handleId) === instance) {
|
|
354
|
+
this.instances.delete(handleId);
|
|
355
|
+
}
|
|
356
|
+
},
|
|
357
|
+
};
|
|
358
|
+
const markExited = (code, signal) => {
|
|
359
|
+
if (!instance.exited) {
|
|
360
|
+
instance.exited = true;
|
|
361
|
+
instance.exitResult = { code, signal };
|
|
362
|
+
observer.exited({ code, signal });
|
|
363
|
+
for (const listener of exitListeners) {
|
|
364
|
+
listener();
|
|
365
|
+
}
|
|
366
|
+
}
|
|
367
|
+
};
|
|
368
|
+
const markOutputClosed = (reason) => {
|
|
369
|
+
if (instance.drainTimer) {
|
|
370
|
+
clearTimeout(instance.drainTimer);
|
|
371
|
+
instance.drainTimer = undefined;
|
|
372
|
+
}
|
|
373
|
+
if (!instance.outputClosed) {
|
|
374
|
+
instance.outputClosed = true;
|
|
375
|
+
observer.outputClosed(reason);
|
|
376
|
+
}
|
|
377
|
+
instance.selfRelease();
|
|
378
|
+
};
|
|
379
|
+
// 同步完成 stdout/stderr 监听绑定,防止产生数据丢失竞态
|
|
380
|
+
if (child.stdout) {
|
|
381
|
+
child.stdout.on("data", (chunk) => {
|
|
382
|
+
observer.output("stdout", new Uint8Array(chunk.buffer, chunk.byteOffset, chunk.byteLength));
|
|
383
|
+
});
|
|
384
|
+
}
|
|
385
|
+
if (child.stderr) {
|
|
386
|
+
child.stderr.on("data", (chunk) => {
|
|
387
|
+
observer.output("stderr", new Uint8Array(chunk.buffer, chunk.byteOffset, chunk.byteLength));
|
|
388
|
+
});
|
|
389
|
+
}
|
|
390
|
+
// 监听 stdin 错误避免未捕获 EPIPE 导致宿主异常退出
|
|
391
|
+
if (child.stdin) {
|
|
392
|
+
child.stdin.on("error", () => {
|
|
393
|
+
// 忽略管道断开异常
|
|
394
|
+
});
|
|
395
|
+
}
|
|
396
|
+
child.on("exit", (code, signal) => {
|
|
397
|
+
markExited(code, signal);
|
|
398
|
+
if (!instance.outputClosed && !instance.drainTimer) {
|
|
399
|
+
instance.drainTimer = setTimeout(() => {
|
|
400
|
+
markOutputClosed("drain-timeout");
|
|
401
|
+
}, this.drainDeadlineMs);
|
|
402
|
+
instance.drainTimer.unref?.();
|
|
403
|
+
}
|
|
404
|
+
});
|
|
405
|
+
child.on("close", (code, signal) => {
|
|
406
|
+
markExited(code, signal);
|
|
407
|
+
markOutputClosed("natural");
|
|
408
|
+
});
|
|
409
|
+
child.on("error", (err) => {
|
|
410
|
+
instance.cleanup();
|
|
411
|
+
observer.fault?.(err);
|
|
412
|
+
markExited(null, null);
|
|
413
|
+
markOutputClosed("natural");
|
|
414
|
+
});
|
|
415
|
+
this.instances.set(handleId, instance);
|
|
416
|
+
return this.createHandleObject(instance);
|
|
417
|
+
}
|
|
418
|
+
/**
|
|
419
|
+
* 构造对齐驱动操作的 ProcessHandle 对象。
|
|
420
|
+
*/
|
|
421
|
+
createHandleObject(instance) {
|
|
422
|
+
return {
|
|
423
|
+
id: instance.id,
|
|
424
|
+
pid: instance.pid,
|
|
425
|
+
write: (data) => this.write(instance, data),
|
|
426
|
+
sendInputEOF: () => this.inputEOF(instance),
|
|
427
|
+
interruptForeground: () => this.interruptForeground(instance),
|
|
428
|
+
resize: (cols, rows) => this.resize(instance, cols, rows),
|
|
429
|
+
terminate: (graceMs) => this.terminate(instance, graceMs),
|
|
430
|
+
};
|
|
431
|
+
}
|
|
432
|
+
/**
|
|
433
|
+
* 向受管进程输入流写入字节数据,支持背压与管道提早关闭错误捕获。
|
|
434
|
+
* 终态自清理(selfRelease)或 dispose 先行移除实例时,进程已退出且输入管道必然关闭,
|
|
435
|
+
* 按已关闭语义抛出 INPUT_CLOSED 而非笼统异常。
|
|
436
|
+
*/
|
|
437
|
+
async write(handle, data) {
|
|
438
|
+
const instance = this.instances.get(handle.id);
|
|
439
|
+
if (!instance) {
|
|
440
|
+
throw new ProcessError(INPUT_CLOSED, "Process stdin is closed or destroyed");
|
|
441
|
+
}
|
|
442
|
+
if (instance.mode === "pty" && instance.ptyProcess) {
|
|
443
|
+
const text = new TextDecoder().decode(data);
|
|
444
|
+
instance.ptyProcess.write(text);
|
|
445
|
+
return;
|
|
446
|
+
}
|
|
447
|
+
const stdin = instance.child.stdin;
|
|
448
|
+
if (!stdin || stdin.destroyed || !stdin.writable) {
|
|
449
|
+
throw new ProcessError(INPUT_CLOSED, "Process stdin is closed or destroyed");
|
|
450
|
+
}
|
|
451
|
+
return new Promise((resolve, reject) => {
|
|
452
|
+
let settled = false;
|
|
453
|
+
const cleanup = () => {
|
|
454
|
+
stdin.removeListener("error", onError);
|
|
455
|
+
stdin.removeListener("drain", onDrain);
|
|
456
|
+
};
|
|
457
|
+
const onError = (err) => {
|
|
458
|
+
if (!settled) {
|
|
459
|
+
settled = true;
|
|
460
|
+
cleanup();
|
|
461
|
+
reject(new ProcessError(INPUT_CLOSED, `Failed to write to stdin: ${err.message}`));
|
|
462
|
+
}
|
|
463
|
+
};
|
|
464
|
+
const onDrain = () => {
|
|
465
|
+
if (!settled) {
|
|
466
|
+
settled = true;
|
|
467
|
+
cleanup();
|
|
468
|
+
resolve();
|
|
469
|
+
}
|
|
470
|
+
};
|
|
471
|
+
stdin.once("error", onError);
|
|
472
|
+
const buffer = Buffer.from(data.buffer, data.byteOffset, data.byteLength);
|
|
473
|
+
const canContinue = stdin.write(buffer, (err) => {
|
|
474
|
+
if (err) {
|
|
475
|
+
onError(err);
|
|
476
|
+
}
|
|
477
|
+
});
|
|
478
|
+
if (canContinue) {
|
|
479
|
+
if (!settled) {
|
|
480
|
+
settled = true;
|
|
481
|
+
cleanup();
|
|
482
|
+
resolve();
|
|
483
|
+
}
|
|
484
|
+
}
|
|
485
|
+
else {
|
|
486
|
+
stdin.once("drain", onDrain);
|
|
487
|
+
}
|
|
488
|
+
});
|
|
489
|
+
}
|
|
490
|
+
/**
|
|
491
|
+
* 结束输入流写入,发送 EOF。
|
|
492
|
+
*/
|
|
493
|
+
async inputEOF(handle) {
|
|
494
|
+
const instance = this.resolveInstance(handle);
|
|
495
|
+
if (instance.mode === "pty") {
|
|
496
|
+
// PTY 模式下发送 EOF 控制符 Ctrl+D (\x04)
|
|
497
|
+
if (instance.ptyProcess) {
|
|
498
|
+
instance.ptyProcess.write("\x04");
|
|
499
|
+
}
|
|
500
|
+
return;
|
|
501
|
+
}
|
|
502
|
+
const stdin = instance.child.stdin;
|
|
503
|
+
if (!stdin || stdin.destroyed || !stdin.writable) {
|
|
504
|
+
return;
|
|
505
|
+
}
|
|
506
|
+
return new Promise((resolve) => {
|
|
507
|
+
stdin.end(() => {
|
|
508
|
+
resolve();
|
|
509
|
+
});
|
|
510
|
+
});
|
|
511
|
+
}
|
|
512
|
+
/**
|
|
513
|
+
* 中断前台作业组。
|
|
514
|
+
*/
|
|
515
|
+
async interruptForeground(handle) {
|
|
516
|
+
const instance = this.resolveInstance(handle);
|
|
517
|
+
const pid = instance.pid;
|
|
518
|
+
if (!pid || instance.exited) {
|
|
519
|
+
return;
|
|
520
|
+
}
|
|
521
|
+
if (instance.mode === "pty" && instance.ptyProcess) {
|
|
522
|
+
// PTY 模式发送 Ctrl+C (\x03)
|
|
523
|
+
instance.ptyProcess.write("\x03");
|
|
524
|
+
return;
|
|
525
|
+
}
|
|
526
|
+
if (process.platform === "win32") {
|
|
527
|
+
throw new ProcessError(UNSUPPORTED_CAPABILITY, "interruptForeground is not supported on Windows in pipe mode");
|
|
528
|
+
}
|
|
529
|
+
else {
|
|
530
|
+
try {
|
|
531
|
+
process.kill(-pid, "SIGINT");
|
|
532
|
+
}
|
|
533
|
+
catch {
|
|
534
|
+
try {
|
|
535
|
+
process.kill(pid, "SIGINT");
|
|
536
|
+
}
|
|
537
|
+
catch {
|
|
538
|
+
// 忽略已退出状态
|
|
539
|
+
}
|
|
540
|
+
}
|
|
541
|
+
}
|
|
542
|
+
}
|
|
543
|
+
/**
|
|
544
|
+
* 动态调整终端尺寸,仅 PTY 模式生效。
|
|
545
|
+
*/
|
|
546
|
+
async resize(handle, cols, rows) {
|
|
547
|
+
const instance = this.resolveInstance(handle);
|
|
548
|
+
if (instance.mode !== "pty" || !instance.ptyProcess) {
|
|
549
|
+
throw new ProcessError(UNSUPPORTED_CAPABILITY, "Terminal resize is unsupported in pipe mode");
|
|
550
|
+
}
|
|
551
|
+
instance.ptyProcess.resize(cols, rows);
|
|
552
|
+
}
|
|
553
|
+
/**
|
|
554
|
+
* 优雅终止进程,超时未退出则发送 SIGKILL 强杀兜底。
|
|
555
|
+
* 终态自清理(selfRelease)或 dispose 先行移除实例时视为已终止,直接无害返回。
|
|
556
|
+
*/
|
|
557
|
+
async terminate(handle, graceMs) {
|
|
558
|
+
const instance = this.instances.get(handle.id);
|
|
559
|
+
if (!instance) {
|
|
560
|
+
return;
|
|
561
|
+
}
|
|
562
|
+
const pid = instance.pid;
|
|
563
|
+
if (!pid || instance.exited) {
|
|
564
|
+
return;
|
|
565
|
+
}
|
|
566
|
+
await killProcessGroup(pid, "SIGTERM", this.spawnFn);
|
|
567
|
+
if (graceMs <= 0) {
|
|
568
|
+
if (!instance.exited) {
|
|
569
|
+
await killProcessGroup(pid, "SIGKILL", this.spawnFn);
|
|
570
|
+
}
|
|
571
|
+
return;
|
|
572
|
+
}
|
|
573
|
+
if (instance.exited) {
|
|
574
|
+
return;
|
|
575
|
+
}
|
|
576
|
+
await new Promise((resolve) => {
|
|
577
|
+
let timer;
|
|
578
|
+
let settled = false;
|
|
579
|
+
let exitFinish;
|
|
580
|
+
const finish = () => {
|
|
581
|
+
if (settled) {
|
|
582
|
+
return;
|
|
583
|
+
}
|
|
584
|
+
settled = true;
|
|
585
|
+
// 完成后自注销本次注册的 exit 监听器,避免同一实例反复 terminate 时累积监听器
|
|
586
|
+
if (exitFinish) {
|
|
587
|
+
const idx = instance.exitListeners.indexOf(exitFinish);
|
|
588
|
+
if (idx >= 0) {
|
|
589
|
+
instance.exitListeners.splice(idx, 1);
|
|
590
|
+
}
|
|
591
|
+
}
|
|
592
|
+
if (timer)
|
|
593
|
+
clearTimeout(timer);
|
|
594
|
+
resolve();
|
|
595
|
+
};
|
|
596
|
+
exitFinish = finish;
|
|
597
|
+
instance.onExit(finish);
|
|
598
|
+
timer = setTimeout(async () => {
|
|
599
|
+
if (!instance.exited) {
|
|
600
|
+
try {
|
|
601
|
+
await killProcessGroup(pid, "SIGKILL", this.spawnFn);
|
|
602
|
+
}
|
|
603
|
+
catch {
|
|
604
|
+
// 忽略终止失败异常
|
|
605
|
+
}
|
|
606
|
+
}
|
|
607
|
+
finish();
|
|
608
|
+
}, graceMs);
|
|
609
|
+
timer.unref?.();
|
|
610
|
+
});
|
|
611
|
+
}
|
|
612
|
+
/**
|
|
613
|
+
* 销毁进程句柄并清理相关资源。
|
|
614
|
+
* 对仍在运行的实例先执行 terminate(0) 兜底(SIGTERM 后立即 SIGKILL),
|
|
615
|
+
* 绝不从受管表移除仍存活的子进程而遗留孤儿;已退出实例直接清理。
|
|
616
|
+
* 终态自清理(selfRelease)与 dispose 可能并发到达,二者均按实例身份判断,
|
|
617
|
+
* 后到方对已删除条目为无害空操作。
|
|
618
|
+
*/
|
|
619
|
+
async dispose(handle) {
|
|
620
|
+
const instance = this.instances.get(handle.id);
|
|
621
|
+
if (instance) {
|
|
622
|
+
if (!instance.exited) {
|
|
623
|
+
try {
|
|
624
|
+
await this.terminate(handle, 0);
|
|
625
|
+
}
|
|
626
|
+
catch {
|
|
627
|
+
// 兜底终止失败不阻断句柄清理,退出事件仍会经监听链路上报
|
|
628
|
+
}
|
|
629
|
+
}
|
|
630
|
+
instance.cleanup();
|
|
631
|
+
if (this.instances.get(handle.id) === instance) {
|
|
632
|
+
this.instances.delete(handle.id);
|
|
633
|
+
}
|
|
634
|
+
}
|
|
635
|
+
}
|
|
636
|
+
/**
|
|
637
|
+
* 解析查找内部受管进程实例。
|
|
638
|
+
*/
|
|
639
|
+
resolveInstance(handle) {
|
|
640
|
+
const instance = this.instances.get(handle.id);
|
|
641
|
+
if (!instance) {
|
|
642
|
+
throw new Error(`Process instance not found for handle id: ${handle.id}`);
|
|
643
|
+
}
|
|
644
|
+
return instance;
|
|
645
|
+
}
|
|
646
|
+
}
|
|
647
|
+
/**
|
|
648
|
+
* 兼容原有命名导出。
|
|
649
|
+
*/
|
|
650
|
+
export { NodeProcessDriver as ProcessDriverImpl };
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import type { spawn } from "node:child_process";
|
|
2
|
+
import { type CallOptions, type ControlGrant, type OperationReceipt, type ProcessAcquireInput, type ProcessControlInput, type ProcessExecOptions, type ProcessInfo, type ProcessListInput, type ProcessListResult, type ProcessReadInput, type ProcessResult, type ProcessRunInput, type ProcessRunResult, type ProcessStartInput, type ProcessStartResult, type ProcessStopInput, type ProcessWriteInput, type ReadResult } from "@actiondock/sdk";
|
|
3
|
+
import type { ProcessDriver } from "./driver.js";
|
|
4
|
+
import { killProcessGroup } from "./process-driver.js";
|
|
5
|
+
import type { ProcessExecutor } from "../runtime/process.js";
|
|
6
|
+
export { killProcessGroup };
|
|
7
|
+
/**
|
|
8
|
+
* 基于 NodeProcessDriver 实现的兼容命令执行器。
|
|
9
|
+
* 核心 OS 进程派生与生命周期管理统一由 NodeProcessDriver 承担,不再重复派生与调度。
|
|
10
|
+
*/
|
|
11
|
+
export declare class NodeProcessExecutor implements ProcessExecutor {
|
|
12
|
+
private readonly driver;
|
|
13
|
+
private readonly gracePeriodMs;
|
|
14
|
+
constructor(options?: number | {
|
|
15
|
+
gracePeriodMs?: number;
|
|
16
|
+
spawnFn?: typeof spawn;
|
|
17
|
+
driver?: ProcessDriver;
|
|
18
|
+
});
|
|
19
|
+
/**
|
|
20
|
+
* 执行外部系统命令,完整支持标准输入管道、超时控制、取消信号、输出容量截断及错误拦截。
|
|
21
|
+
*
|
|
22
|
+
* @param command 执行命令
|
|
23
|
+
* @param args 参数列表
|
|
24
|
+
* @param options 执行选项
|
|
25
|
+
* @param internal 内部专用参数:envAlreadyResolved 为 true 时 options.env 视为已完整解析
|
|
26
|
+
*/
|
|
27
|
+
exec(command: string, args?: string[], options?: ProcessExecOptions, internal?: {
|
|
28
|
+
envAlreadyResolved?: boolean;
|
|
29
|
+
}): Promise<ProcessResult>;
|
|
30
|
+
spawn(command: string, args?: string[], options?: ProcessExecOptions): Promise<ProcessResult>;
|
|
31
|
+
run(input: ProcessRunInput, call?: CallOptions): Promise<ProcessRunResult>;
|
|
32
|
+
start(_input: ProcessStartInput, _call?: CallOptions): Promise<ProcessStartResult>;
|
|
33
|
+
inspect(_id: string, _call?: CallOptions): Promise<ProcessInfo>;
|
|
34
|
+
list(_input: ProcessListInput, _call?: CallOptions): Promise<ProcessListResult>;
|
|
35
|
+
acquire(_id: string, _input: ProcessAcquireInput, _call?: CallOptions): Promise<ControlGrant>;
|
|
36
|
+
renew(_id: string, _token: string, _ttlMs: number, _call?: CallOptions): Promise<ControlGrant>;
|
|
37
|
+
release(_id: string, _token: string, _call?: CallOptions): Promise<void>;
|
|
38
|
+
write(_id: string, _input: ProcessWriteInput, _call?: CallOptions): Promise<OperationReceipt>;
|
|
39
|
+
operation(_id: string, _requestId: string, _call?: CallOptions): Promise<OperationReceipt>;
|
|
40
|
+
read(_id: string, _input: ProcessReadInput, _call?: CallOptions): Promise<ReadResult>;
|
|
41
|
+
control(_id: string, _input: ProcessControlInput, _call?: CallOptions): Promise<OperationReceipt>;
|
|
42
|
+
stop(_id: string, _input: ProcessStopInput, _call?: CallOptions): Promise<ProcessInfo>;
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* 兼容原有类名导出。
|
|
46
|
+
*/
|
|
47
|
+
export { NodeProcessExecutor as ExecaProcessExecutor };
|