@switchbot/openapi-cli 2.7.2 → 3.1.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/README.md +481 -103
- package/dist/api/client.js +23 -1
- package/dist/commands/agent-bootstrap.js +47 -2
- package/dist/commands/auth.js +354 -0
- package/dist/commands/batch.js +20 -4
- package/dist/commands/capabilities.js +155 -65
- package/dist/commands/config.js +109 -0
- package/dist/commands/daemon.js +367 -0
- package/dist/commands/devices.js +62 -11
- package/dist/commands/doctor.js +417 -8
- package/dist/commands/events.js +3 -3
- package/dist/commands/explain.js +1 -2
- package/dist/commands/health.js +113 -0
- package/dist/commands/install.js +246 -0
- package/dist/commands/mcp.js +888 -7
- package/dist/commands/plan.js +379 -103
- package/dist/commands/policy.js +586 -0
- package/dist/commands/rules.js +875 -0
- package/dist/commands/scenes.js +140 -0
- package/dist/commands/schema.js +0 -2
- package/dist/commands/status-sync.js +131 -0
- package/dist/commands/uninstall.js +237 -0
- package/dist/commands/upgrade-check.js +88 -0
- package/dist/config.js +14 -0
- package/dist/credentials/backends/file.js +101 -0
- package/dist/credentials/backends/linux.js +129 -0
- package/dist/credentials/backends/macos.js +129 -0
- package/dist/credentials/backends/windows.js +215 -0
- package/dist/credentials/keychain.js +88 -0
- package/dist/credentials/prime.js +52 -0
- package/dist/devices/catalog.js +4 -10
- package/dist/index.js +30 -1
- package/dist/install/default-steps.js +257 -0
- package/dist/install/preflight.js +212 -0
- package/dist/install/steps.js +67 -0
- package/dist/lib/command-keywords.js +17 -0
- package/dist/lib/daemon-state.js +46 -0
- package/dist/lib/destructive-mode.js +12 -0
- package/dist/lib/devices.js +1 -1
- package/dist/lib/plan-store.js +68 -0
- package/dist/policy/add-rule.js +124 -0
- package/dist/policy/diff.js +91 -0
- package/dist/policy/examples/policy.example.yaml +99 -0
- package/dist/policy/format.js +57 -0
- package/dist/policy/load.js +61 -0
- package/dist/policy/migrate.js +67 -0
- package/dist/policy/schema/v0.2.json +331 -0
- package/dist/policy/schema.js +18 -0
- package/dist/policy/validate.js +262 -0
- package/dist/rules/action.js +205 -0
- package/dist/rules/audit-query.js +89 -0
- package/dist/rules/conflict-analyzer.js +203 -0
- package/dist/rules/cron-scheduler.js +186 -0
- package/dist/rules/destructive.js +52 -0
- package/dist/rules/engine.js +757 -0
- package/dist/rules/matcher.js +230 -0
- package/dist/rules/pid-file.js +95 -0
- package/dist/rules/quiet-hours.js +45 -0
- package/dist/rules/suggest.js +95 -0
- package/dist/rules/throttle.js +116 -0
- package/dist/rules/types.js +34 -0
- package/dist/rules/webhook-listener.js +223 -0
- package/dist/rules/webhook-token.js +90 -0
- package/dist/status-sync/manager.js +268 -0
- package/dist/utils/audit.js +12 -2
- package/dist/utils/health.js +101 -0
- package/dist/utils/output.js +72 -23
- package/dist/utils/retry.js +81 -0
- package/package.json +12 -4
package/README.md
CHANGED
|
@@ -14,17 +14,30 @@ Run scenes, stream real-time events over MQTT, and plug AI agents into your home
|
|
|
14
14
|
- **Releases / changelog:** [GitHub Releases](https://github.com/OpenWonderLabs/switchbot-openapi-cli/releases)
|
|
15
15
|
- **Issues / feature requests:** [GitHub Issues](https://github.com/OpenWonderLabs/switchbot-openapi-cli/issues)
|
|
16
16
|
|
|
17
|
+
> Looking for the **conversational skill** that drives this CLI from a chat
|
|
18
|
+
> agent? A companion skill for third-party agent hosts is maintained in a
|
|
19
|
+
> separate repository.
|
|
20
|
+
> See [`docs/agent-guide.md`](./docs/agent-guide.md) for the authoritative
|
|
21
|
+
> surfaces (MCP, `agent-bootstrap`, `schema export`, `capabilities --json`)
|
|
22
|
+
> the skill consumes. Skill packaging + registry entry is tracked
|
|
23
|
+
> as Phase 3B — see [`docs/design/roadmap.md`](./docs/design/roadmap.md).
|
|
24
|
+
|
|
17
25
|
---
|
|
18
26
|
|
|
19
27
|
## Who is this for?
|
|
20
28
|
|
|
21
29
|
Three entry points, same binary — pick the one that matches how you use it:
|
|
22
30
|
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
31
|
+
- **Human**: start with this README ([Quick start](#quick-start)).
|
|
32
|
+
You get colored tables, helpful error hints, shell completion, and
|
|
33
|
+
`switchbot doctor` self-check.
|
|
34
|
+
- **Script**: start with [Output modes](#output-modes) and
|
|
35
|
+
[Scripting examples](#scripting-examples).
|
|
36
|
+
You get `--json`, `--format=tsv/yaml/id`, `--fields`, stable exit codes,
|
|
37
|
+
`history replay`, and audit log support.
|
|
38
|
+
- **Agent**: start with [`docs/agent-guide.md`](./docs/agent-guide.md).
|
|
39
|
+
You get `switchbot mcp serve` (stdio MCP server), `schema export`,
|
|
40
|
+
`plan run`, and destructive-command guards.
|
|
28
41
|
|
|
29
42
|
Under the hood every surface shares the same catalog, cache, and HMAC client — switching between them costs nothing.
|
|
30
43
|
|
|
@@ -37,6 +50,7 @@ Under the hood every surface shares the same catalog, cache, and HMAC client —
|
|
|
37
50
|
- [Installation](#installation)
|
|
38
51
|
- [Quick start](#quick-start)
|
|
39
52
|
- [Credentials](#credentials)
|
|
53
|
+
- [Policy](#policy)
|
|
40
54
|
- [Global options](#global-options)
|
|
41
55
|
- [Commands](#commands)
|
|
42
56
|
- [`config`](#config--credential-management)
|
|
@@ -46,18 +60,22 @@ Under the hood every surface shares the same catalog, cache, and HMAC client —
|
|
|
46
60
|
- [`scenes`](#scenes--run-manual-scenes)
|
|
47
61
|
- [`webhook`](#webhook--receive-device-events-over-http)
|
|
48
62
|
- [`events`](#events--receive-device-events)
|
|
63
|
+
- [`status-sync`](#status-sync--mqttopenclaw-bridge)
|
|
49
64
|
- [`plan`](#plan--declarative-batch-operations)
|
|
50
65
|
- [`mcp`](#mcp--model-context-protocol-server)
|
|
51
66
|
- [`doctor`](#doctor--self-check)
|
|
67
|
+
- [`health`](#health--runtime-health-report)
|
|
68
|
+
- [`upgrade-check`](#upgrade-check--version-check)
|
|
52
69
|
- [`quota`](#quota--api-request-counter)
|
|
53
70
|
- [`history`](#history--audit-log)
|
|
54
71
|
- [`catalog`](#catalog--device-type-catalog)
|
|
55
72
|
- [`schema`](#schema--export-catalog-as-json)
|
|
56
73
|
- [`capabilities`](#capabilities--cli-manifest)
|
|
57
74
|
- [`cache`](#cache--inspect-and-clear-local-cache)
|
|
75
|
+
- [`policy`](#policy--validate-scaffold-and-migrate-policyyaml)
|
|
58
76
|
- [`completion`](#completion--shell-tab-completion)
|
|
59
77
|
- [Output modes](#output-modes)
|
|
60
|
-
- [Cache](#cache
|
|
78
|
+
- [Cache](#cache)
|
|
61
79
|
- [Exit codes & error codes](#exit-codes--error-codes)
|
|
62
80
|
- [Environment variables](#environment-variables)
|
|
63
81
|
- [Scripting examples](#scripting-examples)
|
|
@@ -76,7 +94,7 @@ Under the hood every surface shares the same catalog, cache, and HMAC client —
|
|
|
76
94
|
- 🎨 **Dual output modes** — colorized tables by default; `--json` passthrough for `jq` and scripting
|
|
77
95
|
- 🔐 **Secure credentials** — HMAC-SHA256 signed requests; config file written with `0600`; env-var override for CI
|
|
78
96
|
- 🔍 **Dry-run mode** — preview every mutating request before it hits the API
|
|
79
|
-
- 🧪 **Fully tested** —
|
|
97
|
+
- 🧪 **Fully tested** — 1856 Vitest tests, mocked axios, zero network in CI
|
|
80
98
|
- ⚡ **Shell completion** — Bash / Zsh / Fish / PowerShell
|
|
81
99
|
|
|
82
100
|
## Requirements
|
|
@@ -113,6 +131,16 @@ switchbot --help
|
|
|
113
131
|
|
|
114
132
|
## Quick start
|
|
115
133
|
|
|
134
|
+
The fast path (credentials + policy + skill link, with rollback on failure):
|
|
135
|
+
|
|
136
|
+
```bash
|
|
137
|
+
switchbot install --agent claude-code --skill-path ../switchbot-skill
|
|
138
|
+
# or preview first
|
|
139
|
+
switchbot install --dry-run
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
Prefer the manual 4-step walk-through? Here it is:
|
|
143
|
+
|
|
116
144
|
```bash
|
|
117
145
|
# 1. Save your credentials (one-time)
|
|
118
146
|
switchbot config set-token <token> <secret>
|
|
@@ -120,16 +148,44 @@ switchbot config set-token <token> <secret>
|
|
|
120
148
|
# 2. List every device on your account
|
|
121
149
|
switchbot devices list
|
|
122
150
|
|
|
123
|
-
# 3. Control a device
|
|
124
|
-
switchbot devices command <deviceId> turnOn
|
|
151
|
+
# 3. Control a device, writing a structured entry to the audit log
|
|
152
|
+
switchbot devices command <deviceId> turnOn --audit-log
|
|
153
|
+
|
|
154
|
+
# 4. Confirm everything is healthy — network, catalog, credentials, cache.
|
|
155
|
+
# Any non-"ok" check prints with a hint; fix those first.
|
|
156
|
+
switchbot doctor --json | jq '.checks[] | select(.status!="ok")'
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
Adding an AI agent or declarative automation? A few more one-liners
|
|
160
|
+
round out the first-day path:
|
|
161
|
+
|
|
162
|
+
```bash
|
|
163
|
+
# 5. Cold-start snapshot an LLM can read before its first tool call.
|
|
164
|
+
switchbot agent-bootstrap --compact | jq '.identity, .devices.total'
|
|
165
|
+
|
|
166
|
+
# 6. Scaffold a policy.yaml (aliases, quiet hours, confirmations) and
|
|
167
|
+
# validate it. Safe to run — defaults apply if you never edit it.
|
|
168
|
+
switchbot policy new
|
|
169
|
+
switchbot policy validate
|
|
170
|
+
|
|
171
|
+
# 7. Stream real-time device events over MQTT (events land as JSONL).
|
|
172
|
+
switchbot events mqtt-tail --max 3 --json
|
|
173
|
+
|
|
174
|
+
# 8. Run the OpenClaw status bridge in the background.
|
|
175
|
+
switchbot status-sync start --openclaw-model home-agent
|
|
125
176
|
```
|
|
126
177
|
|
|
178
|
+
See [Policy](#policy) for the authoring flow, [Rules engine](#rules-engine)
|
|
179
|
+
for automations, and [`docs/agent-guide.md`](./docs/agent-guide.md)
|
|
180
|
+
for the agent surface.
|
|
181
|
+
|
|
127
182
|
## Credentials
|
|
128
183
|
|
|
129
184
|
The CLI reads credentials in this order (first match wins):
|
|
130
185
|
|
|
131
186
|
1. **Environment variables** — `SWITCHBOT_TOKEN` and `SWITCHBOT_SECRET`
|
|
132
|
-
2. **
|
|
187
|
+
2. **OS keychain** — native keychain (macOS Keychain / Windows Credential Manager / libsecret on Linux) when populated via `switchbot auth keychain set`
|
|
188
|
+
3. **Config file** — `~/.switchbot/config.json` (written by `config set-token`, mode `0600`)
|
|
133
189
|
|
|
134
190
|
Obtain the token and secret from the SwitchBot mobile app:
|
|
135
191
|
**Profile → Preferences → Developer Options → Get Token**.
|
|
@@ -146,30 +202,150 @@ export SWITCHBOT_SECRET=...
|
|
|
146
202
|
switchbot config show
|
|
147
203
|
```
|
|
148
204
|
|
|
205
|
+
### OS keychain
|
|
206
|
+
|
|
207
|
+
Prefer native OS storage over the `0600` JSON on disk:
|
|
208
|
+
|
|
209
|
+
```bash
|
|
210
|
+
# See which backend is active on this machine
|
|
211
|
+
switchbot auth keychain describe
|
|
212
|
+
|
|
213
|
+
# Move existing ~/.switchbot/config.json into the keychain.
|
|
214
|
+
# With --delete-file, the CLI deletes the source only when it contains
|
|
215
|
+
# nothing except token/secret; otherwise it scrubs those fields and keeps
|
|
216
|
+
# profile metadata such as labels and limits.
|
|
217
|
+
switchbot auth keychain migrate
|
|
218
|
+
|
|
219
|
+
# Or write credentials directly (TTY prompt or --stdin-file <path>)
|
|
220
|
+
switchbot auth keychain set
|
|
221
|
+
|
|
222
|
+
# Verify a profile has credentials without leaking the material
|
|
223
|
+
switchbot auth keychain get
|
|
224
|
+
```
|
|
225
|
+
|
|
226
|
+
Backends: `security(1)` on macOS, `libsecret` / `secret-tool` on Linux,
|
|
227
|
+
Credential Manager (via PowerShell + Win32 `CredReadW`/`CredWriteW`) on
|
|
228
|
+
Windows. If no native backend is available, the file backend takes
|
|
229
|
+
over transparently so the CLI keeps working. `switchbot doctor`
|
|
230
|
+
surfaces which backend is active and warns when file-stored credentials
|
|
231
|
+
could be moved into a writable keychain.
|
|
232
|
+
|
|
233
|
+
## Policy
|
|
234
|
+
|
|
235
|
+
`policy.yaml` is an optional per-user file that declares preferences
|
|
236
|
+
the CLI (and any connected AI agent) should honour: device aliases,
|
|
237
|
+
quiet-hours, confirmation overrides, audit-log location, and CLI
|
|
238
|
+
profile. The file lives at:
|
|
239
|
+
|
|
240
|
+
- Linux / macOS: default policy path resolved by the CLI
|
|
241
|
+
- Windows: default policy path resolved by the CLI
|
|
242
|
+
|
|
243
|
+
Everything in it is optional — if the file is missing, safe defaults
|
|
244
|
+
apply. Scaffold, edit, and validate:
|
|
245
|
+
|
|
246
|
+
```bash
|
|
247
|
+
switchbot policy new # write a commented starter template
|
|
248
|
+
$EDITOR <policy-path>
|
|
249
|
+
switchbot policy validate # exit 0 if OK, otherwise line-accurate error
|
|
250
|
+
```
|
|
251
|
+
|
|
252
|
+
Why most users want a policy file: it makes name resolution
|
|
253
|
+
deterministic. Without it, "turn on the bedroom light" falls through
|
|
254
|
+
the CLI's prefix/substring/fuzzy match strategies and can pick the
|
|
255
|
+
wrong device when two names collide. A one-line `aliases` entry
|
|
256
|
+
removes the ambiguity.
|
|
257
|
+
|
|
258
|
+
**Schema version.** The CLI requires **policy v0.2**. If you have an existing
|
|
259
|
+
v0.1 file from an earlier release, migrate it first:
|
|
260
|
+
|
|
261
|
+
```bash
|
|
262
|
+
switchbot policy migrate # in-place upgrade, preserves comments
|
|
263
|
+
```
|
|
264
|
+
|
|
265
|
+
The v0.2 schema adds a typed `automation.rules[]` block (triggers, conditions,
|
|
266
|
+
throttles, dry-run) used by the rules engine (see
|
|
267
|
+
[Rules engine](#rules-engine)). Full field-by-field reference, validation flow,
|
|
268
|
+
and error catalogue: [`docs/policy-reference.md`](./docs/policy-reference.md).
|
|
269
|
+
Five annotated starter files covering common setups live in
|
|
270
|
+
[`examples/policies/`](./examples/policies/).
|
|
271
|
+
|
|
272
|
+
### Rules engine
|
|
273
|
+
|
|
274
|
+
With a policy.yaml (v0.2) you can declare automations that the CLI
|
|
275
|
+
executes for you. Supported triggers: **MQTT** (device events),
|
|
276
|
+
**cron** (schedule-driven), and **webhook** (local HTTP POST).
|
|
277
|
+
Supported conditions: `time_between` (quiet hours) and `device_state`
|
|
278
|
+
(live API check with per-tick dedup). Every fire is recorded in
|
|
279
|
+
`~/.switchbot/audit.log`. `rules run` is long-running; use
|
|
280
|
+
`daemon start` / `daemon reload` for the managed background mode.
|
|
281
|
+
|
|
282
|
+
```bash
|
|
283
|
+
# 1. Author rules under `automation.rules`. See examples/policies/automation.yaml
|
|
284
|
+
# for a walkthrough covering the three trigger sources.
|
|
285
|
+
|
|
286
|
+
# 2. Static-check before running.
|
|
287
|
+
switchbot rules lint # exit 0 valid, 1 error
|
|
288
|
+
switchbot rules list --json | jq . # structured summary
|
|
289
|
+
|
|
290
|
+
# 3. Inspect a single rule in full detail (trigger, conditions, actions,
|
|
291
|
+
# cooldown, hysteresis, maxFiringsPerHour, suppressIfAlreadyDesired, last fired).
|
|
292
|
+
switchbot rules explain "motion on"
|
|
293
|
+
switchbot rules explain "motion on" --json
|
|
294
|
+
|
|
295
|
+
# 4. Run the engine. --dry-run overrides every rule into audit-only mode;
|
|
296
|
+
# --max-firings bounds a demo session.
|
|
297
|
+
switchbot rules run --dry-run --max-firings 5
|
|
298
|
+
|
|
299
|
+
# 5. Edit policy.yaml in another shell, then hot-reload without restart.
|
|
300
|
+
switchbot daemon reload # managed daemon reload
|
|
301
|
+
|
|
302
|
+
# 6. Review recorded fires.
|
|
303
|
+
switchbot rules tail --follow # stream rule-* audit lines
|
|
304
|
+
switchbot rules replay --since 1h --json # per-rule fires/dries/throttled/errors
|
|
305
|
+
switchbot rules summary # aggregate fires/errors per rule (24h window)
|
|
306
|
+
switchbot rules last-fired -n 20 # 20 most recent fire entries
|
|
307
|
+
|
|
308
|
+
# 7. Conflict and health analysis.
|
|
309
|
+
switchbot rules conflicts # opposing actions, high-frequency MQTT,
|
|
310
|
+
# destructive commands, quiet-hours gaps
|
|
311
|
+
switchbot rules doctor --json # lint + conflicts combined; exit 0 when clean
|
|
312
|
+
```
|
|
313
|
+
|
|
314
|
+
When `quiet_hours` is configured in `policy.yaml`, `rules conflicts` additionally flags event-driven (MQTT / webhook) rules that lack a `time_between` condition — they would fire uninhibited during the quiet window. The hint in each finding includes a ready-to-paste `time_between` condition to add.
|
|
315
|
+
|
|
316
|
+
Webhook trigger token management:
|
|
317
|
+
|
|
318
|
+
```bash
|
|
319
|
+
switchbot rules webhook-rotate-token # rotate the bearer token for webhook triggers
|
|
320
|
+
switchbot rules webhook-show-token # print current token (creates one if absent)
|
|
321
|
+
```
|
|
322
|
+
|
|
323
|
+
See [`docs/design/phase4-rules.md`](./docs/design/phase4-rules.md) for
|
|
324
|
+
the engine's pipeline (subscribe → classify → match → conditions →
|
|
325
|
+
throttle → action → audit).
|
|
326
|
+
|
|
149
327
|
## Global options
|
|
150
328
|
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
| `-V`, `--version` | Print the CLI version |
|
|
172
|
-
| `-h`, `--help` | Show help for any command or subcommand |
|
|
329
|
+
- `--json`: Print the raw JSON response instead of a formatted table.
|
|
330
|
+
- `--format <fmt>`: Output format: `tsv`, `yaml`, `jsonl`, `json`, `id`.
|
|
331
|
+
- `--fields <cols>`: Comma-separated column names to include (for example `deviceId,type`).
|
|
332
|
+
- `-v`, `--verbose`: Log HTTP request/response details to stderr.
|
|
333
|
+
- `--dry-run`: Print mutating requests (POST/PUT/DELETE) without sending them.
|
|
334
|
+
- `--timeout <ms>`: HTTP request timeout in milliseconds (default `30000`).
|
|
335
|
+
- `--config <path>`: Override credential file location (default `~/.switchbot/config.json`).
|
|
336
|
+
- `--profile <name>`: Use a named credential profile (`~/.switchbot/profiles/<name>.json`).
|
|
337
|
+
- `--cache <dur>`: Set list and status cache TTL, for example `5m`, `1h`, `off`, `auto` (default).
|
|
338
|
+
- `--cache-list <dur>`: Set list-cache TTL independently (overrides `--cache`).
|
|
339
|
+
- `--cache-status <dur>`: Set status-cache TTL independently (default off; overrides `--cache`).
|
|
340
|
+
- `--no-cache`: Disable all cache reads for this invocation.
|
|
341
|
+
- `--retry-on-429 <n>`: Max 429 retry attempts (default `3`).
|
|
342
|
+
- `--no-retry`: Disable automatic 429 retries.
|
|
343
|
+
- `--backoff <strategy>`: Retry backoff: `exponential` (default) or `linear`.
|
|
344
|
+
- `--no-quota`: Disable local request-quota tracking.
|
|
345
|
+
- `--audit-log`: Append mutating commands to a JSONL audit log (default path `~/.switchbot/audit.log`).
|
|
346
|
+
- `--audit-log-path <path>`: Custom audit log path; use together with `--audit-log`.
|
|
347
|
+
- `-V`, `--version`: Print the CLI version.
|
|
348
|
+
- `-h`, `--help`: Show help for any command or subcommand.
|
|
173
349
|
|
|
174
350
|
Every subcommand supports `--help`, and most include a parameter-format reference and examples.
|
|
175
351
|
|
|
@@ -203,6 +379,12 @@ switchbot devices command ABC123 turnOn --dry-run
|
|
|
203
379
|
switchbot config set-token <token> <secret> # Save to ~/.switchbot/config.json
|
|
204
380
|
switchbot config show # Print current source + masked secret
|
|
205
381
|
switchbot config list-profiles # List saved profiles
|
|
382
|
+
|
|
383
|
+
# Print (or write) the recommended AI-agent profile template
|
|
384
|
+
switchbot config agent-profile # print to stdout
|
|
385
|
+
switchbot config agent-profile --write # write to ~/.switchbot/profiles/agent.json (mode 0600)
|
|
386
|
+
switchbot config agent-profile --write --force # overwrite if it already exists
|
|
387
|
+
switchbot config agent-profile --json # structured JSON envelope
|
|
206
388
|
```
|
|
207
389
|
|
|
208
390
|
### `devices` — list, status, control
|
|
@@ -231,7 +413,7 @@ switchbot devices list --filter 'name~living'
|
|
|
231
413
|
switchbot devices list --filter 'type=/Hub.*/'
|
|
232
414
|
switchbot devices list --filter 'name~office,type=/Bulb|Strip/'
|
|
233
415
|
|
|
234
|
-
# Filter by family / room (family & room info requires the
|
|
416
|
+
# Filter by family / room (family & room info requires the platform source
|
|
235
417
|
# header, which this CLI sends on every request)
|
|
236
418
|
switchbot devices list --json | jq '.deviceList[] | select(.familyName == "Home")'
|
|
237
419
|
switchbot devices list --json | jq '[.deviceList[], .infraredRemoteList[]] | group_by(.familyName)'
|
|
@@ -270,11 +452,16 @@ switchbot devices commands curtain # Case-insensitive, substring match
|
|
|
270
452
|
Three commands accept `--filter`. They share one four-operator grammar,
|
|
271
453
|
but each exposes its own key set:
|
|
272
454
|
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
455
|
+
- `devices list`
|
|
456
|
+
Operators: `=` (substring; **exact** for `category`), `!=` (negated),
|
|
457
|
+
`~` (substring), `=/regex/` (case-insensitive regex).
|
|
458
|
+
Keys: `type`, `name`, `category`, `room`.
|
|
459
|
+
- `devices batch`
|
|
460
|
+
Operators: same as `devices list`.
|
|
461
|
+
Keys: `type`, `family`, `room`, `category`.
|
|
462
|
+
- `events tail` / `events mqtt-tail`
|
|
463
|
+
Operators: same (tail only; mqtt-tail uses `--topic` instead).
|
|
464
|
+
Keys: `deviceId`, `type`.
|
|
278
465
|
|
|
279
466
|
Clauses are comma-separated and AND-ed. No OR across clauses — use regex
|
|
280
467
|
alternation (`=/A|B/`) for that. `category` is the one key that stays exact
|
|
@@ -393,6 +580,10 @@ skipped devices appear under `summary.skipped` with `skippedReason:'offline'`.
|
|
|
393
580
|
```bash
|
|
394
581
|
switchbot scenes list # Columns: sceneId, sceneName
|
|
395
582
|
switchbot scenes execute <sceneId>
|
|
583
|
+
|
|
584
|
+
# One-shot summary: risk profile, execution hint, estimated commands
|
|
585
|
+
switchbot scenes explain <sceneId>
|
|
586
|
+
switchbot scenes explain <sceneId> --json
|
|
396
587
|
```
|
|
397
588
|
|
|
398
589
|
### `webhook` — receive device events over HTTP
|
|
@@ -441,7 +632,8 @@ switchbot events tail --port 8080 --path /hook --json
|
|
|
441
632
|
Run `switchbot webhook setup https://your.host/hook` first to tell SwitchBot where to send events, then expose the local port via ngrok/cloudflared and point the webhook URL at it. `events tail` only runs the local receiver — tunnelling is up to you.
|
|
442
633
|
|
|
443
634
|
Output (one JSON line per matched event):
|
|
444
|
-
|
|
635
|
+
|
|
636
|
+
```json
|
|
445
637
|
{ "t": "2024-01-01T12:00:00.000Z", "remote": "1.2.3.4:54321", "path": "/", "body": {...}, "matched": true }
|
|
446
638
|
```
|
|
447
639
|
|
|
@@ -466,7 +658,8 @@ switchbot events mqtt-tail --for 30s --json
|
|
|
466
658
|
Connects to the SwitchBot MQTT service automatically using the same credentials configured for the REST API (`SWITCHBOT_TOKEN` + `SWITCHBOT_SECRET`). No additional MQTT configuration is required — the client certificates are provisioned on first use.
|
|
467
659
|
|
|
468
660
|
Output (one JSON line per message):
|
|
469
|
-
|
|
661
|
+
|
|
662
|
+
```json
|
|
470
663
|
{ "t": "2024-01-01T12:00:00.000Z", "topic": "switchbot/abc123/status", "payload": {...} }
|
|
471
664
|
```
|
|
472
665
|
|
|
@@ -482,31 +675,65 @@ nohup switchbot events mqtt-tail --json >> ~/switchbot-events.log 2>&1 &
|
|
|
482
675
|
|
|
483
676
|
Run `switchbot doctor` to verify MQTT credentials are configured correctly before connecting.
|
|
484
677
|
|
|
678
|
+
### `status-sync` — MQTT/OpenClaw bridge
|
|
679
|
+
|
|
680
|
+
Use this command family when you want the CLI itself to own the lifecycle of a
|
|
681
|
+
long-running bridge that forwards SwitchBot MQTT shadow events into an OpenClaw
|
|
682
|
+
gateway. Internally it reuses `events mqtt-tail --sink openclaw`, but adds a
|
|
683
|
+
stable command surface for foreground execution, background startup, status
|
|
684
|
+
inspection, and shutdown.
|
|
685
|
+
|
|
686
|
+
```bash
|
|
687
|
+
# Foreground mode for supervisors / containers
|
|
688
|
+
switchbot status-sync run --openclaw-model home-agent
|
|
689
|
+
|
|
690
|
+
# Background mode for a normal shell session
|
|
691
|
+
switchbot status-sync start --openclaw-model home-agent
|
|
692
|
+
|
|
693
|
+
# Inspect the current bridge
|
|
694
|
+
switchbot status-sync status --json
|
|
695
|
+
|
|
696
|
+
# Stop the running bridge
|
|
697
|
+
switchbot status-sync stop
|
|
698
|
+
```
|
|
699
|
+
|
|
700
|
+
Required input:
|
|
701
|
+
|
|
702
|
+
- `OPENCLAW_MODEL` or `--openclaw-model <id>`
|
|
703
|
+
- `OPENCLAW_TOKEN` or `--openclaw-token <token>`
|
|
704
|
+
|
|
705
|
+
Optional input:
|
|
706
|
+
|
|
707
|
+
- `OPENCLAW_URL` or `--openclaw-url <url>`
|
|
708
|
+
- `--topic <pattern>` to narrow the MQTT subscription
|
|
709
|
+
- `SWITCHBOT_STATUS_SYNC_HOME` or `--state-dir <path>` for custom runtime state
|
|
710
|
+
|
|
711
|
+
Background mode writes these files under the state directory:
|
|
712
|
+
|
|
713
|
+
- `state.json` — current pid, start time, effective command
|
|
714
|
+
- `stdout.log` — child stdout
|
|
715
|
+
- `stderr.log` — child stderr
|
|
716
|
+
|
|
717
|
+
Foreground vs background:
|
|
718
|
+
|
|
719
|
+
- `status-sync run` keeps the bridge attached to the current terminal
|
|
720
|
+
- `status-sync start` detaches the bridge and returns immediately
|
|
721
|
+
- `status-sync status` reports whether the bridge is alive plus paths/logs
|
|
722
|
+
- `status-sync stop` terminates the managed bridge process tree
|
|
723
|
+
|
|
485
724
|
#### `mqtt-tail` sinks — route events to external services
|
|
486
725
|
|
|
487
726
|
By default `mqtt-tail` prints JSONL to stdout. Use `--sink` (repeatable) to route events to one or more destinations instead:
|
|
488
727
|
|
|
489
728
|
| Sink | Required flags |
|
|
490
|
-
|
|
729
|
+
| --- | --- |
|
|
491
730
|
| `stdout` | (default when no `--sink` given) |
|
|
492
731
|
| `file` | `--sink-file <path>` — append JSONL |
|
|
493
732
|
| `webhook` | `--webhook-url <url>` — HTTP POST each event |
|
|
494
|
-
| `openclaw` | `--openclaw-url`, `--openclaw-token` (or `$OPENCLAW_TOKEN`), `--openclaw-model` |
|
|
495
733
|
| `telegram` | `--telegram-token` (or `$TELEGRAM_TOKEN`), `--telegram-chat <chatId>` |
|
|
496
734
|
| `homeassistant` | `--ha-url <url>` + `--ha-webhook-id` (no auth) or `--ha-token` (REST event API) |
|
|
497
735
|
|
|
498
736
|
```bash
|
|
499
|
-
# Push events to an OpenClaw agent (replaces the SwitchBot channel plugin)
|
|
500
|
-
switchbot events mqtt-tail \
|
|
501
|
-
--sink openclaw \
|
|
502
|
-
--openclaw-token <token> \
|
|
503
|
-
--openclaw-model my-home-agent
|
|
504
|
-
|
|
505
|
-
# Write to file + push to OpenClaw simultaneously
|
|
506
|
-
switchbot events mqtt-tail \
|
|
507
|
-
--sink file --sink-file ~/.switchbot/events.jsonl \
|
|
508
|
-
--sink openclaw --openclaw-token <token> --openclaw-model home
|
|
509
|
-
|
|
510
737
|
# Generic webhook (n8n, Make, etc.)
|
|
511
738
|
switchbot events mqtt-tail --sink webhook --webhook-url https://n8n.local/hook/abc
|
|
512
739
|
|
|
@@ -540,18 +767,27 @@ Supported shells: `bash`, `zsh`, `fish`, `powershell` (`pwsh` is accepted as an
|
|
|
540
767
|
# Print the plan JSON Schema (give to your agent framework)
|
|
541
768
|
switchbot plan schema
|
|
542
769
|
|
|
770
|
+
# Draft a candidate plan from natural language intent
|
|
771
|
+
switchbot plan suggest --intent "turn off all lights" --device <id1> --device <id2>
|
|
772
|
+
|
|
543
773
|
# Validate a plan file without running it
|
|
544
774
|
switchbot plan validate plan.json
|
|
545
775
|
|
|
546
776
|
# Preview — mutations skipped, GETs still execute
|
|
547
777
|
switchbot --dry-run plan run plan.json
|
|
548
778
|
|
|
549
|
-
#
|
|
550
|
-
switchbot plan
|
|
779
|
+
# Save / review / approve / execute for destructive plans
|
|
780
|
+
switchbot plan save plan.json
|
|
781
|
+
switchbot plan review <planId>
|
|
782
|
+
switchbot plan approve <planId>
|
|
783
|
+
switchbot plan execute <planId>
|
|
551
784
|
switchbot plan run plan.json --continue-on-error
|
|
785
|
+
|
|
786
|
+
# Run with per-step TTY confirmation for destructive steps (human-in-the-loop)
|
|
787
|
+
switchbot plan run plan.json --require-approval
|
|
552
788
|
```
|
|
553
789
|
|
|
554
|
-
A plan file is a JSON document with `version`, `description`, and a `steps` array of `command`, `scene`, or `wait` steps. Steps execute sequentially; a failed step stops the run unless `--continue-on-error` is set. See [`docs/agent-guide.md`](./docs/agent-guide.md) for the full schema and agent integration patterns.
|
|
790
|
+
A plan file is a JSON document with `version`, `description`, and a `steps` array of `command`, `scene`, or `wait` steps. Steps execute sequentially; a failed step stops the run unless `--continue-on-error` is set. `plan run` is the preview/direct path, but destructive steps are blocked by default and should go through `plan save` → `plan review` → `plan approve` → `plan execute`. See [`docs/agent-guide.md`](./docs/agent-guide.md) for the full schema and agent integration patterns.
|
|
555
791
|
|
|
556
792
|
### `devices watch` — poll status
|
|
557
793
|
|
|
@@ -575,7 +811,12 @@ Output is a JSONL stream of status-change events (with `--json`) or a refreshed
|
|
|
575
811
|
switchbot mcp serve
|
|
576
812
|
```
|
|
577
813
|
|
|
578
|
-
Exposes
|
|
814
|
+
Exposes MCP tools (`list_devices`, `describe_device`, `get_device_status`,
|
|
815
|
+
`send_command`, `list_scenes`, `run_scene`, `search_catalog`,
|
|
816
|
+
`account_overview`, `plan_suggest`, `plan_run`, `audit_query`,
|
|
817
|
+
`audit_stats`, `policy_diff`, `policy_validate`, `policy_new`,
|
|
818
|
+
`policy_migrate`) plus a `switchbot://events` resource for real-time
|
|
819
|
+
shadow updates.
|
|
579
820
|
See [`docs/agent-guide.md`](./docs/agent-guide.md) for the full tool reference and safety rules (destructive-command guard).
|
|
580
821
|
|
|
581
822
|
### `doctor` — self-check
|
|
@@ -585,7 +826,57 @@ switchbot doctor
|
|
|
585
826
|
switchbot doctor --json
|
|
586
827
|
```
|
|
587
828
|
|
|
588
|
-
Runs
|
|
829
|
+
Runs local checks (Node version, credentials, profiles, catalog, cache, quota, clock, MQTT, policy, MCP) and exits 1 if any check fails. `warn` results exit 0. The MQTT check reports `ok` when REST credentials are configured (auto-provisioned on first use). Use this to diagnose connectivity or config issues before running automation.
|
|
830
|
+
|
|
831
|
+
`--json` output includes `maturityScore` (0–100) and `maturityLabel` (`production-ready` / `mostly-ready` / `needs-work` / `not-ready`) to give an at-a-glance readiness rating:
|
|
832
|
+
|
|
833
|
+
```bash
|
|
834
|
+
switchbot doctor --json | jq '{score: .data.maturityScore, label: .data.maturityLabel}'
|
|
835
|
+
```
|
|
836
|
+
|
|
837
|
+
Pass `--fix --yes` to auto-apply safe fixes (e.g. clear stale cache entries) without a prompt.
|
|
838
|
+
|
|
839
|
+
### `health` — runtime health report
|
|
840
|
+
|
|
841
|
+
```bash
|
|
842
|
+
# One-shot report: quota, audit error rate, circuit-breaker state
|
|
843
|
+
switchbot health check
|
|
844
|
+
switchbot health check --prometheus # Prometheus text format
|
|
845
|
+
switchbot health check --json
|
|
846
|
+
|
|
847
|
+
# Start a long-running HTTP server with /healthz and /metrics
|
|
848
|
+
switchbot health serve # default port 3100, bind 127.0.0.1
|
|
849
|
+
switchbot health serve --port 8080
|
|
850
|
+
switchbot health serve --json # print {"status":"listening",...} on start
|
|
851
|
+
```
|
|
852
|
+
|
|
853
|
+
`/healthz` returns a JSON health report (HTTP 200 when `ok`/`degraded`, 503 when circuit is open).
|
|
854
|
+
`/metrics` returns Prometheus text metrics (`switchbot_quota_used_total`, `switchbot_circuit_open`, …).
|
|
855
|
+
Port conflicts are reported immediately with a clear hint to choose a different port via `--port`.
|
|
856
|
+
|
|
857
|
+
### `upgrade-check` — version check
|
|
858
|
+
|
|
859
|
+
```bash
|
|
860
|
+
switchbot upgrade-check # human output; exits 1 when update available
|
|
861
|
+
switchbot upgrade-check --json # structured JSON output
|
|
862
|
+
switchbot upgrade-check --timeout 5000 # custom registry timeout (ms)
|
|
863
|
+
```
|
|
864
|
+
|
|
865
|
+
Queries the npm registry for the latest published version and compares it against the running version.
|
|
866
|
+
`--json` output:
|
|
867
|
+
|
|
868
|
+
```json
|
|
869
|
+
{
|
|
870
|
+
"current": "3.2.1",
|
|
871
|
+
"latest": "4.0.0",
|
|
872
|
+
"upToDate": false,
|
|
873
|
+
"updateAvailable": true,
|
|
874
|
+
"breakingChange": true,
|
|
875
|
+
"installCommand": "npm install -g @switchbot/openapi-cli@4.0.0"
|
|
876
|
+
}
|
|
877
|
+
```
|
|
878
|
+
|
|
879
|
+
`breakingChange` is `true` when the latest major version is higher than the current — useful for agents or CI that need to distinguish breaking upgrades from patch releases.
|
|
589
880
|
|
|
590
881
|
### `quota` — API request counter
|
|
591
882
|
|
|
@@ -654,7 +945,50 @@ switchbot cache clear --key list
|
|
|
654
945
|
switchbot cache clear --key status
|
|
655
946
|
```
|
|
656
947
|
|
|
948
|
+
### `policy` — validate, scaffold, and migrate policy.yaml
|
|
949
|
+
|
|
950
|
+
Companion to the separate SwitchBot skill repository for third-party agent hosts. The skill reads behaviour (aliases, confirmations, quiet hours, audit path) from `policy.yaml`. This command group checks that file before the skill ever sees it, turning what used to be silent failures into line-accurate errors.
|
|
951
|
+
|
|
952
|
+
```bash
|
|
953
|
+
# Write a starter policy at the default location
|
|
954
|
+
switchbot policy new # writes to the resolved default policy path
|
|
955
|
+
switchbot policy new ./custom/policy.yaml --force
|
|
956
|
+
|
|
957
|
+
# Validate (compiler-style errors with line:col + caret + hints)
|
|
958
|
+
switchbot policy validate
|
|
959
|
+
switchbot policy validate ./custom/policy.yaml
|
|
960
|
+
switchbot policy validate --json | jq '.data.errors'
|
|
961
|
+
switchbot policy validate --no-snippet # plain error list, no source preview
|
|
962
|
+
|
|
963
|
+
# Report the schema version the file declares
|
|
964
|
+
switchbot policy migrate
|
|
965
|
+
|
|
966
|
+
# Snapshot and restore the active policy
|
|
967
|
+
switchbot policy backup # write timestamped backup alongside policy file
|
|
968
|
+
switchbot policy backup --out ./backups/ # custom destination directory
|
|
969
|
+
switchbot policy restore <backup-file> # overwrite active policy from backup (auto-backups first)
|
|
970
|
+
```
|
|
971
|
+
|
|
972
|
+
Path resolution order: positional `[path]` > `SWITCHBOT_POLICY_PATH` env var > default policy path.
|
|
657
973
|
|
|
974
|
+
**Exit codes:** `0` valid / `1` invalid / `2` file-not-found / `3` yaml-parse / `4` internal / `5` file already exists (on `new`, overridden with `--force`) / `6` unsupported schema version (on `migrate`).
|
|
975
|
+
|
|
976
|
+
Example — editing an alias without quoting the deviceId:
|
|
977
|
+
|
|
978
|
+
```console
|
|
979
|
+
$ switchbot policy validate
|
|
980
|
+
<policy-path>:14:11
|
|
981
|
+
14 | bedroom light: 01-abc-12345
|
|
982
|
+
^^^^^^^^^^^^^
|
|
983
|
+
error: /aliases/bedroom light does not match pattern ^[A-Z0-9]{2,}-[A-Z0-9-]+$
|
|
984
|
+
hint: paste the deviceId from `switchbot devices list --format=tsv`, e.g. 01-202407090924-26354212
|
|
985
|
+
|
|
986
|
+
✗ 1 error in <policy-path> (schema v0.1)
|
|
987
|
+
```
|
|
988
|
+
|
|
989
|
+
The default policy schema shipped with the CLI (`src/policy/schema/v0.2.json`) is mirrored as `examples/policy.schema.json` in the companion skill repo; a CI job on every push diffs the two to prevent drift.
|
|
990
|
+
|
|
991
|
+
## Output modes
|
|
658
992
|
|
|
659
993
|
- **Default** — ANSI-colored tables for `list`/`status`, key-value tables for details.
|
|
660
994
|
- **`--json`** — raw API payload passthrough. Output is the exact JSON the SwitchBot API returned, ideal for `jq` and scripting. Errors are also JSON on stderr: `{ "error": { "code", "kind", "message", "hint?" } }`.
|
|
@@ -675,10 +1009,10 @@ switchbot devices status <id> --format yaml
|
|
|
675
1009
|
|
|
676
1010
|
The CLI maintains two local disk caches under `~/.switchbot/`:
|
|
677
1011
|
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
1012
|
+
- `devices.json`: Device metadata (id, name, type, category, hub, room…).
|
|
1013
|
+
Default TTL: 1 hour.
|
|
1014
|
+
- `status.json`: Per-device status bodies.
|
|
1015
|
+
Default TTL: off (0).
|
|
682
1016
|
|
|
683
1017
|
The device-list cache powers offline validation (command name checks, destructive-command guard) and the MCP server's `send_command` tool. It is refreshed automatically on every `devices list` call.
|
|
684
1018
|
|
|
@@ -718,32 +1052,28 @@ switchbot cache clear --key status
|
|
|
718
1052
|
|
|
719
1053
|
## Exit codes & error codes
|
|
720
1054
|
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
| 401 | Authentication failed (check token/secret) |
|
|
738
|
-
| 429 | Request rate too high (10,000 req/day cap) |
|
|
1055
|
+
- `0`: Success (including `--dry-run` intercept when validation passes).
|
|
1056
|
+
- `1`: Runtime error — API error, network failure, missing credentials.
|
|
1057
|
+
- `2`: Usage error — bad flag, missing/invalid argument, unknown subcommand,
|
|
1058
|
+
unknown device type, invalid URL, conflicting flags.
|
|
1059
|
+
|
|
1060
|
+
Typical errors bubble up in the form `Error: <message>` on stderr. The
|
|
1061
|
+
SwitchBot-specific error codes mapped to readable messages:
|
|
1062
|
+
|
|
1063
|
+
- `151`: Device type error.
|
|
1064
|
+
- `152`: Device not found.
|
|
1065
|
+
- `160`: Command not supported by this device.
|
|
1066
|
+
- `161`: Device offline (BLE devices need a Hub).
|
|
1067
|
+
- `171`: Hub offline.
|
|
1068
|
+
- `190`: Device internal error / server busy.
|
|
1069
|
+
- `401`: Authentication failed (check token/secret).
|
|
1070
|
+
- `429`: Request rate too high (10,000 req/day cap).
|
|
739
1071
|
|
|
740
1072
|
## Environment variables
|
|
741
1073
|
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
| `SWITCHBOT_SECRET` | API secret — takes priority over the config file |
|
|
746
|
-
| `NO_COLOR` | Disable ANSI colors in all output (automatically respected) |
|
|
1074
|
+
- `SWITCHBOT_TOKEN`: API token — takes priority over the config file.
|
|
1075
|
+
- `SWITCHBOT_SECRET`: API secret — takes priority over the config file.
|
|
1076
|
+
- `NO_COLOR`: Disable ANSI colors in all output (automatically respected).
|
|
747
1077
|
|
|
748
1078
|
## Scripting examples
|
|
749
1079
|
|
|
@@ -766,37 +1096,74 @@ npm install
|
|
|
766
1096
|
|
|
767
1097
|
npm run dev -- <args> # Run from TypeScript sources via tsx
|
|
768
1098
|
npm run build # Compile to dist/
|
|
769
|
-
npm test # Run the Vitest suite (
|
|
1099
|
+
npm test # Run the Vitest suite (1856 tests)
|
|
770
1100
|
npm run test:watch # Watch mode
|
|
771
1101
|
npm run test:coverage # Coverage report (v8, HTML + text)
|
|
772
1102
|
```
|
|
773
1103
|
|
|
774
1104
|
### Project layout
|
|
775
1105
|
|
|
776
|
-
```
|
|
1106
|
+
```text
|
|
777
1107
|
src/
|
|
778
1108
|
├── index.ts # Commander entry; mounts all subcommands; global flags
|
|
779
1109
|
├── auth.ts # HMAC-SHA256 signature (token + t + nonce → sign)
|
|
780
|
-
├── config.ts # Credential load/save; env > file priority
|
|
1110
|
+
├── config.ts # Credential load/save; env > keychain > file priority
|
|
781
1111
|
├── api/client.ts # axios instance + request/response interceptors;
|
|
782
1112
|
│ # --verbose / --dry-run / --timeout wiring
|
|
1113
|
+
├── credentials/
|
|
1114
|
+
│ ├── keychain.ts # Credential store interface + OS backend selection
|
|
1115
|
+
│ └── backends/ # macos.ts / linux.ts / windows.ts / file.ts
|
|
783
1116
|
├── devices/
|
|
784
1117
|
│ ├── catalog.ts # Static device catalog (commands, params, status fields)
|
|
785
1118
|
│ └── cache.ts # Disk + in-memory cache for device list and status
|
|
1119
|
+
├── install/
|
|
1120
|
+
│ ├── steps.ts # Generic step runner with rollback support
|
|
1121
|
+
│ ├── preflight.ts # Pre-flight checks (Node, npm, network, agent)
|
|
1122
|
+
│ └── default-steps.ts # Concrete steps: credentials, keychain, policy, skill, doctor
|
|
1123
|
+
├── policy/
|
|
1124
|
+
│ ├── validate.ts # Schema version dispatch + JSON Schema validation
|
|
1125
|
+
│ ├── migrate.ts # v0.1 → v0.2 migration
|
|
1126
|
+
│ ├── load.ts # YAML file loading + error handling
|
|
1127
|
+
│ ├── add-rule.ts # Rule injection into automation.rules[]
|
|
1128
|
+
│ ├── diff.ts # Structural + line diff
|
|
1129
|
+
│ └── schema/v0.2.json # Authoritative v0.2 JSON Schema
|
|
1130
|
+
├── rules/
|
|
1131
|
+
│ ├── engine.ts # Main orchestrator (MQTT + cron + webhook)
|
|
1132
|
+
│ ├── matcher.ts # Trigger + condition matchers
|
|
1133
|
+
│ ├── action.ts # Command renderer + executor
|
|
1134
|
+
│ ├── throttle.ts # Per-rule throttle gate
|
|
1135
|
+
│ ├── cron-scheduler.ts # 5-field cron + days filter
|
|
1136
|
+
│ ├── webhook-listener.ts # HTTP listener (bearer token, localhost-only)
|
|
1137
|
+
│ ├── pid-file.ts # Hot-reload via SIGHUP or sentinel file
|
|
1138
|
+
│ ├── audit-query.ts # Audit log filtering + aggregation
|
|
1139
|
+
│ ├── conflict-analyzer.ts # Static conflict detection (opposing actions,
|
|
1140
|
+
│ │ # high-freq MQTT, destructive cmds, quiet-hours gaps)
|
|
1141
|
+
│ ├── suggest.ts # Heuristic-based rule YAML generation
|
|
1142
|
+
│ └── types.ts # Shared rule/trigger/condition/action types
|
|
1143
|
+
├── status-sync/
|
|
1144
|
+
│ └── manager.ts # Spawn/stop logic, state file, OpenClaw bridge
|
|
786
1145
|
├── lib/
|
|
787
1146
|
│ └── devices.ts # Shared logic: listDevices, describeDevice, isDestructiveCommand
|
|
788
1147
|
├── commands/
|
|
1148
|
+
│ ├── auth.ts # `auth keychain` subcommand group
|
|
789
1149
|
│ ├── config.ts
|
|
790
1150
|
│ ├── devices.ts
|
|
791
1151
|
│ ├── expand.ts # `devices expand` — semantic flag builder
|
|
792
1152
|
│ ├── explain.ts # `devices explain` — one-shot device summary
|
|
793
1153
|
│ ├── device-meta.ts # `devices meta` — local aliases / hide flags
|
|
1154
|
+
│ ├── install.ts # `switchbot install` / `uninstall`
|
|
1155
|
+
│ ├── policy.ts # `policy validate/new/migrate/diff/add-rule`
|
|
1156
|
+
│ ├── rules.ts # `rules suggest/lint/list/explain/run/reload/tail/replay/
|
|
1157
|
+
│ │ # conflicts/doctor/summary/last-fired/webhook-*`
|
|
794
1158
|
│ ├── scenes.ts
|
|
1159
|
+
│ ├── health.ts # `health check/serve` — report + HTTP endpoints
|
|
1160
|
+
│ ├── upgrade-check.ts # `upgrade-check` — npm registry version check
|
|
1161
|
+
│ ├── status-sync.ts # `status-sync run/start/stop/status`
|
|
795
1162
|
│ ├── webhook.ts
|
|
796
1163
|
│ ├── watch.ts # `devices watch <deviceId>`
|
|
797
1164
|
│ ├── events.ts # `events tail` / `events mqtt-tail`
|
|
798
1165
|
│ ├── mcp.ts # `mcp serve` (MCP stdio/HTTP server)
|
|
799
|
-
│ ├── plan.ts # `plan run/validate`
|
|
1166
|
+
│ ├── plan.ts # `plan run/validate/suggest`
|
|
800
1167
|
│ ├── cache.ts # `cache show/clear`
|
|
801
1168
|
│ ├── history.ts # `history show/replay`
|
|
802
1169
|
│ ├── quota.ts # `quota status/reset`
|
|
@@ -807,11 +1174,11 @@ src/
|
|
|
807
1174
|
│ └── completion.ts # `completion bash|zsh|fish|powershell`
|
|
808
1175
|
└── utils/
|
|
809
1176
|
├── flags.ts # Global flag readers (isVerbose / isDryRun / getCacheMode / …)
|
|
810
|
-
├── output.ts # printTable / printKeyValue / printJson / handleError
|
|
1177
|
+
├── output.ts # printTable / printKeyValue / printJson / handleError
|
|
811
1178
|
├── format.ts # renderRows / filterFields / output-format dispatch
|
|
812
1179
|
├── audit.ts # JSONL audit log writer
|
|
813
1180
|
└── quota.ts # Local daily-quota counter
|
|
814
|
-
tests/ # Vitest suite (
|
|
1181
|
+
tests/ # Vitest suite (1856 tests, mocked axios, no network)
|
|
815
1182
|
```
|
|
816
1183
|
|
|
817
1184
|
### Release flow
|
|
@@ -836,18 +1203,29 @@ Bug reports, feature requests, and PRs are welcome.
|
|
|
836
1203
|
|
|
837
1204
|
## Roadmap
|
|
838
1205
|
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
-
|
|
848
|
-
|
|
849
|
-
- **
|
|
850
|
-
|
|
1206
|
+
Phase 1 through Phase 4 are shipped. The authoritative phase/track table
|
|
1207
|
+
(including skill-side `autonomyLevel` L1/L2/L3 mapping) lives in
|
|
1208
|
+
[`docs/design/roadmap.md`](./docs/design/roadmap.md).
|
|
1209
|
+
|
|
1210
|
+
Shipped tracks summary:
|
|
1211
|
+
|
|
1212
|
+
- **Track β**: one-command install/uninstall surface (`switchbot install` / `switchbot uninstall`).
|
|
1213
|
+
- **Track γ**: rules v0.2 runtime increment (`days` + `all`/`any`/`not`).
|
|
1214
|
+
- **Track δ (L2)**: plan authoring + guarded execution (`plan suggest`, `plan run --require-approval`) and MCP review/execute tools (`plan_suggest`, `plan_run`, `audit_query`, `audit_stats`, `policy_diff`).
|
|
1215
|
+
- **Track ζ (L3)**: autonomous rule authoring (`rules suggest`, `policy add-rule`) with MCP parity (`rules_suggest`, `policy_add_rule`).
|
|
1216
|
+
- **Track ε**: cross-OS keychain CI matrix (macOS + Linux libsecret + Windows Credential Manager).
|
|
1217
|
+
|
|
1218
|
+
Backlog tracks still open:
|
|
1219
|
+
|
|
1220
|
+
1. **Daemon mode** — long-running local process with Unix/named-pipe
|
|
1221
|
+
transport so repeated MCP or plan invocations avoid fresh-process
|
|
1222
|
+
startup cost.
|
|
1223
|
+
2. **`npx @switchbot/mcp-server`** — split the MCP server into a tiny
|
|
1224
|
+
package so non-CLI users can run it directly with `npx`.
|
|
1225
|
+
3. **`switchbot self-test`** — scripted end-to-end go/no-go checks for
|
|
1226
|
+
token/secret validity plus representative device control.
|
|
1227
|
+
4. **Record / replay** — capture request/response fixtures and replay
|
|
1228
|
+
offline for deterministic integration tests and CI.
|
|
851
1229
|
|
|
852
1230
|
## License
|
|
853
1231
|
|