Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
72 commits
Select commit Hold shift + click to select a range
cdb132b
feat: browser-based login via custom local login page
May 20, 2026
f93a662
refactor(auth): extract shared getFreePort and escapeHtml into utils.ts
May 20, 2026
c17b4d4
fix(auth): XSS in errorHtml, double-close guard, security headers in …
May 20, 2026
95dfee2
refactor(auth): rename pkce.ts to csrf.ts, update all callers
May 20, 2026
30a96fe
fix(auth): botRegion allowlist, body size cap, double-close guard, se…
May 20, 2026
c654557
fix(auth): validate OAuth state in login.html before forwarding code …
May 20, 2026
e26bf25
test(auth): add unit tests for token-exchange happy path and error paths
May 20, 2026
7d3bd16
test(auth): add oauth-callback integration tests (XSS, CSRF, timeout,…
May 20, 2026
d4b5bee
test(auth): add local-login-server integration tests (all routes, bot…
May 20, 2026
f810fe4
fix(auth): decrypt AES-128-CBC token/secret from openUser/token v2
May 21, 2026
bfab185
feat(reset): add `switchbot reset` command
May 21, 2026
a3e645f
refactor(auth): apply code-review improvements
May 21, 2026
8ff89d1
feat(auth): replace Cognito with sp.oauth.switchbot.net + add User-Ag…
May 21, 2026
66f7674
feat(auth): add countdown timer and fix merchant OAuth client credent…
May 21, 2026
2036aa6
fix(auth): use fixed port 53245 for OAuth callback server
May 21, 2026
cb82cb7
fix(auth): fix token-exchange Step 2 — use Wonder API instead of mobi…
May 21, 2026
60303f7
feat(ux): suggest `switchbot auth login` in no-credentials error message
May 21, 2026
adfea59
fix(ux): reformat no-credentials error as numbered choice list
May 21, 2026
80c64a8
fix(mcp): make list_devices roomID nullable in outputSchema (F-3)
May 21, 2026
9685213
fix(plan): compound keyword rules prevent 'open the lock' → lock misf…
May 21, 2026
799f366
fix(quota): respect --dry-run in quota reset (D-1)
May 21, 2026
7ad40df
fix(mcp): strengthen plan_run result types in outputSchema (F-1)
May 21, 2026
d11d405
fix(mcp): prefix error content text with human-readable summary (F-2)
May 21, 2026
a6d78d8
fix(devices): apply --fields projection when --json shorthand is used…
May 21, 2026
fa45c84
fix(cli): validation failures exit 2 not 0 (E-1)
May 21, 2026
eee9546
fix(history): use query midpoint timestamp for no-bucket aggregation …
May 21, 2026
a396356
fix(devices): fetchedAt reflects API fetch time, not render time (C-1)
May 21, 2026
1d95b46
docs(devices): document --cache global flag placement in subcommand h…
May 21, 2026
4dfd375
docs(history): add --cache global flag placement note to history help
May 21, 2026
656c846
fix(tests): update dry-run tests to parse new mcpError text format (F…
May 21, 2026
63fd2da
docs(spec): MCP test coverage gap design — boundary tests + error for…
May 21, 2026
044522d
refactor(tests): extract parseErrorText to shared mcp-test-utils helper
May 21, 2026
68a103e
test(mcp): add outputSchema boundary tests for nullable/optional fields
May 21, 2026
8e99c15
test(mcp): add error-format-contract test to pin mcpError() text stru…
May 21, 2026
1fbd536
chore: remove completed plan and spec files
May 21, 2026
25f2ef8
chore: remove dead web/login.html and local-login-server
May 21, 2026
fa3c406
chore: remove stale design docs and contrib directory
May 21, 2026
61e2bb9
feat(devices): show family and room columns by default in devices list
May 21, 2026
161a571
fix: address code review P1+P2 regressions
May 21, 2026
ed57dfa
test(capabilities): add reset to ALL_EXPECTED_LEAF_COMMANDS whitelist
May 21, 2026
694ab7f
refactor(test): replace hardcoded command whitelist with dynamic CLI …
May 21, 2026
037fcd8
fix: address code review P1+P2 regressions
May 21, 2026
77ef001
test(auth): update header count expectation to include User-Agent
May 21, 2026
0f79b75
security: add env-var overrides for OAuth client secret and AES const…
May 21, 2026
396ec96
docs: clarify OAuth client ID comments and document new env var overr…
May 21, 2026
224e8ba
refactor(auth): remove unused getFreePort export from utils
May 21, 2026
868f72c
fix(reset): return on abort instead of process.exit; report credentia…
May 21, 2026
3da65b9
fix(auth): add return after exitWithError in login action; remove non…
May 21, 2026
0f2b58a
refactor(devices): extract ALIAS and ALL_COLS to module-level exporte…
May 21, 2026
32d6fd3
test(token-exchange): fix dead-code in region-fallback test; move des…
May 21, 2026
a415da2
refactor(devices): add explicit Set<string> type annotation to DEVICE…
May 21, 2026
a0fa827
fix(history-agg): compute no-bucket key once before loop to prevent p…
May 21, 2026
d4a5343
fix(reset): resolve data paths relative to --config dir instead of ha…
May 21, 2026
3707cf9
fix(reset): exit 1 in --json mode when any reset step fails
May 21, 2026
3d419c8
refactor(reset): add comment clarifying global vs config-aware paths …
May 21, 2026
feb3767
fix(config): include --profile in auth login hint when a named profil…
May 21, 2026
f6580c3
fix(devices): emit cloud as boolean/null in --json --fields path inst…
May 21, 2026
758e0fa
fix(auth): save credentials to --config file path instead of keychain…
May 21, 2026
3f5e2c0
docs(changelog): fix markdownlint blank-line errors around headings a…
May 22, 2026
ed44437
fix(auth,reset): wrap decryptField errors, surface removeItem reason,…
May 22, 2026
1061b59
fix(reset,history-agg): scope credential deletion to --config, clamp …
May 22, 2026
0b51278
test(reset,history-agg): add regression tests for --config credential…
May 22, 2026
498cb28
test(browser-login,cache,devices): add missing coverage for browserLo…
May 22, 2026
ea70854
fix(reset,devices,config): respect --config in reset cache scope, JSO…
May 22, 2026
f128341
fix(reset): non-interactive abort message and JSON error envelope con…
May 22, 2026
f8f4d83
refactor(auth): extract verifyCredentials to src/auth/verify.ts for s…
May 22, 2026
6523e29
refactor(devices): extract column constants to devices-columns.ts
May 22, 2026
c3cb2f8
test(history-agg): add boundary test for open-ended range with no bucket
May 22, 2026
0c7ef22
docs(changelog): document MCP list_devices nullable schema change
May 22, 2026
478bcd0
docs: add .env.example with all supported environment variables
May 22, 2026
78c3660
test(doctor): mock credential store to isolate from real OS keychain
May 22, 2026
ea1a756
fix(reset): distinguish TTY user-abort from non-interactive abort
May 22, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
# SwitchBot CLI — environment variables
# Copy to .env and fill in values as needed.

# API credentials (alternative to `switchbot config set-token`)
# SWITCHBOT_TOKEN=
# SWITCHBOT_SECRET=

# OAuth constant overrides (advanced — only needed if SwitchBot rotates these)
# SWITCHBOT_OAUTH_CLIENT_SECRET=
# SWITCHBOT_TOKEN_AES_KEY=
# SWITCHBOT_TOKEN_AES_IV=

# Disable ANSI colors
# NO_COLOR=1
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ npm-debug.log*
# Environment & credentials
.env
.env.*
!.env.example
.switchbot/

# Editor / OS
Expand Down
17 changes: 13 additions & 4 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,20 @@ This project follows [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [Unreleased]

### Added

- `auth login` — browser-based OAuth 2.0 sign-in via `sp.oauth.switchbot.net`; stores credentials in OS keychain after verification
- `auth keychain set/get/delete/migrate/describe` — manage OS keychain credential backend
- `SWITCHBOT_OAUTH_CLIENT_SECRET`, `SWITCHBOT_TOKEN_AES_KEY`, `SWITCHBOT_TOKEN_AES_IV` env vars to override baked-in OAuth/AES constants
- **`devices expand` supports lighting commands**: `setBrightness` (`--brightness`), `setColor` (`--color`), and `setColorTemperature` (`--color-temp`) flags now expand for Color Bulb, Strip Light, Ceiling Light, and similar devices.

### Fixed

- `reset`: aborting at the confirmation prompt no longer continues the reset action in test environments
- `reset`: credential deletion failures are now reported as `failed` instead of `not found`
- `reset --config <path>`: no longer recursively deletes a sibling `cache/` directory next to the override file. The CLI never creates that path in `--config` mode, so removing it could wipe an unrelated project's data.
- `devices list --json --fields`: alias inputs (e.g. `id,name`) now resolve to canonical output keys (`deviceId`, `deviceName`), matching `--format json`. The JSON schema is now stable regardless of which input form callers used.
- `config`: credential-missing hint now preserves `--config <path>` in both the `auth login` and `config set-token` recovery commands. Without this, the suggested `auth login` would write to the default backend, which `loadConfig` ignores while `--config` is active.
- **Daemon start failed in bundled builds** (BUG-001): CLI entry path resolution navigated above the dist/ directory when running from the single-file bundle. Now correctly detects the bundled scenario.
- **`rules run` exited 0 when `automation.enabled` was false** (BUG-002): daemon interpreted this as success. Now exits 1 with a clear message.
- **Unknown subcommands exited 0** (BUG-005/BUG-008): `cache list`, `history list`, and other invalid subcommand inputs triggered Commander help display and exited 0. Now exits 2 (usage error).
Expand All @@ -24,10 +36,7 @@ This project follows [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
- **`devices commands <Type> --json`**: same change — `data` is always an array.
- **`_fetchedAt` renamed to `fetchedAt`**: removed underscore prefix from the CLI-added timestamp field in `devices status` JSON output.
- **`rules run --json` when `automation.enabled` is false**: previously emitted `{data: {kind:"control", controlKind:"disabled"}}` (success envelope) with exit 1. Now emits `{error: {code:1, kind:"runtime", message:"..."}}` (error envelope) — consistent with the JSON protocol.

### Added

- **`devices expand` supports lighting commands**: `setBrightness` (`--brightness`), `setColor` (`--color`), and `setColorTemperature` (`--color-temp`) flags now expand for Color Bulb, Strip Light, Ceiling Light, and similar devices.
- **MCP `list_devices` outputSchema**: `roomID` and `controlType` fields now accept `null` in addition to `string | undefined`. Consumers with strict JSON-Schema or Zod validation may need to update their parsers.

## [3.6.3]

Expand Down
3 changes: 3 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -813,6 +813,9 @@ SwitchBot-specific error codes mapped to readable messages:

- `SWITCHBOT_TOKEN`: API token — takes priority over the config file.
- `SWITCHBOT_SECRET`: API secret — takes priority over the config file.
- `SWITCHBOT_OAUTH_CLIENT_SECRET`: Override the bundled OAuth client secret (advanced).
- `SWITCHBOT_TOKEN_AES_KEY`: Override the AES-128-CBC key used for token decryption (advanced).
- `SWITCHBOT_TOKEN_AES_IV`: Override the AES-128-CBC IV used for token decryption (advanced).
- `NO_COLOR`: Disable ANSI colors in all output (automatically respected).

## Scripting examples
Expand Down
26 changes: 0 additions & 26 deletions contrib/systemd/switchbot-mcp.service

This file was deleted.

242 changes: 0 additions & 242 deletions docs/design/phase3-install.md

This file was deleted.

Loading
Loading