Skip to content

进程管理 ​

本文引用的源码文件

本文引用的文件

目录 ​

  1. 引言
  2. 项目结构
  3. 核心组件
  4. 架构总览
  5. 详细组件分析
  6. 依赖关系分析
  7. 性能与资源特性
  8. 故障排查指南
  9. 结论
  10. 附录:API 与使用建议

引言 ​

本文聚焦 Agent 端的进程管理能力,围绕命令执行、Shell 选择、环境变量白名单、运行监控、优雅与强制终止、进程树清理、生命周期与资源回收等主题展开。Agent 采用双进程架构:Chrome 扩展端通过本地 HTTP/WebSocket 调用 Agent;Agent 内部通过 Node.js child_process 派生子进程执行命令,并提供 WebSocket 流式输出、超时策略、安全分级与跨平台兼容处理。

项目结构 ​

与进程管理直接相关的代码主要分布在以下模块:

  • agent/src/executor.js:命令执行器,负责 Shell 选择、子进程创建、输出缓冲、WebSocket 流式广播、超时策略、进程停止与查询。
  • agent/src/process-tree.js:进程树终止工具,提供整树 SIGTERM/SIGKILL 能力与优雅等待。
  • agent/src/security.js:安全管控(路径沙箱与命令分级),对危险命令进行黑名单/灰名单拦截。
  • agent/bin/agent.js:CLI 入口,负责 Agent 进程启停、健康检查、PID 管理与跨平台终止。
  • agent/src/server.js:HTTP + WebSocket 服务,聚合 executor、security、process-tree 等能力对外暴露 API。
graph TB
subgraph "扩展端"
BG["background/tool-executor.js<br/>扩展侧工具执行"]
end
subgraph "Agent 进程"
CLI["agent/bin/agent.js<br/>CLI 启动/停止/重启"]
SRV["agent/src/server.js<br/>HTTP + WebSocket 路由"]
EXEC["agent/src/executor.js<br/>命令执行器"]
PTREE["agent/src/process-tree.js<br/>进程树终止"]
SEC["agent/src/security.js<br/>路径沙箱 + 命令分级"]
end
OS["操作系统 / Shell<br/>Git Bash / PowerShell / cmd / zsh / bash"]
BG --> |HTTP/WebSocket| SRV
CLI --> |spawn/kill| SRV
SRV --> EXEC
SRV --> SEC
SRV --> PTREE
EXEC --> OS

图表来源

章节来源

核心组件 ​

  • 命令执行器(executor.js):实现 Shell 选择、安全环境变量构建、子进程创建、输出流式广播、超时策略、进程停止与运行状态查询。
  • 进程树工具(process-tree.js):封装跨平台整树终止逻辑,支持 SIGTERM → 延迟 → SIGKILL 的优雅关闭流程。
  • 安全管控(security.js):路径白名单/硬阻止与命令分级(黑名单 deny、灰名单 confirm、允许 allow)。
  • CLI 入口(agent/bin/agent.js):负责 Agent 进程守护、健康检查、PID 文件、优雅/强制终止与跨平台兼容。
  • 服务端(server.js):聚合上述能力,对外暴露 HTTP/WebSocket 接口,并设置语言上下文。

章节来源

架构总览 ​

下图展示一次命令执行的端到端流程:扩展端发起请求,Agent 服务端校验安全策略后调度执行器,执行器选择 Shell、构建环境、派生子进程,并通过 WebSocket 流式推送 stdout/stderr,同时维护超时与终止策略。

sequenceDiagram
participant Ext as "扩展端"
participant Srv as "Agent 服务端(server.js)"
participant Sec as "安全管控(security.js)"
participant Exec as "命令执行器(executor.js)"
participant PT as "进程树(process-tree.js)"
participant OS as "系统 Shell"
Ext->>Srv : "POST /api/exec(command, cwd, timeoutMs?)"
Srv->>Sec : "checkCommand(command, force)"
Sec-->>Srv : "{safe, level, reason}"
alt 允许或用户已确认
Srv->>Exec : "executeCommand(command, cwd, wsClient, opts)"
Exec->>Exec : "pickShell() + buildSafeEnv()"
Exec->>OS : "spawn(shell, args, {env, detached, windowsHide})"
OS-->>Exec : "stdout/stderr 事件"
Exec-->>Srv : "WS 广播 stdout/stderr/exit/error"
Note over Exec,PT : "超时到期或显式 kill → 优雅→强制终止"
else 拒绝或需确认
Srv-->>Ext : "错误/确认提示"
end

