# dsh-port-manager > dsh 原生侧边栏应用:**本机现在开着哪些端口、是谁占的、一句话把它处理掉。** [English](README.md) · **中文** 一个纯本地、零运行时依赖的 dsh web 插件。它把自己注册成**右侧栏的原生 page 类型 tab** (走 `ctx.sidebarRightTabs` + 带 key 的 `sidebar.right.pane.tab` 插槽,和官方「文件」页同一套机制), 数据由插件自己的宿主半用 `lsof` / `ps` 采集后经围栏 JSON 接口送到面板。 **关键词:** `dsh` · `deepseek-harness` · `plugin` · `sidebar` · `port` · `lsof` · `port-manager` **基本信息:** MIT · DSH `^0.1.5-rc.1` · Node `>= 20` · macOS · Linux · 无 `dependencies` ``` 打开右侧栏 → 点 guide 里的 “Port Manager” 胶囊 → 端口列表 ``` --- ## 功能 ### 1. 侧边栏入口 在右侧栏的 guide 页贡献一枚「Port Manager」胶囊(`order 15`,图标为插头),点开即在当前分栏 打开应用;tab 胶囊自带图标,可拖拽 / 分栏 / 浮动 / 全屏,全部由 dsh 原生机制负责。 ### 2. 端口全貌 + 占用它的应用 每个监听一条卡片,展示: | 字段 | 说明 | | --- | --- | | 端口 / 协议 | `:3080`、TCP(UDP 需手动开开关) | | 绑定范围 | **仅本机**(回环)/ **局域网**(指定网卡)/ **所有网卡**(对外暴露,橙色警示) | | 应用 | 友好名:`.app` 包名、`node · vite`、`python · http.server`、Docker 容器名…… 并标注类别(Node / Python / Docker / 应用 / 服务 / 进程) | | 进程 | PID、所属用户、已运行时长、CPU、内存 | | 工作目录 | 进程 cwd(一行路径,用「定位」按钮打开) | | 常见用途 | `:5173 Vite dev`、`:5432 PostgreSQL`、`:7000 macOS AirPlay 接收器` 这类提示 | | 容器 | 命中 `docker ps` 端口映射时显示容器名与镜像 | 顶部还有:`可见/总数 个端口 · N 个应用 · M 个对外 · 上次扫描时间`、搜索框(端口 / 应用 / 命令 / 目录 / 容器名)、筛选(全部 / 仅本机 / 对外暴露 / 可结束)、开关(UDP、系统项)、 排序(端口 / 应用 / CPU / 内存)、自动刷新(手动 / 3s / 10s / 30s,切回 tab 时也会自动刷新一次)。 ### 3. 每个端口下方的常用操作 | 操作 | 行为 | | --- | --- | | **打开** | 用系统默认浏览器打开 `http://localhost:`(TLS 端口走 https) | | **复制** | 菜单:`localhost:port` / `http://localhost:port` / `:port` / `lsof -i :port` / `kill ` / 工作目录 / 启动命令 | | **详情** | 展开进程详情:完整命令行(点击即复制)、cwd、父进程链、监听绑定明细、容器;内含 **HTTP 探测**(状态码、Server、X-Powered-By、Content-Type、页面标题、耗时) | | **定位** | 在访达(Linux 为文件管理器)里打开该进程的工作目录 | | **结束** | 二次确认后就地结束:先 `SIGTERM`,1.7 秒没退出自动升级 `SIGKILL`;也可直接「强制 -9」 | 右上角 `⋯` 可**立即刷新**,也能一键**复制端口清单(Markdown 表格)**或**端口 + 进程列表**,方便直接贴进对话里让模型排查。 --- ## 安装 ```bash cd /path/to/dsh-PortManager # 本插件目录 dsh plugin --profile web add "link:$PWD" ``` 该命令是 pnpm 的转发器,装完会把 `dsh-port-manager` 追加进 profile 的 `dsh.profile.bundles` (因为本包含 `dsh.bundle.patch`)。**新增 bundle 层需要重启 `dsh web`**;之后只改 `lib/client.js` 时会由客户端 HMR 触发重载,不必重启。 验证: ```bash node -e 'const h=process.env.DSH_HOME??process.env.HOME+"/.dsh";const p=require(h+"/profiles/web/package.json");console.log(p.dependencies["dsh-port-manager"], p.dsh.profile.bundles)' ``` (`dsh --profile` 的说明里 profile 目录就是 `$DSH_HOME/profiles`,未设置时默认 `~/.dsh/profiles`。) 卸载: ```bash dsh plugin --profile web remove dsh-port-manager ``` --- ## 兼容性 ### 平台 | 平台 | 扫描 | 打开 / 定位 | 说明 | | --- | --- | --- | --- | | **macOS** | `lsof`(+ `ps`,可选 `docker ps`) | `open` | 主要且完整验证过的目标平台。Docker 信息通过 `/var/run/docker.sock` 与 `~/.docker/run/docker.sock` 探测 | | **Linux** | `lsof`,缺失时回退 `ss -ltnpH` / `ss -lunpH` | `xdg-open` | 功能对齐,含 Docker | | **Windows** | 没有 `lsof`,`ss` 又是 Linux 专有,扫描会给出警告并返回空列表 | `cmd /c start`、`explorer` | **非支持目标**:扫描半没有 Windows 后端。`open` 另外会拒绝含 `cmd` 控制符的路径 | ### 依赖要求 | 项 | 版本 | 声明位置 | | --- | --- | --- | | DSH | `^0.1.5-rc.1` | `dsh.plugin.json` → `engines.dsh` | | Node.js | `>= 20` | `package.json` → `engines.node` | | `@deepseek-ai/cordis` | `^4.0.1`(peer) | `package.json` → `peerDependencies` | | React | `^18.2.0`(peer) | `package.json` → `peerDependencies` | | 外部命令 | `lsof`、`ps`(系统自带);可选 `ss`、`docker` | — | 本包**没有 `dependencies`**:宿主半只用 `node:fs` / `node:http` / `node:https` / `node:child_process` / `node:os` / `node:util` 加同目录的 `./scan.js`。所以插件目录**不需要 `node_modules`**(`link:` 安装后即可加载),也不会踩「裸 import 从插件目录解析不到」的坑。 ### 不同版本自适应 插件被写成「遇到不完整认识的宿主 / 客户端就降级,而不是坏掉」。下表的每一行都由代码保证, 不是约定: | 面 | 插件怎么做 | 换个版本会怎样 | | --- | --- | --- | | 宿主半激活 | `export const inject = ["webServer"]` | 在没有 web server 的 profile(headless / CLI)下插件直接不激活,而不是加载失败 | | 可选宿主服务 | `ctx.get("webRuntime")?.trustedHosts ?? []` | 服务存在时按可信主机列表放行;不存在时围栏退回「仅回环」,这是更严格的那一侧 | | 浏览器半激活 | `export const inject = ["slots", "sidebarRightTabs"]` | 客户端构建里没有原生侧栏页签注册表时,浏览器半不激活而不是抛错;宿主半与它的接口照常工作 | | 插槽契约 | `ctx.slots.inject(name, () => ctx.slots.register(...))`,包在 `ctx.effect` 里 | 插槽注册是响应式且可回收的:插槽晚一点出现、或某个版本改了贡献位置,都是「插槽在时就注册,插槽没了就拆掉」 | | 设计 token | 每个 token 都写成 `var(--dsw-alias-*, <字面兜底值>)` | token 被改名或缺失时降级成可读的硬编码颜色,而不是整块面板失去样式;明暗主题自动跟随宿主 | | 模块表 | bundle 只 `require("react")` | 图标全部内联 SVG、样式走一个 `