@andrian.yablonskyy/thub-agent 1.1.22 → 1.1.24
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/RELEASE.md +48 -0
- package/package.json +2 -2
- package/src/cli.js +16 -5
package/RELEASE.md
CHANGED
|
@@ -2,8 +2,56 @@
|
|
|
2
2
|
|
|
3
3
|
What changed in each release, newest first. `## Unreleased` collects the changes since the version on npm; `bin/publish` turns that heading into the version and date it releases.
|
|
4
4
|
|
|
5
|
+
## 1.1.24 — 2026-10-16
|
|
6
|
+
|
|
7
|
+
### Added
|
|
8
|
+
|
|
9
|
+
- **`thub connect --json` streams NDJSON events** for tools such as the VS Code extension. The first line is `{"event": "ready", …}`: the same object as before, with `event` added, so existing readers still work. Then there's one line per change:
|
|
10
|
+
- `status` (`waiting` / `ready`, with the reservation's end);
|
|
11
|
+
- `disconnected` (retry delay, reason) and `connected` (`again`);
|
|
12
|
+
- `video` (the camera streams, or why not);
|
|
13
|
+
- `fatal` (e.g. *The reservation ended*), just before it exits.
|
|
14
|
+
|
|
15
|
+
The human messages still go to stderr.
|
|
16
|
+
- **`thub whoami --json`**: whose key it is (`kind`, `user` or `name`, `group`), as the Agent API's `/me` returns it.
|
|
17
|
+
|
|
18
|
+
## 1.1.23 — 2026-10-15
|
|
19
|
+
|
|
20
|
+
### Changed
|
|
21
|
+
|
|
22
|
+
- Requires thub-common 2.2.4.
|
|
23
|
+
|
|
24
|
+
## 1.1.22 — 2026-10-15
|
|
25
|
+
|
|
26
|
+
### Changed
|
|
27
|
+
|
|
28
|
+
- **`thub connect` shows the camera's state.** The Video line says whether the board's camera is streaming, and if not, why, for example `(not streaming — ffmpeg isn't installed on this Client host …)`. Each change is printed as it happens (`Video: streaming`, `Video: not streaming — …`), with no viewer needed. Needs Client 1.1.26.
|
|
29
|
+
|
|
30
|
+
## 1.1.21 — 2026-10-15
|
|
31
|
+
|
|
32
|
+
### Fixed
|
|
33
|
+
|
|
34
|
+
- **`thub connect` and `thub console` behind a proxy without WebSocket support** stop with the reason instead of retrying forever: *The Coordinator answered HTTP 302 → /login instead of opening a WebSocket: a reverse proxy in front of the Coordinator isn't passing WebSocket upgrades …* The same goes for `426` (Coordinator 1.1.41). Other refusals (`401`, `403`, `404`, `409`) were already final.
|
|
35
|
+
|
|
5
36
|
## 1.1.20 — 2026-10-15
|
|
6
37
|
|
|
38
|
+
### Added
|
|
39
|
+
|
|
40
|
+
- **`thub reserve <client> [--for <dur>]`** holds a runner for your own jobs (README §5.5).
|
|
41
|
+
- **Duration:** whole minutes (`30m`, `2h`; 1 h by default), up to the runner's maximum. Running it again extends the reservation from now.
|
|
42
|
+
- **Output:** the end time, how to use the runner, and the reservation's own remote access link.
|
|
43
|
+
- **Release:** **`thub release <client>`** ends it; maintainers and admins can end anyone's.
|
|
44
|
+
- **`thub resources`** has a RESERVED column (who, until when). With `--json`, each runner has its `reservation`, and for your own reservation its `id` and `link`.
|
|
45
|
+
- **`thub connect <client>`** keeps a live connection to your reserved board (README §5.6) and prints that reservation's link and a local port per device:
|
|
46
|
+
- **UARTs:** `127.0.0.1:5001` and up (`--uart-port`), for socat, picocom or pyserial's `socket://`.
|
|
47
|
+
- **ST-Links:** a GDB port each, `127.0.0.1:3333` and up (`--gdb-port`). Each connection starts its own OpenOCD on the Client; `--target <name>` gives the OpenOCD target.
|
|
48
|
+
- **Camera:** if the board has one (README §5.7), `http://127.0.0.1:8090/<reservation id>/video.ts` (`--video-port`) for VLC, ffplay or mpv. The URL is that reservation's own. `--video-udp <port>` also sends it as UDP.
|
|
49
|
+
- **Reconnecting:** it reconnects by itself (1 s, 2 s … 30 s). Serial terminals and video viewers stay connected through a reconnect; GDB has to connect again.
|
|
50
|
+
- **Exiting:** it exits with the reason when the reservation ends.
|
|
51
|
+
- **Options:** `--bind` and `--json`.
|
|
52
|
+
- **`thub console <client> [--uart <n>]`** puts one UART of your reserved board in the terminal. Ctrl-] quits.
|
|
53
|
+
- New dependency: `ws` 8.21.3.
|
|
54
|
+
|
|
7
55
|
### Changed
|
|
8
56
|
|
|
9
57
|
- Requires thub-common 2.2.3.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@andrian.yablonskyy/thub-agent",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.24",
|
|
4
4
|
"description": "TestHub Agent CLI — the single entry point CI/CD and developers use to submit and follow test jobs",
|
|
5
5
|
"license": "SEE LICENSE IN LICENSE.md",
|
|
6
6
|
"author": "Andrian Yablonskyy <andrian.yablonskyy@gmail.com>",
|
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
"lint:fix": "eslint . --fix"
|
|
16
16
|
},
|
|
17
17
|
"dependencies": {
|
|
18
|
-
"@andrian.yablonskyy/thub-common": "^2.2.
|
|
18
|
+
"@andrian.yablonskyy/thub-common": "^2.2.4",
|
|
19
19
|
"commander": "^13.1.0",
|
|
20
20
|
"ws": "8.21.3"
|
|
21
21
|
},
|
package/src/cli.js
CHANGED
|
@@ -487,7 +487,7 @@ program
|
|
|
487
487
|
.option('--bind <address>', 'Local address to listen on (another than loopback shares the board with your network)', '127.0.0.1')
|
|
488
488
|
.option('--video-port <port>', 'Local HTTP port of the board\'s USB camera stream, if it has one', (v) => Number(v), 8090)
|
|
489
489
|
.option('--video-udp <port>', 'Also send the camera stream as UDP (MPEG-TS) to this local port, e.g. 5600', (v) => Number(v))
|
|
490
|
-
.option('--json', '
|
|
490
|
+
.option('--json', 'NDJSON on stdout: "ready" with the ports once connected, then status/disconnected/connected/video/fatal events', false)
|
|
491
491
|
.action(async (name, opts) => {
|
|
492
492
|
try {
|
|
493
493
|
if (opts.target !== undefined && !OPENOCD_TARGET_RE.test(opts.target)){
|
|
@@ -500,7 +500,16 @@ program
|
|
|
500
500
|
}
|
|
501
501
|
}
|
|
502
502
|
const session = await remoteSession(name),
|
|
503
|
-
log = (m) => console.error(m)
|
|
503
|
+
log = (m) => console.error(m),
|
|
504
|
+
// --json: NDJSON on stdout — `ready` (the ports, below), then one line
|
|
505
|
+
// per change, for tools such as the VS Code extension. The human
|
|
506
|
+
// messages still go to stderr.
|
|
507
|
+
emit = opts.json ? (e) => console.log(JSON.stringify(e)) : () => {};
|
|
508
|
+
session.on('status', (st) => emit({ event: 'status', state: st.state, client: st.client, until: st.until }));
|
|
509
|
+
session.on('disconnected', ({ retryMs, reason }) => emit({ event: 'disconnected', retryMs, reason: reason || null }));
|
|
510
|
+
session.on('connected', ({ again }) => emit({ event: 'connected', again }));
|
|
511
|
+
session.on('fatal', (message) => emit({ event: 'fatal', message }));
|
|
512
|
+
session.on('devices', (d) => d.camera && emit({ event: 'video', streaming: Boolean(d.camera.streaming), error: d.camera.error || null }));
|
|
504
513
|
let listening = null,
|
|
505
514
|
until = null;
|
|
506
515
|
const cleanup = () => {
|
|
@@ -564,7 +573,7 @@ program
|
|
|
564
573
|
function printConnection(name, link, until, ports, devices, opts, video){
|
|
565
574
|
if (opts.json){
|
|
566
575
|
return console.log(JSON.stringify({
|
|
567
|
-
client: name, link, until, ports: ports.map((p) => ({ kind: p.kind, ...p.device, host: opts.bind, port: p.port })),
|
|
576
|
+
event: 'ready', client: name, link, until, ports: ports.map((p) => ({ kind: p.kind, ...p.device, host: opts.bind, port: p.port })),
|
|
568
577
|
video: video ? { camera: devices.camera.name, url: video.url, udp: video.udp } : null
|
|
569
578
|
}));
|
|
570
579
|
}
|
|
@@ -730,9 +739,11 @@ function describeMe(me){
|
|
|
730
739
|
program
|
|
731
740
|
.command('whoami')
|
|
732
741
|
.description('Show whose access key this Agent uses')
|
|
733
|
-
.
|
|
742
|
+
.option('--json', 'Machine-readable output', false)
|
|
743
|
+
.action(async (opts) => {
|
|
734
744
|
try {
|
|
735
|
-
|
|
745
|
+
const me = await client().get('/me');
|
|
746
|
+
console.log(opts.json ? JSON.stringify(me) : describeMe(me));
|
|
736
747
|
}
|
|
737
748
|
catch (err){
|
|
738
749
|
fail(err);
|