@thinger-io/cli 0.2.3 → 0.5.0
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 +142 -0
- package/README.md +204 -36
- package/lib/identity.js +9 -6
- package/package.json +3 -3
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,147 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [0.5.0] - 2026-10-31
|
|
4
|
+
|
|
5
|
+
Every command follows one grammar, noun first:
|
|
6
|
+
`thinger <noun> [<noun>…] <verb> [<parent ids>…] [<id>] [options]`.
|
|
7
|
+
Nouns nest under their parent (`device property`, `product profile api`),
|
|
8
|
+
ids are positional and named after their noun, and the options keep one
|
|
9
|
+
meaning everywhere (`-j` JSON, `-s` a body field, `-f` one field of the
|
|
10
|
+
answer, `-o` a file, `-y` no questions). A few commands of 0.3 change
|
|
11
|
+
form: see the table below. The old forms are gone, not aliased.
|
|
12
|
+
|
|
13
|
+
The MCP server serves eight tools instead of 25: `thinger_resource_*`
|
|
14
|
+
reach everything by `type`, and records are addressed with `ids`. The old
|
|
15
|
+
tool names and the `parent`/`id` arguments are gone, not aliased: see the
|
|
16
|
+
second table below.
|
|
17
|
+
|
|
18
|
+
### Added
|
|
19
|
+
|
|
20
|
+
- Commands for every resource type the MCP server reaches, generated from
|
|
21
|
+
the same catalog: `list|get|create|update|delete|clone|describe` and the
|
|
22
|
+
type's actions (`thinger endpoint call`, `thinger alarm rule test`,
|
|
23
|
+
`thinger admin host restart`…), with bodies from `--from` and
|
|
24
|
+
`-s key=value`, `-n`/`-d` for the name and description, and
|
|
25
|
+
`set <property> <value>` on every kind of property. Endpoints, tokens,
|
|
26
|
+
alarms, storages, projects, assets, syncs, claims, plugins, product
|
|
27
|
+
profiles, properties and the server administration are now reachable from
|
|
28
|
+
the command line and from CI.
|
|
29
|
+
- `thinger api <path>`: any request to the server, as `gh api` does.
|
|
30
|
+
- Commands over the operations that are not CRUD:
|
|
31
|
+
`thinger bucket write|export`,
|
|
32
|
+
`thinger storage file list|upload|download|delete`,
|
|
33
|
+
`thinger device send|overview`, `thinger device resource list|call`,
|
|
34
|
+
`thinger product apply --from`, `thinger product profile api call` and
|
|
35
|
+
`thinger plugin call`. `product export` and `product apply` keep a
|
|
36
|
+
product in a repository and deploy it.
|
|
37
|
+
- `device list`, `product list` and `bucket list` take `--search`,
|
|
38
|
+
`--filter`, `--count` and `--index`; `device create` and `product create`
|
|
39
|
+
take `--from`, `-s` and `--projects`; `get` takes `-f <dot.path>`.
|
|
40
|
+
- `thinger doc list` and `thinger doc get <doc>`: the guides for agents
|
|
41
|
+
from the command line.
|
|
42
|
+
- MCP: `resource_describe` shows each type's ids, actions, the permission
|
|
43
|
+
each operation needs and ready-to-send examples; actions that change a
|
|
44
|
+
lot at once (`replace_all`, a host's settings or restart, removing a
|
|
45
|
+
plugin) answer a plan and run with `confirm: true` (or ask through the
|
|
46
|
+
client when it supports it); `thinger mcp --read-only` (or
|
|
47
|
+
`THINGER_MCP_READ_ONLY=1`) serves only what reads.
|
|
48
|
+
|
|
49
|
+
### Changed (breaking)
|
|
50
|
+
|
|
51
|
+
| 0.3 | 0.4 |
|
|
52
|
+
| ------------------------------------------------ | ----------------------------------------------------------- |
|
|
53
|
+
| `thinger device list <pattern>` | `thinger device list --search <text>` |
|
|
54
|
+
| `thinger device info <device>` | `thinger device get <device>` |
|
|
55
|
+
| `thinger device property <device>` | `thinger device property list <device>` |
|
|
56
|
+
| `thinger device property <device> <prop>` | `thinger device property get <device> <property>` |
|
|
57
|
+
| `thinger device property-set <device> <p> <v>` | `thinger device property set <device> <property> <value>` |
|
|
58
|
+
| `thinger device resource <device>` | `thinger device resource list <device>` |
|
|
59
|
+
| `thinger device resource <device> <r> -i k=v` | `thinger device resource call <device> <resource> -s k=v` |
|
|
60
|
+
| `thinger product info <product>` | `thinger product get <product>` |
|
|
61
|
+
| `thinger product property-list <product>` | `thinger product property list <product>` |
|
|
62
|
+
| `thinger product property-get <product> <p>` | `thinger product property get <product> <property>` |
|
|
63
|
+
| `thinger product property-set <product> <p> <v>` | `thinger product property set <product> <property> <value>` |
|
|
64
|
+
| `thinger product property-delete <product> <p>` | `thinger product property delete <product> <property> -y` |
|
|
65
|
+
|
|
66
|
+
- `device property get` and `product property get` print the property
|
|
67
|
+
record, with its value under `value`: `-f` paths start there
|
|
68
|
+
(`-f value.setpoint` where 0.3 took `-f setpoint`). `device property list`
|
|
69
|
+
and `product property list` print the records (`-j`: the records, not
|
|
70
|
+
`{ product, properties: [names] }`). `product property delete` asks
|
|
71
|
+
unless `-y`. `device resource call` takes its input from `--from` and
|
|
72
|
+
`-s` (`-i` is gone); `-s` values are parsed as JSON, as before.
|
|
73
|
+
- The root help groups the commands as Resources, Administration,
|
|
74
|
+
Configuration and Integration.
|
|
75
|
+
- The MCP tools (the commands keep their forms and `-j` outputs; the help
|
|
76
|
+
names some positionals as the server does: `asset type get <type>`,
|
|
77
|
+
`asset group get <group>`, `alarm rule get <rule>`,
|
|
78
|
+
`alarm instance get <instance>`,
|
|
79
|
+
`product profile <category> get <product> <resource>`):
|
|
80
|
+
|
|
81
|
+
| 0.3 tool | 0.4 call |
|
|
82
|
+
| ------------------------------------------------ | ----------------------------------------------------------------------------------------- |
|
|
83
|
+
| `thinger_resource_* parent "d1" id "p1"` | `thinger_resource_* ids {"device": "d1", "property": "p1"}` |
|
|
84
|
+
| `thinger_bucket_data_read` | `thinger_resource_list type "bucket_data" ids {bucket}` (`filter` for the query) |
|
|
85
|
+
| `thinger_bucket_data_write` | `thinger_resource_create type "bucket_data" ids {bucket} body <samples>` |
|
|
86
|
+
| `thinger_storage_file_list` | `thinger_resource_list type "storage_file" ids {storage} filter {path}` |
|
|
87
|
+
| `thinger_storage_file_read` | `thinger_resource_get type "storage_file" ids {storage, file}` |
|
|
88
|
+
| `thinger_storage_file_write` | `thinger_resource_create type "storage_file" ids {storage, file} body {content or local}` |
|
|
89
|
+
| `thinger_storage_file_delete` | `thinger_resource_delete type "storage_file" ids {storage, file}` |
|
|
90
|
+
| `thinger_device_resource_list` | `thinger_resource_list type "device_resource" ids {device}` |
|
|
91
|
+
| `thinger_device_resource_call` | `thinger_resource_call type "device_resource" action "call" ids {device, resource}` |
|
|
92
|
+
| `thinger_device_data_send` | `thinger_resource_call type "device" action "send" ids {device} body <data>` |
|
|
93
|
+
| `thinger_device_overview` | `thinger_resource_call type "device" action "overview"` |
|
|
94
|
+
| `thinger_product_resource_call` | `thinger_resource_call type "product_profile_api" action "call" ids {product, resource}` |
|
|
95
|
+
| `thinger_plugin_call` | `thinger_resource_call type "plugin" action "call" ids {plugin} body {path, method}` |
|
|
96
|
+
| `thinger_doc_read` | `thinger_resource_get type "doc" ids {doc}` (`thinger_resource_list type "doc"` lists) |
|
|
97
|
+
| `thinger_profile_list` | `thinger_resource_list type "profile"` |
|
|
98
|
+
| `thinger_dashboard_init` / `_dev` / `_publish` | `thinger_resource_call type "dashboard" action "init"` / `"dev"` / `"publish"` |
|
|
99
|
+
|
|
100
|
+
- Requires `@thinger-io/cli-core` 0.5.0. From this release the CLI's minor
|
|
101
|
+
version follows the core's (0.5.x runs on cli-core 0.5.x), so there is no
|
|
102
|
+
0.4.0.
|
|
103
|
+
|
|
104
|
+
|
|
105
|
+
### Fixed
|
|
106
|
+
|
|
107
|
+
- Tokens created with an expiry such as "30d" (`thinger_resource_create`)
|
|
108
|
+
were refused by the server: it takes milliseconds.
|
|
109
|
+
|
|
110
|
+
## [0.3.0] - 2026-10-16
|
|
111
|
+
|
|
112
|
+
### Added
|
|
113
|
+
|
|
114
|
+
- `thinger dashboard dev [url]`: develop a dashboard app on its own dev
|
|
115
|
+
server (ng serve, Vite…) against a real server: a link with a temporary
|
|
116
|
+
token opens the local app as a standalone page whose SDK calls the server
|
|
117
|
+
directly.
|
|
118
|
+
- `thinger dashboard publish [dir]`: upload the build to a public storage
|
|
119
|
+
and point dashboards at it (`--to`, repeatable; `--prune`, `--bump`,
|
|
120
|
+
`--preview`, `--no-point`). Both read their settings from `thinger.json`.
|
|
121
|
+
- `thinger dashboard init <dir>`: a new dashboard app from a template of
|
|
122
|
+
`@thinger-io/dashboard-sdk` (React or Angular, TypeScript), with its
|
|
123
|
+
`thinger.json` and an `AGENTS.md`; `--ci` adds a GitHub workflow.
|
|
124
|
+
- Publish and dev warn when the app's SDK needs a newer server, a newer SDK
|
|
125
|
+
is on npm, or a page loads the deprecated script build.
|
|
126
|
+
- MCP tools `thinger_dashboard_init` and `thinger_dashboard_dev` (25
|
|
127
|
+
tools): the same for agents, which open the dev link with their browser
|
|
128
|
+
tools.
|
|
129
|
+
- `THINGER_TOKEN` (an access token) and `THINGER_SERVER` replace the saved
|
|
130
|
+
profile in every command and the MCP server (CI), unless `--profile` or
|
|
131
|
+
`THINGER_PROFILE` names one; `thinger login` warns while `THINGER_TOKEN`
|
|
132
|
+
is set.
|
|
133
|
+
|
|
134
|
+
### Changed
|
|
135
|
+
|
|
136
|
+
- Requires `@thinger-io/cli-core` 0.4.0.
|
|
137
|
+
- The guides for agents (`thinger_doc_read`: concepts, product code, server
|
|
138
|
+
administration, the dashboard SDK reference and types) ship with the CLI
|
|
139
|
+
and the SDK package instead of coming from the server, which stops
|
|
140
|
+
serving `/sdk/`. Same ids; what needs a newer server says "since Thinger
|
|
141
|
+
X".
|
|
142
|
+
- Preview links no longer come with a layout check link: the server
|
|
143
|
+
retires `/sdk/preview.html`.
|
|
144
|
+
|
|
3
145
|
## [0.2.3] - 2026-10-14
|
|
4
146
|
|
|
5
147
|
### Changed
|
package/README.md
CHANGED
|
@@ -4,10 +4,10 @@ A command-line tool for any [Thinger.io](https://thinger.io) server, and an
|
|
|
4
4
|
MCP server that lets AI assistants (Claude Code, Claude Desktop, Cursor…)
|
|
5
5
|
operate it with the permissions of your token.
|
|
6
6
|
|
|
7
|
-
- **CLI** — devices, products, buckets and profiles from a
|
|
8
|
-
`--json` output for scripts.
|
|
9
|
-
- **MCP server** — `thinger mcp` serves
|
|
10
|
-
stdio.
|
|
7
|
+
- **CLI** — devices, products, buckets, dashboard apps and profiles from a
|
|
8
|
+
shell, with `--json` output for scripts.
|
|
9
|
+
- **MCP server** — `thinger mcp` serves eight `thinger_resource_*` tools
|
|
10
|
+
over stdio.
|
|
11
11
|
|
|
12
12
|
Both share the same profiles and API layer: sign in once, use either.
|
|
13
13
|
|
|
@@ -58,32 +58,188 @@ THINGER_PROFILE=staging thinger device list
|
|
|
58
58
|
`-u, --user <account>` addresses another account on the same server when
|
|
59
59
|
your profile has admin rights.
|
|
60
60
|
|
|
61
|
+
`THINGER_TOKEN` (an access token) and `THINGER_SERVER` stand for a profile
|
|
62
|
+
in every command and in the MCP server, for CI: they replace the saved
|
|
63
|
+
profile unless `--profile` or `THINGER_PROFILE` names one, and
|
|
64
|
+
`thinger login` warns while `THINGER_TOKEN` is set.
|
|
65
|
+
|
|
61
66
|
## Commands
|
|
62
67
|
|
|
68
|
+
Every command reads the same way: nouns, then a verb, then the ids,
|
|
69
|
+
outermost first.
|
|
70
|
+
|
|
71
|
+
```
|
|
72
|
+
thinger <noun> [<noun>…] <verb> [<parent ids>…] [<id>] [options]
|
|
73
|
+
```
|
|
74
|
+
|
|
63
75
|
```bash
|
|
64
|
-
thinger device list [
|
|
65
|
-
thinger device
|
|
66
|
-
thinger device create <
|
|
67
|
-
thinger device
|
|
68
|
-
thinger device
|
|
69
|
-
thinger device
|
|
70
|
-
thinger device property
|
|
71
|
-
thinger device
|
|
72
|
-
|
|
73
|
-
thinger
|
|
74
|
-
thinger
|
|
75
|
-
thinger
|
|
76
|
-
thinger
|
|
77
|
-
|
|
78
|
-
thinger product
|
|
76
|
+
thinger device list [--search sensor] [--filter product=meteo]
|
|
77
|
+
thinger device get <device> [-f connection.active]
|
|
78
|
+
thinger device create <device> [-t Generic|MQTT|HTTP|Virtual|Subdevice] [-p product] [-n name]
|
|
79
|
+
thinger device update <device> [-n name] [-s key=value …] [--from device.json]
|
|
80
|
+
thinger device delete <device> [-y]
|
|
81
|
+
thinger device set-product <device> <product>
|
|
82
|
+
thinger device property list <device>
|
|
83
|
+
thinger device property get <device> <property> [-f value.setpoint]
|
|
84
|
+
thinger device property set <device> <property> <json>
|
|
85
|
+
thinger device resource list <device>
|
|
86
|
+
thinger device resource call <device> <resource> [-s key=value …] [-f field]
|
|
87
|
+
thinger device send <device> -s temperature=21.5 # as an HTTP device
|
|
88
|
+
thinger device bucket tag list <device> <bucket>
|
|
89
|
+
|
|
90
|
+
thinger product list | get <product> | delete <product>
|
|
91
|
+
thinger product create <product> [--from product.json] # { config, profile }
|
|
92
|
+
thinger product property list|get|set|delete <product> [property] [value]
|
|
93
|
+
thinger product profile api list <product>
|
|
94
|
+
thinger product profile bucket create <product> <bucket> --from bucket.json
|
|
95
|
+
thinger product profile api call <product> <resource> [--from payload.json]
|
|
96
|
+
thinger product export <product> -o product.json
|
|
97
|
+
thinger product apply --from product.json # create or update: profile, properties
|
|
79
98
|
|
|
80
99
|
thinger bucket list
|
|
81
100
|
thinger bucket read <bucket> [-d device] [-n 10] [-m minutes] [--agg 5m --agg-type mean]
|
|
101
|
+
thinger bucket write <bucket> --from samples.ndjson # or -s temperature=21.5
|
|
102
|
+
thinger bucket export <bucket> -o data.csv [--format csv|json|arff]
|
|
103
|
+
thinger bucket export-file list <bucket>
|
|
104
|
+
|
|
105
|
+
thinger storage file list <storage> [folder]
|
|
106
|
+
thinger storage file upload <storage> ./dist [--to web]
|
|
107
|
+
thinger storage file download <storage> <path> [-o file]
|
|
108
|
+
thinger storage file delete <storage> <path> [-y]
|
|
109
|
+
|
|
110
|
+
thinger plugin call <plugin> [path] [-X post] [--from body.json]
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
Every resource type the MCP server reaches has its commands, generated from
|
|
114
|
+
the same catalog, with the verbs it supports and its actions. Child types
|
|
115
|
+
nest under their parent (`device property`, `device bucket tag`,
|
|
116
|
+
`product profile api`, `project member`, `sync lock`) and server types go
|
|
117
|
+
under `admin`:
|
|
118
|
+
|
|
119
|
+
```bash
|
|
120
|
+
thinger <noun…> list [parents…] [--search text] [--filter key=value] [--count n]
|
|
121
|
+
thinger <noun…> get [parents…] <id> [-f dot.path] [-o file]
|
|
122
|
+
thinger <noun…> create [parents…] [id] [-n name] [-d text] [--from file.json] [-s key=value …]
|
|
123
|
+
thinger <noun…> update [parents…] <id> [--from file.json] [-s key=value …] [--merge]
|
|
124
|
+
thinger <noun…> delete [parents…] <id> [-y]
|
|
125
|
+
thinger <noun…> clone [parents…] <id> <new-id>
|
|
126
|
+
thinger <noun…> set [parents…] <property> <json> # properties only
|
|
127
|
+
thinger <noun…> describe # fields and examples, from the server
|
|
128
|
+
thinger <noun…> <action> [parents…] [id] [--from file.json] [-q key=value]
|
|
129
|
+
|
|
130
|
+
thinger endpoint call notify -s message=hello
|
|
131
|
+
thinger token create ci -n CI -s expire='"30d"' -s 'allow={"Device":{"*":"*"}}'
|
|
132
|
+
thinger alarm rule test overheat
|
|
133
|
+
thinger device property update boiler setpoint -s value.target=21 --merge
|
|
134
|
+
thinger asset type property set boiler max_temp 90
|
|
135
|
+
thinger admin host get-settings <host> # server types, for admins
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
`-s` values are parsed as JSON when they are (`21`, `true`, `{"a":1}`;
|
|
139
|
+
quote strings that look like numbers: `-s code='"007"'`) and dots nest
|
|
140
|
+
(`-s data.source=resource`).
|
|
141
|
+
|
|
142
|
+
Anything else the API offers, with `thinger api` (`{user}` is the account):
|
|
143
|
+
|
|
144
|
+
```bash
|
|
145
|
+
thinger api /v1/users/{user}/products/boiler/firmwares
|
|
146
|
+
thinger api -X PUT /v1/users/{user}/devices/sensor1 -s enabled=false
|
|
147
|
+
thinger api /v2/users/{user}/storages/web/files/logo.png -o logo.png
|
|
82
148
|
```
|
|
83
149
|
|
|
84
150
|
Every command takes `-j, --json` and then prints `{ ok, data }` or
|
|
85
151
|
`{ ok: false, error: { message, code } }`.
|
|
86
152
|
|
|
153
|
+
## Dashboard apps
|
|
154
|
+
|
|
155
|
+
Custom dashboards are web apps (React, Angular…) built on the dashboard SDK,
|
|
156
|
+
[`@thinger-io/dashboard-sdk`](https://www.npmjs.com/package/@thinger-io/dashboard-sdk).
|
|
157
|
+
Create one from a template, develop it on its own dev server against a real
|
|
158
|
+
server, and publish it when it works:
|
|
159
|
+
|
|
160
|
+
```bash
|
|
161
|
+
thinger dashboard init greenhouse --to device:gh_01 # --template angular, --ci, --install
|
|
162
|
+
cd greenhouse && npm install
|
|
163
|
+
npm run dev # Angular: npm start. Leave it running
|
|
164
|
+
thinger dashboard dev --open # in another terminal
|
|
165
|
+
npm run build && thinger dashboard publish
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
`dashboard init` copies a template of the SDK package (`react` by default,
|
|
169
|
+
`angular`) from its latest release on npm (offline, the copy the CLI
|
|
170
|
+
installs; `--from` takes another version or tag, or a folder or .tgz of it) into a new
|
|
171
|
+
folder, with the SDK as a dependency, a `thinger.json` for the commands
|
|
172
|
+
below (storage `app_<folder>_<random>` unless `--storage`), and an `AGENTS.md`
|
|
173
|
+
(with a `CLAUDE.md` pointing at it) with the rules of the console's frame
|
|
174
|
+
for the agents that work on it. `--ci` adds a GitHub workflow that
|
|
175
|
+
publishes it.
|
|
176
|
+
|
|
177
|
+
`dashboard dev` prints (or opens) a link to your local app that runs it as a
|
|
178
|
+
standalone page against the server, in the context you pick (`--device`,
|
|
179
|
+
`--product`, `--asset-type`, `--asset-group`, `--project`, or
|
|
180
|
+
`--to device:<id>`; by default the first destination in `thinger.json`):
|
|
181
|
+
the SDK calls the server directly with a temporary token with full access
|
|
182
|
+
to your account (to the project with `--project`; 8 h, `--hours`; the next
|
|
183
|
+
link for the same project replaces it), so writes are real. The url must
|
|
184
|
+
be on this machine (localhost) unless you pass `--allow-remote`: the link
|
|
185
|
+
carries that token. Your dev server
|
|
186
|
+
keeps reloading the app and the browser's tools show its errors. The app
|
|
187
|
+
bundles the dashboard SDK, so its dev server needs no proxy, and the SDK
|
|
188
|
+
takes the server from the link.
|
|
189
|
+
|
|
190
|
+
Outside the console's sandboxed iframe, localStorage, cookies and a `<base>`
|
|
191
|
+
tag work: don't rely on them, they fail once published.
|
|
192
|
+
|
|
193
|
+
`dashboard publish` uploads the build folder to a public storage and points
|
|
194
|
+
the destinations at it (`dashboard:<id>`, `device:<id>`, `product:<id>`,
|
|
195
|
+
`asset_type:<id>`, `asset_group:<id>`, `project:<id>`; repeat `--to` for
|
|
196
|
+
several). `--preview` adds standalone review links with a read-only token.
|
|
197
|
+
Both commands warn when the app's SDK needs a newer server than the
|
|
198
|
+
profile's, when a newer SDK is on npm, or when the page loads the
|
|
199
|
+
deprecated script build (`thinger-dashboard.js`).
|
|
200
|
+
|
|
201
|
+
A `thinger.json` next to the app keeps the settings of these commands, so
|
|
202
|
+
they run without arguments (`dev.context` defaults to the first
|
|
203
|
+
destination's; `dev.route` and `dev.hours` are optional too):
|
|
204
|
+
|
|
205
|
+
```json
|
|
206
|
+
{
|
|
207
|
+
"dashboard": {
|
|
208
|
+
"dir": "dist",
|
|
209
|
+
"storage": "app_greenhouse",
|
|
210
|
+
"prune": true,
|
|
211
|
+
"to": [{ "type": "device", "id": "gh_01", "route": "/" }],
|
|
212
|
+
"dev": { "url": "http://localhost:5173/" }
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
```
|
|
216
|
+
|
|
217
|
+
To publish from CI, set the repository variable `THINGER_SERVER` and the
|
|
218
|
+
secret `THINGER_TOKEN` (an access token allowed to write storages and
|
|
219
|
+
dashboards, or the resources' `dashboard` property); `dashboard init --ci`
|
|
220
|
+
writes this workflow:
|
|
221
|
+
|
|
222
|
+
```yaml
|
|
223
|
+
# .github/workflows/dashboard.yml
|
|
224
|
+
name: Publish dashboard
|
|
225
|
+
on:
|
|
226
|
+
push:
|
|
227
|
+
branches: [main]
|
|
228
|
+
jobs:
|
|
229
|
+
publish:
|
|
230
|
+
runs-on: ubuntu-latest
|
|
231
|
+
steps:
|
|
232
|
+
- uses: actions/checkout@v4
|
|
233
|
+
- uses: actions/setup-node@v4
|
|
234
|
+
with:
|
|
235
|
+
node-version: 22
|
|
236
|
+
- run: npm ci && npm run build
|
|
237
|
+
- run: npx -y @thinger-io/cli dashboard publish
|
|
238
|
+
env:
|
|
239
|
+
THINGER_SERVER: ${{ vars.THINGER_SERVER }}
|
|
240
|
+
THINGER_TOKEN: ${{ secrets.THINGER_TOKEN }}
|
|
241
|
+
```
|
|
242
|
+
|
|
87
243
|
## MCP server
|
|
88
244
|
|
|
89
245
|
```bash
|
|
@@ -95,24 +251,36 @@ claude mcp add thinger -- thinger mcp
|
|
|
95
251
|
Other hosts take the same command (`thinger`, args `["mcp"]`), or
|
|
96
252
|
`npx` with args `["-y", "@thinger-io/cli", "mcp"]`.
|
|
97
253
|
|
|
98
|
-
Tools:
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
`
|
|
113
|
-
`
|
|
114
|
-
|
|
254
|
+
Tools: `thinger_resource_describe`, `_list`, `_get`, `_create`,
|
|
255
|
+
`_update`, `_delete`, `_clone` and `_call` (actions). Each takes a `type`
|
|
256
|
+
and the record's `ids`, one key per level (`{"device": "d1"}`,
|
|
257
|
+
`{"device": "d1", "property": "setpoint"}`,
|
|
258
|
+
`{"product": "p1", "resource": "temp"}`):
|
|
259
|
+
|
|
260
|
+
- The server's resources: devices, products, buckets, dashboards,
|
|
261
|
+
endpoints, storages, asset types and groups, projects and their members,
|
|
262
|
+
tokens, alarms, claims, plugins, properties, their children, and the
|
|
263
|
+
server's administration (users, hosts, domains, brands, OAuth clients,
|
|
264
|
+
identity providers, proxies). `resource_call` runs their actions, such as
|
|
265
|
+
verifying a domain, calling an endpoint or testing an alarm rule.
|
|
266
|
+
- Data and files: `bucket_data` (list reads a bucket, create writes
|
|
267
|
+
samples), `storage_file` (a storage's files; uploads folders of this
|
|
268
|
+
machine), `device_resource` (a connected device's resources: list, and
|
|
269
|
+
the `call` action); actions `device` `send` and `overview`,
|
|
270
|
+
`product_profile_api` `call` and `plugin` `call`.
|
|
271
|
+
- `doc` (the guides for agents), `profile` (the configured servers) and the
|
|
272
|
+
`dashboard` actions `init`, `dev` and `publish`. `dev` gives an agent the
|
|
273
|
+
dev link above: with browser tools it opens the app, reads its console
|
|
274
|
+
and iterates, then publishes it once.
|
|
275
|
+
|
|
276
|
+
`resource_describe` lists the types with their ids and examples; with a
|
|
277
|
+
type it shows its fields, filter, actions, the permission each operation
|
|
278
|
+
needs and ready-to-send calls, read from the server's own API description.
|
|
279
|
+
Actions that change a lot at once (`replace_all`, a host's settings or
|
|
280
|
+
restart, removing a plugin) answer a plan and run with `confirm: true`.
|
|
115
281
|
Every tool takes an optional `profile`, and most an optional `user`.
|
|
282
|
+
`thinger mcp --read-only` (or `THINGER_MCP_READ_ONLY=1`) serves only what
|
|
283
|
+
reads: describe, list, get and the actions that change nothing.
|
|
116
284
|
|
|
117
285
|
## Shared core
|
|
118
286
|
|
package/lib/identity.js
CHANGED
|
@@ -14,8 +14,9 @@ export const thingerIdentity = {
|
|
|
14
14
|
name: 'thinger',
|
|
15
15
|
displayName: 'Thinger.io',
|
|
16
16
|
description:
|
|
17
|
-
'CLI for Thinger.io servers — devices, products, buckets, with an MCP server for AI clients',
|
|
17
|
+
'CLI for Thinger.io servers — devices, products, buckets, dashboard apps, with an MCP server for AI clients',
|
|
18
18
|
configDir: 'thinger-cli',
|
|
19
|
+
npmPackage: '@thinger-io/cli',
|
|
19
20
|
envPrefix: 'THINGER',
|
|
20
21
|
token: { id: 'thinger_cli', name: 'Thinger CLI' },
|
|
21
22
|
// No OAuth client ships with Thinger servers yet: the browser login asks
|
|
@@ -28,9 +29,11 @@ export const thingerIdentity = {
|
|
|
28
29
|
/** Server-level guidance sent to MCP clients on `initialize`. */
|
|
29
30
|
export const mcpInstructions = `Tools to operate a Thinger.io IoT server with the permissions of the token stored in the CLI profile.
|
|
30
31
|
|
|
31
|
-
-
|
|
32
|
+
- Everything is a resource type behind eight tools: thinger_resource_list / _get / _create / _update / _delete / _clone, and thinger_resource_call for actions. Start with thinger_resource_describe without arguments: it lists the types with their ids, operations and actions and explains the platform's concepts (which data source fits each need, recipes). Each type's ids, filter, bodies, actions and ready-to-send examples are in thinger_resource_describe with that type: read it before the first call on a type.
|
|
33
|
+
- A record is located by \`ids\`, one key per level: {"device": "d1"}, {"device": "d1", "property": "setpoint"}, {"product": "p1", "resource": "temp"}. The records the tools answer carry their ids: pass them back as they are.
|
|
32
34
|
- List before acting to discover ids (thinger_resource_list with type "device", "product", "bucket"…); never guess them.
|
|
33
|
-
- Device resources (the API a connected device's firmware exposes) are
|
|
34
|
-
-
|
|
35
|
-
-
|
|
36
|
-
-
|
|
35
|
+
- Data and files are types too: a bucket's time series is "bucket_data" (list reads it, create writes samples), a storage's files "storage_file". Device resources (the API a connected device's firmware exposes) are "device_resource": list them, and run one with thinger_resource_call action "call".
|
|
36
|
+
- Guides: thinger_resource_list type "doc", then thinger_resource_get type "doc" with ids {"doc": <id>} (concepts, product-code, server-admin, dashboard-sdk…). Read the relevant one before building something new.
|
|
37
|
+
- Custom dashboards are web apps on the dashboard SDK, the npm package @thinger-io/dashboard-sdk (reference: thinger_resource_describe type "dashboard", or the guide "dashboard-sdk"). thinger_resource_call on type "dashboard": action "init" starts one (a TypeScript project from a template of the SDK), "dev" develops it on its own dev server (start the dev server first; the link opens the local app against the server with a temporary token: open it with browser tools to see it and read its console), and "publish" uploads the build folder once it works.
|
|
38
|
+
- Every tool takes an optional \`profile\` (another configured server, see thinger_resource_list type "profile") and most take \`user\` (another account, admin only).
|
|
39
|
+
- Deletes and most actions act immediately: confirm with the user before deleting, overwriting, or running an action that changes, removes or notifies. Actions that change a lot at once (replace_all, a host's settings or restart, removing a plugin) answer a plan first: show it to the user and repeat the call with confirm: true only if they agree.`;
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@thinger-io/cli",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "CLI for Thinger.io servers — devices, products, buckets — with an MCP server for AI clients",
|
|
3
|
+
"version": "0.5.0",
|
|
4
|
+
"description": "CLI for Thinger.io servers — devices, products, buckets, dashboard apps — with an MCP server for AI clients",
|
|
5
5
|
"main": "bin/thinger.js",
|
|
6
6
|
"bin": {
|
|
7
7
|
"thinger": "bin/thinger.js"
|
|
@@ -38,7 +38,7 @@
|
|
|
38
38
|
"author": "Thinger.io",
|
|
39
39
|
"license": "MIT",
|
|
40
40
|
"dependencies": {
|
|
41
|
-
"@thinger-io/cli-core": "^0.
|
|
41
|
+
"@thinger-io/cli-core": "^0.5.0"
|
|
42
42
|
},
|
|
43
43
|
"type": "module",
|
|
44
44
|
"engines": {
|