图表来源

详细组件分析 ​

Shell 选择与环境变量白名单 ​

  • Shell 选择逻辑(纯函数 pickShell):
    • Windows:优先检测 SHELL 是否为 Git Bash/Powershell/cmd 且存在;否则回退到常见 Git Bash 安装路径;若仍不可用则回退 COMSPEC 或 cmd.exe。
    • macOS:优先 SHELL 中的 zsh/bash,否则默认 /bin/zsh。
    • Linux:优先 SHELL 中的 bash/zsh/fish,否则探测 /bin/bash、/usr/bin/bash、/bin/sh,最终兜底 /bin/sh。
  • 环境变量白名单(SAFE_ENV_KEYS):仅透传 PATH、HOME、USER、SHELL、LANG、COMSPEC、PSModulePath、JAVA_HOME、PYTHONPATH 等必要键,避免泄露宿主敏感信息;强制 TERM=dumb、FORCE_COLOR=0。
flowchart TD
Start(["进入 pickShell"]) --> CheckWin{"平台为 Windows?"}
CheckWin --> |是| WinCheck["检查 SHELL 是否包含 bash/powershell/cmd 且存在"]
WinCheck --> |命中| UseShell["返回 shell + 对应参数"]
WinCheck --> |未命中| TryGitBash["尝试常见 Git Bash 路径"]
TryGitBash --> FoundGB{"找到 Git Bash?"}
FoundGB --> |是| UseShell
FoundGB --> |否| UseCmd["回退 COMSPEC 或 cmd.exe"]
CheckWin --> |否| CheckMac{"平台为 macOS?"}
CheckMac --> |是| MacCheck["检查 SHELL 是否包含 zsh/bash 且存在"]
MacCheck --> |命中| UseShell
MacCheck --> |未命中| DefaultZsh["默认 /bin/zsh"]
CheckMac --> |否| LinCheck["检查 SHELL 是否包含 bash/zsh/fish 且存在"]
LinCheck --> |命中| UseShell
LinCheck --> |未命中| ProbeSh["探测 /bin/bash -> /usr/bin/bash -> /bin/sh"]
ProbeSh --> FoundSh{"找到任一?"}
FoundSh --> |是| UseShell
FoundSh --> |否| Fallback["兜底 /bin/sh"]

图表来源

章节来源

进程创建与运行监控 ​

  • 子进程创建:
    • 使用 spawn(shell, [...args, command]),根据平台与 shell 类型决定是否 detached 与 windowsHide。
    • 标准输出/错误以 pipe 方式读取,按 execId 广播给所有 WebSocket 客户端。
  • 运行状态跟踪:
    • runningProcesses 映射记录 execId → {process, wsClients, stdoutBuf, stderrBuf, startTime, baseTimeout, managed, extensions, outputInPeriod, detached, timedOut}。
    • completedProcesses 缓存已完成进程的输出与退出码,供延迟连接的 WS 客户端回放。
  • 资源使用与异常检测:
    • 输出缓冲区上限 MAX_OUTPUT_BUFFER = 5MB,超过时截断并广播 truncated 消息。
    • 超时策略:受管模式(传入 timeoutMs)下依据 decideTimeoutAction 决策延长或终止;旧模式直接终止。
    • 进程 close/error 事件统一清理定时器、移出 runningProcesses、写入 completedProcesses 并回调 onComplete。
flowchart TD
A["executeCommand 开始"] --> B["生成 execId"]
B --> C["pickShell + buildSafeEnv"]
C --> D["spawn(shell, args, env, stdio, detached/windowsHide)"]
D --> E["注册 stdout/stderr 监听"]
E --> F["广播 stdout/stderr 片段"]
F --> G{"收到输出?"}
G --> |是| H["标记 outputInPeriod=true"]
G --> |否| I["保持静默"]
H --> J["armTimeout(timeout)"]
I --> J
J --> K{"超时到达?"}
K --> |是| L["decideTimeoutAction 决策"]
L --> |extend| M["延长定时器"]
L --> |kill| N["killProcess(execId)"]
K --> |否| O["继续运行"]
O --> P["close/error 事件"]
P --> Q["清理定时器/移出 runningProcesses/写入 completedProcesses"]
Q --> R["onComplete 回调"]

图表来源

章节来源

进程终止策略与跨平台兼容 ​

  • 优雅关闭(SIGTERM):
    • POSIX:优先向进程组发送 SIGTERM(-pid),失败时回退单进程 kill。
    • Windows:taskkill /T /PID 递归终止整个进程树。
  • 强制终止(SIGKILL):
    • POSIX:5 秒后向进程组发送 SIGKILL,再失败回退单进程。
    • Windows:taskkill /F /T /PID 强制终止整棵树。
  • 进程树清理:
    • process-tree.js 提供 killProcessTree 与 stopProcessTree,后者在 graceMs 后升级 SIGKILL,并保证 close/error 不永久挂起。
  • CLI 层终止:
    • agent/bin/agent.js 的 killByPid 在 Windows 使用 taskkill /F /T,POSIX 使用 process.kill(pid, 'SIGTERM')。
flowchart TD
S["stopProcessTree(child, graceMs)"] --> T{"child.pid 有效?"}
T --> |否| End["立即 resolve"]
T --> |是| U["注册 close/error 完成回调"]
U --> V["killProcessTree(SIGTERM)"]
V --> W["graceMs 后 killProcessTree(SIGKILL)"]
W --> X["hardTimer(graceMs+5s) 兜底完成"]
X --> End

图表来源

章节来源

安全管控与命令分级 ​

  • 路径沙箱:
    • 硬阻止目录(HARD_BLOCKED_PATHS):Agent 配置、日志、回收站等关键路径不可访问。
    • 工作目录放行:workdir 始终可访问,但 realpath 仍需过硬阻止检查。
    • allowedPaths 前缀匹配 + realpath 校验,防止符号链接绕过。
  • 命令分级:
    • 黑名单(deny):高危破坏性命令绝对禁止,force 不可绕过。
    • 灰名单(confirm):sudo、rm -rf、chmod 777、网络外联、脚本解释器等需用户确认。
    • 白名单(allow):普通只读或低风险命令。
    • 链式命令拆分、包装器剥壳、内联载荷解析、命令替换扫描,确保复杂命令不被绕过。
flowchart TD
A["checkCommand(command, force)"] --> B["collectCommandScopes(原始串 + 拆分段 + 内联载荷)"]
B --> C{"命中黑名单?"}
C --> |是| Deny["level='deny'"]
C --> |否| D{"force=true?"}
D --> |是| Allow["level='allow'"]
D --> |否| E{"命中灰名单?"}
E --> |是| Confirm["level='confirm'"]
E --> |否| Allow

图表来源

章节来源

进程生命周期管理 ​

  • 进程池管理:
    • runningProcesses 作为“运行中进程表”,completedProcesses 作为“已完成缓存”(TTL 30s)。
    • addWsClient/disconnectWsClient 支持动态加入/移除 WS 监听;断开连接时仅在非受管模式或显式 detach 才取消超时。
  • 资源回收:
    • clearTimers 清理超时与强制终止定时器。
    • completedProcesses 条目在 TTL 后自动清理。
  • 僵尸进程清理:
    • process-tree.js 的 stopProcessTree 保证 close/error 事件触发后不再等待,避免孤儿进程长期残留。
  • 内存泄漏防护:
    • 输出缓冲区上限截断 + trunc 标志广播。
    • 受管模式下超时策略基于 decideTimeoutAction,避免无限延长。
classDiagram
class Executor {
+executeCommand(command, cwd, wsClient, onComplete, collectOutput, execOpts) string
+executeCommandSync(command, cwd, timeoutMs) Promise
+addWsClient(execId, wsClient) boolean
+disconnectWsClient(execId, wsClient) boolean
+killProcess(execId) boolean
+detachProcess(execId) boolean
+getRunningProcesses() array
}
class ProcessTree {
+killProcessTree(child, signal) boolean
+stopProcessTree(child, options) Promise
}
class Security {
+checkCommand(command, force, tFn) object
+checkPath(pathStr, tFn) object
}
Executor --> ProcessTree : "终止策略"
Executor --> Security : "命令安全校验"

