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

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

版本：1\.1\.27
npm 元数据更新时间：2026-11-03T15:00:45.955Z
中文译文更新时间：2026-11-06T15:19:37.757Z
软件包许可：SEE LICENSE IN LICENSE\.md

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

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

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

- 包体积（解压后）：497 kB，17 个文件
- 模块格式：CommonJS
- TypeScript 类型：未声明
- Node.js 要求：\>=24
- 运行依赖：3 个
- 首次发布：2026-09-22T11:34:16.090Z
- 最新版本发布：2026-11-03T15:00:45.676Z
- 近 30 天下载量：2927（2026-10-06 至 2026-11-04，npm 官方下载统计）
- 已发布版本数：61（近 12 个月 61 个）

## 中文简介

TestHub Agent CLI — CI/CD 和开发者用来提交和跟踪测试任务的单一切入点

## 安装

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

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

## README

# @andrian.yablonskyy/thub-agent (英语)

CLI探员(`thub`)是一个自我托管的职类,允许CI/CD管道,个人开发人员在私人实验室对真正的硬件或仿真器进行固件测试. `thub` 是两个单一的切入点: 无国籍,它知道的一切来自 [协调员](https://github.com/users/andrianyablonskyy/packages/container/package/thub-coordinator) API,它同样运行在GitHub托管的跑道上和开发者笔记本电脑上——一个复制CI故障的开发者运行的指令与管道运行的完全相同.

看这怎么配合 [协调员](https://github.com/users/andrianyablonskyy/packages/container/package/thub-coordinator) 编辑 [客户端](https://github.com/andrianyablonskyy/thub-client)协调员从其多克的形象出发, `ghcr.io/andrianyablonskyy/thub-coordinator`数字 :

```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
```

然后在其仪表板上创建 CI 令牌或访问密钥,用于 `thub`。 。 。 .

## 安装

探员继续前进 **节点.js 24或更新** (和npm)在每一个工作站或CI跑者援引 `thub`。从 [节点js.org](https://nodejs.org/en/download) 对于您的操作系统,请确保 npm 包含和 Node.js 打开 `PATH`,然后与 `node --version` 财务报告和审定财务报表 `npm --version`. Windows用户可以使用节点.js Windows安装器(`.msi`; 在安装后重新启动PowerShell和VS代码, 因此两者都继承更新 `PATH`。 。 。 .

```bash
npm i -g @andrian.yablonskyy/thub-agent
# or, one-off in CI:
npx -y @andrian.yablonskyy/thub-agent run --type sw --download-file "$IMAGE_URL" --command ./ci/test.sh --wait
```

### 窗口工作站

安装 **节点.js 24或更新** 从 [节点js.org](https://nodejs.org/) ,并确保安装器将Node.js和npm添加到 `PATH`。打开一个新的PowerShell终端,然后安装和配置代理 :

```powershell
node --version
npm --version
npm install --global @andrian.yablonskyy/thub-agent
thub config set url https://thub.example.com
thub config set key thk_...
thub whoami
```

代理存储其配置于 `%APPDATA%\thub\agent.json`。如果 npm 报告权限出错,则使用 PowerShell 终端作为管理员启动,或为您的用户配置 npm 的全局前缀;自动自动更新不会提示升空 。 要使用 VS 代码中的代理,请安装 **thub -- -- 远程板** 扩展并保留 vS 代码进程上的 npm 全球可执行目录 `PATH`。 。 。 .

## 配置

从旗帜读取( N)`--url`, (中文(简体) ), `--key`),然后是环境(`THUB_URL`, (中文(简体) ), `THUB_KEY`,则 `%APPDATA%\thub\agent.json` 在窗口上或 `~/.config/thub/agent.json` 其他地方,然后是捆绑的默认值. `url`编号 :`key` 在指挥部与协调员进行实际会谈时,必须这样做; `group`编号 :`user` 到处都是可选的.

`npm install -g` 为您创建每个用户代理配置( 空白) `url`编号 :`token`如果它还没有存在的话 重新安装永远不会覆盖它 填进去 `thub config set`数字 :

```bash
thub config set url https://thub.example.com
thub config set key thk_...       # your access key: from an admin (Users), or your dashboard profile
thub whoami                       # jane (user) <jane@example.com>
thub key show                     # its last characters, created, last used
thub key rotate                   # a new key; the old one stops at once (saved here if it came from here)
```

## 图标

```
thub run      [options]        Submit a test job and follow its log
thub status   <jobId>          Show status; follow log if running, verdict, test counts and artifacts if done
thub cancel   <jobId>          Cancel a job
thub power    on|off|reset <jobId> [--delay <sec>] [--port <n>]   Switch the USB power of the Client running your job (owner only)
thub report   <jobId> [--post gitlab|bitbucket|github] [--commit-status]   The job's report, or a sticky MR/PR comment
thub resources                 List resources and their status
thub reserve  <client> [--for <dur>]   Only your jobs run on this runner until then (default 1h)
thub release  <client>                 End your reservation (maintainers: anyone's)
thub connect  <client> [--target <name>] [--forward <name=port>]... [--rtt <index=address,size[,channel[,target]]>]... [--video-port <p>] [--video-udp <p>] [--json]   Your reserved board's UARTs, SWD (GDB), RTT, camera and Client services
thub console  <client> [--uart <n>]    A reserved board's UART in this terminal (Ctrl-] quits)
thub jobs     [--mine] [--state <s>]   List recent jobs (a cli token: only its own; a ci token: all, or its own with --mine)
thub config   set <key> <value>        Save coordinator URL / key / default user locally
thub whoami   [--json]                 Whose access key this is (and the group its jobs run in)
thub check-update                      Compare this Agent with the latest published version
thub self-update [--to <x.y.z>]        Update this Agent with npm i -g
thub --version
```

**自相更新.** 管理员可在协调员的代理页面上请求更新此代理(或所有代理). 与协调员交谈的下一个命令安装在 `npm i -g` (重试通过) `sudo` ),并在新版本上重新运行。 在 Windows 上,以 npm 全球前缀所需的权限运行终端; Agent 从未尝试自动提升. 如果安装失败——比如在CI中没有权限——它会打印手动命令并沿用当前版本;运行永远不会因为更新而失败. 设定 `THUB_NO_SELF_UPDATE=1` 选择退出.

关键选项 `thub run`。 。 。 . **在客户端上** 命名该任务命令中的环境变量 _客户环境变量_ 下图:

| 选项 | 说明 | 在客户端上 |
| --- | --- | --- |
| `--type hw|sw` | 所需资源类型. | `JOB_TYPE` |
| `--label <l>` | 需要的标签( 可重复; 棋盘为 `--label board:<name>`:这个工作只运行在拥有他们全部的跑道上. 每个 1–64 个字符,没有白空间,逗号或分号. | `JOB_LABEL`, (中文(简体) ), `JOB_LABEL_<n>` |
| `--client <name|id>` | 只在此特定客户端( 资源名或 id) 上运行; 即使其他匹配资源闲置, 任务仍在该客户端的队列中等待 . | `JOB_CLIENT` |
| `--command <string>` | **要求.** 任务的切入点: 客户端运行的 shell 命令( S)`sh -c`)在工作的工作目录中,在下载后. 它复制储存库并自行运行容器(见下文Git和Docker),其证书来自 `--env`。退出代码 0 = PASSED. | `JOB_COMMAND` |
| `--download-file <url>` | 运行命令前客户端下载的文件( repeatable,), `http(s)`),进入工作 `downloads/` 目录. | `JOB_DOWNLOAD_FILE`, (中文(简体) ), `JOB_DOWNLOAD_FILE_<n>` (当地汇率); `THUB_DOWNLOAD_<n>` (当地路径) |
| `--env <vars>` | 客户端为任务运行的每个命令的环境变量( git 和 git ) `--command`: `NAME=value[,NAME=value]`可重复的; `--env NAME` 单从你的外壳取出价值 任何名字——对代理人或客户没有任何意义(只有 `THUB_*`, (中文(简体) ), `JOB_*`, (中文(简体) ), `GIT_TERMINAL_PROMPT`, (中文(简体) ), `GIT_ALLOW_PROTOCOL` (b) 拒绝。 每个值都是个秘密:它只到达运行该任务的客户端;协调员掩盖它,并在任务结束时放弃它. | 每个 `NAME` 本身 |
| `--suite <name>` | 测试命令的套件名称 . | `JOB_SUITE` |
| `--arg <value>` | 命令的额外参数, 如 `"$@"` (可重现. | `JOB_ARG`, (中文(简体) ), `JOB_ARG_<n>` (和 `"$@"`(中文(简体) ) |
| `--timeout <dur>` | 譬如说. `30m`默认值 `30m`。 。 。 . | `JOB_TIMEOUT` (单位:秒) |
| `--priority <n>` | 0–100;CI默认为50,CLI为60,因此开发商不会被繁忙的管道饿死. | `JOB_PRIORITY` |
| `--meta <key=value>` | 任意的元数据存储在工作(可重复)上——CI job ids, git 坐标,任何其它值得附加在运行中的东西. | `JOB_META_<KEY>` (另见: `THUB_META_<KEY>`(中文(简体) ) |
| `--dry-run` | 运行整个管道 客户不执行任何真实的. | \- (命令不运行) |
| `--id-file <path>` | 排队后立即将工作ID写入此文件, 稍后 `thub report`。 。 。 . | ——(仅代理) |
| `--power-on-start on|off|reset` | HW 仅: 在 DUT 准备前切换客户端的 USB 电源端口( uhubctl) ; 失败结束此工作 `ERROR`。 。 。 . | `JOB_POWER_ON_START` |
| `--power-on-end on|off|reset` | 仅限HW:工作结束后切换,无论它的判决如何. | `JOB_POWER_ON_END` |
| `--power-reset-delay <sec>` | 多久一个 `reset` 0-60 s; 默认 `1`。 。 。 . | `JOB_POWER_RESET_DELAY` |
| `--wait` | 不得在工作结束时拆分;退出时使用工作裁决代码(在CI中使用). | ——(仅代理) |
| `--detach` | 立即打印工作标识并退出. | ——(仅代理) |
| `--json` | 机器可读输出. | ——(仅代理) |

-   `thub run` 打印 **任务标识**,然后流出日志,直到 Ctrl-C. Ctrl-C 调试;该任务持续运行在客户端上.
-   `thub status <jobId>` 打印当前状态; 如果活动持续流出, 如果完成, 打印判断, 命令的退出代码和 JUnit 测试计数 . `--json` 打印一次并永不跟踪(参见 [就业状况和PAS/FAIL](https://npmcn.com/package/%40andrian.yablonskyy/thub-agent/#readme-job-status-and-passfail)) (中文(简体) ).

退出代码使代理作为CI步骤可用 :

| 代码 | 含义 |
| --- | --- |
| `0` | `PASSED` |
| `1` | `FAILED` |
| `2` | `ERROR`, (中文(简体) ), `TIMEOUT`,或 `LOST` |
| `3` | `CANCELED` |
| `4` | 用法、 认证或连接出错 |
| `5` | `thub status <jobId> --json`: 任务仍然排队或运行 |
| `130` | 用 Ctrl- C 调试( 工作仍在运行) |

### USB 端口动力( HW)

在拥有USB电源端口的客户端(uhubctl,参见主README 第8.7节)上,一个工作可以冷却地启动它的板并关闭到尾端. 它的主人还可以在运行时进行电循环,而不取消工作:

```bash
thub run --type hw --label board:nucleo-f401re \
  --download-file "$IMAGE_URL" --command './ci/flash-and-test.sh' \
  --power-on-start reset --power-reset-delay 2 --power-on-end off --wait

thub power reset M-00131                      # every port, 1 s off (the default delay)
thub power reset M-00131 --port 2 --delay 3   # the Client's second port, 3 s off
thub power off M-00131
```

`thub power` 工作只为你的工作, 而它是 `PREPARING` 或者说 `RUNNING`否则协调员会说它拒绝的原因。 工作日志显示每个动作:

```
[runner] USB power reset (port 2) requested by alice (thub power)
[runner] USB power reset: 1-1.4:3 (off 3 s)
```

### 智能插座、PDU和其他实验室设备

智能插座(Shelly、Tasmota、Kasa、家庭助理)或PDU出口的板块由工作本身切换。 内容 `--command`,或从它克隆的寄存器中调用设备的脚本 `curl`, (中文(简体) ), `snmpset` 或设备本身的CLI, 证书通过为 `--env`。每个客户实例都在其环境中命名其长凳设备(例如:. `BENCH_POWER=shelly:10.0.20.11`,设置为系统投放:

```bash
# inline: Shelly Gen2 off, 2 s, on, then the tests
thub run --type hw --label board:nucleo-f401re --env SHELLY_PASSWORD \
  --command 'S="http://$BENCH_IP/rpc/Switch.Set?id=0"
             curl -fsS --digest -u "admin:$SHELLY_PASSWORD" "$S&on=false" && sleep 2 &&
             curl -fsS --digest -u "admin:$SHELLY_PASSWORD" "$S&on=true" && ./ci/test.sh' --wait

# from the test repository: ci/run.sh resets the bench's socket or PDU outlet, tests, and always powers it off
thub run --type hw --env GH_TOKEN --env POWER_PASSWORD \
  --command 'git clone --depth 1 "https://x-access-token:$GH_TOKEN@github.com/yourorg/firmware-tests.git" src && cd src && exec ci/run.sh' --wait
```

使用 `exec` 所以一个取消的工作 `SIGTERM` 到达剧本的陷阱。 全数 `ci/power.sh` 财务报告和审定财务报表 `ci/run.sh` 例如(Shelly、Tasmota、家庭助理、Kasa、APC PDU over SNMP)在主要README第8.8节和仪表板的帮助中.

## 实例

**运行任务** ——下载固件,以标签,闪光和测试复制测试(HW):

```bash
export GH_TOKEN=…   # read access to the tests repository
thub run --type hw --label board:nucleo-f401re \
  --download-file "$IMAGE_URL" --env GH_TOKEN \
  --command 'git clone --depth 1 --branch v1.4.0 "https://x-access-token:$GH_TOKEN@github.com/yourorg/firmware-tests.git" src && cd src &&
             st-flash --reset write "$THUB_DOWNLOAD_1" 0x08000000 && ./ci/test.sh "$@"' \
  --arg --junit --wait
```

**针对您自己的模拟容器的 SW 任务** (命令开始并删除):

```bash
thub run --type sw --download-file "$IMAGE_URL" \
  --command 'dut="thub-$THUB_JOB_ID" && trap "docker rm -f $dut >/dev/null" EXIT &&
             docker run -d --name "$dut" -p 127.0.0.1:5555:5555 -v "$THUB_DOWNLOADS_DIR:/downloads:ro" registry.lab.local:5000/dut-emulator:2026.08 &&
             make test DUT=127.0.0.1:5555' --wait
```

**将CI/CD工作证明与内部工作证明联系起来:**

```bash
thub run --type sw --download-file "$IMAGE_URL" --command ./ci/test.sh \
  --meta ciJobId="$GITHUB_RUN_ID" --wait
thub status A-00123 --json | jq '.spec.meta.ciJobId'
```

**通过额外的元数据** —— 说 `--meta key=value` 到达命令为 `THUB_META_<KEY>` (单位:千美元)`ciJobId` → `THUB_META_CI_JOB_ID`) (中文(简体) ).

**管道干燥** 校对:Soup

```bash
thub run --type sw --download-file https://does-not-exist.invalid/app.bin \
  --command ./ci/test.sh --dry-run --wait
```

**在资源组中运行 :** 没有 `--group` 选项。 管理员或维护者在仪表板上给用户一个组(或一个CI标志),它提交的每一项工作只运行在该组的资源上; `thub whoami` 显示它.

**保留 a 董事会** 在它上,没有管道 取它之间的跑道: `thub reserve lab-hw-01 --for 2h`。在那之前,排程器只给 lab-hw-01 工作(`thub run --client lab-hw-01 …`);其他人去另一个跑者或等待. `thub release lab-hw-01` 提前还给它,否则它会在时间到来时自由自在——一个仍在运行的工作会不停地运行. `--for` 需要整个时间(`30m`, (中文(简体) ), `2h`最高可达跑跑跑跑跑跑跑跑跑跑跑跑跑跑跑跑跑跑跑跑跑跑跑跑跑跑跑跑跑跑跑跑跑跑跑跑跑跑跑跑跑跑跑跑跑跑跑跑跑跑跑跑跑跑跑跑跑跑跑跑跑跑跑跑跑跑跑跑跑跑跑跑跑跑跑跑跑跑跑跑跑跑跑跑跑跑跑跑跑跑跑跑跑跑跑跑跑跑跑跑跑跑跑跑跑跑跑跑跑跑跑跑跑跑跑跑跑跑跑跑跑跑跑跑跑跑跑跑跑跑跑跑跑跑跑跑跑跑跑跑跑跑跑跑跑跑跑跑跑跑跑跑跑跑跑跑跑跑跑跑跑跑跑跑跑跑跑跑跑跑跑跑跑跑跑跑跑跑跑跑跑跑跑跑跑跑跑跑跑跑跑跑跑跑跑跑跑跑跑跑跑跑跑跑跑跑跑跑跑跑跑跑跑跑跑跑跑跑跑跑跑跑跑跑跑跑跑跑跑跑跑跑跑跑跑跑跑跑跑跑跑跑跑跑跑跑跑跑跑跑跑跑. `thub resources` 显示谁持有什么。 需要用户的密钥——CI符不能保留.

**您的UART和社署:** `thub connect lab-hw-01 --target stm32f4x` 保持与保留板的实时连接, 并打印链接和每个设备的本地端口: UART 1 on `127.0.0.1:5001` (和上; `--uart-port`),ST-Link 1的GDB服务器打开 `127.0.0.1:3333` (和上; `--gdb-port`(b) —— `arm-none-eabi-gdb -ex "target extended-remote 127.0.0.1:3333"`, (中文(简体) ), `socat -,raw,echo=0 TCP:127.0.0.1:5001`, 或 pyserial's , 或 pyserial's , 或 pyserial's , 或 pyserial's `socket://127.0.0.1:5001`。每个 GDB 连接在客户端上启动自己的 OpenOCD `target/<name>.cfg` (单位:千美元)`--target`,否则探测器的OpenOCD目标设定在跑道卡上. `thub console lab-hw-01 --uart 1` 将一个 UART 放在您的终端( Ctrl -)\] 退出 。 一个被丢弃的连接由自己再次实现(一个UART端口通过它保持连接,GDB必须重新连接);会话以保留结束. 每项保留都有其本身的联系(`thub reserve` 打印: 稍后再保留 `thub connect` 再次为新的.

如果默认的本地端口之一已经在使用中, `thub connect` 自动指定 UART、GDB 或相机监听器一个可用的端口,并报告实际地址。 如果您自己指定了端口 `--uart-port`, (中文(简体) ), `--gdb-port` 或者说 `--video-port`,冲突仍然是个错误.

**看着板子:** 带USB相机的跑道上(标签) `video-stream`),它的溪流始于你的预定,和 `thub connect` 打印该保留的本地链接—— `http://127.0.0.1:8090/<reservation id>/video.ts` (单位:千美元)`--video-port`用于VLC、ffplay或mpv; `--video-udp 5600` 作为UDP发送到 `udp://127.0.0.1:5600`。 。 。 .

**转发客户端- 主机服务 :** `thub connect lab-hw-01 --forward "Web UI=3000"` 打开本地的 TCP 端口,将交通载至 `127.0.0.1:3000` 在保留客户端主机上。 代理选择并打印其本地端口; 多个 `--forward "name=port"` 选项被支持。 客户端只连接到自己的回路接口,前端在 `thub connect` 或保留结束.

**读取 SEGGER RTT 日志 :** `thub connect lab-hw-01 --rtt 1=0x20000000,0x10000,0,stm32g4x` 搜索给定的 RAM 区域用于RTT 控制块,并打开本地只读的 TCP 听器用于上行道 0 。 可选频道默认为0;可选的OpenOCD目标会超越ST-Link所配置的目标. 重复 `--rtt` 为其他ST-Links。 RTT只使用OpenOCD和所选的ST-Link,直到本地阅读器断开,所以不要同时使用GDB的探测器.

**机器可读输出.** `--json` 打开 `resources`, (中文(简体) ), `jobs`, (中文(简体) ), `status`, (中文(简体) ), `reserve`, (中文(简体) ), `release`, (中文(简体) ), `power` 财务报告和审定财务报表 `whoami` 打印 JSON 而不是文本. `thub connect --json` 指纹 **邓杰森** 在 stdout 上, 用于会话之后的工具( 人类信息仍为 stderr ):

-   第一个 `{"event":"ready","client":…,"link":…,"until":…,"ports":[…],"forwards":[…],"video":…}`,一旦董事会客户端链接;
-   然后每变一行: `status` (单位:千美元)`waiting` 编号 : `ready`, (中文(简体) ), `disconnected` (单位:千美元)`retryMs`, (中文(简体) ), `reason`, (中文(简体) ), `connected` (单位:千美元)`again`, (中文(简体) ), `video` (单位:千美元)`streaming`, (中文(简体) ), `error`(三);
-   `fatal` (单位:千美元)`message`)在退出前,例如保留结束时(退出代码4).

**在VS代码中:** 页:1 [vS 代码的 thub](https://marketplace.visualstudio.com/items?itemName=adsystem-pro.thub-vscode) 扩展从编辑器中进行所有这一切:保留,闪出(也是在每次构建之后),通过 Cortex-Debug,串行终端和相机调试. 它在下面运行这个特工,所以先安装特工.

**谁提交了工作** 来源于您的密钥: 您的用户名( CI 代号: 它的名字), 显示在仪表板上, in `thub jobs`在客户端控制台上 `JOB_USER`没有 `--user`。 。 。 .

## 环境变量和秘密

`--env NAME=value[,NAME=value]` (可重复)为 `--command`。这就是所有的数据和秘密如何到达一个工作(一个git sident,一个注册密码,一个API密钥). 名字是你的,对代理人和客户都无意义. `--env NAME` 仅从自己的环境取取出价值,所以一个秘密在命令行之外和CI日志之外:

```bash
export API_TOKEN=…
thub run --type sw \
  --env TARGET=staging --env API_TOKEN \
  --command './run-tests.sh --target "$TARGET"' --wait
```

**如何将数值保密:**

-   他们到达 **只有运行此任务的客户端**。 。 。 .
-   代理 API 显示每个值为 `***`数字 : `thub status --json`, (中文(简体) ), `thub jobs --json`甚至为了你自己的工作 仪表盘只列出名字.
-   协调员将数值改为: `***` 一旦工作结束.
-   A 类 `--dry-run` 显示每个值为 `***`,无论它的名字.

你的命令输出是工作日志,所以不要打印机密. 其它的都一样.. `--command`, (中文(简体) ), `--arg`, (中文(简体) ), `--meta`, (中文(简体) ), `--download-file` - 保存的和可见的, 所以永远不要把秘密在那里.

## 图形

客户端不克隆任何东西( 也不需要自定义 ) : 命令确实复制到其工作目录中, 并带有来自 `--env`数字 :

```bash
export GH_TOKEN=…
thub run --type sw --env GH_TOKEN,REF=main \
  --command 'git clone --depth 1 --branch "$REF" "https://x-access-token:$GH_TOKEN@github.com/yourorg/tests.git" src && cd src && ./ci/test.sh' --wait
```

对于 SSH , 通过私钥本身为 `--env` (基数64)并通过 `GIT_SSH_COMMAND` 从任务目录中的文件中删除,随任务一起删除(主 README, 第7.2节).

## 夹克

客户端不拉出图像或启动容器(也不需要多克自己):命令确实如此.

**登录到自定义登记册 :** 内 `--command`,通过全权证书作为 `--env` 以任何名称。 点 `DOCKER_CONFIG` 首先在任务的工作目录中,所以登录会随任务被删除而不是留在客户端用户的 `~/.docker` 用于以后的工作:

```bash
export DOCKER_PASSWORD=…
thub run --type hw \
  --env DOCKER_REGISTRY=registry.lab.local:5000,DOCKER_USER=ci --env DOCKER_PASSWORD \
  --command 'echo "$DOCKER_PASSWORD" | docker login "$DOCKER_REGISTRY" --username "$DOCKER_USER" --password-stdin &&
             docker pull "$DOCKER_REGISTRY/team/test-runner:1.4"' \
  --wait
```

**在容器内运行命令 :** `--command` 在任务目录中的客户端主机上启动( T)`$THUB_WORK_DIR`) (中文(简体) ). 克隆进 `src/`,然后只启动容器安装 `src/` (目录还载有 `.docker/`,任务注册登录:

```bash
thub run --type sw \
  --env DOCKER_REGISTRY=registry.lab.local:5000,DOCKER_USER=ci --env DOCKER_PASSWORD --env GH_TOKEN \
  --command 'git clone --depth 1 "https://x-access-token:$GH_TOKEN@github.com/yourorg/web-ui-tests.git" src && cd src &&
             echo "$DOCKER_PASSWORD" | docker login "$DOCKER_REGISTRY" --username "$DOCKER_USER" --password-stdin &&
             docker run --rm --user "$(id -u):$(id -g)" -v "$THUB_WORK_DIR/src:/work" -w /work "$DOCKER_REGISTRY/python:3.14" ./run-tests.sh' \
  --wait
```

**克隆和在容器内测试,配有部署密钥和登记册登录号 `--env`** (向工作传递数据和秘密的参考实例):

```bash
# In CI, from its secret store — never typed on the command line:
export THUB_KEY=…                              # a CI token (dashboard → CI tokens)
export DOCKER_PASSWORD=…                       # the registry password
export GIT_KEY="$(cat ~/.ssh/thub_deploy)"     # a private deploy key with read access to the repository

thub run --type sw \
  --env DOCKER_REGISTRY=registry.lab:5000,DOCKER_USERNAME=ci-reader \
  --env DOCKER_PASSWORD --env GIT_KEY \
  --command 'echo "$DOCKER_PASSWORD" | docker login "$DOCKER_REGISTRY" --username "$DOCKER_USERNAME" --password-stdin &&
             mkdir -p "$THUB_WORK_DIR/src" &&
             docker run --rm -e GIT_KEY -e HOME=/tmp --user "$(id -u):$(id -g)" \
               -v "$THUB_WORK_DIR/src:/work" -w /work --entrypoint sh alpine/git -c "
               eval \$(ssh-agent -s) > /dev/null &&
               printf \"%s\n\" \"\$GIT_KEY\" | ssh-add - &&
               GIT_SSH_COMMAND=\"ssh -o StrictHostKeyChecking=accept-new\" git clone --depth 1 git@bitbucket.org:yourorg/web-ui-tests.git . &&
               ./run-tests.sh"' \
  --wait
```

普通值为 `--env NAME=value`,秘密为 `--env NAME` (取自您的环境,所以永远不要在命令行;多行值到达完好无损). 内部剧本 `\$` 在容器中扩大; `ssh-agent` 仅将密钥保存在内; `--entrypoint sh` 因为 `alpine/git`的切入点是 `git`· ; `--user` 保留客户端可删除的克隆。 仅 `src/` 已挂载,所以注册登录(客户端的) `DOCKER_CONFIG`, (中文(简体) ), `$THUB_WORK_DIR/.docker`远离集装箱。 更多在主要研究中,第7.2节.

客户端主机需要 Docker 和客户端的用户在 `docker` 组合这些( 在客户端前安装 Docker) 。 添加 `--dry-run` 以查看一个任务会在客户端上运行的每个命令(每个命令) `--env` 显示为 `***`没有运行任何。 更多在主要研究中,第7.2节.

## 客户环境变量

在客户端,工作 `--command` 获得所有选项作为 `JOB_<NAME>` 变量( **在客户端上** 页:1 未给出选项的变量是未设置的 。 可重复选项给出 `<NAME>` 包含所有值加 `<NAME>_<n>` 每个。 这也得到了:

-   联合国 `--env` (一) 变量,以其自己的名称;
-   `THUB_JOB_ID`, (中文(简体) ), `THUB_WORK_DIR` (在它运行的地方), `THUB_DOWNLOADS_DIR`, (中文(简体) ), `THUB_DOWNLOADS`, (中文(简体) ), `THUB_DOWNLOAD_<n>` (当地路径)和 `THUB_META_<KEY>`. HW装置用于: `/dev/thub/dut<N>-uart|usb|stlink` 路径; 没有通过设备变量.

`THUB_*` 财务报告和审定财务报表 `JOB_*` 无法设置名称 `--env`. 完整列表在主README, 第7.4节.

```bash
thub run --type hw --label uart --suite smoke --command 'echo "suite $JOB_SUITE on $JOB_LABEL" && ./ci/test.sh' --wait
```

## 就业状况和PAS/FAIL

判决是 `--command`退出代码 : `0` → **已通过**任何其它东西 **失败**错误 时间过后 失去和CANCELED 意味着这份工作没有被判决 JUnit XML 写入 `results/` 或者说 `artifacts/` 在工作目录中被归纳为工作 `summary` 由客户代理。 无内容被上传: 任务的文件停留在客户端的工作空间中, 当它结束时删除 —— 发布任何您需要保存的文件 `--command`,例如到艺术.

**在CI中:** `thub run … --wait` 带有判决代码的退出(上表): `0` 通过, `1` 失败, `2` 基础设施, `3` 取消了 .

**检查工作 :**

```bash
thub status M-00125          # state; follows the log while active; then "Verdict: …" and test counts; exit = verdict
thub jobs --mine --state FAILED
```

**从脚本 :** `thub status <jobId> --json` 打印工作一次,使用 `state`, (中文(简体) ), `exit_code`, (中文(简体) ), `summary`, (中文(简体) ), `message` 财务报告和审定财务报表 `resource.name`以判决代码退出,或 `5` 任务仍在排队或运行时 :

```bash
JOB=$(thub run --type sw --command ./ci/test.sh --detach --json | jq -r .jobId)
while thub status "$JOB" --json > job.json; [ $? -eq 5 ]; do sleep 10; done
jq -r '"\(.state) exit=\(.exit_code) failed=\(.summary.failed // 0)"' job.json   # PASSED exit=0 failed=0
```

## CI/CD: GitHub Actions, GitLab, Bitbucket, Jenkins (中文(简体) )

每个 CI 系统的工作方式相同: 存储一个 CI 符号( dashboard ~ CI 符号) 作为密件 `THUB_KEY`设置 `THUB_URL`运行 `thub run … --wait` 跑道上有24号节点 该步骤的出站代码是判决. 设定 `THUB_NO_SELF_UPDATE=1` 在短命的跑者.

### GitHub 动作

TestHub 动作在一步内完成:步骤中的任务日志, 包含每个测试的作业摘要, 牵引请求注释( 核查、 棋盘、 时间、 日志链接; 重运行时更新) 和可选的承诺状态 :

```yaml
- uses: andrianyablonskyy/thub-action@v1
  with:
    url: https://thub.example.com
    key: ${{ secrets.THUB_CI_TOKEN }}
    type: hw
    labels: board:nucleo-f401re
    download-files: ${{ needs.build.outputs.image_url }}
    command: st-flash --reset write "$THUB_DOWNLOAD_1" 0x08000000 && ./ci/hw-tests.sh
```

它留下的公关评论:

```
### ❌ TestHub HW smoke: FAILED
| Job      | A-00042                                   |
| Result   | FAILED (exit code 1)                      |
| Board    | nucleo-f401re on lab-hw-01                |
| Tests    | 42 total · 40 passed · 2 failed · 0 skipped |
| Duration | 3m 12s (queued 20s)                       |
| Commit   | abcdef1                                   |
| Links    | Job page and full log · Workflow run      |
▸ Failed tests (2)
```

在以后的步骤中使用其产出:

```yaml
      - id: thub
        uses: andrianyablonskyy/thub-action@v1
        with:
          url: https://thub.example.com
          key: ${{ secrets.THUB_CI_TOKEN }}
          type: hw
          labels: board:nucleo-f401re
          command: ./ci/hw-tests.sh
      - if: always() && steps.thub.outputs.job-id
        run: |
          echo "TestHub ${{ steps.thub.outputs.job-id }} on ${{ steps.thub.outputs.client }}: ${{ steps.thub.outputs.state }}"
          echo "${{ steps.thub.outputs.passed }}/${{ steps.thub.outputs.total }} tests passed in ${{ steps.thub.outputs.duration-sec }} s"
          echo "Log: ${{ steps.thub.outputs.job-url }}"
```

只能悄悄地报告 判决为犯罪状态:

```yaml
      - uses: andrianyablonskyy/thub-action@v1
        with:
          url: https://thub.example.com
          key: ${{ secrets.THUB_CI_TOKEN }}
          type: sw
          command: ./ci/sw-tests.sh
          fail: false
          comment: on-failure
          commit-status: true
```

完成工作流程、每一项投入以及 PR 评论和测试表的工作方式 [th-动作读取器](https://github.com/andrianyablonskyy/thub-action#readme) 和主要读取法第11.1条.

与特工直接:

```yaml
test-sw:
  needs: build
  runs-on: ubuntu-latest
  env:
    THUB_URL: https://thub.example.com
    THUB_KEY: ${{ secrets.THUB_CI_TOKEN }}   # a CI token (dashboard → CI tokens)
  steps:
    - run: |
        npx -y @andrian.yablonskyy/thub-agent run --type sw \
          --download-file "${{ needs.build.outputs.image_url }}" \
          --env GH_TOKEN="${{ secrets.TESTS_READ_TOKEN }}",REPO="$GITHUB_REPOSITORY",SHA="$GITHUB_SHA" \
          --command 'git init -q src && cd src && git fetch -q --depth 1 "https://x-access-token:$GH_TOKEN@github.com/$REPO.git" "$SHA" &&
                     git checkout -q FETCH_HEAD && ./ci/sw-tests.sh' --suite full --wait
```

单位 `--wait` 模式, `SIGINT` 财务报告和审定财务报表 `SIGTERM` (GitHub,GitLab和Jenkins如何停止取消一步) 让特工取消工作(`POST /jobs/:id/cancel`) 出道前,因此被废弃的CI任务不持有硬件. 在交互模式下, Ctrl- C 只能去除.

### GitLab CI/光盘

```yaml
test-hw:
  image: node:24
  variables: { THUB_URL: https://thub.example.com, THUB_NO_SELF_UPDATE: "1" }   # THUB_KEY: a masked CI/CD variable
  script:
    - |
      npx -y @andrian.yablonskyy/thub-agent run --type hw --label board:nucleo-f401re --download-file "$IMAGE_URL" \
        --env CI_JOB_TOKEN --env CI_SERVER_HOST --env CI_PROJECT_PATH --env CI_COMMIT_SHA \
        --command 'git init -q src && cd src &&
                   git fetch -q --depth 1 "https://gitlab-ci-token:$CI_JOB_TOKEN@$CI_SERVER_HOST/$CI_PROJECT_PATH.git" "$CI_COMMIT_SHA" &&
                   git checkout -q FETCH_HEAD && ./ci/hw-tests.sh' \
        --wait --meta pipelineUrl="$CI_PIPELINE_URL"
```

### 点球管

```yaml
- step:
    name: HW tests
    image: node:24
    script:   # repository variables: THUB_URL, THUB_KEY (secured), TESTS_TOKEN (a repository access token)
      - >-
        npx -y @andrian.yablonskyy/thub-agent run --type hw --download-file "$IMAGE_URL"
        --env TESTS_TOKEN --env BITBUCKET_REPO_FULL_NAME --env BITBUCKET_COMMIT
        --command 'git init -q src && cd src &&
        git fetch -q --depth 1 "https://x-token-auth:$TESTS_TOKEN@bitbucket.org/$BITBUCKET_REPO_FULL_NAME.git" "$BITBUCKET_COMMIT" &&
        git checkout -q FETCH_HEAD && ./ci/hw-tests.sh' --wait
```

### 詹金斯(英语:

```groovy
stage('HW tests') {
  agent { docker { image 'node:24' } }
  environment {
    THUB_URL = 'https://thub.example.com'
    THUB_KEY = credentials('thub-ci-token')          // Secret text
    NPM_CONFIG_CACHE = "${env.WORKSPACE}/.npm"
  }
  steps {
    sh '''
      npx -y @andrian.yablonskyy/thub-agent run --type hw --download-file "$IMAGE_URL" \
        --command './ci/hw-tests.sh' --wait --meta buildUrl="$BUILD_URL"
    '''
  }
}
```

完整的管线——建造,测试,以及把JUnit报告带回GitLab, Bitbucket或Jenkins——在主要README, 第11节,以及仪表板的帮助中.

### 合并/推请评论:GitLab、Bitbucket、Jenkins

`thub report <jobId>` gitHub 动作留下同样的报告 : 判断、 棋盘、 客户端、 持续时间、 测试、 测试失败、 以及与工作日志和管道的链接 . `--post gitlab|bitbucket|github` 将其保留为对合并/拉动请求的一个注释,由以后的每一个运行更新,以及 `--commit-status` 设置任务状态,与任务连接。 以 `thub run --id-file`,并报告步骤 运行任何结果.

GitLab,带有项目访问符号(`api` 范围, 报告者), 在被遮蔽的变量中 `GITLAB_TOKEN`数字 :

```yaml
# .gitlab-ci.yml
test-hw:
  stage: test
  image: node:24
  rules:
    - if: $CI_PIPELINE_SOURCE == "merge_request_event"     # CI_MERGE_REQUEST_IID: the MR to comment on
    - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH            # status only (a branch pipeline's open MR, if any, is found by commit)
  variables:
    THUB_URL: https://thub.example.com                       # THUB_KEY, GITLAB_TOKEN: masked CI/CD variables
    THUB_NO_SELF_UPDATE: "1"
  before_script:
    - npm i -g @andrian.yablonskyy/thub-agent
  script:
    - thub run --type hw --label board:nucleo-f401re --download-file "$IMAGE_URL"
        --command './ci/hw-tests.sh' --suite smoke --timeout 30m --wait --id-file .thub-job
        --meta pipelineUrl="$CI_PIPELINE_URL"
  after_script:                                              # runs after failures and cancels too
    - '[ -s .thub-job ] && thub report "$(cat .thub-job)" --post gitlab --commit-status --title "HW smoke"'
```

Bitbucket Cloud, 安全变量中有寄存器访问符( Pull request: Write) `BITBUCKET_TOKEN`数字 :

```yaml
# bitbucket-pipelines.yml
image: node:24
pipelines:
  pull-requests:
    '**':
      - step:
          name: HW tests
          max-time: 60
          script:                                            # THUB_URL, THUB_KEY, BITBUCKET_TOKEN: repository variables
            - export THUB_NO_SELF_UPDATE=1
            - npm i -g @andrian.yablonskyy/thub-agent
            - thub run --type hw --label board:nucleo-f401re --command './ci/hw-tests.sh' --suite smoke --timeout 30m --wait --id-file .thub-job
          after-script:                                      # runs whether the step passed or failed
            - '[ -s .thub-job ] && thub report "$(cat .thub-job)" --post bitbucket --commit-status --title "HW smoke"'
```

Jenkins, Bitbucket 数据中心, 每一个 `thub report` 选项,并且每个代码主机的 CI 变量为: 主 README, 第11.5.

## 测试框架和PR评论

判决是指挥部的出局代码. 测试计数来自命令所写的 JUnit XML `results/` (或 `artifacts/`,或者将一个文件夹降下:

```bash
--command '… ./build/uart_tests --gtest_output=xml:results/ …'                          # GoogleTest
--command '… ctest --test-dir build --output-junit "$PWD/results/ctest.xml" …'          # CTest (absolute path)
--command '… pytest tests/ --junitxml=results/pytest.xml -o junit_family=xunit2 …'      # pytest
--command '… mvn -B test; rc=$?; mkdir -p results && cp target/surefire-reports/TEST-*.xml results/; exit $rc'   # JUnit / Maven
```

拥有 **每个测试案例** 在 PR/MR 注释中,请命令公布 XML 并将其列为文物(`ci/publish-junit.sh`) (中文(简体) ). GitHub 动作或 `thub report --artifact-header …` 然后把它捡起来。 完整的例子,包括有pytest的硬件即用:主README 第7.6.

## 人工活性存储

`--download-file` 一个普通的,匿名的。 对于私人存储,要么通过一个短寿命签名的URL(`aws s3 presign …`),或获取文件进入 `--command` 全权证书以 `--env`。输出由命令上传并列出于 `$THUB_ARTIFACTS_FILE`数字 :

```bash
thub run --type sw --env ART_TOKEN \
  --command './ci/test.sh; rc=$?
             curl -fsS -H "Authorization: Bearer $ART_TOKEN" -T results/junit.xml "https://artifactory.example.com/qa/$THUB_JOB_ID/junit.xml"
             exit $rc' --wait
```

主要的README, 第7.5节, 以及仪表板的帮助 都有Artifactory, AWS S3, Google Drive (rclone), FTP/FTPS/SFTP, 以及自定义的 HTTP 认证( 承担者, API 密钥, 基础, ) 的例子 , `.netrc`,相互TLS,OAuth2).

更多认证方式, 在主 README 和仪表板的帮助 :

-   **通过 HTTPS 下载 :** 私人CA(`NODE_EXTRA_CA_CERTS` )和客户证书(`curl --cert` 内 `--command`· ; `--download-file` 无法呈现). 见7.5节.
-   **艺术:** 被放入范围,短寿命访问符每CI运行刻出,JFrog CLI,并签名URL. 见7.5节.
-   **通过 SSH :** 部署密钥加被钉 `known_hosts`,两个都通过 `--env`。见第7.2节.
-   **`docker login`数字 :** 您自己的注册, Artifacty, ghcr, GitLab, Docker Hub, ECR, Google Artifact Register and ACR. 见 第7.2节.

## 发展

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

## 许可证

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

## 常见问题

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

TestHub Agent CLI — CI/CD 和开发者用来提交和跟踪测试任务的单一切入点

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

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

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

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

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

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

### @andrian\.yablonskyy/thub-agent 需要什么版本的 Node\.js？

package\.json 的 engines 字段要求 Node\.js \>=24。版本不符时 npm 默认只给出警告，开启 engine-strict 后会拒绝安装。

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

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

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

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

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

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

