@switchbot/openapi-cli 2.0.1 → 2.2.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 CHANGED
@@ -7,7 +7,7 @@
7
7
  [![CI](https://github.com/OpenWonderLabs/switchbot-openapi-cli/actions/workflows/ci.yml/badge.svg)](https://github.com/OpenWonderLabs/switchbot-openapi-cli/actions/workflows/ci.yml)
8
8
 
9
9
  Command-line interface for the [SwitchBot API v1.1](https://github.com/OpenWonderLabs/SwitchBotAPI).
10
- List devices, query live status, send control commands, run scenes, and manage webhooks — all from your terminal or shell scripts.
10
+ List devices, query live status, send control commands, run scenes, receive real-time events, and connect AI agents via the built-in MCP server — all from your terminal or shell scripts.
11
11
 
12
12
  - **npm package:** [`@switchbot/openapi-cli`](https://www.npmjs.com/package/@switchbot/openapi-cli)
13
13
  - **Source code:** [github.com/OpenWonderLabs/switchbot-openapi-cli](https://github.com/OpenWonderLabs/switchbot-openapi-cli)
@@ -41,11 +41,19 @@ Under the hood every surface shares the same catalog, cache, and HMAC client —
41
41
  - [Commands](#commands)
42
42
  - [`config`](#config--credential-management)
43
43
  - [`devices`](#devices--list-status-control)
44
+ - [`devices batch`](#devices-batch--bulk-commands)
45
+ - [`devices watch`](#devices-watch--poll-status)
44
46
  - [`scenes`](#scenes--run-manual-scenes)
45
47
  - [`webhook`](#webhook--receive-device-events-over-http)
46
- - [`batch`](#batch--run-multiple-commands)
47
- - [`watch`](#watch--poll-device-status)
48
+ - [`events`](#events--receive-device-events)
49
+ - [`plan`](#plan--declarative-batch-operations)
48
50
  - [`mcp`](#mcp--model-context-protocol-server)
51
+ - [`doctor`](#doctor--self-check)
52
+ - [`quota`](#quota--api-request-counter)
53
+ - [`history`](#history--audit-log)
54
+ - [`catalog`](#catalog--device-type-catalog)
55
+ - [`schema`](#schema--export-catalog-as-json)
56
+ - [`capabilities`](#capabilities--cli-manifest)
49
57
  - [`cache`](#cache--inspect-and-clear-local-cache)
50
58
  - [`completion`](#completion--shell-tab-completion)
51
59
  - [Output modes](#output-modes)
@@ -67,7 +75,7 @@ Under the hood every surface shares the same catalog, cache, and HMAC client —
67
75
  - 🎨 **Dual output modes** — colorized tables by default; `--json` passthrough for `jq` and scripting
68
76
  - 🔐 **Secure credentials** — HMAC-SHA256 signed requests; config file written with `0600`; env-var override for CI
69
77
  - 🔍 **Dry-run mode** — preview every mutating request before it hits the API
70
- - 🧪 **Fully tested** — 592 Vitest tests, mocked axios, zero network in CI
78
+ - 🧪 **Fully tested** — 692 Vitest tests, mocked axios, zero network in CI
71
79
  - ⚡ **Shell completion** — Bash / Zsh / Fish / PowerShell
72
80
 
73
81
  ## Requirements
@@ -157,7 +165,8 @@ switchbot config show
157
165
  | `--no-retry` | Disable automatic 429 retries |
158
166
  | `--backoff <strategy>` | Retry backoff: `exponential` (default) or `linear` |
159
167
  | `--no-quota` | Disable local request-quota tracking |
160
- | `--audit-log [path]` | Append mutating commands to a JSONL audit log (default path: `~/.switchbot/audit.log`) |
168
+ | `--audit-log` | Append mutating commands to a JSONL audit log (default path: `~/.switchbot/audit.log`) |
169
+ | `--audit-log-path <path>` | Custom audit log path; use together with `--audit-log` |
161
170
  | `-V`, `--version` | Print the CLI version |
162
171
  | `-h`, `--help` | Show help for any command or subcommand |
163
172
 
@@ -187,6 +196,7 @@ switchbot devices command ABC123 turnOn --dry-run
187
196
  ```bash
188
197
  switchbot config set-token <token> <secret> # Save to ~/.switchbot/config.json
189
198
  switchbot config show # Print current source + masked secret
199
+ switchbot config list-profiles # List saved profiles
190
200
  ```
191
201
 
192
202
  ### `devices` — list, status, control
@@ -203,6 +213,11 @@ switchbot devices list --json | jq '.deviceList[].deviceId'
203
213
  # Physical: category = "physical"
204
214
  switchbot devices list --format=tsv --fields=deviceId,type,category
205
215
 
216
+ # Filter devices by type / name / category / room (server-side filter keys)
217
+ switchbot devices list --filter category=physical
218
+ switchbot devices list --filter type=Bot
219
+ switchbot devices list --filter name=living,category=physical
220
+
206
221
  # Filter by family / room (family & room info requires the 'src: OpenClaw'
207
222
  # header, which this CLI sends on every request)
208
223
  switchbot devices list --json | jq '.deviceList[] | select(.familyName == "Home")'
@@ -212,6 +227,16 @@ switchbot devices list --json | jq '[.deviceList[], .infraredRemoteList[]] | gro
212
227
  switchbot devices status <deviceId>
213
228
  switchbot devices status <deviceId> --json
214
229
 
230
+ # Resolve device by fuzzy name instead of ID (status, command, describe, expand, watch)
231
+ switchbot devices status --name "客厅空调"
232
+ switchbot devices command --name "Office Light" turnOn
233
+ switchbot devices describe --name "Kitchen Bot"
234
+
235
+ # Batch status across multiple devices
236
+ switchbot devices status --ids ABC,DEF,GHI
237
+ switchbot devices status --ids ABC,DEF --fields power,battery # only show specific fields
238
+ switchbot devices status --ids ABC,DEF --format jsonl # one JSON line per device
239
+
215
240
  # Send a control command
216
241
  switchbot devices command <deviceId> <cmd> [parameter] [--type command|customize]
217
242
 
@@ -220,7 +245,7 @@ switchbot devices describe <deviceId>
220
245
  switchbot devices describe <deviceId> --json
221
246
 
222
247
  # Discover what's supported (offline reference, no API call)
223
- switchbot devices types # List all device types + IR remote types
248
+ switchbot devices types # List all device types + IR remote types (incl. role column)
224
249
  switchbot devices commands <type> # Show commands, parameter formats, and status fields
225
250
  switchbot devices commands Bot
226
251
  switchbot devices commands "Smart Lock"
@@ -259,6 +284,8 @@ Some commands require a packed string like `"26,2,2,on"`. `devices expand` build
259
284
  ```bash
260
285
  # Air Conditioner — setAll
261
286
  switchbot devices expand <acId> setAll --temp 26 --mode cool --fan low --power on
287
+ # Resolve by name
288
+ switchbot devices expand --name "客厅空调" setAll --temp 26 --mode cool --fan low --power on
262
289
 
263
290
  # Curtain / Roller Shade — setPosition
264
291
  switchbot devices expand <curtainId> setPosition --position 50 --mode silent
@@ -272,13 +299,48 @@ switchbot devices expand <relayId> setMode --channel 1 --mode edge
272
299
 
273
300
  Run `switchbot devices expand <id> <command> --help` to see the available flags for any device command.
274
301
 
275
- #### `devices explain` — plain-language command description
302
+ #### `devices explain` — one-shot device summary
303
+
304
+ ```bash
305
+ # Metadata + supported commands + live status in one call
306
+ switchbot devices explain <deviceId>
307
+
308
+ # Skip live status fetch (catalog-only output, no API call)
309
+ switchbot devices explain <deviceId> --no-live
310
+ ```
311
+
312
+ Returns a combined view: static catalog info (commands, parameters, status fields) merged with the current live status. For Hub devices, also lists connected child devices. Prefer this over separate `status` + `describe` calls.
313
+
314
+ #### `devices meta` — local device metadata
315
+
316
+ ```bash
317
+ switchbot devices meta set <deviceId> --alias "Office Light"
318
+ switchbot devices meta set <deviceId> --hide # hide from `devices list`
319
+ switchbot devices meta get <deviceId>
320
+ switchbot devices meta list # show all saved metadata
321
+ switchbot devices meta clear <deviceId>
322
+ ```
323
+
324
+ Stores local annotations (alias, hidden flag, notes) in `~/.switchbot/device-meta.json`. The alias is used as a display name; `--show-hidden` on `devices list` reveals hidden devices.
325
+
326
+ #### `devices batch` — bulk commands
276
327
 
277
328
  ```bash
278
- switchbot devices explain <deviceId> <command> # e.g. "explain ABC123 setAll"
329
+ # Send the same command to every device matching a filter
330
+ switchbot devices batch turnOff --filter 'type=Bot'
331
+ switchbot devices batch setBrightness 50 --filter 'type~=Light,family=Living'
332
+
333
+ # Explicit device IDs (comma-separated)
334
+ switchbot devices batch turnOn --ids ID1,ID2,ID3
335
+
336
+ # Pipe device IDs from `devices list`
337
+ switchbot devices list --format=id --filter 'type=Bot' | switchbot devices batch toggle -
338
+
339
+ # Destructive commands require --yes
340
+ switchbot devices batch unlock --filter 'type=Smart Lock' --yes
279
341
  ```
280
342
 
281
- Returns a human-readable description of what the command does and what each parameter means.
343
+ Sends the same command to many devices in one run. Uses the same `--filter` expressions as `devices list`. Destructive commands (Smart Lock unlock, Garage Door Opener, etc.) require `--yes` to prevent accidents.
282
344
 
283
345
  ### `scenes` — run manual scenes
284
346
 
@@ -307,6 +369,101 @@ switchbot webhook delete https://your.host/hook
307
369
 
308
370
  The CLI validates that `<url>` is an absolute `http://` or `https://` URL before calling the API. `--enable` and `--disable` are mutually exclusive.
309
371
 
372
+ ### `events` — receive device events
373
+
374
+ Two subcommands cover the two ways SwitchBot can push state changes to you.
375
+
376
+ #### `events tail` — local webhook receiver
377
+
378
+ ```bash
379
+ # Listen on port 3000 and print every incoming webhook POST
380
+ switchbot events tail
381
+
382
+ # Filter to one device
383
+ switchbot events tail --filter deviceId=ABC123
384
+
385
+ # Stop after 5 matching events
386
+ switchbot events tail --filter 'type=WoMeter' --max 5
387
+
388
+ # Custom port / path
389
+ switchbot events tail --port 8080 --path /hook --json
390
+ ```
391
+
392
+ 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.
393
+
394
+ Output (one JSON line per matched event):
395
+ ```
396
+ { "t": "2024-01-01T12:00:00.000Z", "remote": "1.2.3.4:54321", "path": "/", "body": {...}, "matched": true }
397
+ ```
398
+
399
+ Filter keys: `deviceId=<id>`, `type=<deviceType>` (comma-separated for AND logic).
400
+
401
+ #### `events mqtt-tail` — real-time MQTT stream
402
+
403
+ ```bash
404
+ # Stream all shadow-update events (runs in foreground until Ctrl-C)
405
+ switchbot events mqtt-tail
406
+
407
+ # Filter to a topic subtree
408
+ switchbot events mqtt-tail --topic 'switchbot/#'
409
+
410
+ # Stop after 10 events
411
+ switchbot events mqtt-tail --max 10 --json
412
+ ```
413
+
414
+ 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.
415
+
416
+ Output (one JSON line per message):
417
+ ```
418
+ { "t": "2024-01-01T12:00:00.000Z", "topic": "switchbot/abc123/status", "payload": {...} }
419
+ ```
420
+
421
+ This command runs in the foreground and streams events until you press Ctrl-C. To run it persistently in the background, use a process manager:
422
+
423
+ ```bash
424
+ # pm2
425
+ pm2 start "switchbot events mqtt-tail --json" --name switchbot-events
426
+
427
+ # nohup
428
+ nohup switchbot events mqtt-tail --json >> ~/switchbot-events.log 2>&1 &
429
+ ```
430
+
431
+ Run `switchbot doctor` to verify MQTT credentials are configured correctly before connecting.
432
+
433
+ #### `mqtt-tail` sinks — route events to external services
434
+
435
+ By default `mqtt-tail` prints JSONL to stdout. Use `--sink` (repeatable) to route events to one or more destinations instead:
436
+
437
+ | Sink | Required flags |
438
+ |---|---|
439
+ | `stdout` | (default when no `--sink` given) |
440
+ | `file` | `--sink-file <path>` — append JSONL |
441
+ | `webhook` | `--webhook-url <url>` — HTTP POST each event |
442
+ | `openclaw` | `--openclaw-url`, `--openclaw-token` (or `$OPENCLAW_TOKEN`), `--openclaw-model` |
443
+ | `telegram` | `--telegram-token` (or `$TELEGRAM_TOKEN`), `--telegram-chat <chatId>` |
444
+ | `homeassistant` | `--ha-url <url>` + `--ha-webhook-id` (no auth) or `--ha-token` (REST event API) |
445
+
446
+ ```bash
447
+ # Push events to an OpenClaw agent (replaces the SwitchBot channel plugin)
448
+ switchbot events mqtt-tail \
449
+ --sink openclaw \
450
+ --openclaw-token <token> \
451
+ --openclaw-model my-home-agent
452
+
453
+ # Write to file + push to OpenClaw simultaneously
454
+ switchbot events mqtt-tail \
455
+ --sink file --sink-file ~/.switchbot/events.jsonl \
456
+ --sink openclaw --openclaw-token <token> --openclaw-model home
457
+
458
+ # Generic webhook (n8n, Make, etc.)
459
+ switchbot events mqtt-tail --sink webhook --webhook-url https://n8n.local/hook/abc
460
+
461
+ # Forward to Home Assistant via webhook trigger
462
+ switchbot events mqtt-tail --sink homeassistant --ha-url http://homeassistant.local:8123 --ha-webhook-id switchbot
463
+ ```
464
+
465
+ Device state is also persisted to `~/.switchbot/device-history/<deviceId>.json` (latest + 100-entry ring buffer) regardless of sink configuration. This enables the `get_device_history` MCP tool to answer state queries without an API call.
466
+
310
467
  ### `completion` — shell tab-completion
311
468
 
312
469
  ```bash
@@ -325,28 +482,36 @@ switchbot completion powershell >> $PROFILE
325
482
 
326
483
  Supported shells: `bash`, `zsh`, `fish`, `powershell` (`pwsh` is accepted as an alias).
327
484
 
328
- ### `batch` — run multiple commands
485
+ ### `plan` — declarative batch operations
329
486
 
330
487
  ```bash
331
- # Run a sequence of commands from a JSON/YAML file
332
- switchbot batch run commands.json
333
- switchbot batch run commands.yaml --dry-run
488
+ # Print the plan JSON Schema (give to your agent framework)
489
+ switchbot plan schema
490
+
491
+ # Validate a plan file without running it
492
+ switchbot plan validate plan.json
334
493
 
335
- # Validate a plan file without executing it
336
- switchbot batch validate commands.json
494
+ # Preview mutations skipped, GETs still execute
495
+ switchbot --dry-run plan run plan.json
496
+
497
+ # Run — pass --yes to allow destructive steps
498
+ switchbot plan run plan.json --yes
499
+ switchbot plan run plan.json --continue-on-error
337
500
  ```
338
501
 
339
- A batch file is a JSON array of `{ deviceId, command, parameter?, commandType? }` objects.
502
+ 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.
340
503
 
341
- ### `watch` — poll device status
504
+ ### `devices watch` — poll status
342
505
 
343
506
  ```bash
344
507
  # Poll a device's status every 30 s until Ctrl-C
345
- switchbot watch <deviceId>
346
- switchbot watch <deviceId> --interval 10s --json
508
+ switchbot devices watch <deviceId>
509
+
510
+ # Custom interval; emit every tick even when nothing changed
511
+ switchbot devices watch <deviceId> --interval 10s --include-unchanged --json
347
512
  ```
348
513
 
349
- Output is a stream of JSON status objects (with `--json`) or a refreshed table.
514
+ Output is a JSONL stream of status-change events (with `--json`) or a refreshed table. Use `--max <n>` to stop after N ticks.
350
515
 
351
516
  ### `mcp` — Model Context Protocol server
352
517
 
@@ -358,6 +523,65 @@ switchbot mcp serve
358
523
  Exposes 8 MCP tools (`list_devices`, `describe_device`, `get_device_status`, `send_command`, `list_scenes`, `run_scene`, `search_catalog`, `account_overview`) plus a `switchbot://events` resource for real-time shadow updates.
359
524
  See [`docs/agent-guide.md`](./docs/agent-guide.md) for the full tool reference and safety rules (destructive-command guard).
360
525
 
526
+ ### `doctor` — self-check
527
+
528
+ ```bash
529
+ switchbot doctor
530
+ switchbot doctor --json
531
+ ```
532
+
533
+ Runs 8 local checks (Node version, credentials, profiles, catalog, cache, quota file, clock, MQTT) 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.
534
+
535
+ ### `quota` — API request counter
536
+
537
+ ```bash
538
+ switchbot quota status # today's usage + last 7 days
539
+ switchbot quota reset # delete the counter file
540
+ ```
541
+
542
+ Tracks daily API calls against the 10,000/day account limit. The counter is stored in `~/.switchbot/quota.json` and incremented on every mutating request. Pass `--no-quota` to skip tracking for a single run.
543
+
544
+ ### `history` — audit log
545
+
546
+ ```bash
547
+ switchbot history show # recent entries (newest first)
548
+ switchbot history show --limit 20 # last 20 entries
549
+ switchbot history replay 7 # re-run entry #7
550
+ switchbot --json history show --limit 50 | jq '.entries[] | select(.result=="error")'
551
+ ```
552
+
553
+ Reads the JSONL audit log (`~/.switchbot/audit.log` by default; override with `--audit-log --audit-log-path <path>`). Each entry records the timestamp, command, device ID, result, and dry-run flag. `replay` re-runs the original command with the original arguments.
554
+
555
+ ### `catalog` — device type catalog
556
+
557
+ ```bash
558
+ switchbot catalog show # all 42 built-in types
559
+ switchbot catalog show Bot # one type
560
+ switchbot catalog diff # what a local overlay changes vs built-in
561
+ switchbot catalog path # location of the local overlay file
562
+ switchbot catalog refresh # reload local overlay (clears in-process cache)
563
+ ```
564
+
565
+ The built-in catalog ships with the package. Create `~/.switchbot/catalog-overlay.json` to add, extend, or override type definitions without modifying the package.
566
+
567
+ ### `schema` — export catalog as JSON
568
+
569
+ ```bash
570
+ switchbot schema export # all types as structured JSON
571
+ switchbot schema export --type 'Strip Light' # one type
572
+ switchbot schema export --role sensor # filter by role
573
+ ```
574
+
575
+ Exports the effective catalog in a machine-readable format. Pipe the output into an agent's system prompt or tool schema to give it a complete picture of controllable devices.
576
+
577
+ ### `capabilities` — CLI manifest
578
+
579
+ ```bash
580
+ switchbot capabilities --json
581
+ ```
582
+
583
+ Prints a versioned JSON manifest describing available surfaces (CLI, MCP, MQTT, plan runner), commands, and environment variables. Designed for agents and tooling that need to discover the CLI's capabilities programmatically.
584
+
361
585
  ### `cache` — inspect and clear local cache
362
586
 
363
587
  ```bash
@@ -457,11 +681,11 @@ Typical errors bubble up in the form `Error: <message>` on stderr. The SwitchBot
457
681
 
458
682
  ## Environment variables
459
683
 
460
- | Variable | Description |
461
- | ------------------- | ------------------------------------------------------------------ |
462
- | `SWITCHBOT_TOKEN` | API token — takes priority over the config file |
463
- | `SWITCHBOT_SECRET` | API secret — takes priority over the config file |
464
- | `NO_COLOR` | Disable ANSI colors in all output (automatically respected) |
684
+ | Variable | Description |
685
+ | --------------------------- | ------------------------------------------------------------------ |
686
+ | `SWITCHBOT_TOKEN` | API token — takes priority over the config file |
687
+ | `SWITCHBOT_SECRET` | API secret — takes priority over the config file |
688
+ | `NO_COLOR` | Disable ANSI colors in all output (automatically respected) |
465
689
 
466
690
  ## Scripting examples
467
691
 
@@ -484,7 +708,7 @@ npm install
484
708
 
485
709
  npm run dev -- <args> # Run from TypeScript sources via tsx
486
710
  npm run build # Compile to dist/
487
- npm test # Run the Vitest suite (592 tests)
711
+ npm test # Run the Vitest suite (692 tests)
488
712
  npm run test:watch # Watch mode
489
713
  npm run test:coverage # Coverage report (v8, HTML + text)
490
714
  ```
@@ -506,21 +730,23 @@ src/
506
730
  ├── commands/
507
731
  │ ├── config.ts
508
732
  │ ├── devices.ts
733
+ │ ├── expand.ts # `devices expand` — semantic flag builder
734
+ │ ├── explain.ts # `devices explain` — one-shot device summary
735
+ │ ├── device-meta.ts # `devices meta` — local aliases / hide flags
509
736
  │ ├── scenes.ts
510
737
  │ ├── webhook.ts
511
- │ ├── batch.ts # `switchbot batch run/validate`
512
- │ ├── watch.ts # `switchbot watch <deviceId>`
513
- │ ├── mcp.ts # `switchbot mcp serve` (MCP stdio server)
514
- │ ├── cache.ts # `switchbot cache show/clear`
515
- │ ├── history.ts # `switchbot history [replay]`
516
- │ ├── events.ts # `switchbot events`
517
- │ ├── quota.ts # `switchbot quota`
518
- │ ├── explain.ts # `switchbot explain <deviceId>`
519
- │ ├── plan.ts # `switchbot plan run <file>`
520
- │ ├── doctor.ts # `switchbot doctor`
521
- │ ├── schema.ts # `switchbot schema export`
522
- ├── catalog.ts # `switchbot catalog search`
523
- │ └── completion.ts # `switchbot completion bash|zsh|fish|powershell`
738
+ │ ├── watch.ts # `devices watch <deviceId>`
739
+ │ ├── events.ts # `events tail` / `events mqtt-tail`
740
+ │ ├── mcp.ts # `mcp serve` (MCP stdio/HTTP server)
741
+ │ ├── plan.ts # `plan run/validate`
742
+ │ ├── cache.ts # `cache show/clear`
743
+ │ ├── history.ts # `history show/replay`
744
+ │ ├── quota.ts # `quota status/reset`
745
+ │ ├── catalog.ts # `catalog show/diff/path`
746
+ │ ├── schema.ts # `schema export`
747
+ │ ├── doctor.ts # `doctor`
748
+ │ ├── capabilities.ts # `capabilities`
749
+ └── completion.ts # `completion bash|zsh|fish|powershell`
524
750
  └── utils/
525
751
  ├── flags.ts # Global flag readers (isVerbose / isDryRun / getCacheMode / …)
526
752
  ├── output.ts # printTable / printKeyValue / printJson / handleError / buildErrorPayload
@@ -26,32 +26,42 @@ const MCP_TOOLS = [
26
26
  'run_scene',
27
27
  'search_catalog',
28
28
  'account_overview',
29
+ 'get_device_history',
29
30
  ];
30
31
  export function registerCapabilitiesCommand(program) {
31
32
  program
32
33
  .command('capabilities')
33
34
  .description('Print a machine-readable manifest of CLI capabilities (for agent bootstrap)')
34
- .action(() => {
35
+ .option('--minimal', 'Omit per-subcommand flag details to reduce output size')
36
+ .action((opts) => {
35
37
  const catalog = getEffectiveCatalog();
36
- const commands = program.commands
37
- .filter((c) => c.name() !== 'capabilities')
38
- .map((c) => ({
39
- name: c.name(),
40
- description: c.description(),
41
- subcommands: c.commands.map((s) => ({
42
- name: s.name(),
43
- description: s.description(),
44
- args: s.registeredArguments.map((a) => ({
45
- name: a.name(),
46
- required: a.required,
47
- variadic: a.variadic,
48
- })),
49
- flags: s.options.map((o) => ({
50
- flags: o.flags,
51
- description: o.description,
52
- })),
53
- })),
54
- }));
38
+ const allCommands = [
39
+ ...program.commands,
40
+ // Commander adds 'help' implicitly; include it explicitly so it appears in the manifest
41
+ { name: () => 'help', description: () => 'Display help for a command', commands: [], options: [], registeredArguments: [] },
42
+ ];
43
+ const commands = allCommands.map((c) => {
44
+ const entry = {
45
+ name: c.name(),
46
+ description: c.description(),
47
+ };
48
+ if (!opts.minimal) {
49
+ entry.subcommands = c.commands.map((s) => ({
50
+ name: s.name(),
51
+ description: s.description(),
52
+ args: s.registeredArguments.map((a) => ({
53
+ name: a.name(),
54
+ required: a.required,
55
+ variadic: a.variadic,
56
+ })),
57
+ flags: s.options.map((o) => ({
58
+ flags: o.flags,
59
+ description: o.description,
60
+ })),
61
+ }));
62
+ }
63
+ return entry;
64
+ });
55
65
  const globalFlags = program.options.map((opt) => ({
56
66
  flags: opt.flags,
57
67
  description: opt.description,
@@ -68,6 +78,13 @@ export function registerCapabilitiesCommand(program) {
68
78
  tools: MCP_TOOLS,
69
79
  resources: ['switchbot://events'],
70
80
  },
81
+ mqtt: {
82
+ mode: 'consumer',
83
+ authSource: 'SWITCHBOT_TOKEN + SWITCHBOT_SECRET (auto-provisioned via POST /v1.1/iot/credential)',
84
+ cliCmd: 'events mqtt-tail',
85
+ mcpResource: 'switchbot://events',
86
+ protocol: 'MQTTS with TLS client certificates (AWS IoT)',
87
+ },
71
88
  plan: {
72
89
  schemaCmd: 'plan schema',
73
90
  validateCmd: 'plan validate -',