# 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 ""` 执行时,首行 `#!/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。*