Skip to content

Reject unknown arguments and keep page cursors opaque - #598

Draft
razor-x wants to merge 3 commits into
mainfrom
claude/page-cursor-arg-support-ahwlll
Draft

Reject unknown arguments and keep page cursors opaque#598
razor-x wants to merge 3 commits into
mainfrom
claude/page-cursor-arg-support-ahwlll

Conversation

@razor-x

@razor-x razor-x commented Aug 4, 2026

Copy link
Copy Markdown
Member

Summary

Two fixes to how the CLI reads arguments, found while adding --page-cursor support.

--page-cursor turned out to already be a normal request parameter on every paginated endpoint, so no flag needed adding. What was broken was the value: minimist read it as a number, and unrecognized flags were forwarded to the API instead of being reported.

A page cursor is read as an opaque string

parseCliArgs only forced code to a string, so a cursor that looks numeric was silently corrupted:

given sent before sent now
--page-cursor 0755 755 "0755"
--page-cursor 1e5 100000 "1e5"
--page-cursor 12345 12345 "12345"

A cursor is opaque, so this named a page the API never issued, and failed invisibly. page-cursor and page_cursor now join code in minimist's string list.

An unknown argument is an error

Anything not recognized as a CLI flag was previously added to the request params and sent, so a typo either failed somewhere less obvious or was quietly ignored — and the request went out either way.

$ seam devices list --limitt 5
Unknown parameter for /devices/list: --limitt
Run 'seam devices list --help' to see what it accepts.

The check runs after the command path is resolved and before the command acts on anything, so nothing is sent and nothing is half applied. It covers both kinds of command:

  • Endpoint commands are checked against the endpoint's own request parameters.
  • Commands the CLI handles itself are checked against the flags already declared in the command spec, so seam logout --force, seam completion bash --shell, and a misspelled seam login --toekn are now reported instead of ignored.

Params read from stdin are deliberately not checked — they are passed through as given, so anything the API itself accepts can still be sent that way:

echo '{"limit": 2, "whatever": true}' | seam devices list   # still forwarded

Multiple unknowns are named at once, and a one-letter key is reported as the short form it must have been written as (-n, not --n). --help is handled before the check, so it always works.

Along the way

  • An argument was sent twice when written in mixed case. Key normalization added the normalized form alongside the original, so --LIMIT 5 sent both LIMIT: 5 and limit: 5. It now replaces the key, which is also what lets the new check see one argument instead of two.
  • Dropped --id-only from the README. seam devices get --name "Front Door" --id-only only ever appeared to work because id_only was forwarded and ignored; no version of the CLI implements it. Replaced with | jq -r '.device.device_id', matching the piping idiom used elsewhere in the README.
  • Added a Pagination section to the README covering the cursor round trip via pagination.next_page_cursor, plus a help example.

Notes for review

  • The check is enforced against the documented API surface: the blueprint is built with omitUndocumented: true, so a real-but-undocumented param is now rejected as unknown. The stdin passthrough is the escape hatch. Say the word if it should consult the unfiltered definitions instead.
  • Three endpoints take page_cursor but are not marked hasPagination, because that flag is derived from the response schema declaring pagination: /locks/list, /noise_sensors/list, /thermostats/list. They are device-list aliases with the same responseKey and resourceType as /devices/list, which is marked paginated. That looks like an upstream inconsistency in @seamapi/types and is not addressed here.

Testing

116 tests pass; typecheck, lint, prettier, and build are clean. Beyond the unit and end-to-end tests added here, the argument handling was smoke-tested against a fake server using the real API definitions to confirm the check does not over-reject: --page-cursor on devices list and acs users list, events list --between (with the since default still dropped), --accepted-providers august,schlage splitting to an array, devices get --name, dotted --custom-metadata.foo bar keeping its nested object, --json/--no-json, and every command the CLI handles itself.

🤖 Generated with Claude Code

https://claude.ai/code/session_01QQvXm83ki7Mn9dXGhHrK7i

Paginated commands take a page cursor to select a page of results, but
the CLI only offered one where the API definitions happened to document
the parameter, and minimist read the value as a number.

Derive the flag from the endpoint's own pagination instead, so every
paginated command offers --page-cursor in its help, its completions, and
its interactive prompt. Read the value as a string so an opaque cursor
survives verbatim rather than losing a leading zero or being rewritten
from exponent notation.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QQvXm83ki7Mn9dXGhHrK7i
@razor-x razor-x changed the title Add --page-cursor flag support for paginated commands feat: Add --page-cursor flag support for paginated commands Aug 4, 2026
claude added 2 commits August 4, 2026 05:42
An argument the command does not accept was forwarded to the API as a
param, so a typo either failed somewhere less obvious or was quietly
ignored, and the request went out either way.

Hold the arguments to what the endpoint accepts and name every one it
does not, pointing at the command's own help. Params read from stdin are
left as they are: only the arguments are checked.

Normalizing an argument key now replaces it rather than adding the
normalized form alongside it, which had sent --LIMIT as both LIMIT and
limit. Drop the README's --id-only from seam devices get, which no
version of the CLI has ever implemented.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QQvXm83ki7Mn9dXGhHrK7i
Extend the check to the commands the CLI handles itself, which took
arguments they did not accept and silently did nothing with them, e.g.
seam logout --force or a misspelled seam login --toekn. Their flags are
already declared in the command spec, so look them up there.

Arguments are now read and collected before the command runs, so
completion can be checked too, and hitting 'back' is handled before the
check rather than after it.

Drop get-request-parameters. Every endpoint the definitions mark as
paginated already documents page_cursor, so synthesizing one only added a
description that can drift from upstream, keyed on a flag that is false
for endpoints that do paginate. If the definitions ever omit a cursor
that belongs in @seamapi/types, not in a patch here.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QQvXm83ki7Mn9dXGhHrK7i
@razor-x razor-x changed the title feat: Add --page-cursor flag support for paginated commands Reject unknown arguments and keep page cursors opaque Aug 4, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants