6.2 KiB
6.2 KiB
Deepcheck:启动端口与统一 Bash 实现
1. 实现范围
- shared/startupPorts.ts:端口默认值、配置键、
resolvePortsFromSettings(getSetting)、getPortsToCheck(ports, includeVite) - main/services/startupPorts.ts:
getConfiguredPorts()、getPortList()、checkPortsInUse()、isPortInUse()(bash 优先,Windows 回退 cmd+netstat) - scripts/tools/check-port.sh:单端口占用检查(netstat/lsof),供 bash 执行
- scripts/tools/check-startup-ports.js:CLI,读 DB、解析端口、调用 bash+check-port.sh 或回退 Node 内联
2. 正确性
2.1 三处脚本逻辑一致性
| 位置 | 来源 | 端口参数 | Windows 分支 | Unix 分支 | 输出/exit |
|---|---|---|---|---|---|
| check-port.sh | 文件 | $1 |
cmd //c "netstat -ano | findstr ":${port} "" | lsof -t -i ":${port}" | 占用: exit 0 + echo PID;未占用: exit 1 |
| main CHECK_PORT_SCRIPT | 内嵌字符串 | $1 |
同上(\":$1 \" 在 JS 中产生 ":$1 ") | lsof -t -i ":$1" | 同左 |
| 脚本 | 读 check-port.sh | spawnSync(..., '_', port) | 由 .sh 决定 | 由 .sh 决定 | 同左 |
- 结论:.sh 与内嵌脚本语义一致;端口均通过
$1传入,无注入(端口为数字的 String(port))。 - 已修复:CLI 原先用
execSync(bashPath, [args], options),Node 的execSync仅支持(command, options),第二个参数被当成 options,导致 bash 未按参数执行。已改为spawnSync(bashPath, ['-c', scriptContent, '_', String(port)], options)。
2.2 配置解析(shared + 脚本)
- step1_config:
step1?.agentPort ?? default、step1?.fileServerPort ?? default。若 DB 存的是{}或缺失,则用默认值;若agentPort: 0,会得到 0(端口 0 在部分系统上表示“任选”,可能不符合预期,见 4.1)。 - mcp_proxy_port:兼容 number 与 string;
parseInt失败或非整数时用默认值。 - 脚本 DEFAULTS:与 shared/constants 数值一致,需人工与 shared 同步(见 4.2)。
2.3 端口占用结果
- spawnSync:
status === 0表示脚本 exit 0(端口占用);stdout 取首行/最后一列解析 PID;空 stdout 时inUse: true, pid: undefined,行为合理。 - 回退路径(Windows 无 bash / 脚本无 .sh):main 用
execSync+ cmd;脚本用execSync+ shell: true(或 lsof),行为与之前一致。
3. 平台与环境
3.1 Windows
- 有 prepare-git:
getBundledGitBashPath()返回resources/git/bin/bash.exe(或 usr/bin),main 与 CLI 均用该 bash 执行脚本;脚本内OSTYPE=msys*,走 cmd+netstat+findstr,一致。 - 无 prepare-git:main 回退 cmd+netstat;脚本
winBashPath不存在则回退 Node netstat,逻辑一致。 - 路径:DB 路径
%USERPROFILE%\.qimingclaw\;脚本中 sqlite3 路径用正斜杠归一化,避免反斜杠转义问题。
3.2 macOS / Linux
- main 与脚本均用系统
bash;脚本来自文件或内嵌,均包含$OSTYPE判断,非 msys/cygwin 走 lsof。 - 无 bash(如 Alpine 仅 ash):
spawnSync('bash', ...)会失败,当前实现将status !== 0视为未占用并返回inUse: false,属保守回退,可接受;若需严格“未知”可再区分 error/status。
3.3 check-port.sh 被读入后的执行
- 通过
bash -c "<scriptContent>"执行时,首行#!/usr/bin/env bash被当作注释(#起头),不影响执行,无需 strip。
4. 边界与改进建议
4.1 端口合法性
- 当前未校验端口范围(1–65535)及 0。若配置了
agentPort: 0或错误大数,会直接传给startComputerServer/lsof/netstat。 - 建议:在
resolvePortsFromSettings或调用方对端口做范围校验,非法时回退默认或报错。
4.2 脚本与 shared 同步
- check-startup-ports.js 的 DEFAULTS/LABELS 与 shared/constants、shared/startupPorts 需人工同步;脚本无法 require 编译后的 shared。
- 建议:在脚本顶部注释中写明“与 shared/startupPorts.ts、constants 保持一致”;或考虑 build 时生成一份 ports-defaults.json 供脚本读取(可选)。
4.3 错误与超时
spawnSync未设 timeout;若 bash 或子命令卡住会阻塞。- 建议:若需在 UI 或敏感路径调用,可加
timeout选项或异步封装。
4.4 安全性
- 端口来自配置或常量,
String(port)后传入 spawn,无用户自由输入,无命令注入风险;脚本内$1仅用于端口,且由调用方控制。 - sqlite3 的 key 做单引号转义,key 来自内部常量,风险可控。
5. 调用链与依赖
- startup.ts:
getConfiguredPorts().agent→ ComputerServer 端口。 - serviceManager.ts:
getConfiguredPorts().fileServer→ File Server 端口。 - processHandlers.ts:动态 import
getConfiguredPorts,取fileServer→ 重启时的 File Server 端口。 - dependencies.ts:导出
getBundledGitBashPath(),供 main startupPorts 使用;prepare-git 仅 Windows 下载并解压 Git 到resources/git/。
6. 测试建议
- 单元:
resolvePortsFromSettings用 mock getSetting 测默认值、step1 部分键、mcp 为 number/string/非法。 - 集成:在 macOS 上运行
npm run check-ports与npm run check-ports:dev,确认有 bash + check-port.sh 时输出与 exit code 正确;关闭应用后再次检查,确认“未占用”与 exit 0。 - Windows:在装有 prepare-git 与未装两种情况下各跑一次 CLI,确认有 bash 时走脚本、无时走 netstat 回退。
7. 小结
| 项 | 状态 |
|---|---|
| 三处脚本逻辑一致(.sh / 内嵌 / CLI 调用方式) | ✅ 一致 |
| CLI 使用 spawnSync 传参(原 execSync 误用已修复) | ✅ 已修复 |
| 配置解析与默认值 | ✅ 合理,0 与范围未校验见 4.1 |
| Windows 有/无 bash 回退 | ✅ 正确 |
| Unix 使用 bash,无 bash 时保守回退 | ✅ 可接受 |
| 安全与注入 | ✅ 端口与 key 受控 |
| 改进点 | 端口范围校验、DEFAULTS 同步方式、可选 timeout |
Deepcheck 完成;CLI 中 execSync 误用已改为 spawnSync。