Strayd 是一个通过 npm 分发的跨平台 Rust TUI/CLI,用来发现、关联和停止散落在本机上的开发服务与临时公网隧道。
开发服务器和临时隧道经常由不同终端、IDE 或后台任务启动。端口还在监听,但原始终端早已找不到;看到一个进程时,又无法判断它是否正在承载别的服务。
Strayd 会:
- 识别 Next.js、Vite、Nuxt、Astro、SvelteKit、Remix、Angular、Storybook、Webpack、Rspack、Parcel、Node.js、Bun 和 Deno 服务。
- 识别 Cloudflare Quick Tunnel、ngrok、SSH 反向转发、frp、localtunnel 和 bore。
- 解析隧道的本地目标,把隧道与对应端口的源服务放进同一组。
- 支持只停开发服务、只停隧道,或按依赖顺序停止整个关联组。
- 展示并保护
sshd,避免误关远程入口。 - 在详情区按 1 秒采样展示每个进程的 CPU 与驻留内存。
- 根据当前系统自动使用 Windows、Linux/WSL 或 macOS 的原生探测与终止方式。
- 内置简体中文与英文界面,按系统语言自动选择,并在中性 locale 下使用时区兜底。
要求 Node.js 18 或更高版本;不需要安装 Rust。
npm install --global strayd
strayd也可以不安装直接体验:
npx strayd支持以下原生组合:
- Linux x64 / arm64,包括 WSL
- Windows x64 / arm64
- macOS Intel / Apple Silicon
启动后左侧是资源组,右侧展示端口、进程、创建时间、运行时长、资源占用、工作目录以及隧道到源服务的关联链路。创建时间按本机时区显示并标明 UTC 偏移;运行时长显示为 HH:MM:SS,超过一天时附带天数,界面重绘时自动更新。读取不到时间时显示“未知”。strayd list 同样展示时间,JSON 输出中的 startedAt 为 Unix 秒(不可用时为 null)。所有停止操作都需要再次确认。
本进程用量按 CPU … · 驻留内存 … 显示,每 1 秒单独采样,不等待整轮扫描(--refresh)。CPU 以占满一个逻辑核计为 100%,多线程进程可以超过 100%,读数是采样窗口内的均值;驻留内存包含共享页,各进程的数值不能相加,也不代表停掉它能回收多少,详情面板顶部会随用量一起显示这条口径说明。CPU 需要一个差分基线,所以刚发现的进程先显示“采样中”,一秒后起才有数值;这不是读失败。strayd list 的文本输出不变,JSON 新增 cpuPermille(CPU 百分比的 10 倍,124 即 12.4%)和 memoryBytes(字节);单次 list 只采样一次,因此 cpuPermille 为 null。
展示名按以下来源选择,列表、详情、关联链路与 CLI 使用同一结果:
- macOS
.app中的主程序或辅助进程使用外层应用名,例如“测试播放器”“Strayd Test Desk”。 - 开发框架使用项目目录名;Node、Python、Java、.NET 等解释器优先识别明确的脚本、模块、JAR 或包名,通用的
server/index入口回退到项目目录。macOS 上解释器自带的.app包装不会覆盖脚本或模块名称。 - 普通二进制、系统服务和隧道使用可执行文件名,避免启动目录覆盖
fixture-agent、nginx或cloudflared的名称。 - 推导项目目录时跳过
bin、构建输出、虚拟环境等通用目录;用户主目录、系统根目录及共享根目录不作为项目名。无法确定时回退到可执行文件名、系统进程名或 PID。
命名使用系统提供的结构化参数,不按空格拆分命令;未知的解释器选项不会把后续参数猜成脚本名。JSON 的 displayName 是展示名,processName 保留系统原始进程名,右侧也单独列出进程名。扫描覆盖所有 TCP 监听进程,因此有监听端口的桌面应用也会出现在“全部”分类中。Linux 上资源按进程而不是线程列出,多线程程序不会因为线程而重复出现条目或隧道数量。
| 操作 | 键盘 | 鼠标 |
|---|---|---|
| 切换分类 | ←/→、Tab、Shift+Tab、1-4 |
点击顶部完整分类区域 |
| 选择资源组 | ↑/↓、j/k、Home/End |
点击资源行或滚轮 |
| 滚动右侧详情 | PageUp / PageDown |
在详情区滚轮 |
| 保护 / 解除保护 | p |
点击 PROTECT / 保护;已保护时点击 UNPROTECT / 解除保护 |
| 创建隐藏规则 | h |
点击 HIDE / 隐藏 |
| 勾选规则字段 | Space |
点击字段行 |
| 打开 Settings | , |
点击 SETTINGS / 设置 |
| 选择 / 移除规则 | ↑/↓,u / Delete |
点击规则,再点击 REMOVE RULE / 移除规则 |
| 停止当前范围 | s |
点击随分类变化的 STOP… / 停止… |
| 复制命令 | — | 点击命令下方的 COPY COMMAND / 复制命令 色块 |
| 选择右侧文字 | c,再次按 c / Esc 返回 |
点击 SELECT TEXT / 选择文字 后直接拖选 |
| 刷新 / 退出 | r / q |
点击 REFRESH / QUIT |
| 确认 / 取消 | Enter / Esc |
点击确认框按钮 |
TUI 只保留一个停止入口,作用范围由当前分类明确决定:全部 停止整个关联组,开发服务器 只停止开发服务,公网隧道 只停止隧道,系统服务 只停止可终止的系统服务。确认框会再次显示实际类型和进程数量。CLI 仍保留 dev、tunnel、system、group、resource 等精细目标。
进入“选择文字”后,Strayd 会暂时释放终端鼠标并暂停界面重绘,此时右侧详情可以像普通终端输出一样直接拖选复制;按 c 或 Esc 恢复点击操作。
命令会在右侧详情区按终端宽度完整换行,不会用省略号截断。点击命令下方的纯色复制按钮,会通过 OSC 52 把原始完整命令写入终端剪贴板;该功能需要当前终端支持并允许 OSC 52。
Strayd 可以直接在 TUI 中维护保护和隐藏规则:按 p 创建保护规则,匹配的进程标记为 PROTECTED,不能通过 Strayd 单独或整组停止。保护与隐藏相互独立,受保护进程也可以隐藏,隐藏不会解除保护。选中手动保护的资源后再次按 p 或点击“解除保护”,会弹出二次确认;按 Enter 或点击确认,一次移除所有匹配的手动保护规则,按 Esc 取消。移除规则也会影响这些规则匹配的其他资源,内置的系统进程保护仍生效。规则会跨刷新和重启保留,适合防止误停的常驻服务、数据库或隧道;只约束 Strayd,不阻止进程自行退出或被其他工具终止。
创建隐藏规则:选中一个资源后按 h,勾选作为匹配条件的字段并保存;默认选择“端口 + 运行时”。按 , 或点击底部 Settings / 设置 打开弹窗,即可查看并移除自己添加的规则。修改会立即写入配置文件并刷新界面。
保护规则使用 [[protect]],支持与 [[display.hide]] 相同的匹配字段,例如:
[[protect]]
ports = [3000]
runtimes = ["next-js"]也可以直接维护 TOML。先生成带注释的模板:
strayd config init
strayd config path
strayd config show配置位置遵循系统约定:
- Linux/WSL:
$XDG_CONFIG_HOME/strayd/config.toml,默认是~/.config/strayd/config.toml - macOS:
~/Library/Application Support/strayd/config.toml - Windows:
%APPDATA%\strayd\config.toml
例如,只隐藏监听 22 端口的 sshd,但不会隐藏同组中代理该端口的隧道:
version = 1
language = "auto"
[[display.hide]]
ports = [22]
runtimes = ["sshd"]每条 [[display.hide]] 都是一条独立规则。规则之间是 OR;同一规则中填写的字段是 AND;同一数组内任意值匹配即可。空规则不会隐藏任何内容。
| 字段 | 匹配方式 |
|---|---|
ports |
监听端口或隧道本地目标端口 |
runtimes |
运行时名称,如 sshd、vite、cloudflared |
kinds |
dev、tunnel、system、other |
platforms |
windows、linux、macos |
process_names |
进程名,忽略大小写的包含匹配 |
projects |
项目名或工作目录,忽略大小写的包含匹配 |
commands |
完整命令行,忽略大小写的包含匹配 |
ids |
Strayd 资源 ID,忽略大小写的精确匹配 |
规则同时作用于 TUI、list 和 stop。临时绕过配置可使用 --no-config;此时 Settings 弹窗为只读。指定其他文件可使用 --config <PATH>:
strayd --no-config
strayd --config ./team-strayd.toml listlanguage = "auto" 会优先读取系统 locale;C、POSIX 等中性 locale 再通过系统时区判断,仍无法判断时使用英文。配置和命令行都可以显式固定语言:
language = "zh-cn" # 或 "en"strayd --language zh-cn
strayd --language en
strayd --language auto优先级为 --language > 配置文件 > 系统语言/时区。JSON 字段、命令名、筛选参数和运行时标识保持不变,便于脚本稳定使用。
无子命令时默认进入 TUI。脚本和自动化场景可以使用:
strayd list
strayd --language en list
strayd list --kind tunnel --json
strayd list --platform linux --port 5000
strayd stop tunnel --port 5000 --dry-run
strayd stop tunnel --port 5000 --yes
strayd stop system --port 8080 --yes
strayd stop group --port 5000 --yes
strayd stop dev --project storefront --all --yeslist 与 stop 支持 --id、--port/-p、--project、--platform windows|linux|macos 和 --runtime。停止命令匹配多项时必须显式传入 --all;实际关闭前需要交互确认或传入 --yes,--dry-run 只打印计划。
- Linux/WSL:读取 Linux 端口和进程;systemd 托管服务会尝试停止对应 unit。
- Windows:读取 Windows 原生端口和进程,并通过
taskkill /T /F结束进程树。 - macOS:读取 macOS 原生端口和进程,先发送
TERM,必要时再发送KILL。 - 每次停止前都会复核 PID 与进程启动标识,避免 PID 被复用后误杀新进程。
- 包含受保护资源的组拒绝整组停止;
sshd始终不可由 Strayd 终止。 - 部分系统进程的端口或命令行受操作系统权限限制。Strayd 只展示当前用户可读取的信息,不主动提权。
bun install
bun install --frozen-lockfile
bun run test
bun run check
bun run pack:clibun run pack:cli 只装箱当前宿主的二进制。完整 npm 包由 build-npm.yml 在六种原生 runner 上分别构建、测试并统一装箱。
正式版本在六平台安装验收通过后通过 GitHub OIDC 发布到 npm,无需保存长期发布 token。版本标签、权限配置和手动备用方式见发布说明。
真实进程、PTY、容器、安装包、故障清理和 CI 的运行方式见测试环境。快速运行:bun scripts/test-env.ts run --suite native,tui,runtime-smoke,faults,replay;原生 macOS/Windows 与可选系统专项的验证边界在文档中单列。