# @andrian\.yablonskyy/thub-client 中文文档

规范地址：https://npmcn.com/package/%40andrian.yablonskyy/thub-client/

版本：1\.1\.31
npm 元数据更新时间：2026-11-03T15:28:51.269Z
中文译文更新时间：2026-11-06T15:08:44.923Z
软件包许可：SEE LICENSE IN LICENSE\.md

本文由上游 README 翻译，可能存在偏差，请结合原文核对 API、命令与配置。版权与许可归原作者所有。

原始 npm 页面：https://www.npmjs.com/package/%40andrian.yablonskyy/thub-client
原文对照：https://npmcn.com/package/%40andrian.yablonskyy/thub-client/?lang=original

## 关键信息（来自 npm 元数据）

- 包体积（解压后）：342 kB，59 个文件
- 模块格式：CommonJS
- TypeScript 类型：未声明
- 运行依赖：3 个
- 首次发布：2026-09-22T11:34:20.907Z
- 最新版本发布：2026-11-03T15:28:51.092Z
- 近 30 天下载量：2953（2026-10-06 至 2026-11-04，npm 官方下载统计）
- 已发布版本数：68（近 12 个月 68 个）

## 中文简介

thub-客户端——运行在实验室机器上,执行针对 DUT(HW)或模拟器(SW)的测试任务

## 安装

```sh
npm install @andrian.yablonskyy/thub-client
```

也可以使用：`pnpm add @andrian.yablonskyy/thub-client`、`yarn add @andrian.yablonskyy/thub-client`、`bun add @andrian.yablonskyy/thub-client`

## README

# @andrian.yablonskyy/tub-客户端

客户`thub-client`TestHub的组件——一个让CI/CD管道和个人开发人员在私人实验室对真正的硬件或模拟器进行固件测试的自办工作网络. 这是运行在实验室机器上的守护进程,执行针对 DUT 的测试任务,流日志返回,并上传结果. 它每个进程都拥有一个完全的DUT插槽——一台有两板的机器运行两个有不同配置的例.

