@brierb/brier-cli 0.0.11 → 0.0.13
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/daemon/TaskExecutor.js +40 -4
- package/package.json +1 -1
|
@@ -1,6 +1,30 @@
|
|
|
1
1
|
import { spawn } from 'node:child_process';
|
|
2
|
+
import { chmodSync } from 'node:fs';
|
|
3
|
+
import { dirname, join } from 'node:path';
|
|
4
|
+
import { createRequire } from 'node:module';
|
|
2
5
|
import pty from 'node-pty';
|
|
3
6
|
import { logger, resolveRuntimeExecutable, RUNTIME_PROMPT_FLAGS } from '../core/index.js';
|
|
7
|
+
const require = createRequire(import.meta.url);
|
|
8
|
+
/**
|
|
9
|
+
* 修复 node-pty 的 darwin spawn-helper 可执行权限。
|
|
10
|
+
*
|
|
11
|
+
* 现象:node-pty 在 macOS 上先 spawn 自带的 spawn-helper 再执行目标命令;
|
|
12
|
+
* 若该 helper 因下载/安装而缺失可执行位(0644),posix_spawnp 返回 EACCES,
|
|
13
|
+
* 且 node-pty 只抛出笼统的 "posix_spawnp failed."(无 errno),难以定位。
|
|
14
|
+
* 每次 pty 启动前兜底 chmod +x,兼容重装后权限再丢失的情况。
|
|
15
|
+
*/
|
|
16
|
+
const ensurePtyHelperExecutable = () => {
|
|
17
|
+
if (process.platform !== 'darwin')
|
|
18
|
+
return;
|
|
19
|
+
try {
|
|
20
|
+
const pkgDir = dirname(require.resolve('node-pty/package.json'));
|
|
21
|
+
const helper = join(pkgDir, 'prebuilds', `darwin-${process.arch}`, 'spawn-helper');
|
|
22
|
+
chmodSync(helper, 0o755);
|
|
23
|
+
}
|
|
24
|
+
catch {
|
|
25
|
+
// helper 权限修正失败不致命:若 node-pty 自身可执行则正常走;否则抛错由上层捕获
|
|
26
|
+
}
|
|
27
|
+
};
|
|
4
28
|
const MAX_CONCURRENT = 3;
|
|
5
29
|
/** 取消后等待 SIGTERM 生效的时间,超时升级 SIGKILL(仅 pipe 模式需要;pty.kill 为同步终止) */
|
|
6
30
|
const KILL_GRACE_MS = 2_000;
|
|
@@ -118,10 +142,14 @@ export const createTaskExecutor = (callbacks) => {
|
|
|
118
142
|
* pty 模式:伪终端交互子进程。
|
|
119
143
|
* CLI 检测到 tty 后进入交互模式(会提问、渲染进度、等待输入);
|
|
120
144
|
* 屏幕字节经 onData 上行(含 ANSI),用户输入经 writeInput 写入(模拟击键)。
|
|
145
|
+
*
|
|
146
|
+
* 与 pipe 模式的关键差异:prompt 任务不再把 prompt 拼成命令行参数,
|
|
147
|
+
* 而是启动后作为“用户输入”敲进终端(交互式 CLI 从会话里读取首条消息)。
|
|
121
148
|
*/
|
|
122
|
-
const executePty = (task, cmd, args, childEnv) => {
|
|
149
|
+
const executePty = (task, cmd, args, childEnv, initialInput) => {
|
|
123
150
|
let handle;
|
|
124
151
|
try {
|
|
152
|
+
ensurePtyHelperExecutable();
|
|
125
153
|
handle = pty.spawn(cmd, args, {
|
|
126
154
|
name: 'xterm-256color',
|
|
127
155
|
cols: 120,
|
|
@@ -136,6 +164,10 @@ export const createTaskExecutor = (callbacks) => {
|
|
|
136
164
|
}
|
|
137
165
|
ptyProcs.set(task.taskId, handle);
|
|
138
166
|
logger.info(`Task ${task.taskId} started in pty mode: ${cmd} ${args.join(' ')}`, task.runtime);
|
|
167
|
+
// prompt 作为首条会话消息敲入(补回车触发提交);无 prompt(command 模式)不注入
|
|
168
|
+
if (initialInput) {
|
|
169
|
+
handle.write(initialInput);
|
|
170
|
+
}
|
|
139
171
|
handle.onData((data) => {
|
|
140
172
|
// pty 只有一路输出(合并 stdout/stderr 的终端字节流),统一按 stdout 上行;
|
|
141
173
|
// 前端如需区分文本/控制序列,属于展示层解析,不在执行层拆流。
|
|
@@ -168,13 +200,17 @@ export const createTaskExecutor = (callbacks) => {
|
|
|
168
200
|
callbacks.onError(task.taskId, `Cannot resolve command for runtime: ${task.runtime} (no command provided)`);
|
|
169
201
|
return;
|
|
170
202
|
}
|
|
171
|
-
const args = buildArgs(task);
|
|
172
203
|
const childEnv = buildEnv(task);
|
|
173
204
|
if (task.execMode === 'pty') {
|
|
174
|
-
|
|
205
|
+
// 交互模式:prompt 不拼参数,作为首条输入敲入;command 模式透传 args
|
|
206
|
+
const args = task.prompt ? [] : (task.args ?? []);
|
|
207
|
+
const initialInput = task.prompt !== undefined && task.prompt.trim() !== ''
|
|
208
|
+
? `${task.prompt.replace(/\r?\n/g, '\r')}\r`
|
|
209
|
+
: undefined;
|
|
210
|
+
executePty(task, cmd, args, childEnv, initialInput);
|
|
175
211
|
return;
|
|
176
212
|
}
|
|
177
|
-
executePipe(task, cmd,
|
|
213
|
+
executePipe(task, cmd, buildArgs(task), childEnv);
|
|
178
214
|
};
|
|
179
215
|
const writeInput = (taskId, data) => {
|
|
180
216
|
if (!data)
|