@thinremote/thinr-cli 1.5.0 → 1.6.1
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/CHANGELOG.md +113 -0
- package/README.md +167 -120
- package/bin/thinr.js +3 -58
- package/commands/_shared.js +1 -0
- package/commands/{device/update.js → agent/device.js} +10 -26
- package/commands/agent/fleet.js +254 -0
- package/commands/agent/index.js +79 -0
- package/commands/device/console.js +1 -1
- package/commands/device/exec.js +1 -1
- package/commands/device/fs.js +6 -6
- package/commands/device/index.js +4 -6
- package/commands/device/logs.js +1 -1
- package/commands/device/proxy.js +15 -6
- package/commands/device/status.js +1 -1
- package/commands/device/transfer.js +2 -2
- package/commands/product/exec.js +1 -1
- package/commands/product/fs.js +3 -3
- package/commands/product/index.js +5 -4
- package/commands/product/logs.js +35 -36
- package/commands/product/metric.js +24 -14
- package/commands/product/playbook.js +10 -5
- package/commands/product/property.js +4 -14
- package/commands/product/push.js +1 -1
- package/commands/product/resource.js +56 -56
- package/commands/product/status.js +1 -1
- package/docs/guides/thinremote-metrics-logs.md +21 -22
- package/docs/guides/thinremote-playbooks.md +15 -11
- package/docs/guides/thinremote-scripts.md +11 -10
- package/docs/guides/thinremote.md +53 -42
- package/lib/agent-releases.js +1 -1
- package/lib/cli.js +172 -0
- package/lib/constants.js +1 -1
- package/lib/guides.js +1 -1
- package/lib/identity.js +8 -6
- package/lib/mcp/{tools-exec.js → device-exec.js} +84 -55
- package/lib/mcp/helpers.js +2 -2
- package/lib/mcp/resource-hooks.js +104 -6
- package/lib/mcp/resource-types.js +114 -227
- package/lib/playbook/actions.js +1 -1
- package/lib/playbook/schema.js +1 -1
- package/lib/product/log-presets.js +1 -1
- package/lib/product.js +26 -0
- package/package.json +2 -2
- package/commands/fleet/index.js +0 -17
- package/commands/fleet/upgrade.js +0 -275
- package/lib/mcp/registry.js +0 -12
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,118 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [1.6.1] - 2026-10-31
|
|
4
|
+
|
|
5
|
+
### Fixed
|
|
6
|
+
|
|
7
|
+
- `thinr device tcp|tls|http -p` is described as what it is: the port
|
|
8
|
+
of the relay on the server (random between 50000 and 51000 by default),
|
|
9
|
+
not a local port.
|
|
10
|
+
- From `@thinger-io/cli-core` 0.5.1: the browser login on a server that does
|
|
11
|
+
not know the CLI's OAuth client says so and offers username and password
|
|
12
|
+
or a token, and the host `update_settings` action is described as the
|
|
13
|
+
merge the server does.
|
|
14
|
+
- Requires `@thinger-io/cli-core` 0.5.1.
|
|
15
|
+
|
|
16
|
+
## [1.6.0] - 2026-10-27
|
|
17
|
+
|
|
18
|
+
Every command follows one grammar, the one of `@thinger-io/cli-core` 0.5.0
|
|
19
|
+
shared with the `thinger` CLI, noun first:
|
|
20
|
+
`thinr <noun> [<noun>…] <verb> [<parent ids>…] [<id>] [options]`. Nouns
|
|
21
|
+
nest under their parent (`device property`, `product metric`), ids are
|
|
22
|
+
positional and named after their noun (`<device>`, `<product>`), and the
|
|
23
|
+
options keep one meaning everywhere (`-j` JSON, `-s` a body field, `-f` one
|
|
24
|
+
field of the answer, `-o` a file, `-y` no questions). Several commands of
|
|
25
|
+
1.5 change form: see the table below. The old forms are gone, not aliased.
|
|
26
|
+
|
|
27
|
+
The MCP server serves eight tools instead of 24: `thinr_resource_*` reach
|
|
28
|
+
everything by `type`, records are addressed with `ids`, and the shell
|
|
29
|
+
command is the `exec` action of type `device`. The old tool names and the
|
|
30
|
+
`parent`/`id` arguments are gone, not aliased: see the second table below.
|
|
31
|
+
|
|
32
|
+
### Added
|
|
33
|
+
|
|
34
|
+
- `thinr agent check <device>` and `thinr agent update <device>`, and
|
|
35
|
+
`thinr agent update --all` for the whole fleet (with the options of the
|
|
36
|
+
old `fleet upgrade`: `-p`, `-g`, `--batch-size`, `--no-canary`,
|
|
37
|
+
`--continue-on-error`, `--dry-run`, `-y`).
|
|
38
|
+
- From `@thinger-io/cli-core` 0.5.0: commands for every resource type
|
|
39
|
+
(`list|get|create|update|delete|clone|describe`, `set` on every kind of
|
|
40
|
+
property, the type's actions), `thinr api <path>`,
|
|
41
|
+
`thinr bucket write|export`, `thinr storage file list|upload|download|delete`,
|
|
42
|
+
`thinr device send|overview`, `thinr device resource list|call`,
|
|
43
|
+
`thinr product apply --from`, `thinr product profile api call`,
|
|
44
|
+
`thinr plugin call`; `--search`, `--filter`, `--count` and `--index` on
|
|
45
|
+
`device list`, `product list` and `bucket list`; `thinr doc list|get`.
|
|
46
|
+
- MCP: `resource_describe` shows each type's ids, actions, permissions and
|
|
47
|
+
ready-to-send examples; `exec` on several devices, playbook runs on
|
|
48
|
+
several devices and rollouts answer their targets first and run with
|
|
49
|
+
`confirm: true` (or ask through the client when it supports it);
|
|
50
|
+
`thinr mcp --read-only` (or `THINR_MCP_READ_ONLY=1`) serves only what
|
|
51
|
+
reads. The product properties `logs` and `dashboard_metrics` are checked
|
|
52
|
+
before they are written, and `resource_describe` type `product_property`
|
|
53
|
+
shows their shape.
|
|
54
|
+
|
|
55
|
+
### Changed (breaking)
|
|
56
|
+
|
|
57
|
+
| 1.5 | 1.6 |
|
|
58
|
+
| ------------------------------------------------------- | ----------------------------------------------------------- |
|
|
59
|
+
| `thinr device list <pattern>` | `thinr device list --search <text>` |
|
|
60
|
+
| `thinr device info <device>` | `thinr device get <device>` |
|
|
61
|
+
| `thinr device property <device>` | `thinr device property list <device>` |
|
|
62
|
+
| `thinr device property <device> <prop>` | `thinr device property get <device> <property>` |
|
|
63
|
+
| `thinr device property-set <device> <p> <v>` | `thinr device property set <device> <property> <value>` |
|
|
64
|
+
| `thinr device resource <device>` | `thinr device resource list <device>` |
|
|
65
|
+
| `thinr device resource <device> <r> -i k=v` | `thinr device resource call <device> <resource> -s k=v` |
|
|
66
|
+
| `thinr device update check <device>` | `thinr agent check <device>` |
|
|
67
|
+
| `thinr device update apply <device>` | `thinr agent update <device>` |
|
|
68
|
+
| `thinr fleet upgrade [options]` | `thinr agent update --all [options]` |
|
|
69
|
+
| `thinr product info <product>` | `thinr product get <product>` |
|
|
70
|
+
| `thinr product property-list <product>` | `thinr product property list <product>` |
|
|
71
|
+
| `thinr product property-get <product> <p>` | `thinr product property get <product> <property>` |
|
|
72
|
+
| `thinr product property-set <product> <p> <v>` | `thinr product property set <product> <property> <value>` |
|
|
73
|
+
| `thinr product property-delete <product> <p>` | `thinr product property delete <product> <property> -y` |
|
|
74
|
+
| `thinr product property <product> <prop>` (fan-out) | `thinr product device-property <product> <property>` |
|
|
75
|
+
| `thinr product resource <product> <r> -i k=v` (fan-out) | `thinr product device-resource <product> <resource> -s k=v` |
|
|
76
|
+
| `thinr product metric-list <product>` | `thinr product metric list <product>` |
|
|
77
|
+
| `thinr product metric-set <product> <name>` | `thinr product metric set <product> <name>` |
|
|
78
|
+
| `thinr product metric-delete <product> <name>` | `thinr product metric delete <product> <name>` |
|
|
79
|
+
| `thinr product logs add <product> <name>` | `thinr product logs create <product> <name>` |
|
|
80
|
+
| `thinr product logs show <product> <name>` | `thinr product logs get <product> <name>` |
|
|
81
|
+
| `thinr product logs remove\|rm <product> <name>` | `thinr product logs delete <product> <name>` |
|
|
82
|
+
|
|
83
|
+
- `thinr fleet` is gone: `agent update --all` took its only command.
|
|
84
|
+
- `device property get` and `product property get` print the property
|
|
85
|
+
record, with its value under `value`: `-f` paths start there
|
|
86
|
+
(`-f value.setpoint` where 1.5 took `-f setpoint`). `product property
|
|
87
|
+
delete` asks unless `-y`.
|
|
88
|
+
- `product metric delete`, `product logs delete` and
|
|
89
|
+
`product playbook delete` ask for confirmation too: scripts pass `-y`.
|
|
90
|
+
- `device resource call` and `product device-resource` take their input
|
|
91
|
+
from `--from <file>` and `-s, --set key=value` (`-i` is gone); `-s`
|
|
92
|
+
values are parsed as JSON when they are.
|
|
93
|
+
- `product metric set` takes `-j, --json` (it took only `--json`).
|
|
94
|
+
- The help groups the root commands as Resources, Administration,
|
|
95
|
+
Configuration, Integration and Operations, and the verbs of a noun as
|
|
96
|
+
Records, Data, Actions and Subresources, before thinr's own groups.
|
|
97
|
+
- The MCP tools (the commands keep their forms and `-j` outputs):
|
|
98
|
+
|
|
99
|
+
| 1.5 tool | 1.6 call |
|
|
100
|
+
| ---------------------------------------------------- | --------------------------------------------------------------------------------------------------- |
|
|
101
|
+
| `thinr_resource_* parent "gw_1" id "/etc/hosts"` | `thinr_resource_* ids {"device": "gw_1", "path": "/etc/hosts"}` |
|
|
102
|
+
| `thinr_device_exec device` … | `thinr_resource_call type "device" action "exec" ids {device} body {command, …}` |
|
|
103
|
+
| `thinr_device_exec devices\|product\|group\|all` … | `thinr_resource_call type "device" action "exec" body {command, devices\|product\|group\|all, …}` |
|
|
104
|
+
| `type "device_script"` / `"product_script"` id | ids `{device, script}` / `{product, script}` (body `name` on create) |
|
|
105
|
+
| `type "product_playbook"` id | ids `{product, playbook}` |
|
|
106
|
+
| `type "product_metric"` | `type "product_property"` ids `{product, property: "dashboard_metrics"}`, the whole array as value |
|
|
107
|
+
| `type "product_log_source"` | `type "product_property"` ids `{product, property: "logs"}`, `{sources, default}` as value |
|
|
108
|
+
| `thinr_bucket_data_read` / `_write` | `thinr_resource_list` / `_create` `type "bucket_data" ids {bucket}` |
|
|
109
|
+
| `thinr_device_resource_list` / `_call` | `thinr_resource_list type "device_resource"` / `_call action "call" ids {device, resource}` |
|
|
110
|
+
| `thinr_storage_file_*` | `thinr_resource_* type "storage_file" ids {storage, file}` |
|
|
111
|
+
| `thinr_doc_read`, `thinr_profile_list` | `thinr_resource_get type "doc" ids {doc}`, `thinr_resource_list type "profile"` |
|
|
112
|
+
| `thinr_dashboard_*`, `thinr_plugin_call`, `thinr_product_resource_call`, `thinr_device_data_send`, `thinr_device_overview` | `thinr_resource_call` actions `dashboard` `init\|dev\|publish`, `plugin` `call`, `product_profile_api` `call`, `device` `send`, `device` `overview` |
|
|
113
|
+
|
|
114
|
+
- Requires `@thinger-io/cli-core` 0.5.0.
|
|
115
|
+
|
|
3
116
|
## [1.5.0] - 2026-10-16
|
|
4
117
|
|
|
5
118
|
### Added
|
package/README.md
CHANGED
|
@@ -12,7 +12,7 @@ Two operating modes:
|
|
|
12
12
|
|
|
13
13
|
- **CLI** — interactive or scripted device management from a shell.
|
|
14
14
|
- **MCP server** — a stdio [Model Context Protocol][mcp] server that
|
|
15
|
-
exposes the same operations as
|
|
15
|
+
exposes the same operations as eight resource tools for AI clients like
|
|
16
16
|
Claude Code, Claude Desktop and Cursor.
|
|
17
17
|
|
|
18
18
|
Both modes share the same auth, profiles, and device API layer, so
|
|
@@ -28,8 +28,9 @@ task at hand.
|
|
|
28
28
|
- [Global options and environment variables](#global-options-and-environment-variables)
|
|
29
29
|
- [Part 1 — CLI](#part-1--cli)
|
|
30
30
|
- [JSON output](#json-output)
|
|
31
|
-
- [`thinr device
|
|
32
|
-
- [`thinr product
|
|
31
|
+
- [`thinr device`](#thinr-device)
|
|
32
|
+
- [`thinr product`](#thinr-product)
|
|
33
|
+
- [`thinr agent`](#thinr-agent)
|
|
33
34
|
- [`thinr playbook <action>`](#thinr-playbook-action)
|
|
34
35
|
- [`thinr profile`](#thinr-profile)
|
|
35
36
|
- [`thinr logout`](#thinr-logout)
|
|
@@ -95,13 +96,18 @@ These apply to every subcommand:
|
|
|
95
96
|
|
|
96
97
|
## Part 1 — CLI
|
|
97
98
|
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
99
|
+
Every command follows one grammar, shared with the `thinger` CLI: nouns
|
|
100
|
+
first, then a verb, then the ids from the outermost to the innermost, then
|
|
101
|
+
the options (`thinr device property get <device> <property>`). Records
|
|
102
|
+
take the same verbs everywhere (`list`, `get`, `create`, `update`,
|
|
103
|
+
`delete`, `clone`, `set`, `describe`), a body comes from `--from <file>`
|
|
104
|
+
and `-s, --set key=value`, and `-j, --json` gives the JSON envelope below.
|
|
105
|
+
`thinr --help` lists the nouns; `thinr <noun> --help` their verbs.
|
|
101
106
|
|
|
102
107
|
```
|
|
103
|
-
thinr device <
|
|
104
|
-
thinr product <
|
|
108
|
+
thinr device <verb> <device> [args…] [options]
|
|
109
|
+
thinr product <verb> <product> [args…] [options]
|
|
110
|
+
thinr device property <verb> <device> <property> [options]
|
|
105
111
|
```
|
|
106
112
|
|
|
107
113
|
### JSON output
|
|
@@ -138,35 +144,33 @@ don't change their behaviour — they don't produce a discrete result.
|
|
|
138
144
|
`exec` buffers stdout/stderr when `--json` is set and emits a single
|
|
139
145
|
envelope on exit.
|
|
140
146
|
|
|
141
|
-
### `thinr device
|
|
147
|
+
### `thinr device`
|
|
142
148
|
|
|
143
|
-
Most
|
|
144
|
-
|
|
145
|
-
`<pattern>` to filter results.
|
|
149
|
+
Most verbs take a `<device>` as their first positional; `list` works on
|
|
150
|
+
the whole account.
|
|
146
151
|
|
|
147
152
|
#### `list`
|
|
148
153
|
|
|
149
|
-
List every device visible to the active profile, or
|
|
150
|
-
|
|
151
|
-
server side):
|
|
154
|
+
List every device visible to the active profile, or search and filter
|
|
155
|
+
them on the server:
|
|
152
156
|
|
|
153
157
|
```bash
|
|
154
|
-
thinr device list
|
|
155
|
-
thinr device list supermicro
|
|
156
|
-
thinr device list
|
|
157
|
-
thinr device list --json
|
|
158
|
+
thinr device list # every device
|
|
159
|
+
thinr device list --search supermicro # ids/names containing "supermicro"
|
|
160
|
+
thinr device list --filter product=my-product # filters are repeatable
|
|
161
|
+
thinr device list --json # JSON envelope with the raw API records
|
|
158
162
|
```
|
|
159
163
|
|
|
160
164
|
Combine with the global `-u, --user` flag for admin impersonation.
|
|
161
165
|
|
|
162
|
-
#### Records — `
|
|
166
|
+
#### Records — `get` / `create` / `update` / `delete` / `set-product`
|
|
163
167
|
|
|
164
168
|
```bash
|
|
165
|
-
thinr device
|
|
166
|
-
thinr device create <
|
|
167
|
-
thinr device
|
|
168
|
-
thinr device
|
|
169
|
-
thinr device
|
|
169
|
+
thinr device get <device> # server record as JSON (-f <path> for one field)
|
|
170
|
+
thinr device create <device> [-t Generic|MQTT|HTTP|Virtual|Subdevice] [-p product] [-n name]
|
|
171
|
+
thinr device update <device> -s name="Boiler 1"
|
|
172
|
+
thinr device delete <device> [-y]
|
|
173
|
+
thinr device set-product <device> <product> # "" to unassign
|
|
170
174
|
```
|
|
171
175
|
|
|
172
176
|
`create` generates random credentials for Generic/MQTT devices unless
|
|
@@ -177,7 +181,7 @@ thinr device property-set <deviceId> <property> <json>
|
|
|
177
181
|
Open an interactive terminal on the device:
|
|
178
182
|
|
|
179
183
|
```bash
|
|
180
|
-
thinr device console <
|
|
184
|
+
thinr device console <device>
|
|
181
185
|
```
|
|
182
186
|
|
|
183
187
|
#### Proxies — `tcp` / `tls` / `http`
|
|
@@ -186,9 +190,9 @@ Create a TCP, TLS, or HTTP proxy to a remote endpoint reachable from
|
|
|
186
190
|
the device:
|
|
187
191
|
|
|
188
192
|
```bash
|
|
189
|
-
thinr device tcp <
|
|
190
|
-
thinr device tls <
|
|
191
|
-
thinr device http <
|
|
193
|
+
thinr device tcp <device> [target] [options]
|
|
194
|
+
thinr device tls <device> [target] [options]
|
|
195
|
+
thinr device http <device> [target] [options]
|
|
192
196
|
```
|
|
193
197
|
|
|
194
198
|
`target` is the remote address and port on the device side. Defaults
|
|
@@ -216,24 +220,24 @@ thinr device http RevPi20679 http://192.168.1.45:8080
|
|
|
216
220
|
#### `status`
|
|
217
221
|
|
|
218
222
|
```bash
|
|
219
|
-
thinr device status <
|
|
223
|
+
thinr device status <device> [-j, --json]
|
|
220
224
|
```
|
|
221
225
|
|
|
222
226
|
Returns the device's connection stats (uptime, tx/rx, last-seen).
|
|
223
227
|
|
|
224
228
|
#### `property`
|
|
225
229
|
|
|
226
|
-
|
|
230
|
+
The properties of a device are records of their own:
|
|
227
231
|
|
|
228
232
|
```bash
|
|
229
|
-
thinr device property <
|
|
230
|
-
thinr device property <
|
|
233
|
+
thinr device property list <device>
|
|
234
|
+
thinr device property get <device> <property> [-f value.threshold]
|
|
235
|
+
thinr device property set <device> <property> '{"threshold": 30}' # created when missing
|
|
236
|
+
thinr device property delete <device> <property> [-y]
|
|
231
237
|
```
|
|
232
238
|
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
- `-j, --json`: Output as JSON
|
|
236
|
-
- `-f, --field <path>`: Extract a sub-field via dot path (`-f data.value`)
|
|
239
|
+
`-f, --field <path>` prints one field of the record: the value of a
|
|
240
|
+
property is under `value`.
|
|
237
241
|
|
|
238
242
|
#### `resource`
|
|
239
243
|
|
|
@@ -241,22 +245,21 @@ List the resources exposed by the device (with their `in`/`out`
|
|
|
241
245
|
schemas when advertised), or call one:
|
|
242
246
|
|
|
243
247
|
```bash
|
|
244
|
-
thinr device resource <
|
|
245
|
-
thinr device resource <
|
|
248
|
+
thinr device resource list <device>
|
|
249
|
+
thinr device resource call <device> <resource> # read its output
|
|
250
|
+
thinr device resource call <device> <resource> -s value=true # run it with an input
|
|
246
251
|
```
|
|
247
252
|
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
- `-j, --json`: Output as JSON
|
|
252
|
-
- `-f, --field <path>`: Extract a sub-field from the result (dot path)
|
|
253
|
+
`call` takes the input from `--from <file>` (`-` for stdin) and
|
|
254
|
+
`-s, --set key=value` (repeatable, values parsed as JSON when they are),
|
|
255
|
+
and prints the answer, or one field of it with `-f, --field <path>`.
|
|
253
256
|
|
|
254
257
|
#### `exec`
|
|
255
258
|
|
|
256
259
|
Run a shell command on the device and stream stdout/stderr back:
|
|
257
260
|
|
|
258
261
|
```bash
|
|
259
|
-
thinr device exec <
|
|
262
|
+
thinr device exec <device> "<command>" [options]
|
|
260
263
|
```
|
|
261
264
|
|
|
262
265
|
Options:
|
|
@@ -267,28 +270,18 @@ Options:
|
|
|
267
270
|
|
|
268
271
|
The process exits with the remote command's exit code.
|
|
269
272
|
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
Check for or apply an agent update on the device:
|
|
273
|
-
|
|
274
|
-
```bash
|
|
275
|
-
thinr device update check <deviceId> [options]
|
|
276
|
-
thinr device update apply <deviceId> [options]
|
|
277
|
-
```
|
|
278
|
-
|
|
279
|
-
Options:
|
|
273
|
+
### `thinr product`
|
|
280
274
|
|
|
281
|
-
|
|
282
|
-
|
|
275
|
+
Besides its records (`list`, `get`, `create`, `update`, `delete`,
|
|
276
|
+
`export`, `apply`, `profile`…), a product fans operations out across
|
|
277
|
+
every device that belongs to it.
|
|
283
278
|
|
|
284
|
-
|
|
279
|
+
#### `device-property`
|
|
285
280
|
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
#### `property`
|
|
281
|
+
Read a property on every device of the product:
|
|
289
282
|
|
|
290
283
|
```bash
|
|
291
|
-
thinr product property <
|
|
284
|
+
thinr product device-property <product> <property> [options]
|
|
292
285
|
```
|
|
293
286
|
|
|
294
287
|
Options:
|
|
@@ -299,10 +292,12 @@ Options:
|
|
|
299
292
|
- `-a, --all`: Include offline devices (default: only active)
|
|
300
293
|
- `-g, --group <group>`: Filter devices by asset group
|
|
301
294
|
|
|
302
|
-
#### `resource`
|
|
295
|
+
#### `device-resource`
|
|
296
|
+
|
|
297
|
+
Call a resource on every active device of the product:
|
|
303
298
|
|
|
304
299
|
```bash
|
|
305
|
-
thinr product resource <
|
|
300
|
+
thinr product device-resource <product> <resource> [options]
|
|
306
301
|
```
|
|
307
302
|
|
|
308
303
|
Options:
|
|
@@ -310,10 +305,28 @@ Options:
|
|
|
310
305
|
- `-j, --json`: Output as JSON (`results[]` array, same shape as above)
|
|
311
306
|
- `-f, --field <path>`: Extract a sub-field from each result (dot path)
|
|
312
307
|
- `-g, --group <group>`: Filter devices by asset group
|
|
313
|
-
- `-
|
|
308
|
+
- `--from <file>`, `-s, --set <key=value>`: Resource input (`-s` is
|
|
309
|
+
repeatable)
|
|
314
310
|
|
|
315
|
-
Offline devices are skipped for `resource` — the server would
|
|
316
|
-
the call anyway.
|
|
311
|
+
Offline devices are skipped for `device-resource` — the server would
|
|
312
|
+
reject the call anyway.
|
|
313
|
+
|
|
314
|
+
#### `metric` and `logs`
|
|
315
|
+
|
|
316
|
+
What thinr's terminal dashboard shows for the devices of a product:
|
|
317
|
+
|
|
318
|
+
```bash
|
|
319
|
+
thinr product metric list <product>
|
|
320
|
+
thinr product metric set <product> <name> [options]
|
|
321
|
+
thinr product metric delete <product> <name> [-y]
|
|
322
|
+
|
|
323
|
+
thinr product logs presets # patterns shipped with thinr
|
|
324
|
+
thinr product logs list <product>
|
|
325
|
+
thinr product logs get <product> <name>
|
|
326
|
+
thinr product logs create <product> <name> [options]
|
|
327
|
+
thinr product logs delete <product> <name> [-y]
|
|
328
|
+
thinr product logs set-default <product> <name>
|
|
329
|
+
```
|
|
317
330
|
|
|
318
331
|
#### `exec`
|
|
319
332
|
|
|
@@ -322,7 +335,7 @@ product and report a per-device status table plus each device's
|
|
|
322
335
|
output:
|
|
323
336
|
|
|
324
337
|
```bash
|
|
325
|
-
thinr product exec <
|
|
338
|
+
thinr product exec <product> <command...> [options]
|
|
326
339
|
```
|
|
327
340
|
|
|
328
341
|
Options:
|
|
@@ -349,9 +362,9 @@ thinr product exec my-product "apt-get -y upgrade" -c 5 --timeout 600
|
|
|
349
362
|
thinr product exec my-product "systemctl restart agent" -g staging
|
|
350
363
|
```
|
|
351
364
|
|
|
352
|
-
Also exposed to MCP clients as `
|
|
353
|
-
`group`), so agents run a fleet operation with a
|
|
354
|
-
looping per device.
|
|
365
|
+
Also exposed to MCP clients as the `exec` action of type `device` with
|
|
366
|
+
body `product` (and `group`), so agents run a fleet operation with a
|
|
367
|
+
single call instead of looping per device.
|
|
355
368
|
|
|
356
369
|
#### `playbook`
|
|
357
370
|
|
|
@@ -359,11 +372,11 @@ Manage playbooks stored on a product and run them against one device
|
|
|
359
372
|
or the whole fleet:
|
|
360
373
|
|
|
361
374
|
```bash
|
|
362
|
-
thinr product playbook list <
|
|
363
|
-
thinr product playbook upload <
|
|
364
|
-
thinr product playbook download <
|
|
365
|
-
thinr product playbook delete <
|
|
366
|
-
thinr product playbook run <
|
|
375
|
+
thinr product playbook list <product> [--json]
|
|
376
|
+
thinr product playbook upload <product> <name> [file] [--description <text>] [--skip-validation] [--json]
|
|
377
|
+
thinr product playbook download <product> <name> [-o <file>] [--json]
|
|
378
|
+
thinr product playbook delete <product> <name> [-y] [--json]
|
|
379
|
+
thinr product playbook run <product> <name> (--device <id> | --fleet) [options]
|
|
367
380
|
```
|
|
368
381
|
|
|
369
382
|
`upload` reads the YAML from a file, or from stdin when the path is
|
|
@@ -400,6 +413,28 @@ Each fleet rollout writes a persistent JSON report to
|
|
|
400
413
|
storage, capturing resolved variables, per-device outcomes, and any
|
|
401
414
|
abort reason.
|
|
402
415
|
|
|
416
|
+
### `thinr agent`
|
|
417
|
+
|
|
418
|
+
The ThinRemote agent running on the devices: check whether a device has a
|
|
419
|
+
newer release, and update one device or the whole fleet.
|
|
420
|
+
|
|
421
|
+
```bash
|
|
422
|
+
thinr agent check <device> [--channel latest] [-j]
|
|
423
|
+
thinr agent update <device> [--channel latest] [-j]
|
|
424
|
+
thinr agent update --all [-p <product>] [-g <group>] [options]
|
|
425
|
+
```
|
|
426
|
+
|
|
427
|
+
`update --all` updates every outdated device: a canary first, then in
|
|
428
|
+
batches. Options (only with `--all`):
|
|
429
|
+
|
|
430
|
+
- `-p, --product <id>`, `-g, --group <id>` — narrow the fleet.
|
|
431
|
+
- `--batch-size <n>` — devices updated in parallel once the canary
|
|
432
|
+
passes (default: 5).
|
|
433
|
+
- `--no-canary` — everything in batches from the start.
|
|
434
|
+
- `--continue-on-error` — keep rolling after a batch failure.
|
|
435
|
+
- `--dry-run` — list what would be updated, without updating it.
|
|
436
|
+
- `-y, --yes` — no confirmation (required in non-interactive shells).
|
|
437
|
+
|
|
403
438
|
### `thinr playbook <action>`
|
|
404
439
|
|
|
405
440
|
Run or validate a local playbook YAML file (not stored on a product).
|
|
@@ -447,7 +482,7 @@ active profile; `--server`, `--username` and `--token` skip the prompts.
|
|
|
447
482
|
## Part 2 — MCP server
|
|
448
483
|
|
|
449
484
|
`thinr` ships an [MCP][mcp] server for AI clients (Claude Code, Claude
|
|
450
|
-
Desktop, Cursor and any other MCP host):
|
|
485
|
+
Desktop, Cursor and any other MCP host): eight tools that reach everything the
|
|
451
486
|
CLI does, through the same API, with stable schemas and one error contract.
|
|
452
487
|
|
|
453
488
|
### Starting the server
|
|
@@ -465,37 +500,47 @@ device of any configured environment without a restart.
|
|
|
465
500
|
### Tools
|
|
466
501
|
|
|
467
502
|
thinr is built on [`@thinger-io/cli-core`][cli-core], the core it shares
|
|
468
|
-
with the `thinger` CLI, and serves its
|
|
469
|
-
prefix
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
|
477
|
-
|
|
|
478
|
-
|
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
|
488
|
-
|
|
|
489
|
-
| `
|
|
490
|
-
| `
|
|
491
|
-
|
|
492
|
-
and
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
503
|
+
with the `thinger` CLI, and serves its eight tools with the `thinr_`
|
|
504
|
+
prefix: `thinr_resource_describe`, `_list`, `_get`, `_create`, `_update`,
|
|
505
|
+
`_delete`, `_clone` and `_call` (actions). Each takes a `type` and the
|
|
506
|
+
record's `ids`, one key per level (`{"device": "gw_1"}`,
|
|
507
|
+
`{"device": "gw_1", "path": "/etc/hosts"}`,
|
|
508
|
+
`{"product": "gateways", "playbook": "app-config"}`); the records they
|
|
509
|
+
answer carry their ids.
|
|
510
|
+
|
|
511
|
+
| Types | What for |
|
|
512
|
+
| ---------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
513
|
+
| The server's (`device`, `product`, `bucket`, `token`, `alarm_rule`…) | Every resource of the account and their actions |
|
|
514
|
+
| `device_resource` (list; action `call`) | What a connected device exposes: agent resources (`monitoring`, `cmd`…) and its scripts |
|
|
515
|
+
| `bucket_data` (list reads, create writes) | Time series, monitoring history included (bucket `monitoring`) |
|
|
516
|
+
| `storage_file`; `dashboard` actions `init` / `dev` / `publish`; others | Storages, web dashboards (create, develop against the server, publish), plugins (`plugin` `call`), product APIs (`product_profile_api` `call`), HTTP devices (`device` `send`), account usage (`device` `overview`) |
|
|
517
|
+
| `doc`, `profile` | Guides for agents (`thinremote`, `thinremote-scripts`, `thinremote-playbooks`, `thinremote-metrics-logs`, and the platform's: `concepts`, `product-code`, `server-admin`, `dashboard-sdk`) and profiles |
|
|
518
|
+
|
|
519
|
+
ThinRemote adds its own resource types, listed, read, written and deleted
|
|
520
|
+
like a device or a token:
|
|
521
|
+
|
|
522
|
+
| Type | ids | What it is | Actions (`thinr_resource_call`) |
|
|
523
|
+
| ------------------ | --------------------- | ------------------------------------------------------------------------------ | ------------------------------- |
|
|
524
|
+
| `device_fs` | `device`, `path` | Files and folders of the device | `move`, `push`, `pull` |
|
|
525
|
+
| `device_script` | `device`, `script` | Scripts of the agent, each a resource of the device | |
|
|
526
|
+
| `product_script` | `product`, `script` | Scripts run on any device of the product, kept once in its storage | |
|
|
527
|
+
| `product_playbook` | `product`, `playbook` | Playbooks: YAML steps validated, tried on one device and rolled out in batches | `validate`, `run`, `rollout` |
|
|
528
|
+
|
|
529
|
+
and three actions to the server's `device` type: `exec` (a shell command
|
|
530
|
+
on one device, `ids.device`, or on several at once: body `devices`,
|
|
531
|
+
`product`, `group`, `all`), `agent_update` (check for or install a new
|
|
532
|
+
agent) and `agent_install` (the command that installs the agent on a new
|
|
533
|
+
machine). Live monitoring is the device resource `monitoring`; its
|
|
534
|
+
history, the bucket `monitoring`. The fleet metrics and log sources of
|
|
535
|
+
thinr's terminal dashboard are the product properties `dashboard_metrics`
|
|
536
|
+
and `logs`, checked before they are written.
|
|
537
|
+
|
|
538
|
+
`exec` on several devices, playbook runs on several devices and rollouts
|
|
539
|
+
answer their targets first and run with `confirm: true` (clients that
|
|
540
|
+
support elicitation ask the user instead). `thinr mcp --read-only` (or
|
|
541
|
+
`THINR_MCP_READ_ONLY=1`) serves only what reads. Full input schemas come
|
|
542
|
+
with the standard MCP `tools/list`, and `thinr_resource_describe` gives
|
|
543
|
+
each type's ids, fields, actions and examples.
|
|
499
544
|
|
|
500
545
|
[cli-core]: https://github.com/thinger-io/thinger-cli-core
|
|
501
546
|
|
|
@@ -513,15 +558,16 @@ writing YAML by hand:
|
|
|
513
558
|
2. **Draft and validate.** Write the YAML and call `thinr_resource_call`
|
|
514
559
|
type `product_playbook`, action `validate`, with it in `body.content`;
|
|
515
560
|
fix what it reports until it is clean.
|
|
516
|
-
3. **Save.** `thinr_resource_create` type `product_playbook`,
|
|
517
|
-
product,
|
|
518
|
-
nothing is saved if invalid.
|
|
519
|
-
4. **Pre-flight on one device.** Action `run` with
|
|
561
|
+
3. **Save.** `thinr_resource_create` type `product_playbook`, ids
|
|
562
|
+
`{"product", "playbook": <a short name>}`, body `{content}`. It is
|
|
563
|
+
validated again and nothing is saved if invalid.
|
|
564
|
+
4. **Pre-flight on one device.** Action `run` with `ids.playbook` and
|
|
520
565
|
`body.device`, with `dry_run: true` or `check: true` for a read-only
|
|
521
566
|
preview, then for real.
|
|
522
567
|
5. **Roll out.** Action `rollout` runs it across the fleet in batches with a
|
|
523
568
|
failure-rate stop, and writes a report to `playbooks/runs/` in the
|
|
524
|
-
product storage.
|
|
569
|
+
product storage. It answers its plan first and runs with
|
|
570
|
+
`confirm: true` once the user agrees.
|
|
525
571
|
|
|
526
572
|
Example prompt:
|
|
527
573
|
|
|
@@ -537,10 +583,10 @@ A second message like "looks good, roll it out to staging" maps to the
|
|
|
537
583
|
### Per-call controls
|
|
538
584
|
|
|
539
585
|
- **`profile`**: optional on every tool. Uses another configured server for
|
|
540
|
-
that call only; `
|
|
586
|
+
that call only; `thinr_resource_list` type `profile` lists them.
|
|
541
587
|
- **`user`**: optional admin impersonation; defaults to the profile's user.
|
|
542
|
-
- Devices are named per call (`device
|
|
543
|
-
|
|
588
|
+
- Devices are named per call (`ids.device`): list them with
|
|
589
|
+
`thinr_resource_list` type `device`.
|
|
544
590
|
|
|
545
591
|
### Integrating with Claude Code
|
|
546
592
|
|
|
@@ -611,16 +657,17 @@ Use `thinr profile use <name>` to change the persisted default, or
|
|
|
611
657
|
```
|
|
612
658
|
thinr-cli/
|
|
613
659
|
├── bin/ # CLI entry point (thinr)
|
|
614
|
-
├── commands/ # ThinRemote subcommands (agent,
|
|
660
|
+
├── commands/ # ThinRemote subcommands (agent, device, product, playbooks…)
|
|
615
661
|
├── lib/ # ThinRemote modules: identity, device-api, proxy,
|
|
616
662
|
│ # console, playbooks, product scripts, MCP tools…
|
|
617
663
|
├── package.json
|
|
618
664
|
└── README.md
|
|
619
665
|
```
|
|
620
666
|
|
|
621
|
-
The generic part — API client, auth, profiles, REST helpers, the
|
|
622
|
-
commands (login, logout, profile,
|
|
623
|
-
|
|
667
|
+
The generic part — API client, auth, profiles, REST helpers, the command
|
|
668
|
+
grammar, the generic commands (login, logout, profile, api, the records of
|
|
669
|
+
every resource type, device resource, bucket, storage…) and the generic MCP
|
|
670
|
+
tools — comes from
|
|
624
671
|
[@thinger-io/cli-core](https://github.com/thinger-io/cli-core), shared
|
|
625
672
|
with the `thinger` CLI. `lib/identity.js` is what makes it `thinr`: names,
|
|
626
673
|
`~/.config/thinr-cli`, `THINR\__`, the OAuth client and the product
|