客户端只提供 **出境** 连接到 [协调员](https://github.com/users/andrianyablonskyy/packages/container/package/thub-coordinator) - 实验室里没有任何东西需要暴露 协调员从Docker的形象出发 `THUB_CLIENT_JOIN_KEY` 开始是 `joinKey` 在每个客户端配置中 :

在保留资源的同时,其外出远程接入链接可以承载保留持有人所要求的服务流量. 客户端打开这些连接到 `127.0.0.1` 和客户端主机上的所选端口;它不绑定或显示新的网络端口。 对于RTT日志,代理请求ST-Link,目标RAM搜索范围和上行通道;OpenOCD搜索范围并流出选定的RTT数据到本地读者. 探测器在读取器被连接的同时是专为RTT的,因此它不能同时为GDB或闪存操作服务.

```bash
docker run -d --name thub -p 8080:8080 -v thub-data:/var/lib/thub \
  -e THUB_PUBLIC_URL=https://thub.example.com \
  -e THUB_SESSION_SECRET="$(openssl rand -hex 32)" -e THUB_CLIENT_JOIN_KEY="$(openssl rand -hex 24)" \
  -e THUB_ADMIN_PASSWORD='<first admin password>' -e THUB_LICENSE='<license>' \
  ghcr.io/andrianyablonskyy/thub-coordinator:latest
```

## 安装

客户端需要 **节点.js 24或更新** 和npm在它的实验室主机。 为您的 Linux 发行安装 Node.js 24 发布( 下面支持的系统设置是 Linux), 然后验证 `node --version` 报告 `v24` 或更新后安装软件包。 节点.js 下载和平台安装器在 [节点js.org](https://nodejs.org/en/download)。 。 。 .

```bash
sudo npm i -g @andrian.yablonskyy/thub-client
```

这个命令是完整的安装。 为运行的用户在 Linux 作为根运行 `sudo` (单位:千美元)`SUDO_USER` ——不是root;用户拥有每个文件并运行服务,包的后置脚本:

-   创建 `~/.config/thub` 财务报告和审定财务报表 `~/var/lib/thub/client` (与 `work/`——用于令牌,客户身份,工作空间,控制套接字和pidfile的状态目录; 3;
-   创建 `~/.config/thub/client.json` (0600)如果它还没有存在, 空白 `coordinatorUrl`编号 :`joinKey`, (中文(简体) ), `type: hw` 财务报告和审定财务报表 `varDir` 指向状态目录——重新安装/升级永远不会覆盖它;
-   安装 `/etc/systemd/system/thub-client@.service`,为该用户提供: `User=`编号 :`Group=`, (中文(简体) ), `SupplementaryGroups=` 以 `dialout`, (中文(简体) ), `plugdev` 财务报告和审定财务报表 `docker` 存在于主机上, `THUB_CLIENT_CONFIG=~/.config/thub/%i.json`,状态目录为 `WorkingDirectory=`编号 :`ReadWritePaths=`,以及 `ExecStart` 指着这个装置是真的 `node`编号 :`daemon.js` (与 `apt`\- 已经安装的节点, `nvm` 或任何 npm 前缀) `--config ~/.config/thub/%i.json`外加一个 `ExecStartPre=+` 生成实例的 udev 规则作为每个开始的根(见下文"udev 规则");
-   安装和启用 `thub-client-update.path`编号 :`.service`,应用协调员要求的自我更新的根助手(见下文"更新");
-   编号 **新鲜机器** 仅(无) `thub-client@*` 、启用和启动 `thub-client@client` 一次 `client.json` 已经填入。 在已设置的主机上, 安装从不启用或启动默认实例; 它只重新启动已运行的实例, 因此升级立即生效 .

在新安装时,服务尚未启动——守护进程会立即以需要的空白字段退出. 填入配置,然后开始(下方).

## Ubuntu 26.04 主机设置

```bash
curl -fsSL https://deb.nodesource.com/gpgkey/nodesource-repo.gpg.key | sudo tee /etc/apt/keyrings/nodesource.asc >/dev/null
echo "deb [signed-by=/etc/apt/keyrings/nodesource.asc] https://deb.nodesource.com/node_24.x nodistro main" | sudo tee /etc/apt/sources.list.d/nodesource.list
sudo apt update && sudo apt install -y nodejs   # Node.js 24 (Ubuntu's own is 22); includes npm
sudo apt install -y stlink-tools openocd
# Docker — SW Clients, and HW Clients whose jobs run docker in --command.
# Install it before thub-client so the service gets the docker group
# (re-run the npm i -g below if you add it later). The resource card's
# Capabilities show whether a Client can use it, and why not.
sudo apt install -y docker.io

sudo npm i -g @andrian.yablonskyy/thub-client

# coordinatorUrl, type and joinKey (the Coordinator's clientJoinKey);
# see "Configuration reference" below for every field
nano ~/.config/thub/client.json

sudo systemctl enable --now thub-client@client
journalctl -u thub-client@client -f
```

服务开始于 `thub-client@<instance>.service`。实例名称选择配置文件(`thub-client@<instance>` 读取 `~/.config/thub/<instance>.json`) (中文(简体) ). 客户根据文件登记 `name`,或者当文件无时实例名称,所以默认 `thub-client@client` 登记为 `client`当从仪表板上应用一个配置时,客户端会写出 `coordinatorUrl`, (中文(简体) ), `name`, (中文(简体) ), `type` 财务报告和审定财务报表 `joinKey` 它先进入文件 然而,它之后又重新开始了, 它作为同样的资源又回来了。 A 类 `joinKey` 给出于 `THUB_CLIENT_JOIN_KEY` 留在环境中,没有写.

**每个主机一个HW客户端.** HW客户端拥有主机的 udev 规则,并驱动其所有板块, 由它们分开显示 `hw-devices` 指数(`/dev/thub/dut1-…` . `dut8-…`. 启动时第二个 HW 客户端退出(代码 78, 不由 systemd 重新启动),以及 `register --type hw` 在启用另一个 HW 实例时拒绝 。 主机上的其他实例是SW客户端. `thub-client register` 创建 `~/.config/thub/<name>.json` 从 `client.json` (同样的) `coordinatorUrl`编号 :`joinKey`编号 :`varDir`,给出 `type`,没有 `name`),然后启用并启动 `thub-client@<name>` (它只开始一次) `coordinatorUrl` 财务报告和审定财务报表 `joinKey` 设定并运行 `systemctl` 结束 `sudo` 如果你不是根子的话:

```bash
thub-client register --name client --type hw # the host's one HW Client: all its boards in hw-devices
thub-client register --name emu1 --type sw
thub-client deregister --name dut1           # stop + disable thub-client@dut1, remove dut1.json
```

`--name` 默认为 `client` 财务报告和审定财务报表 `--type` 改为 `hw`。从此 repo 的检出中,相同的命令是 `npm run register -- --name dut1 --type hw` 编号 : `npm run deregister -- --name dut1` (或 `npm run client:register -- ...` 编号 : `npm run client:deregister -- ...` )),从单列波根. 注册已存在的实例时保留其配置, 仅更新 `type`. 行为保持 `client.json` (新实例模板)和实例状态 `varDir`,因此重新登记同名后又作为同名资源出现. 用手做就等于:复制 `client.json` 改为 `dut1.json`,则 `sudo systemctl enable --now thub-client@dut1`。 。 。 .

保留 `varDir` 在一个英寸 `client.json` ——该服务只能写在那里,其下的每一条每条穿行路径已经被配置文件名所命名. 如果你改变了 `client.json`是因为 `varDir`编号 :`runDir`重新运行 `sudo npm i -g @andrian.yablonskyy/thub-client` 所以这个单位 `ReadWritePaths=` 接下来.

每个安装步骤都是最优美的,永远不失败 `npm install` 本身,只运行一个实际的全球安装(`npm install -g`)——平地地 `npm install` (例如,在脱氧核糖核酸中,或作为CI/Docker图像中的根,这是常见的)从不触及 `/etc/systemd`, (中文(简体) ), `~/.config/thub` 或者说 `~/var/lib/thub`。一个没有根的全局安装,或者在非Linux机上,仍然创建目录和 `client.json` 对于当前用户,但跳过系统并打印 `sudo npm i -g` 命令替换运行.

## 直接运行(没有系统化——经过全球安装、开发或一次性手工运行)

`npm install -g` 也给你 `thub-client-daemon`,直接命令守护进程本身(`thub-client` 单是控制CLI——锁定/解锁/状态/停止/重新启动/登记/删除:

```bash
THUB_CLIENT_CONFIG=/etc/thub/dut0.json thub-client-daemon
thub-client-daemon --config /etc/thub/dut0.json   # equivalent
thub-client-daemon --config /etc/thub/dut0.json --name lab-hw-01   # override the config's name
```

`--name`编号 :`-n` 覆盖配置文件 `name`;系统化单位用它来传递实例名称.

从此 repo (不是全局安装) 的本地检出中, 同样的是 `node src/daemon.js` 替换 `thub-client-daemon`。 。 。 .

配置解析度 : `--config`编号 :`-c` 旗帜,或 `THUB_CLIENT_CONFIG` (原始内容存档于2018-09-31) (英语). env var, → `~/.config/thub/client.json` - 捆绑的 `config.json` 默认。 仅限JSON 一个具体的例子 总是需要自己的明确 `--config`编号 :`THUB_CLIENT_CONFIG` - 那个 `~/.config/thub/client.json` 倒置只覆盖单一的默认/无旗案件.

`npm install -g` 创建 `~/.config/thub/client.json` 对于你来说,如果它已经不存在(见上文"Install")——一个再安装永远不会覆盖它. 为多机构设置`dutN.json` 文档,上),这只是您第一次/默认实例的起点.

**在一个主机上运行多个客户端** ——每个配置文件启动一个守护进程,每个进程都指向自己的进程 `dutN.json`; 每一个默认路径( e)`tokenFile`, (中文(简体) ), `workDir`, (中文(简体) ), `socketPath`, (中文(简体) ), `pidFile`, (中文(简体) ), `clientIdFile`) 已经被配置文件自己的基名所命名, 最多可达8个实例(`dut0`.`dut7`,每个UART/ST-Link)与零额外设置共存:

```bash
THUB_CLIENT_CONFIG=/etc/thub/dut0.json thub-client-daemon &
THUB_CLIENT_CONFIG=/etc/thub/dut1.json thub-client-daemon &
```

如果两个实例相反共享完全相同的配置文件( 仅用 `name`),名称间距崩溃,两者都登记为 _不变_ 资源。 设定 `clientId` (或 `THUB_CLIENT_ID`)和区别 `socketPath`编号 :`pidFile` (并告诉他们) `--name` 而不是编辑文件).

