feat(devices): harden devices command for agent-safe control (2.3.0)#14
Merged
chenliuyun merged 2 commits intomainfrom Apr 20, 2026
Merged
feat(devices): harden devices command for agent-safe control (2.3.0)#14chenliuyun merged 2 commits intomainfrom
chenliuyun merged 2 commits intomainfrom
Conversation
added 2 commits
April 20, 2026 09:08
… module Lift buildAcSetAll/buildCurtainSetPosition/buildBlindTiltSetPosition/buildRelaySetMode out of expand.ts into a new src/devices/param-validator.ts. No behavior change — expand.ts imports the same builders from the shared module. Prepares the ground for validateParameter() to be consumed by devices command in the next commit.
Closes the gaps that blocked agents from safely issuing complex control
commands via devices command:
- Raw-parameter validation: setAll (AC), setPosition (Curtain / Blind
Tilt), and setMode (Relay Switch) now validate the wire-format string
client-side via validateParameter(). Malformed shapes, out-of-range
values, and JSON payloads where CSV is expected fail fast with exit 2
instead of being forwarded to the API.
- Case-only command-name mismatches (turnon, TurnOn) are normalized to
the canonical name with a stderr warning and the request proceeds.
Genuinely unknown commands still exit 2 with the supported-commands
list. --json output reports the canonical name in data.command.
- devices command --name <query> <cmd> [parameter] now correctly shifts
the positional args instead of throwing 'provide either deviceId or
--name, not both'.
- intArg no longer rejects pure negative integers up-front; they fall
through to the min/max check so --max -1 classifies as a range error
('must be >= 1') rather than 'requires a numeric value'.
Version bumps from 2.2.1 to 2.3.0 (minor) because the case-normalize
behavior changes the exit code of previously-erroring invocations (2
to 0). No breaking changes to previously-successful paths.
README: adds one paragraph under 'Parameter formats' documenting the
new client-side validation and case normalization behavior.
chenliuyun
pushed a commit
that referenced
this pull request
Apr 20, 2026
C1 (#14): update --idempotency-key / --idempotency-key-prefix help text in devices.ts and batch.ts to mention process-local scope, per-process cache semantics, and that independent CLI invocations do not share cache. C2 (#15): mcp --help "eight tools" → "eleven tools"; list all 11 by name including get_device_history, query_device_history, aggregate_device_history. C3 (#17): add `scenes describe <sceneId>` subcommand. Returns sceneId, sceneName, stepCount:null, and a note explaining v1.1 API limitation. Exits 2 with scene_not_found + candidate list on unknown sceneId. Adds 'scenes describe' to COMMAND_META in capabilities.ts. Adds 2 tests (known + unknown scene). C4 (#13): add JSDoc comment on hints field in agent-bootstrap.ts clarifying empty array semantics. Add 'hints' field to cliAddedFields in schema.ts. C5 (#16): create docs/verbose-redaction.md documenting masked headers (authorization, token, sign, nonce, x-api-key, cookie, set-cookie, x-auth-token, t) and the --trace-unsafe opt-out flag. C6 (#18): plan schema output now includes agentNotes.deviceNameStrategy documenting that deviceName uses require-unique resolution and plans should pin deviceId for determinism. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
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
chenliuyun
pushed a commit
that referenced
this pull request
Apr 20, 2026
C1 (#14): update --idempotency-key / --idempotency-key-prefix help text in devices.ts and batch.ts to mention process-local scope, per-process cache semantics, and that independent CLI invocations do not share cache. C2 (#15): mcp --help "eight tools" → "eleven tools"; list all 11 by name including get_device_history, query_device_history, aggregate_device_history. C3 (#17): add `scenes describe <sceneId>` subcommand. Returns sceneId, sceneName, stepCount:null, and a note explaining v1.1 API limitation. Exits 2 with scene_not_found + candidate list on unknown sceneId. Adds 'scenes describe' to COMMAND_META in capabilities.ts. Adds 2 tests (known + unknown scene). C4 (#13): add JSDoc comment on hints field in agent-bootstrap.ts clarifying empty array semantics. Add 'hints' field to cliAddedFields in schema.ts. C5 (#16): create docs/verbose-redaction.md documenting masked headers (authorization, token, sign, nonce, x-api-key, cookie, set-cookie, x-auth-token, t) and the --trace-unsafe opt-out flag. C6 (#18): plan schema output now includes agentNotes.deviceNameStrategy documenting that deviceName uses require-unique resolution and plans should pin deviceId for determinism.
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.
Summary
Closes four gaps that blocked agents from safely issuing complex control commands through
devices command. All fixes ship together in2.3.0(minor).setAll(Air Conditioner),setPosition(Curtain / Blind Tilt), andsetMode(Relay Switch) now validate the wire-format string client-side. Malformed shapes ('on,2,2,30'), empty strings, wrong field counts, JSON where CSV is expected — all fail fast with exit 2 instead of being forwarded to the API.devices command BOT turnonandTurnOnnow emit a stderr warning and continue with the canonicalturnOn.--jsonoutput reports the canonical name indata.command. Genuinely unknown commands (foobar) still exit 2 with the supported-commands list.--name+ positional args:devices command --name '家里空调' setAll '26,2,2,on'no longer throws "provide either deviceId or --name, not both" — positional shift is recognized.intArgrange errors:--max -1now classifies as "must be >= 1" instead of "requires a numeric value".--max --helpstill reports the flag-like error.Why 2.3.0 (minor)?
Case-only command names that previously exited 2 now exit 0. That is a UX-positive behavior change but still a behavior change — hence minor bump, not patch. No previously-successful invocation changes behavior.
Refactor
Extracted the 4 semantic-flag builders (
buildAcSetAll/buildCurtainSetPosition/buildBlindTiltSetPosition/buildRelaySetMode) out ofsrc/commands/expand.tsinto a new shared modulesrc/devices/param-validator.ts.validateParameter()(the raw-string validator consumed bydevices command) lives alongside them and dispatches by(deviceType, command)prefix — unknown combos pass through so the command stays a usable escape hatch.Test plan
npm run build— cleannpm test— 766 tests pass (43 files)tests/devices/param-validator.test.ts— 20+ cases covering all 4 builders +validateParameterdispatch + passthroughtests/commands/devices.test.tscovering raw-param validation, case normalization,--name+ positional shifttests/utils/arg-parsers.test.ts—intArgpure-negative-integer pathswitchbot --dry-run devices command --name 'Living' setAll '30,2,2,on'against real cacheswitchbot devices command <botId> turnon— verify warning emitted