Merged
Conversation
…rich describe with capabilities
- Extend DeviceCatalogEntry with role, readOnly; extend CommandSpec with
idempotent, destructive, exampleParams
- Annotate all 36+ catalog entries: turnOn/turnOff idempotent across the
board; Smart Lock unlock / Garage Door Opener turnOn+turnOff / Keypad
createKey+deleteKey marked destructive; sensor+hub entries readOnly
- Add suggestedActions(): picks up to 3 idempotent, non-destructive,
non-customize commands with exampleParams when available
- describe now surfaces capabilities {role, readOnly, commands, statusFields}
with a source tag ('catalog' | 'live' | 'catalog+live') and suggestedActions
in --json output
- Add --live opt-in flag on describe to merge /v1.1/devices/{id}/status into
capabilities.liveStatus (IR devices no-op; /status failures captured, not fatal)
- Human-readable describe distinguishes physical vs IR fallback; physical
missing from catalog suggests 'devices status', IR suggests '--type customize'
- describe output visually flags destructive commands with [!destructive]
and a trailing warning; shows Role/ReadOnly when present
Tests: 329 total (+27 new). New tests/devices/catalog.test.ts covers schema
integrity, command annotations, role assignments, and suggestedActions
behaviour; describe tests cover capabilities/source, destructive surfacing,
ReadOnly display, and --live success / IR no-op / error-recovery paths.
…o src/lib
- Add `switchbot mcp serve` (stdio) using @modelcontextprotocol/sdk; exposes
seven tools to AI agents over JSON-RPC:
list_devices, get_device_status, send_command, list_scenes, run_scene,
search_catalog, describe_device
- send_command has a built-in destructive-command guard: commands flagged
`destructive: true` in the catalog (Smart Lock unlock, Garage Door Opener
turnOn/turnOff, Keypad createKey/deleteKey) refuse to execute unless the
caller passes `confirm: true`. Returns a structured error_code so the
agent can re-issue with the confirmation.
- send_command also runs the existing catalog-backed validation (unknown
command, unexpected-parameter) before hitting the API, returning a
structured error_code instead of a raw API failure.
- Extract network + parsing core from commander actions into src/lib/
(lib/devices.ts, lib/scenes.ts) so CLI and MCP share the same code path.
Commander actions in src/commands/ are now thin wrappers that only do
argument parsing, output formatting, and process.exit.
Tests: 342 (+13 MCP). tests/commands/mcp.test.ts covers tool listing, the
destructive-requires-confirm guard, confirm-bypass, unknown-command
rejection, cold-cache fallback (one list_devices then the command), and
the describe_device capabilities/source/live-merge shape.
The CLI surface is unchanged; all 329 prior tests still pass against the
new lib-backed command implementations.
… guard, concurrency pool
- New `devices batch <cmd> [param]` subcommand for bulk device control.
- Target resolution: --ids (csv), stdin ("-" or --stdin), --filter (DSL).
- Filter DSL: type|family|room|category with = (exact) or ~= (substring),
comma-separated AND. IR remotes inherit family/room from their hub.
- Pre-flight destructive check: Smart Lock unlock / Garage open / Keypad
create|delete-key blocked without --yes; exits 2 with per-device reasons.
- Concurrency pool (default 5) + 20-60ms jitter between starts (future
home for 429 backoff in Step 7).
- --dry-run surfaces as "skipped" per device; summary carries dryRun:true.
- Structured --json output: { succeeded, failed[{deviceId,error}], summary }.
- 10 batch tests + 16 filter tests; 368/368 green.
Step 6 of the AI-agent roadmap: batch primitive — filter DSL, stdin pipeline, destructive guard, concurrency pool. Unlocks `switchbot devices list --format=id | switchbot devices batch turnOff -` style agent workflows.
…ocal quota counter
Response interceptor now transparently retries HTTP 429 responses up to
--retry-on-429 <n> times (default 3). Retry delay honors the server's
Retry-After header when present; otherwise uses exponential backoff
(1s, 2s, 4s, ..., capped at 30s). --no-retry disables the behavior;
--backoff linear switches to a linear schedule.
Every request hit is counted in ~/.switchbot/quota.json, bucketed by
local date and endpoint pattern (device/scene IDs collapsed to :id).
New `switchbot quota status|reset` command surfaces today's usage and
the last 7 days. Recording is best-effort file I/O — a failed write
never breaks the real API call; --no-quota opts out entirely.
ApiError now carries { retryable, hint } metadata so agents can
differentiate transient failures (429 after retry exhaustion, 5xx)
from permanent ones (401, 152, 160).
33 new tests (retry math, quota bucketing, quota command, retry path).
401/401 green.
Step 7 of the AI-agent roadmap: transparent 429 backoff + quota awareness. Agents hitting the 10k/day ceiling now get automatic Retry-After-respecting retries and can introspect their own spend via `switchbot quota status` without an extra API call.
…ow/path/diff/refresh
Agents and power-users can now extend or patch the built-in device catalog
without waiting on a CLI release by dropping a JSON array at
~/.switchbot/catalog.json. Overlay rules:
- matching type replaces (partial merge — overlay keys win)
- new type is appended (must supply category + commands)
- { type: "X", remove: true } deletes the built-in
New 'switchbot catalog' command exposes the overlay:
path — where the file lives + load status
show — effective/built-in/overlay catalog, with per-type zoom and --json
diff — replaced/added/removed/ignored summary
refresh — clear the in-process overlay cache and re-read
getEffectiveCatalog() is wired through findCatalogEntry() and searchCatalog()
so every lookup respects the overlay transparently. All existing consumers
(devices types / commands / describe / batch / MCP search_catalog) inherit
it without further changes.
Tests: +32 (overlay merge semantics + command integration), suite 401 → 433.
- Per-device status cache at ~/.switchbot/status.json, keyed by deviceId - List cache gains TTL check (listCacheAgeMs, isListCacheFresh); default 1h - New global flags --cache <off|auto|5m|1h|...> and --no-cache - Fresh list cache now short-circuits fetchDeviceList(); status cache short-circuits fetchDeviceStatus when TTL is enabled - New 'switchbot cache show' + 'cache clear --key list|status|all' - 40 new tests; full suite 462/462 green
The 'switchbot devices command <id> <cmd>' path now refuses to send destructive catalog-annotated commands (Smart Lock unlock, Garage Door Opener turn*, Keypad createKey/deleteKey, ...) unless --yes is passed. --dry-run still previews without requiring --yes. Guard only fires when the local cache knows the device's type; unknown devices and --type=customize IR buttons pass through unchanged. Matches the destructive-command behavior already in 'devices batch' and MCP's send_command tool.
… local webhook receiver - devices watch <id...> polls status on an interval (default 30s, min 1s), emits JSONL field-level diffs; first tick seeds with from:null; --fields/--max/--include-unchanged; parallel per-device fetches with isolated error reporting; SIGINT/SIGTERM abort. - events tail starts a local HTTP receiver on --port/--path (default 3000 / '/'); optional --filter "deviceId=..,type=.." with comma-pair grammar that inspects body.context.deviceMac/deviceId/deviceType; JSONL or human output; --max stops after N matched events; rejects non-POST (405), unmatched paths (404), oversize bodies >1MB (413). - Lift parseDurationToMs out of flags.ts to share with watch. - Export startReceiver from events.ts for direct http-level testing. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
…e, --from-op) - Global --profile <name> flag routes credentials to ~/.switchbot/profiles/<name>.json. Absent --profile → legacy ~/.switchbot/config.json for full backward compat. - Resolution priority: --config > --profile > default. - config set-token now accepts --from-env-file <path> (dotenv parser for SWITCHBOT_TOKEN/SWITCHBOT_SECRET; comments and quotes handled) and --from-op <ref> + --op-secret <ref> (shells out to the 1Password CLI). Positional token/secret are now optional when a --from-* source is used. - New config list-profiles subcommand (sorted, JSON-aware). - loadConfig missing-file hint is profile-aware. - Export listProfiles() and profileFilePath() for test/tooling reuse. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
… + audit log - 'devices explain <id>': one-shot agent-friendly summary combining metadata + live status + commands (with idempotent/destructive flags) + children (IR remotes bound to a Hub) + suggested actions + warnings. - 'doctor': self-check across Node version, credentials (env vs file), profiles, catalog, cache, quota, and clock. JSON-aware; exit 1 on fail. - 'schema export [--type <t>]': dump the full device catalog as JSON for prompt engineering / docs generation. Always emits JSON. - 'history show' / 'history replay <n>': read the audit JSONL log and re-run a recorded command. Global '--audit-log [path]' enables append-on-execute in executeCommand (dry-run commands still logged; errors are captured with result:error). - writeAudit() is best-effort: failures never break the actual command. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
…docs
Round out the agent story with a declarative plan runner. The plan JSON
schema is fixed — agents emit plans, the CLI validates them, runs each
step sequentially, and honours the destructive-command guard + --dry-run
+ --audit-log from earlier phases. No LLM inside the CLI.
Three new subcommands:
plan schema print JSON Schema for the plan format
plan validate [file] validate a plan file or stdin (exit 2 on error)
plan run [file] validate + execute; --yes allows destructive
steps, --continue-on-error to keep running
Plan steps: { type: command, deviceId, command, parameter? } |
{ type: scene, sceneId } |
{ type: wait, ms } (0..600000ms)
README gets a top-of-file "Who is this for?" table pointing Human /
Script / Agent users at their entry points. docs/agent-guide.md walks
agents through MCP server, plan runner, direct JSON, catalog, safety
rails, and token budgeting.
14 new tests (validatePlan unit + schema/validate/run integration).
Cap the 14-step AI-agent optimization roadmap. Major bump because the plan runner + MCP server + agent guide formally establish "Agent" as a first-class user of this CLI, alongside Human and Script. No breaking changes to existing commands — every flag and exit code from v1.x stands. Step 14 landed: - switchbot plan schema | validate | run - README rewrite (top-level "Who is this for?" table) - docs/agent-guide.md (MCP / plan / direct / safety / observability) Cumulative v1 → v2 highlights: catalog coverage for 9 new device types (Step 1), --format/--fields (Step 3), MCP server (Step 5), batch (Step 6), 429 backoff + quota (Step 7), catalog refresh (Step 8), status cache (Step 9), destructive-command guard (Step 10), devices watch + events tail (Step 11), profiles + secret sources (Step 12), explain + doctor + schema export + history + audit-log (Step 13), plan runner + docs (Step 14).
…ent output New src/utils/format.ts with parseFormat(), renderRows(), resolveFormat(), and resolveFields(). Supports table, json, jsonl, tsv, yaml, and id formats. --fields filters columns in list commands; --json remains backward-compatible (outputs raw API body). Updated devices list/types, scenes list, catalog show to use the new renderer. Unified watch --fields to read from global getFields(). 29 new tests (18 unit + 11 integration); 559/559 green. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
…egory filters, cache improvements - Add 'switchbot capabilities' command with full CLI manifest (commands, subcommands, args, flags, identity block, catalog stats) for agent bootstrap - Add description field to all 42 DeviceCatalogEntry types in catalog - Add --role and --category filters to 'schema export' - Expand MCP server instructions with product context, device categories, constraints, and recommended bootstrap sequence - Add in-memory hot-cache (resetListCache) and GC to status cache (evict entries > 24h) - Add independent --cache-list / --cache-status TTL overrides - Fix enableCloudService defaulting (false → true) - Update README with new commands, cache section, and project layout - 606 tests passing
chenliuyun
pushed a commit
that referenced
this pull request
Apr 20, 2026
Document every fix landed in this branch beyond the history-aggregate feature: bugs #1, #4, #5, #6, #8, #9, #10, #11, #12, #13, #14, #15, #16, #17, #18 from the OpenClaw v2.4.0 smoke-test report. Call out the deferred items (#2, #7) explicitly so readers don't assume they were overlooked. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
4 tasks
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
♻️ Current situation
Describe the current situation. Explain current problems, if there are any. Be as descriptive as possible (e.g., including examples or code snippets).
💡 Proposed solution
Describe the proposed solution and changes. How does it affect the project? How does it affect the internal structure (e.g., refactorings)?
⚙️ Release Notes
Provide a summary of the changes or features from a user's point of view. If there are breaking changes, provide migration guides using code examples of the affected features.
➕ Additional Information
If applicable, provide additional context in this section.
Testing
Which tests were added? Which existing tests were adapted/changed? Which situations are covered, and what edge cases are missing?
Reviewer Nudging
Where should the reviewer start? what is a good entry point?