## 配置参考

| 外地 | 需求 | 默认 | 含义 |
| --- | --- | --- | --- |
| `coordinatorUrl` | 对 | —— 说 | 协调员的基本URL. |
| `name` | 没有 | 配置文件的基础名称 | 资源名. 被守护神所压倒 `--name` 在系统d下,实例名称(`thub-client@<name>`因此,它被忽略在那里。 身份其实是 `clientId` - 改名是安全的. |
| `type` | 对 | —— 说 | `hw` 或者说 `sw`。 。 。 . |
| `labels` | 没有 | `[]` | Fully 替换每次注册时的资源标签 . |
| `groups` | 没有 | `[]` | 这个客户是哪个资源集团的成员——在每次登记时完全取代其成员. |
| `joinKey` | 是, 除非重新登记被禁用 | —— 说 | 共同的秘密可以证明客户端 自我注册。 也可确定为 `THUB_CLIENT_JOIN_KEY`。每次启动/重新启动时都进行了咨询. |
| `varDir` | 没有 | `<cwd>/.data` (单位:千美元)`~/var/lib/thub/client` 安装中 `client.json`(中文(简体) ) | 基数 `tokenFile`编号 :`workDir`编号 :`clientIdFile` 默认值。 在系统下,它必须留在单位内部 `ReadWritePaths=`。 。 。 . |
| `runDir` | 没有 | `varDir` | 基数 `socketPath`编号 :`pidFile` 默认值. |
| `tokenFile` | 没有 | `<varDir>/<instance>.token` | 在注册后资源 id + 令牌持续( 0600) 的地方 . |
| `workDir` | 没有 | `<varDir>/work/<instance>` | 工作室根,每次工作后清理. |
| `socketPath` | 没有 | `<runDir>/<instance>.sock` | 解开套接字 `thub-client lock/unlock/status`。 。 。 . |
| `pidFile` | 没有 | `<runDir>/<instance>.pid` | PID 文件 `thub-client stop`编号 :`restart` 用于找到守护进程 . |
| `clientIdFile` | 没有 | `<varDir>/<instance>/.client-id` | 稳定身份存在的地方,除非 `clientId` 已经设定. |
| `clientId` | 没有 | —— 说 | 明确身份 UUID, 跳过 `clientIdFile`。也可以确定为 `THUB_CLIENT_ID`。 。 。 . |
| `heartbeatIntervalSec` | 没有 | `10` | 守护进程心跳的频率,直到协调员表示不同: `heartbeat.intervalSec` 在登记和每一次心跳回复时,客户都从那时起跟踪(协调员仪表板上的一个变化在一瞬间到达)。 只有一位年事已高的协调员不会留下这种价值. |
| `longPollWaitSec` | 没有 | `30` | 每次工作要等多久才能回来 `204`。 。 。 . |

**诸能相.** 每次注册( 每个开始/ 重新开始) 客户端都会报告它驱动的配置 : 对于 HW 每个 `hw-devices.stlinks`编号 :`uarts`编号 :`usbs` 设备(路径、 ST- Link 串行、 UART baud 速率, 以及设备节点是否现在存在); 对于 SW , 图像、 其来源和 CPU/ memory 限制。 协调员的资源卡列出它们,并标出缺失的已配置设备. 在插入或移动适配器后, 重新启动实例以刷新它们 .

**心动** (每个 `heartbeat.intervalSec` (d) 报告状态、东道主的网络地址、东道主的起动时间和当前活动(只是运行一项工作,直至其完全完成,包括上传、锁定或自我更新)及其持续时间——显示在协调员的资源卡上.

**SW 客户端** (单位:千美元)`type: sw`)没有自己的设置: SW工作是它的指令. 客户端从不拉出图像或启动容器,也不需要多克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克 `--env`。一个旧文件 `sw` 区域被忽略.

**客户端** (单位:千美元)`type: hw`: `hw-devices` 中,在初始时对照其计划检查,每个方案最多16个 `stlinks`, (中文(简体) ), `uarts`, (中文(简体) ), `usbs` (单位:乌德夫指数1-8 ) `/dev/thub/dut<N>-stlink|uart|usb`,路径,或 `{ index | path, ... }`; ST- Link 条目可能给出 `serial`,未定义 `baudRate` 财务报告和审定财务报表 `label`; 任何一个 `devpath` 加可选 `vendorId`编号 :`productId`编号 :`subsystem` 获得 udev 符号链接规则。 客户端获取工作 `--download-file` 文档从任何工作说, 没有自己的证书.

示例 SW 配置 :

```json
{
  "coordinatorUrl": "https://thub.example.com",
  "name": "lab-sw-01",
  "type": "sw",
  "joinKey": "<same value as the Coordinator's clientJoinKey>"
}
```

## `thub-client` - 控制CLI

```bash
thub-client register [--name client] [--type hw]   # add/update an instance (see "Several DUT slots")
thub-client deregister [--name client]             # remove it
thub-client lock --reason "debugging I2C"   # -> BUSY (source=local)
thub-client unlock                           # -> IDLE
thub-client status
thub-client stop      # SIGTERM; graceful, bounded shutdown
thub-client restart   # stop, then start a new daemon with the same config
thub-client power on|off|reset|status [--port <n>] [--delay <sec>]   # USB port power with uhubctl (hw-devices.usbPower)
```

**USB港口电力.** 安装 `uhubctl` (单位:千美元)`sudo apt install uhubctl`)并找到每个DUT的枢纽和端口 `sudo uhubctl`。中心的位置是后面的词 `hub`,端口是后面的数字 `Port`数字 :

