@thinger-io/cli 0.0.0-stage → 0.2.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 +51 -0
- package/LICENSE +22 -0
- package/README.md +138 -2
- package/bin/thinger.js +16 -0
- package/lib/identity.js +36 -0
- package/package.json +55 -5
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
## [0.2.1] - 2026-10-12
|
|
4
|
+
|
|
5
|
+
### Changed
|
|
6
|
+
|
|
7
|
+
- Published as `@thinger-io/cli` (formerly `@thinger-io/thinger-cli`, now
|
|
8
|
+
deprecated). The command is still `thinger` and profiles stay in
|
|
9
|
+
`~/.config/thinger-cli`.
|
|
10
|
+
|
|
11
|
+
## [0.2.0] - 2026-10-10
|
|
12
|
+
|
|
13
|
+
### Changed
|
|
14
|
+
|
|
15
|
+
- Requires `@thinger-io/cli-core` 0.2.0: the MCP server goes from 48 tools to
|
|
16
|
+
23 (`thinger_resource_*` over a catalog of resource types, plus the
|
|
17
|
+
operations that are not CRUD), less than half the size in `tools/list`.
|
|
18
|
+
Tool names change: `thinger_devices` → `thinger_resource_list` with
|
|
19
|
+
`type: "device"`, `thinger_profiles` → `thinger_profile_list`,
|
|
20
|
+
`thinger_bucket_read` → `thinger_bucket_data_read`, and so on.
|
|
21
|
+
- MCP instructions rewritten for the new tools.
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
## [0.1.1] - 2026-10-10
|
|
25
|
+
|
|
26
|
+
### Changed
|
|
27
|
+
|
|
28
|
+
- Requires `@thinger-io/cli-core` 0.1.1. First release published from GitHub
|
|
29
|
+
Actions through Trusted Publishing.
|
|
30
|
+
|
|
31
|
+
## [0.1.0] - 2026-10-10
|
|
32
|
+
|
|
33
|
+
First version: the `thinger` CLI, built on
|
|
34
|
+
[@thinger-io/cli-core](https://github.com/thinger-io/thinger-cli-core) (the generic
|
|
35
|
+
core of ThinRemote's `thinr`, made independent of the product).
|
|
36
|
+
|
|
37
|
+
### Added
|
|
38
|
+
|
|
39
|
+
- Thinger identity: profiles in `~/.config/thinger-cli`, `THINGER_PROFILE` /
|
|
40
|
+
`THINGER_INSECURE`, MCP tools as `thinger_*`.
|
|
41
|
+
- `login` with username/password (mints the `thinger_cli` API token), an
|
|
42
|
+
existing token (non-interactive with `--server --username --token`) or the
|
|
43
|
+
OAuth device flow with a client registered on the server.
|
|
44
|
+
- `logout` forgets the current profile (or `--all`) and revokes the API token
|
|
45
|
+
the CLI created.
|
|
46
|
+
- Commands: `device` (list, info, create, delete, set-product, property,
|
|
47
|
+
property-set, resource), `product` (list, info, create, delete,
|
|
48
|
+
property-list, property-get, property-set, property-delete), `bucket` (list,
|
|
49
|
+
read), `profile`.
|
|
50
|
+
- `thinger mcp`: devices, resources, properties, products, product profiles,
|
|
51
|
+
buckets, tokens, alarms and profiles.
|
package/LICENSE
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
|
|
2
|
+
MIT License
|
|
3
|
+
|
|
4
|
+
Copyright (c) 2025 Thinger.io
|
|
5
|
+
|
|
6
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
7
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
8
|
+
in the Software without restriction, including without limitation the rights
|
|
9
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
10
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
11
|
+
furnished to do so, subject to the following conditions:
|
|
12
|
+
|
|
13
|
+
The above copyright notice and this permission notice shall be included in all
|
|
14
|
+
copies or substantial portions of the Software.
|
|
15
|
+
|
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
17
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
18
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
19
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
20
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
21
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
22
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -1,3 +1,139 @@
|
|
|
1
|
-
#
|
|
1
|
+
# thinger — Thinger.io CLI
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
A command-line tool for any [Thinger.io](https://thinger.io) server, and an
|
|
4
|
+
MCP server that lets AI assistants (Claude Code, Claude Desktop, Cursor…)
|
|
5
|
+
operate it with the permissions of your token.
|
|
6
|
+
|
|
7
|
+
- **CLI** — devices, products, buckets and profiles from a shell, with
|
|
8
|
+
`--json` output for scripts.
|
|
9
|
+
- **MCP server** — `thinger mcp` serves 23 `thinger_*` tools over
|
|
10
|
+
stdio.
|
|
11
|
+
|
|
12
|
+
Both share the same profiles and API layer: sign in once, use either.
|
|
13
|
+
|
|
14
|
+
> Interim tool. The long-term Thinger MCP is built into the server itself;
|
|
15
|
+
> until then this CLI gives every Thinger server an MCP today.
|
|
16
|
+
|
|
17
|
+
## Installation
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
npm install -g @thinger-io/cli
|
|
21
|
+
# or, from source
|
|
22
|
+
git clone https://github.com/thinger-io/thinger-cli.git && cd thinger-cli && npm install && npm link
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
Requires Node.js 20 or newer.
|
|
26
|
+
|
|
27
|
+
## Signing in
|
|
28
|
+
|
|
29
|
+
```bash
|
|
30
|
+
thinger login # interactive: username/password, token or OAuth
|
|
31
|
+
thinger login --server acme.aws.thinger.io --username alice --token <API token>
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
- **Username and password** — creates (or replaces) an API token named
|
|
35
|
+
_Thinger CLI_ (id `thinger_cli`) on your account and stores it. `thinger
|
|
36
|
+
logout` revokes it.
|
|
37
|
+
- **Token** — paste an existing API token; it is validated and stored as is.
|
|
38
|
+
- **OAuth** — browser device flow. Needs an OAuth client registered on the
|
|
39
|
+
server (`--client-id`); Thinger servers ship none by default yet.
|
|
40
|
+
|
|
41
|
+
The server is a host (`acme.aws.thinger.io`, HTTPS) or a full URL for plain
|
|
42
|
+
HTTP or custom ports (`http://localhost:8080`). Self-signed certificates are
|
|
43
|
+
accepted for `localhost`, or anywhere with `THINGER_INSECURE=1`.
|
|
44
|
+
|
|
45
|
+
## Profiles
|
|
46
|
+
|
|
47
|
+
Each profile is a server plus its credentials, stored in
|
|
48
|
+
`~/.config/thinger-cli/config.json` (mode 600).
|
|
49
|
+
|
|
50
|
+
```bash
|
|
51
|
+
thinger profile add staging # sign in to another server
|
|
52
|
+
thinger profile list
|
|
53
|
+
thinger profile use staging # change the default
|
|
54
|
+
thinger --profile staging device list
|
|
55
|
+
THINGER_PROFILE=staging thinger device list
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
`-u, --user <account>` addresses another account on the same server when
|
|
59
|
+
your profile has admin rights.
|
|
60
|
+
|
|
61
|
+
## Commands
|
|
62
|
+
|
|
63
|
+
```bash
|
|
64
|
+
thinger device list [pattern] # regex on id/name
|
|
65
|
+
thinger device info <id>
|
|
66
|
+
thinger device create <id> [-t Generic|MQTT|HTTP|Virtual|Subdevice] [-p product]
|
|
67
|
+
thinger device delete <id> [-y]
|
|
68
|
+
thinger device set-product <id> <product>
|
|
69
|
+
thinger device property <id> [property] [-f dot.path]
|
|
70
|
+
thinger device property-set <id> <property> <json>
|
|
71
|
+
thinger device resource <id> [resource] [-i key=value …]
|
|
72
|
+
|
|
73
|
+
thinger product list | info <id> | delete <id>
|
|
74
|
+
thinger product create <id> [--from product.json] # { config, profile }
|
|
75
|
+
thinger product property-list <id>
|
|
76
|
+
thinger product property-get <id> <property>
|
|
77
|
+
thinger product property-set <id> <property> <json>
|
|
78
|
+
thinger product property-delete <id> <property>
|
|
79
|
+
|
|
80
|
+
thinger bucket list
|
|
81
|
+
thinger bucket read <bucket> [-d device] [-n 10] [-m minutes] [--agg 5m --agg-type mean]
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
Every command takes `-j, --json` and then prints `{ ok, data }` or
|
|
85
|
+
`{ ok: false, error: { message, code } }`.
|
|
86
|
+
|
|
87
|
+
## MCP server
|
|
88
|
+
|
|
89
|
+
```bash
|
|
90
|
+
claude mcp add thinger -- thinger mcp
|
|
91
|
+
# without installing it: claude mcp add thinger -- npx -y @thinger-io/cli mcp
|
|
92
|
+
# from source: claude mcp add thinger -- node /path/to/thinger-cli/bin/thinger.js mcp
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
Other hosts take the same command (`thinger`, args `["mcp"]`), or
|
|
96
|
+
`npx` with args `["-y", "@thinger-io/cli", "mcp"]`.
|
|
97
|
+
|
|
98
|
+
Tools:
|
|
99
|
+
|
|
100
|
+
- `thinger_resource_describe`, `_list`, `_get`, `_create`, `_update`,
|
|
101
|
+
`_delete`, `_clone`, `_call` — every server resource by `type`: devices,
|
|
102
|
+
products, buckets, dashboards, endpoints, storages, asset types and
|
|
103
|
+
groups, projects and their members, tokens, alarms, claims, properties,
|
|
104
|
+
their children, and the server's administration (users, hosts, domains,
|
|
105
|
+
brands, OAuth clients, identity providers, proxies). `resource_call` runs
|
|
106
|
+
actions such as verifying a domain, calling an endpoint or testing an
|
|
107
|
+
alarm rule. `resource_describe` shows a type's fields, examples and
|
|
108
|
+
actions, read from the server's own API description.
|
|
109
|
+
- `thinger_bucket_data_read` / `_write`, `thinger_device_resource_list` /
|
|
110
|
+
`_call`, `thinger_device_data_send`, `thinger_device_overview`,
|
|
111
|
+
`thinger_product_resource_call`, `thinger_storage_file_list` / `_read` /
|
|
112
|
+
`_write` / `_delete`, `thinger_dashboard_publish`, `thinger_doc_read`,
|
|
113
|
+
`thinger_profile_list`.
|
|
114
|
+
|
|
115
|
+
Every tool takes an optional `profile`, and most an optional `user`.
|
|
116
|
+
|
|
117
|
+
## Shared core
|
|
118
|
+
|
|
119
|
+
Everything that is not Thinger-specific — API client, auth, profiles, REST
|
|
120
|
+
helpers, the generic commands and the MCP tools — lives in
|
|
121
|
+
[@thinger-io/cli-core](https://github.com/thinger-io/thinger-cli-core). This CLI only
|
|
122
|
+
supplies its identity (`lib/identity.js`): binary name, config folder,
|
|
123
|
+
environment prefix, the token the password login creates, OAuth client and
|
|
124
|
+
MCP tool prefix. ThinRemote's `thinr` is built on the same core with its own
|
|
125
|
+
identity, so the two keep separate profiles and tool names and can run side
|
|
126
|
+
by side.
|
|
127
|
+
|
|
128
|
+
## Development
|
|
129
|
+
|
|
130
|
+
```bash
|
|
131
|
+
npm install
|
|
132
|
+
npm test # node --test
|
|
133
|
+
npm run lint
|
|
134
|
+
npm run typecheck
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
## License
|
|
138
|
+
|
|
139
|
+
MIT
|
package/bin/thinger.js
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import { readFileSync } from 'fs';
|
|
4
|
+
import { fileURLToPath } from 'url';
|
|
5
|
+
import { dirname, resolve } from 'path';
|
|
6
|
+
import { defineIdentity } from '@thinger-io/cli-core/identity';
|
|
7
|
+
import { runCli } from '@thinger-io/cli-core/cli';
|
|
8
|
+
import { mcpInstructions, thingerIdentity } from '../lib/identity.js';
|
|
9
|
+
|
|
10
|
+
// Single source of truth for the version: package.json.
|
|
11
|
+
const pkg = JSON.parse(
|
|
12
|
+
readFileSync(resolve(dirname(fileURLToPath(import.meta.url)), '../package.json'), 'utf8'),
|
|
13
|
+
);
|
|
14
|
+
|
|
15
|
+
defineIdentity(thingerIdentity);
|
|
16
|
+
await runCli({ version: pkg.version, mcpInstructions });
|
package/lib/identity.js
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
// @ts-check
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Identity of the `thinger` CLI. This is the only Thinger-specific piece:
|
|
5
|
+
* everything else comes from @thinger-io/cli-core, shared with other CLIs
|
|
6
|
+
* built on it (thinr), which pass their own identity.
|
|
7
|
+
*
|
|
8
|
+
* Profiles live apart from thinr's (~/.config/thinr-cli, THINR_*) on
|
|
9
|
+
* purpose, so neither CLI's MCP server operates on the other's servers.
|
|
10
|
+
*
|
|
11
|
+
* @type {import('@thinger-io/cli-core/identity').CliIdentity}
|
|
12
|
+
*/
|
|
13
|
+
export const thingerIdentity = {
|
|
14
|
+
name: 'thinger',
|
|
15
|
+
displayName: 'Thinger.io',
|
|
16
|
+
description:
|
|
17
|
+
'CLI for Thinger.io servers — devices, products, buckets, with an MCP server for AI clients',
|
|
18
|
+
configDir: 'thinger-cli',
|
|
19
|
+
envPrefix: 'THINGER',
|
|
20
|
+
token: { id: 'thinger_cli', name: 'Thinger CLI' },
|
|
21
|
+
// No OAuth client ships with Thinger servers yet: the browser login asks
|
|
22
|
+
// for one registered on the instance.
|
|
23
|
+
oauth: { clientId: null },
|
|
24
|
+
defaultServer: null,
|
|
25
|
+
mcp: { serverName: 'thinger', toolPrefix: 'thinger' },
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
/** Server-level guidance sent to MCP clients on `initialize`. */
|
|
29
|
+
export const mcpInstructions = `Tools to operate a Thinger.io IoT server with the permissions of the token stored in the CLI profile.
|
|
30
|
+
|
|
31
|
+
- Server resources (devices, products, buckets, dashboards, tokens, alarms, properties…) are reached through thinger_resource_list / _get / _create / _update / _delete / _clone with a \`type\`. Start with thinger_resource_describe without arguments: it lists the types and, on servers that publish it, explains the platform's concepts (which data source fits each need, recipes). With a type it gives its fields and examples: call it before writing one for the first time.
|
|
32
|
+
- 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 a different thing: thinger_device_resource_list / thinger_device_resource_call.
|
|
34
|
+
- Custom dashboards are HTML apps using the server's dashboard SDK: publish them with thinger_dashboard_publish (thinger_resource_describe type "dashboard" has the SDK reference).
|
|
35
|
+
- Every tool takes an optional \`profile\` (another configured server, see thinger_profile_list) and most take \`user\` (another account, admin only).
|
|
36
|
+
- Destructive tools (delete, overwrite) act immediately: confirm with the user first.`;
|
package/package.json
CHANGED
|
@@ -1,6 +1,56 @@
|
|
|
1
1
|
{
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
2
|
+
"name": "@thinger-io/cli",
|
|
3
|
+
"version": "0.2.1",
|
|
4
|
+
"description": "CLI for Thinger.io servers — devices, products, buckets — with an MCP server for AI clients",
|
|
5
|
+
"main": "bin/thinger.js",
|
|
6
|
+
"bin": {
|
|
7
|
+
"thinger": "bin/thinger.js"
|
|
8
|
+
},
|
|
9
|
+
"files": [
|
|
10
|
+
"bin",
|
|
11
|
+
"lib",
|
|
12
|
+
"CHANGELOG.md",
|
|
13
|
+
"LICENSE",
|
|
14
|
+
"README.md"
|
|
15
|
+
],
|
|
16
|
+
"repository": {
|
|
17
|
+
"type": "git",
|
|
18
|
+
"url": "git+https://github.com/thinger-io/thinger-cli.git"
|
|
19
|
+
},
|
|
20
|
+
"bugs": "https://github.com/thinger-io/thinger-cli/issues",
|
|
21
|
+
"homepage": "https://github.com/thinger-io/thinger-cli#readme",
|
|
22
|
+
"scripts": {
|
|
23
|
+
"start": "node bin/thinger.js",
|
|
24
|
+
"lint": "eslint .",
|
|
25
|
+
"lint:fix": "eslint . --fix",
|
|
26
|
+
"format": "prettier --write .",
|
|
27
|
+
"format:check": "prettier --check .",
|
|
28
|
+
"typecheck": "tsc",
|
|
29
|
+
"test": "node --test 'tests/**/*.test.js'"
|
|
30
|
+
},
|
|
31
|
+
"keywords": [
|
|
32
|
+
"cli",
|
|
33
|
+
"iot",
|
|
34
|
+
"thinger",
|
|
35
|
+
"thinger.io",
|
|
36
|
+
"mcp"
|
|
37
|
+
],
|
|
38
|
+
"author": "Thinger.io",
|
|
39
|
+
"license": "MIT",
|
|
40
|
+
"dependencies": {
|
|
41
|
+
"@thinger-io/cli-core": "^0.2.0"
|
|
42
|
+
},
|
|
43
|
+
"type": "module",
|
|
44
|
+
"engines": {
|
|
45
|
+
"node": ">=20"
|
|
46
|
+
},
|
|
47
|
+
"devDependencies": {
|
|
48
|
+
"@eslint/js": "^10.0.1",
|
|
49
|
+
"@types/node": "^25.6.0",
|
|
50
|
+
"eslint": "^10.2.0",
|
|
51
|
+
"eslint-config-prettier": "^10.1.8",
|
|
52
|
+
"globals": "^17.5.0",
|
|
53
|
+
"prettier": "^3.8.3",
|
|
54
|
+
"typescript": "^6.0.2"
|
|
55
|
+
}
|
|
56
|
+
}
|