图表来源

章节来源

依赖关系分析 ​

  • server.js 依赖 executor、security、process-tree,对外暴露 HTTP/WebSocket 接口。
  • executor 依赖 os、fs、crypto,内部使用 child_process.spawn 派生子进程。
  • process-tree 依赖 child_process.spawn 与 process.kill,封装跨平台终止逻辑。
  • security 依赖 path、fs/promises、os,实现路径与命令安全策略。
  • agent/bin/agent.js 依赖 child_process、fs、os,负责 CLI 与进程守护。
graph LR
Server["server.js"] --> Executor["executor.js"]
Server --> Security["security.js"]
Server --> ProcessTree["process-tree.js"]
Executor --> Child["child_process"]
ProcessTree --> Child
Security --> PathFS["path/fs/promises/os"]
CLI["agent/bin/agent.js"] --> Server
CLI --> Child

图表来源

章节来源

性能与资源特性 ​

  • 输出缓冲限制:MAX_OUTPUT_BUFFER = 5MB,避免长时间命令导致内存无限增长;超限时广播 truncated 消息。
  • 超时策略:
    • 受管模式(execOpts.timeoutMs):基于 decideTimeoutAction,期内有输出才延长,静默即杀;最大延长次数 MAX_TIMEOUT_EXTENSIONS = 5,总预算封顶 TOTAL_BUDGET_CAP_MS = 600000ms。
    • 旧模式:到期直接 kill。
  • 进程树终止:
    • POSIX 优先进程组信号,Windows 使用 taskkill /T /PID;5 秒后升级为 SIGKILL 或 /F /T /PID。
  • 资源回收:
    • completedProcesses 缓存 TTL 30s,避免长期驻留;disconnectWsClient 在非受管模式或 detach 时才释放超时。

章节来源

故障排查指南 ​

  • 命令被拒绝:
    • 检查 security.js 的黑名单/灰名单规则;必要时通过前端确认流程(force)放行灰名单。
  • 命令无输出或卡住:
    • 检查 decideTimeoutAction 是否因静默而 kill;确认 WS 客户端是否正确订阅 stdout/stderr。
  • 进程未完全退出:
    • 使用 process-tree.js 的 stopProcessTree 确保 SIGTERM → SIGKILL 升级;Windows 下确认 taskkill /T /PID 生效。
  • Shell 选择异常:
    • 在 Windows 上 SHELL 可能为 MSYS 风格路径(如 /usr/bin/bash),无法直接执行;pickShell 会回退到 Git Bash 或 cmd.exe。
  • 环境变量缺失导致工具失败:
    • 确认 SAFE_ENV_KEYS 是否包含所需键(如 JAVA_HOME、PYTHONPATH、PSModulePath 等)。

章节来源

结论 ​

Agent 的进程管理以 executor.js 为核心,结合 process-tree.js 的跨平台终止能力与 security.js 的安全分级,实现了从 Shell 选择、环境变量白名单、运行监控到优雅/强制终止的完整闭环。CLI 层(agent/bin/agent.js)与 server.js 提供了进程守护与健康检查,确保扩展端与 Agent 端的稳定通信。建议在复杂任务中优先使用受管模式(timeoutMs)并结合 WS 流式输出进行实时监控,同时在安全敏感场景严格遵循黑名单/灰名单策略。

附录:API 与使用建议 ​

  • 命令执行(Executor)
    • executeCommand(command, cwd?, wsClient?, onComplete?, collectOutput?, execOpts?)
    • executeCommandSync(command, cwd?, timeoutMs?)
    • addWsClient(execId, wsClient)
    • disconnectWsClient(execId, wsClient)
    • killProcess(execId)
    • detachProcess(execId)
    • getRunningProcesses()
  • 进程树终止(ProcessTree)
    • killProcessTree(child, signal?)
    • stopProcessTree(child, {graceMs?})
  • 安全策略(Security)
    • checkCommand(command, force?, tFn?)
    • checkPath(pathStr, tFn?)
  • 使用建议
    • 始终传入 execOpts.timeoutMs 启用受管模式,避免 SW 生命周期影响超时权威。
    • 对高风险命令提前走确认流程,减少误报摩擦。
    • 长耗时任务建议使用 WS 流式输出,并在断开连接时注意 detach 语义。

章节来源