```
Current status for hub 1-1.4 [2109:2817 VIA Labs, Inc. USB2.0 Hub, USB 2.10, 4 ports, ppps]
  Port 2: 0103 power enable connect [0483:3748 STMicroelectronics STM32 STLink 066DFF485457725187092834]
```

在配置中列出,最多8个. `--port` 从 1 开始, 占据一个端口在此列表中的位置 :

```json
"hw-devices": { "usbPower": { "ports": [{ "hub": "1-1.4", "port": 2 }, { "hub": "1-1.4", "port": 3 }] } }
```

重新启动客户端: 它安装了 udev 规则, 允许 `plugdev` 组切换中枢端口. 然后说:

```bash
thub-client power status                     # 1. hub 1-1.4 port 2: on  (Port 2: 0103 power enable connect [...])
thub-client power reset                      # every port: off, 1 s, on
thub-client power reset --port 2 --delay 3   # hub 1-1.4 port 3 only, 3 s off
thub-client power off --port 1
```

从特工处,一个工作可以在开始和结束的时候转换它们(`thub run --power-on-start reset --power-on-end off`),其所有者可以在运行时切换它们(`thub power reset <jobId>`) (中文(简体) ). 每个动作都记录在工作日志中. 设置,示例和故障排除在主 README, 第8.7.

