主题
命令执行 API
本文引用的源码文件
**本文引用的文件 **
目录
文档目标与适用范围
本文面向需要调用本地 Agent 命令执行能力的开发者,重点说明:
- 命令执行的 HTTP 接口行为。
- 命令白名单、黑名单、Shell 检测、路径沙箱与安全分级。
- 进程树终止、超时控制、输出截断与完成缓存。
- WebSocket 实时输出、连接建立、消息格式与断开重连策略。
- 运行中进程查询、停止与显式 daemon 化。
- curl 使用方式、客户端实现注意事项和性能调优方向。
需要注意的运行时约束:
- 本项目是 Chrome 扩展端与独立 Node.js Agent 的双进程架构。
- Agent 源码修改后必须重启 Agent 进程,新接口才生效。
- 命令执行能力由 Agent 端的
server.js路由暴露,并由executor.js负责子进程调度,security.js负责命令与路径安全检查。 - 当前仓库中的命令执行入口是
/api/exec,并通过wait字段区分同步或异步语义;同时提供/api/exec/stop、/api/exec/detach等辅助接口。 - 文档标题中提到的
/api/exec/run-sync、/api/exec/kill、/api/exec/list并非当前代码中的实际路径,应理解为对/api/exec同步模式、/api/exec/stop、运行进程状态查询能力的概念性描述。
章节来源
架构总览
命令执行的核心流程如下:
graph TB
Client["调用方<br/>浏览器扩展、脚本或外部工具"] --> Http["Agent HTTP 服务器<br/>/api/exec"]
Http --> Security["安全检查<br/>路径校验 + 命令分级"]
Security --> Executor["命令执行器<br/>spawn 子进程"]
Executor --> Process["操作系统进程树"]
Executor --> WsServer["WebSocket 服务器<br/>/ws/exec/{execId}"]
Process --> Output["stdout / stderr"]
Output --> WsServer
WsServer --> Client
图表来源
关键组件职责:
| 组件 | 主要职责 | 关键行为 |
|---|---|---|
| HTTP 服务器 | 解析请求、鉴权、路由到命令执行逻辑 | 处理 /api/exec、/api/exec/stop、/api/exec/detach |
| 安全检查模块 | 路径白名单、核心敏感路径硬阻止、命令黑白灰名单 | 返回 allow、confirm、deny |
| 命令执行器 | 创建子进程、流式输出、超时控制、进程列表 | 支持异步、同步、WebSocket 回放、输出缓冲上限 |
| 进程树工具 | 递归终止子进程及其孙进程 | POSIX 进程组信号、Windows taskkill |
章节来源
- agent/src/server.js#L1-L56
- agent/src/executor.js#L1-L18
- agent/src/security.js#L1-L17
- agent/src/process-tree.js#L1-L42
端点参考
/api/exec:命令执行入口
该端点是命令执行的主要入口,支持两种模式:
| 参数 | 类型 | 是否必填 | 含义 |
|---|---|---|---|
command | 字符串 | 是 | 要执行的完整命令 |
cwd | 字符串 | 否 | 工作目录;默认使用配置中的工作目录 |
wait | 布尔值 | 否 | 为真时走同步等待模式 |
force | 布尔值 | 否 | 为真时跳过灰名单确认,但黑名单仍不可绕过 |
timeoutMs | 数字 | 否 | 受管超时预算;未传时使用配置默认值 |
同步模式
当 wait 为真时,HTTP 响应会阻塞直到命令结束,返回完整 stdout/stderr。
成功响应包含:
| 字段 | 含义 |
|---|---|
success | 是否成功 |
level | 安全级别,通常为 allow |
execId | 命令执行 ID |
exitCode | 进程退出码 |
stdout | 标准输出 |
stderr | 标准错误 |
killed | 是否被主动终止 |
error | 可选错误信息 |
失败响应可能返回:
| 状态码 | 含义 |
|---|---|
| 400 | 缺少命令或请求体无效 |
| 403 | 工作目录不在允许范围,或命令被黑名单拒绝 |
| 500 | 命令执行异常 |
异步模式
当 wait 为假或未传时,服务端立即启动命令并返回 execId 和 WebSocket 地址。
成功响应包含:
| 字段 | 含义 |
|---|---|
success | 是否接受命令 |
level | 安全级别 |
execId | 命令执行 ID |
wsUrl | WebSocket 实时输出地址 |
安全确认模式
如果命令命中灰名单且未设置 force,服务端不会直接执行,而是返回确认请求:
| 字段 | 含义 |
|---|---|
success | 安全检查通过可继续 |
level | confirm |
reason | 触发确认的原因 |
command | 原始命令 |
cwd | 工作目录 |
调用方应在前端展示用户确认界面;确认后再次调用同一接口并设置 force: true。
章节来源
/api/exec/stop:终止进程
该端点对应题目中的“终止进程”能力。
| 参数 | 类型 | 是否必填 | 含义 |
|---|---|---|---|
execId | 字符串 | 是 | 要终止的命令执行 ID |
成功响应:
| 字段 | 含义 |
|---|---|
success | 是否成功发起终止 |
execId | 被终止的命令执行 ID |
终止逻辑会尝试优雅终止,并在约 5 秒后强制终止,避免僵尸进程长期残留。
章节来源
/api/exec/detach:显式 daemon 化
该端点用于显式声明命令进入后台运行模式:取消超时定时器,让进程继续运行。
| 参数 | 类型 | 是否必填 | 含义 |
|---|---|---|---|
execId | 字符串 | 是 | 要 detach 的命令执行 ID |
成功响应:
| 字段 | 含义 |
|---|---|
success | 是否成功 detach |
execId | 被 detach 的命令执行 ID |
注意:detach 不是“查看运行进程”,它只是解除超时限制。
章节来源
运行进程查询
当前代码没有独立的 /api/exec/list 端点,但运行进程信息会通过 /api/status/detail 返回。
在认证后的 /api/status/detail 响应中,包含:
| 字段 | 含义 |
|---|---|
runningProcesses | 运行中进程列表 |
resourceUsage | Agent 内存、CPU、运行时长等资源信息 |
commandTimeout | 命令超时配置 |
workdir | 当前工作目录 |
allowedPaths | 路径白名单 |
runningProcesses 每个元素包含:
| 字段 | 含义 |
|---|---|
execId | 命令执行 ID |
pid | 子进程 PID |
command | 命令字符串 |
startTime | 开始时间戳 |
duration | 已运行毫秒数 |
章节来源
安全机制
命令执行的安全机制分为两层:
- 路径层安全:限制命令的工作目录和文件访问范围。
- 命令层安全:对命令文本进行黑名单、灰名单和安全分级。
路径白名单与工作目录
路径检查遵循以下优先级:
- 核心敏感路径硬阻止。
- 记忆存储目录放行。
- 工作目录始终放行。
- 配置中的
allowedPaths白名单。 - 符号链接解析后再次校验。
核心敏感路径包括 Agent 配置文件、配对记录、日志目录、回收站目录等,任何情况下都不可访问。
工作目录是用户当前选定的操作目录,即使未出现在 allowedPaths 中也必须可访问。
章节来源
命令白名单、黑名单与灰名单
命令安全检查采用三级分类:
| 级别 | 含义 | 是否可绕过 |
|---|---|---|
allow | 安全命令 | 直接执行 |
confirm | 高风险但非绝对禁止 | 可通过 force 跳过 |
deny | 绝对禁止 | 不可绕过 |
黑名单包含:
- 删除系统根目录、
/dev、/proc、/sys。 - 格式化磁盘、覆盖设备文件。
- 覆盖
/etc/passwd、/etc/shadow、/etc/sudoers。 - fork bomb。
- shebang 直接执行。
- 网络下载管道到 shell。
- 修改根目录权限或属主。
- Windows 格式化、分区、覆盖注册表蜂巢、覆盖 hosts 等。
灰名单包含:
sudo、doas、runas提权。- 全局 npm 安装、pip 安装卸载。
- 递归强制删除。
- Git 强制推送。
- 关机、重启、halt、poweroff。
- 修改
/etc/hosts。 eval。- 命令替换(反引号、
$( ))。 - dd 写入、shred、truncate。
- chmod/chown 危险权限变更。
- curl/wget/nc/telnet/ssh/scp 等网络外联。
- kill/pkill/killall/systemctl/launchctl/crontab/sysctl。
- 解释器执行外部脚本。
- Windows rmdir/del/icacls/takeown/reg/net/sc/taskkill 等高危命令。
黑名单在任何情况下都不允许执行;灰名单在未设置 force 时会要求用户确认。
章节来源
Shell 检测
命令执行器会根据平台和环境选择 shell:
- Windows:优先使用环境变量中的 bash、powershell、cmd;回退到 Git Bash 已知路径或 COMSPEC。
- macOS:优先 zsh 或 bash;否则使用
/bin/zsh。 - Linux:优先 bash、zsh、fish;否则探测
/bin/bash、/usr/bin/bash、/bin/sh。
选择 shell 时会检查路径是否存在,避免 MSYS/Git Bash 的 MSYS 风格路径在 Windows 上直接 spawn 失败。
章节来源
环境变量隔离
命令执行使用安全环境变量白名单,不直接继承宿主全部环境。
白名单包含 PATH、HOME、USER、SHELL、LANG、编辑器相关变量、语言运行时变量、颜色控制变量等。
同时强制设置:
TERM=dumbFORCE_COLOR=0
这能减少终端控制字符和颜色输出对日志和输出的干扰。
章节来源
WebSocket 实时输出
连接建立
异步命令执行成功后,响应中包含 wsUrl,格式为:
ws://{host}:{port}/ws/exec/{execId}调用方应使用该 URL 建立 WebSocket 连接,订阅 stdout、stderr、exit、error 等事件。
如果命令已结束但客户端尚未连接,服务端会从已完成输出缓存中回放历史输出。
章节来源
消息格式
WebSocket 消息统一为 JSON 字符串,常见类型如下:
| type | 含义 | 关键字段 |
|---|---|---|
stdout | 标准输出片段 | data、execId |
stderr | 标准错误片段 | data、execId |
stdout_truncated | stdout 超过缓冲区上限 | message、execId |
stderr_truncated | stderr 超过缓冲区上限 | message、execId |
exit | 进程结束 | exitCode、execId、killed、timedOut |
error | 子进程错误 | error、execId |
exitCode 为数字;若进程因错误无法获取退出码,可能为 -1。
killed 表示是否被主动终止。
timedOut 表示是否因超时策略被终止。
章节来源
断开重连处理
WebSocket 客户端应实现以下重连策略:
- 连接建立后立即订阅所有消息。
- 收到
exit后认为命令生命周期结束。 - 若连接断开且未收到
exit,应延迟重试连接。 - 重试连接后,若命令已结束,服务端会回放历史 stdout/stderr 和 exit 消息。
- 若命令仍在运行,新连接会加入现有进程的 WebSocket 客户端集合,接收后续输出。
- 不要仅根据 WS 断开就自动终止命令;只有显式调用
/api/exec/stop或/api/exec/detach才改变进程行为。
章节来源
进程生命周期管理
进程监控
运行中的命令保存在内存映射中,键为 execId。
每个进程条目包含:
- 子进程对象。
- WebSocket 客户端集合。
- stdout/stderr 缓冲区。
- 是否截断标记。
- 命令字符串。
- 开始时间。
- 基础超时值。
- 是否受管模式。
- 延长次数。
- 本预算期内是否有输出。
- 是否 detach。
- 是否超时。
章节来源
资源清理
输出缓冲区有上限,默认最大 5MB。
超过上限后会:
- 停止追加更多数据。
- 标记截断状态。
- 向 WebSocket 广播截断提示。
- 保留已有内容,避免无限增长导致内存泄漏。
命令完成后,结果会移入已完成缓存,供延迟连接的 WebSocket 客户端回放。
已完成缓存 TTL 为 30 秒,到期后清理。
章节来源
僵尸进程处理
终止命令时,服务端会尽力递归终止整个进程树:
- Unix/macOS:优先向进程组发送 SIGTERM;失败则回退到单进程;5 秒后强制 SIGKILL。
- Windows:使用
taskkill /T /PID;失败后使用/F /T /PID。
此外,process-tree.js 提供通用进程树终止工具,用于 npm 更新等场景,防止孙进程成为孤儿。
章节来源
超时控制
超时控制有两种语义:
- 旧语义:未传入
timeoutMs时,使用配置中的commandTimeout;到期直接终止。 - 受管模式:传入
timeoutMs后,超时到期先由策略函数裁决:- 如果本预算期内有 stdout/stderr 输出,则延长超时。
- 如果完全无输出,视为挂起或静默失败,直接终止。
- 延长次数最多 5 次。
- 总预算封顶为 600000 毫秒。
同步模式下,额外增加 5 秒兜底,确保即使内层策略失效也能返回结果。
章节来源
curl 示例
以下示例假设 Agent 监听在 http://127.0.0.1:18910,并已获取有效 Bearer Token。
同步命令执行
bash
curl -X POST http://127.0.0.1:18910/api/exec \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"command": "echo hello",
"wait": true,
"timeoutMs": 30000
}'异步命令执行
bash
curl -X POST http://127.0.0.1:18910/api/exec \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"command": "sleep 10 && echo done",
"timeoutMs": 60000
}'需要确认的命令
如果命令命中灰名单,首次调用会返回 level: confirm。确认后再次调用:
bash
curl -X POST http://127.0.0.1:18910/api/exec \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"command": "ls -la",
"force": true
}'终止命令
bash
curl -X POST http://127.0.0.1:18910/api/exec/stop \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"execId": "YOUR_EXEC_ID"
}'显式 daemon 化
bash
curl -X POST http://127.0.0.1:18910/api/exec/detach \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"execId": "YOUR_EXEC_ID"
}'查看运行进程
bash
curl -X GET http://127.0.0.1:18910/api/status/detail \
-H "Authorization: Bearer YOUR_TOKEN"章节来源
WebSocket 客户端实现要点
WebSocket 客户端不应只把连接当作一次性通道,而应按命令生命周期管理:
- 从
/api/exec异步响应中取出wsUrl。 - 建立 WebSocket 连接。
- 将收到的每条消息解析为 JSON。
- 根据
type分发:stdout:追加显示标准输出。stderr:追加显示标准错误。stdout_truncated/stderr_truncated:提示输出被截断。exit:记录退出码、是否被杀、是否超时,并关闭连接。error:记录子进程错误。
- 如果连接断开且未收到
exit,应指数退避重试连接。 - 重试成功后,若命令已结束,服务端会回放历史输出和 exit。
- 如果命令仍在运行,新连接会继续接收后续输出。
- 如果需要终止命令,调用
/api/exec/stop,而不是仅关闭 WebSocket。 - 如果需要后台运行,调用
/api/exec/detach。
sequenceDiagram
participant Caller as "调用方"
participant Http as "HTTP 服务器"
participant Exec as "命令执行器"
participant Ws as "WebSocket 服务器"
participant Proc as "子进程"
Caller->>Http : POST /api/exec
Http->>Exec : executeCommand(command, cwd, timeoutMs)
Exec->>Proc : spawn shell + command
Exec-->>Http : { execId, wsUrl }
Http-->>Caller : 异步启动响应
Caller->>Ws : 连接 wsUrl
Ws->>Exec : addWsClient(execId)
Proc-->>Ws : stdout/stderr 流
Ws-->>Caller : stdout/stderr 消息
Proc-->>Ws : close/error
Ws-->>Caller : exit/error 消息
图表来源
章节来源
性能调优建议
合理设置超时
- 短命令建议使用较小的
timeoutMs,避免长时间占用资源。 - 长任务建议使用受管模式,让策略函数根据输出动态延长超时。
- 对于不需要实时输出的后台任务,可在适当时机调用
/api/exec/detach。
控制输出大小
- 大输出命令会产生大量 WebSocket 消息,建议分页消费或限制 UI 渲染长度。
- 注意 5MB 输出缓冲上限;超过后会触发截断提示。
- 同步模式会收集完整 stdout/stderr,不适合超大输出。
避免频繁刷新运行状态
- 运行进程列表来自内存映射,读取成本低,但仍应避免高频轮询
/api/status/detail。 - 更推荐基于 WebSocket 的增量更新,只在必要时查询完整状态。
控制并发命令数量
- 每个命令都会创建子进程和至少两个流句柄。
- 大量并发命令会增加 CPU、内存和文件描述符压力。
- 建议在调用方侧做队列或限流。
避免重复连接
- 多个 WebSocket 客户端可以监听同一个
execId。 - 如果只需要一个消费者,应避免重复连接造成重复渲染。
章节来源
- agent/src/executor.js#L96-L114
- agent/src/executor.js#L165-L186
- agent/src/executor.js#L277-L383
- agent/src/server.js#L725-L749
常见错误与调试技巧
缺少命令
现象:返回 400,提示缺少命令。
原因:未传 command 或类型不是字符串。
处理:确保请求体包含合法命令字符串。
章节来源
工作目录不在允许范围
现象:返回 403,提示工作目录检查失败。
原因:cwd 不在工作目录或 allowedPaths 白名单内,或命中核心敏感路径。
处理:使用配置中的工作目录,或将目标目录加入白名单。
章节来源
命令被黑名单拒绝
现象:返回 403,level: deny。
原因:命令命中黑名单,如删除系统目录、格式化磁盘、覆盖敏感文件等。
处理:更换命令;黑名单不可通过 force 绕过。
章节来源
命令需要确认
现象:返回 level: confirm。
原因:命令命中灰名单,例如 sudo、npm 全局安装、kill、curl、chmod 等。
处理:在前端展示确认提示;确认后再次调用并设置 force: true。
章节来源
命令执行失败
现象:返回 500,提示命令执行失败。
原因:子进程启动失败、命令语法错误、权限不足等。
处理:查看 WebSocket 的 error 消息或同步模式的 error 字段;检查命令是否在目标系统可用。
章节来源
输出被截断
现象:收到 stdout_truncated 或 stderr_truncated。
原因:输出超过 5MB 缓冲上限。
处理:后端过滤无用输出;前端提示用户输出已被截断;避免把超大命令输出直接渲染到 DOM。
章节来源
WebSocket 断开后无 exit
现象:连接断开,但没有收到 exit。
原因:网络闪断、浏览器扩展 Service Worker 被回收、客户端崩溃等。
处理:延迟重连;若命令已结束,服务端会回放历史输出;若命令仍在运行,新连接继续接收输出。
章节来源
命令未被终止
现象:调用 /api/exec/stop 后进程仍存在。
原因:命令已结束、进程组不存在、Windows 下 taskkill 失败等。
处理:检查 success 字段;查看系统进程管理器;必要时结合系统级排查。
章节来源
结论
命令执行 API 以 /api/exec 为核心入口,通过 wait 字段区分同步与异步模式,并通过 WebSocket 提供实时输出。安全机制由路径白名单、核心敏感路径硬阻止、命令黑名单/灰名单共同构成;超时控制支持旧语义和受管模式;进程终止支持跨平台递归终止。
使用建议:
- 短命令优先使用同步模式。
- 长命令优先使用异步模式 + WebSocket。
- 高风险命令使用前展示用户确认。
- 后台任务使用
/api/exec/detach。 - 需要终止时使用
/api/exec/stop。 - 通过
/api/status/detail查看运行进程和资源使用情况。 - 客户端实现健壮的重连、消息回放和生命周期管理逻辑。