**日志中的序列端口 .** 每个条目 `uarts` (USB-UART适配器,以及板块自己的USB序列端口,带有 `"subsystem": "tty"` 而董事会的USB id) 被抓住的整个工作进入 `uart` 流线。 不止一条,每条线路都标有港号 `label` 或设备名称(`[dut2-usb] …`) (中文(简体) ). 一个会消失的端口,如一板的USB串行端口,而一板在闪出后重新发售,一旦回通就重新开放. 开始时不在场的人等着呢 日志上说是这样的 在一个15个端口的枢纽上,有5个板块(ST-Links、FT232RL适配器和板块自己的USB)的例子是主要README,第8.6节(_一个客户5个板_) (中文(简体) ).

**测试结果.** 每次工作后,客户端都会将 JUnit XML 的金额加到 `results/` 或者说 `artifacts/` (在工作目录中,或一个文件夹向下)进入工作测试计数. Google Test's and Ctest's disappointed tests 算作被跳过。 从主机驱动棋盘的工作( pyserial, 说) 必须使用客户端不抓取的端口: UART in `hw-devices.uarts` 整个工作都是开放的,第二个开放失败 _设备或资源繁忙_主要读取,第7.6节.

**二等兵CA.** 若为 `--download-file` URL(或协调员)使用实验室或公司CA的证书,给予客户CA. Node.js不读系统商店:

```bash
sudo systemctl edit thub-client@.service      # [Service]
                                              # Environment=NODE_EXTRA_CA_CERTS=/usr/local/share/ca-certificates/lab-ca.crt
sudo systemctl restart 'thub-client@*'
```

`update-ca-certificates` 仍然覆盖 `curl` 财务报告和审定财务报表 `git` 在工作,和多克读 `/etc/docker/certs.d/<registry>/ca.crt`。需要下载 _客户端_ 证书不能使用 `--download-file`: 工作会用 `curl --cert` (主研究,第7.5节).

**智能套接字,PDU等设备.** 客户端没有驱动程序: 工作从自己的驱动程序切换到 `--command` 或寄存器脚本(主README,§8.8). 在客户端主机上安装这些脚本调用的工具( O)`curl`, (中文(简体) ), `sudo apt install snmp`, (中文(简体) ), `pipx install python-kasa`)和从主机检查设备的答案. 然后告诉每一个实例 哪个设备是它的长凳。 工作继承服务环境:

```bash
sudo systemctl edit thub-client@dut1      # [Service]
                                          # Environment=BENCH_POWER=apc:pdu1.lab:5
sudo systemctl restart thub-client@dut1
```

每一个工作可以读取这些变量, 所以把地址放在那里,并通过证书 每一个工作 `--env`。 。 。 .

以客户端运行的用户运行时运行这些 `sudo` (将寻找 `client.json` 在根的家园. `stop`编号 :`restart` 穿过鼠标而不是控制套接字,所以即使套接字被接上,它们也能起作用。 停止被限制: 闲置的长波立即被中止; 正在运行的工作被本地杀死( Name`SIGTERM`,则 `SIGKILL` 10s宽限期之后)并报告 `ERROR`。 。 。 .

在一个主机上出现一些实例,将目标对准右边一个 `--config` 在子命令前 :

```bash
thub-client --config ~/.config/thub/dut1.json status
thub-client --config ~/.config/thub/dut1.json lock --reason "debugging I2C"
```

## 更新

```bash
thub-client check-update                 # installed vs latest published version
thub-client self-update [--to <x.y.z>]   # sudo npm i -g; restarts every running instance
```

客户端只有在管理员提出要求时才更新(协调员仪表板:每个资源或 **更新所有客户端**(中文(简体) ) **财务报告和审定财务报表** 它不是在运行一个工作。 一份工作算作是运行到完全完成,包括结果和最后的日志冲出. 协调员发送: `self-update` 在心跳响应中命令。 守护进程作为一个没有特权的用户运行沙盒,所以它只写 `<varDir>/update-request.json`,每个版本一次,只在没有本地锁的情况下闲置。 词根 `thub-client-update.path` 单元,由 `sudo npm i -g`开始 `thub-client-update.service`,其中:

1.  创建 `<varDir>/update-hold.json`虽然东道主没有实例可查,但每个协调员都忙于工作(`local — self-update in progress`),因此提交的工作同时保持队列;
2.  等待45 s ,所以在搁置出现之前就下达了任务,然后等待(最多24 h),直到没有工作运行或手动锁定;
3.  运行 `npm i -g @andrian.yablonskyy/thub-client@<version>` 用于客户端用户。 在新版本中重启每个实例;
4.  移除控件, 以及失败时的控件或 `systemctl stop`超过2小时的拘留被忽略.

一个管理员可以中止它,直到它安装时为止 **取消** 在协调员的资源卡上:客户端删除控件并停止帮助而不安装。 同一按钮会取消客户端的运行任务(在下载中自动下载)或发布手动本地锁.

只有安装过 `thub-client`,在一个严格验证的版本。 日志 : `journalctl -u thub-client-update`。 。 。 .

## 工作执行周期

1.  从长波和 `accept` 这个.
2.  创建新工作空间 `<workDir>/<jobId>`。 。 。 .
3.  **准备任务的投入**: 任务目录 `<jobId>/` 是工作目录( y)`$THUB_WORK_DIR`; 下载次数 `--download-file` 输入 `downloads/`。没有任何东西被克隆:需要寄存器的指令将它自己复制到 `src/` 说.
4.  **准备** dUT通过执行器:HW解决了ST-Link序列,并捕获了UARTs(没有闪出-命令这样做);SW没有任何准备.
5.  **运行** 这份工作 `--command` 与 `sh -c` 在工作目录中( e)`$THUB_WORK_DIR`, (中文(简体) ), `DOCKER_CONFIG` 设定为 `.docker/`, (中文(简体) ), `--arg` 数值为 `"$@"`,以及环境: `--env` 变量,其 `thub run` 参数为 `JOB_*` (例如:. `JOB_LABEL`, (中文(简体) ), `JOB_SUITE` - 完整清单:主要内容README 第7.4节, _客户环境变量_, (中文(简体) ), `THUB_DOWNLOAD_<n>`编号 :`THUB_DOWNLOADS_DIR`编号 :`THUB_DOWNLOADS`, (中文(简体) ), `THUB_JOB_ID`, (中文(简体) ), `THUB_WORK_DIR`,一个 `THUB_META_<KEY>` 每个任务元数据字段。 它的退出代码是判决.
6.  读取所剩测试的 JUnit XML `results/` 或者说 `artifacts/` 任务目录,或其中的文件夹 (`src/results/`),并归纳为工作 `summary` (总数/通过/失败/滑倒)。 判决保留出局代码.
7.  公布结果——用文物列出命令 `$THUB_ARTIFACTS_FILE` (JSON阵列 `{name, size, link, timestamp}`,作为元数据——删除工作空间,报告 `IDLE`。 。 。 . **没有上传文件** 除了日志: 任务的文件只存在于其工作空间中, 当任务结束时会被删除 。 需要保存文件的工作 出版它们自己的 `--command`,例如到艺术.

这份工作是 `--env` 为步骤3的 git 命令和 `--command`,在服务自身环境之外,无论工作选择何种名称:客户端中没有任何东西依赖于特定名称. 仅 `THUB_*`, (中文(简体) ), `JOB_*`, (中文(简体) ), `GIT_TERMINAL_PROMPT` 财务报告和审定财务报表 `GIT_ALLOW_PROTOCOL` 不能这样设置。 数值来自负责这项工作的协调员,客户从不登录.

**都克从指挥部.** 命令运行在客户端主机上,作为服务用户. 为了在图像内进行测试,它会启动容器本身(`docker run --rm --user "$(id -u):$(id -g)" -v "$THUB_WORK_DIR/src:/work" -w /work <image> …`),在其自身之后 `docker login` 如果登记处需要一种——最好 `DOCKER_CONFIG="$THUB_WORK_DIR/.docker"`,因此证书随工作被删除,而不是留在服务用户的 `~/.docker`,它需要在主机上安装 Docker 和在 `docker` 组合。 SW主机是这样设置的(参见 _Ubuntu 26.04 主机设置_); 需要添加HW主机. 例如:README特工, _夹克_。 。 。 .

取消命令或工作超时发送 `SIGTERM` 到测试进程组,等待 10s,然后 `SIGKILL`,并总是运行执行器撕毁。 若为 `spec.dryRun` 已经设定,没有执行。 相反,该工作的日志列出了该客户端上将运行的每个命令, 完整且有序: 该工作的日志 `--env` 名称( 每个值显示为 `***`),下载,HW DUT设置,以及 `cd <work> && sh -c …` 它的环境。 它又说 `WOULD FAIL:` 该客户端的配置会拒绝的任何东西的行 .

### HW 执行器

ST-Link通过 `st-flash`编号 :`openocd`,通过 `serialport` npm 软件包. 稳定设备路径( E)`/dev/thub/dut<N>-uart`, (中文(简体) ), `/dev/thub/dut<N>-usb`, (中文(简体) ), `/dev/thub/dut<N>-stlink`, N = 1–8)来自 udev 规则客户端从自己的配置生成.

**udev规则.** 安装时没有 udev 设置 。 每次开始客户端都会写 `/etc/udev/rules.d/99-thub-client-hw.rules` (每个主机一个: HW 客户端; 当其配置没有设备时被删除, 例如在仪表板之后) **删除全部**; 老客户端 `99-thub-<instance>.rules` 文件被删除) `hw-devices.stlinks`编号 :`hw-devices.uarts`编号 :`hw-devices.usbs` 拥有 `devpath` (USB端口路径, `ATTRS{devpath}` 内 `udevadm info -a -n <device>`) (中文(简体) ). 然后重新装入 udev 和再触发器 `usb`编号 :`tty` 设备并等待它们和解,但只有在文件实际更改时。 每类默认值:ST-Link `0483:3748` 打开 `usb`(UART) (中文(简体) ) `0403:6001` 打开 `tty`, USB 数据 `0483:5740` 打开 `usb`; 以 `vendorId`编号 :`productId`编号 :`subsystem`在系统化下 `ExecStartPre=+` 以此为根。 预览规则 `thub-client [--config <path>] udev --print`,然后在不重新启动的情况下应用 `sudo thub-client [--config <path>] udev`。从1.0.17升级:各移动 `ATTR{devpath}` 从旧 `/etc/udev/rules.d/99-thub.rules` ,然后删除该文件。 客户端没有闪出任何东西:工作 `--command` 使用这些设备 `/dev/thub/dut<N>-…` 路径(或 `st-flash`自己的探测器选择; 没有设备变量传递给它 .

### SW 执行器

没有什么可以准备或拆卸的:SW工作就是它 `--command`,它从它需要的开始(一个模拟器 `docker run`说)并阻止它自己。 客户端没有多克依赖性 .

## 发展

```bash
npm install
npm run lint
```

## 许可证

见 [利比里亚](https://npmcn.com/package/%40andrian.yablonskyy/thub-client/LICENSE.md)。 。 。 .

## 常见问题

### @andrian\.yablonskyy/thub-client 是什么？

thub-客户端——运行在实验室机器上,执行针对 DUT\(HW\)或模拟器\(SW\)的测试任务

### 如何安装 @andrian\.yablonskyy/thub-client？

在项目目录运行 npm install @andrian\.yablonskyy/thub-client，或使用 pnpm add / yarn add / bun add。它还提供命令行工具 thub-client、thub-client-daemon，可以用 npx thub-client 直接运行。

### @andrian\.yablonskyy/thub-client 支持 TypeScript 吗？

该包的 package\.json 没有声明类型入口。需要类型提示时，可以在 npm 上查找社区维护的 @types/andrian\.yablonskyy\_\_thub-client 是否存在。

### @andrian\.yablonskyy/thub-client 支持 ESM 还是 CommonJS？

以 CommonJS 形式发布，可以直接 require\(\)；在 ES Module 项目中也可以用 import 引入（Node\.js 会把 module\.exports 作为默认导出）。

### @andrian\.yablonskyy/thub-client 可以商用吗？

@andrian\.yablonskyy/thub-client 使用 SEE LICENSE IN LICENSE\.md 许可。许可条款写在包内的独立文件中，请阅读该文件确认可否商用。以上为概括，不构成法律意见，请以许可原文为准。

### @andrian\.yablonskyy/thub-client 的下载量有多少？

根据 npm 官方下载统计，@andrian\.yablonskyy/thub-client 在 2026/10/06 – 2026/11/04 这 30 天内被下载 2,953 次，日均约 98 次。下载量会把 CI 构建、镜像同步和作为其他包依赖的安装一并计入，适合横向比较热度，不能直接等同于使用人数。

### @andrian\.yablonskyy/thub-client 还在维护吗？

最新版本 1\.1\.31 发布于 2026/11/03（4 天前）；至今共发布 68 个版本，其中过去 12 个月发布了 68 个；首次发布于 2026/09/22。发布频率只是参考信号：功能稳定的工具可能很少需要更新，建议结合源码仓库的 issue 和提交记录判断。

