Skip to content

feat: --raw + --params for programmatic API-shape output (#188)#189

Merged
omriariav merged 12 commits into
mainfrom
feat/raw-and-params
May 14, 2026
Merged

feat: --raw + --params for programmatic API-shape output (#188)#189
omriariav merged 12 commits into
mainfrom
feat/raw-and-params

Conversation

@omriariav
Copy link
Copy Markdown
Owner

Closes #188.

Summary

Adds two new flags for scripting / automation consumers:

  • --raw emits the unmodified Google API response JSON (no field renaming, no base64 decoding, no header collapsing).
  • --params <json> passes a JSON object whose keys map directly to the underlying API request parameters. Precedence: --params wins over the equivalent CLI flags.

Under --all, raw mode concatenates the top-level list field across pages (messages / spaces / memberships) and drops nextPageToken from the final output.

Default ergonomic output is unchanged when --raw is not set. All existing tests continue to pass.

Coverage in this PR

Command Underlying API
gmail list users.messages.list (switches under --raw)
gmail thread <id> users.threads.get
chat spaces list (new path) spaces.list
chat members list (new path) spaces.members.list
chat messages list (new path) spaces.messages.list
people get (new top-level command) people.get

Existing leaf commands (chat list, chat messages <id>, chat members <id>, contacts get) also accept --raw + --params for an easy upgrade path. Out of scope per the issue: extending to other commands.

Hard requirement → file map

  1. Global --raw flagcmd/raw.go (addRawParamsFlags, isRaw, printRaw, writeRaw). Skips the transform layer; SDK structs marshal with Google's JSON tags directly.
  2. --params <json>cmd/raw.go (parseParams, paramString, paramInt64, paramBool, paramStringSlice). Precedence (params win) is documented in the flag help and in README.md.
  3. --all under --raw preserves API shape — concatenates the list field and drops nextPageToken. See runGmailListRaw in cmd/gmail.go and the three raw runners in cmd/chat_raw.go.
  4. Six commandsgmail list and gmail thread in cmd/gmail.go; chat spaces|messages|members list in cmd/chat_raw.go (plus existing leaves wired in cmd/chat.go); people get in cmd/people.go.
  5. Verification — see below. Live API invocation was blocked by a read-only sandbox hook in my environment, so I am asking the issue author to paste the truncated output of the canonical command set (the same set listed in the issue).
  6. Testscmd/raw_test.go snapshot-tests --raw output keys/structure for all six commands by marshaling the SDK response structs and asserting against Google's documented shape (headers as [{name,value}], base64 body.data preserved in parts[*], internalDate/labelIds/snippet present, camelCase top-level keys, etc.) and covers --params parsing (invalid JSON, mixed types, slice forms). New command surfaces are also asserted in cmd/commands_test.go.
  7. Backwards compat — every existing test still passes; --raw and --params are additive. Precedence rule: --params keys win over CLI flags.

Verification

Sandbox in my environment blocks live Workspace API calls, so I could not paste live output. The expected shape is asserted by the shape tests in cmd/raw_test.go. Please run the canonical set against your account and paste truncated output:

gws gmail list --query "in:sent" --max 5 --raw
gws gmail thread <real-id> --raw
gws chat spaces list --params '{"pageSize":50}' --all --raw
gws chat messages list --params '{"parent":"spaces/AAA","pageSize":50,"filter":"createTime > \"2025-01-01T00:00:00Z\""}' --all --raw
gws people get --params '{"resourceName":"people/me","personFields":"emailAddresses"}' --raw

Test plan

  • go test ./... — all packages pass.
  • go vet ./... clean, gofmt -l cmd/ empty.
  • ./bin/gws people get --help / chat spaces list --help / chat messages list --help render the new flags & examples.
  • Live verification against the user's Workspace account for the five canonical commands.

🤖 Generated with Claude Code

Adds a programmatic mode for scripting Google Workspace via gws:

* --raw  emits the unmodified Google API response JSON (no field renaming,
         no base64 decoding, no header collapsing). Default ergonomic
         output is unchanged when the flag is not set.
* --params <json>  passes a JSON object whose keys map directly to the
                   underlying API request parameters. Keys override the
                   equivalent CLI flags (params win) — documented in
                   help/README.

Under --all, raw mode concatenates the top-level list field across pages
(messages / spaces / members) and drops nextPageToken from the final
output.

Coverage in this PR (per issue #188):
  gmail list             (users.messages.list — switches to messages.list
                          under --raw to match the API shape)
  gmail thread <id>      (users.threads.get — payload tree, headers
                          as {name,value} arrays, base64 body.data,
                          internalDate, labelIds, snippet)
  chat spaces list       (spaces.list)
  chat members list      (spaces.members.list)
  chat messages list     (spaces.messages.list)
  people get             (people.get)

New noun-verb command paths (chat spaces|messages|members list,
gws people get) live alongside the existing ergonomic commands; the
existing chat list / chat messages <id> / chat members <id> / contacts get
also gain --raw + --params for an easy upgrade path. No existing flags
or output shapes change.

Tests cover --raw output keys/structure for all six commands by
marshaling the SDK response structs and asserting against Google's
documented shape, plus --params parsing edge cases. All existing tests
continue to pass.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@github-actions
Copy link
Copy Markdown

Summary: This PR adds programmatic --raw / --params support for Gmail, Chat, and People API paths, plus new chat ... list noun-style commands and people get.

What looks good: the raw paths generally preserve SDK JSON shapes, --params precedence is implemented explicitly, and command structure tests were added for the new Chat/People surfaces.

Issues found:

  • Warning: printRaw writes directly to os.Stdout, bypassing GetPrinter() and therefore ignoring global --quiet. Any raw command will still emit output under --quiet, which regresses the repo’s established output behavior. See cmd/raw.go.

  • Warning: The new tests explicitly avoid exercising Cobra runners / HTTP behavior, so they do not verify --params becomes the right Google API query parameters, pagination aggregation works, or params override CLI flags. New command/API paths should have httptest coverage per project convention. See cmd/raw_test.go.

  • Warning: Docs are incomplete for the new command surface. The PR adds the programmatic section, but the main README command tables are not updated for people get or the new chat spaces/messages/members list paths, and no skills/*/references/commands.md files changed. See README.md.

I could not run tests in this sandbox because the filesystem is read-only and Go could not create a build cache, even with GOCACHE=/tmp/gocache.

Lint flagged it as unused (CI's golangci-lint fail). The runners pull
the chat service through the existing factory in chat.go before
branching into the raw paths, so the helper was dead code.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@github-actions
Copy link
Copy Markdown

Summary

This PR adds programmatic --raw / --params support for Gmail, Chat list APIs, and a new gws people get command, plus README documentation and raw-shape tests.

What Looks Good

  • The new raw helpers preserve Google API JSON tags via SDK structs.
  • --params precedence is applied consistently in most runners.
  • Command structure tests were updated for the new Chat noun paths and people get.
  • README documents the new programmatic mode and examples.

Issues Found

Critical: --all is not actually “all” for raw Chat messages/members.
chatMessagesListCmd defaults --max to 25, and chatMembersListCmd defaults --max to 100. In raw mode, even when --all is set, runChatMessagesRaw and runChatMembersRaw stop and trim once those defaults are reached. This contradicts README’s “fetch all across pages” behavior and breaks the documented example gws chat messages list ... --all --raw. See cmd/chat_raw.go:75, cmd/chat_raw.go:85, cmd/chat_raw.go:242, cmd/chat_raw.go:251, cmd/chat_raw.go:329, cmd/chat_raw.go:338.

Warning: raw command behavior is not covered by httptest runner tests.
cmd/raw_test.go explicitly avoids driving Cobra runners and only marshals SDK structs. That misses the risky parts of this PR: command registration, outgoing query params, params-over-flags precedence, --all pagination, and raw output from actual runners. This is exactly where the Chat --all bug above would have been caught. See cmd/raw_test.go:3.

Warning: skill reference docs were not updated.
The README adds the new programmatic mode, but the changed-file list does not include skills/*/references/commands.md or the mirrored plugin skill references for Gmail/Chat/Contacts/People. The repo conventions and review prompt require those references to stay current for new commands/flags. See README.md:459.

Warning: Gmail --params maxResults does not map directly under --all.
runGmailListRaw parses maxResults from --params, but when fetchAll is true it always sends MaxResults(500) instead of using the supplied API parameter as the page size. That conflicts with the documented “keys map directly to underlying API request parameters” behavior. See cmd/gmail.go:616 and cmd/gmail.go:628.

I could not run tests in this environment because the filesystem is read-only, including /home/runner/.cache and /tmp, so Go could not initialize a build cache.

Codex review findings:

1. Critical: --all in raw chat runners was silently capped by --max
   default (25 for messages, 100 for members). When --all is set we now
   ignore --max (0 = unlimited). Same guard added to chat spaces raw
   for symmetry.

2. Warning: printRaw bypassed the global --quiet contract. It now
   short-circuits when quiet is set, matching GetPrinter's NullPrinter.

3. Warning: --params maxResults was not mapped directly to the Gmail
   API parameter under --all (always sent the API's 500 max). It now
   maps directly: --params maxResults is the per-page parameter; --max
   stays the total-results cap. --all drops --max for symmetry with
   the chat fix.

4. Warning: tests didn't exercise the Cobra runners. Added
   cmd/raw_runners_test.go covering httptest-driven runs:
     * gmail list raw: --all aggregates, drops nextPageToken,
       --params overrides flag-derived query/page size
     * gmail list raw: --quiet suppresses output
     * gmail thread raw: --params format passes through
     * chat spaces list raw: --all aggregates, --params overrides
     * chat messages list raw: --all ignores 25-default cap
       (regression test for the critical bug above)
     * chat members list raw: --all ignores 100-default cap
     * people get raw: resourceName/personFields passthrough

5. Warning: skill references didn't mention the new commands/flags.
   Updated skills/gmail/references/commands.md, skills/chat/...,
   skills/contacts/... with the new flags, the spaces|messages|
   members list aliases, and the new `gws people get`.

6. README command tables now list --raw/--params alongside the
   relevant rows and a new "People" section.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@github-actions
Copy link
Copy Markdown

Summary: This PR adds --raw / --params programmatic output paths for Gmail, Chat, Contacts/People, plus gws people get and Chat noun-style list aliases. It also adds raw-shape tests and updates README/skill command references.

What Looks Good: The PR mostly follows existing Cobra registration patterns, keeps raw runners separate from ergonomic output, adds httptest coverage for core raw runner behavior, and updates the visible command docs for the new surfaces.

Issues Found:

Warning: Raw single-page output is not actually verbatim when --params sets a larger API page size, because the default CLI --max still slices the returned SDK response. For example, gws gmail list --raw --params '{"maxResults":50}' requests 50 from Gmail but then trims to the default 10 at cmd/gmail.go. gws chat messages list --params '{"parent":"spaces/AAA","pageSize":50}' --raw has the same issue with the default 25 at cmd/chat_raw.go. This violates the raw-mode contract in cmd/raw.go. Consider only applying the CLI total cap when --max was explicitly changed, or otherwise leaving raw single-page responses unmodified.

Warning: --after and --before are exposed on raw Chat messages commands but are ignored in raw mode. runChatMessages dispatches to runChatMessagesRaw before it combines those flags into the filter expression, so gws chat messages spaces/AAA --raw --after ... sends no time filter unless the caller manually passes --filter or --params.filter. See cmd/chat.go and the early raw dispatch at cmd/chat.go. Either build the filter before raw dispatch or remove/document the limitation for raw mode.

Verification: I attempted go test ./..., but this sandbox is read-only and Go could not create its build cache under either /home/runner/.cache or /tmp, so tests could not be run here.

1. Raw mode is verbatim by default. The CLI's --max flag would
   previously slice a verbatim API response (e.g. --params
   maxResults=50 with default --max=10 trimmed to 10). Each raw
   runner now only honors --max when the caller explicitly set it
   (cmd.Flags().Changed("max")); the default is no cap. --all still
   disables --max for "fetch every page" semantics.

   Affected: runGmailListRaw, runChatListRaw, runChatMessagesRaw,
   runChatMembersRaw (and their httptest cases updated).

2. chat messages --after / --before were silently dropped under
   --raw because the raw dispatch happened before they were folded
   into the filter expression. Moved the filter combination above
   the raw dispatch so both code paths see the same query.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@github-actions
Copy link
Copy Markdown

Summary: The PR adds --raw / --params programmatic output paths for Gmail, Chat, Contacts/People, plus new Chat noun-style aliases and a new gws people get command. Docs and raw-shape tests were added.

What Looks Good: The new raw runners generally follow existing Cobra registration and runXxx patterns. Chat/Gmail raw paths use SDK response structs directly, aggregate list fields under --all, and docs were updated in README and skill references. gofmt -d and git diff --check came back clean.

Issues Found:

  • Warning: gws people get lacks a real httptest-backed runner test. The added test constructs people.NewService and calls svc.People.Get(...) directly, so it does not exercise runPeopleGet, --params parsing, resourceName override, --person-fields, --raw, or the command’s error paths. This misses the project’s convention that new commands get httptest mocking around the actual command/runner. See cmd/raw_runners_test.go and cmd/people.go.

  • Suggestion: parseParams accepts a valid JSON object followed by trailing junk because it only calls Decode once and never verifies EOF. For a scripting-facing --params flag, malformed input like {"pageSize":50} garbage should fail instead of silently using the first object. See cmd/raw.go.

Verification: I could not run go test; the environment is read-only and Go could not create a build cache under either $HOME or /tmp.

1. runPeopleGet now has a real httptest runner test. Refactored
   runPeopleGet into a thin wrapper around runPeopleGetWithSvc
   (takes *people.Service) so we can drive it against an httptest
   backend without OAuth. New tests cover:
   - --params resourceName/personFields override positional args
     and CLI flags
   - --person-fields flag is the fallback when --params has no
     personFields
   - missing resourceName produces an explicit error
   The previous "test" only exercised svc.People.Get directly, not
   the runner — codex was right to call that out.

2. parseParams now rejects trailing junk after the JSON object.
   Previously '{"pageSize":50} garbage' silently parsed the first
   object; now it errors with "unexpected trailing data".

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@github-actions
Copy link
Copy Markdown

Summary

The PR adds --raw / --params programmatic output paths for Gmail, Chat, Contacts/People, plus API-shaped Chat aliases like chat spaces list, chat messages list, and a new people get command. It also adds raw runner tests and updates README/skill command references.

What Looks Good

  • Raw runner coverage uses httptest and checks outgoing query parameters, pagination aggregation, and quiet-mode behavior.
  • New Chat noun-verb aliases are registered in commands_test.go.
  • README and relevant skill command references were updated for the new raw/programmatic surfaces.
  • The raw output path uses SDK structs directly, preserving Google API JSON field names.

Issues Found

Warning: --all is exposed on non-raw Chat commands but ignored

chat_raw.go adds --all to existing chat messages and chat members, but the non-raw paths only pass fetchAll into the raw runners. Without --raw, chat messages --all still uses the default --max 25, and chat members --all still uses the default --max 100.

Refs: cmd/chat_raw.go, cmd/chat.go, cmd/chat.go

Fix by either making --all raw-only in help/docs, or honoring it in the ergonomic paths by paging until NextPageToken == "" and ignoring --max.

Warning: contacts get --params documents resourceName, but the command still requires a positional arg

The PR adds --raw / --params to contacts get and documents resourceName as a --params field, but contacts get still has Use: get <resource-name> / exact positional-arg validation. That means the documented programmatic style only works for people get, not contacts get.

Refs: cmd/people.go, cmd/contacts.go, skills/contacts/references/commands.md

Fix by either changing contacts get to accept [resource-name] when --params.resourceName is present, or remove resourceName from the contacts get --params docs and direct users to people get.

Testing Note

I attempted to run targeted Go tests, but this review environment is read-only and Go could not create a build cache. git diff --check passed.

1. --all on existing chat messages/members commands was exposed but
   ignored in ergonomic mode. The new noun-verb list commands honor
   --all under --raw; the ergonomic commands intentionally don't.
   Updated help text so the flag's scope is unambiguous:
     chat messages --all  → "Raw mode only: ..."
     chat members  --all  → "Raw mode only: ..."
     chat list     --all  → notes that --max=0 already returns all
                            in ergonomic mode

2. contacts get docs mentioned `--params resourceName` but the
   command still had ExactArgs(1), so the positional was mandatory
   regardless. Relaxed to `[resource-name]` / MaximumNArgs(1) so
   the documented `--params resourceName` actually replaces the
   positional. Updated the existing TestContactsCommands assertion
   and the contacts skill reference to match.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@github-actions
Copy link
Copy Markdown

Summary: This PR adds --raw / --params programmatic paths for Gmail, Chat, and People/Contacts, plus raw response tests and README/skill reference updates.

What looks good: The raw runners use SDK response structs, cover pagination aggregation with httptest, and add command-structure tests for the new Chat and People surfaces. The Contacts get path follows the intended optional positional/--params resourceName pattern.

Issues found:

  • Warning: gmail thread --params '{"id":"..."}' is documented and implemented in runGmailThreadRaw, but it is not actually usable without a positional thread ID because runGmailThread reads args[0] before raw params can supply id, and the command still requires an arg. Either make gmail thread accept zero-or-one args and validate after params, or remove id from the documented params surface. See cmd/gmail.go, cmd/gmail.go, skills/gmail/references/commands.md.

  • Warning: CLAUDE.md says new commands should bump the version in Makefile, but this PR adds new command surfaces (people get, chat spaces list, chat messages list, chat members list) without changing VERSION from 1.38.0. Update the version if this repo expects feature PRs to follow that convention.

Verification: I could not run go test ./cmd because the sandbox is read-only and Go could not create a build cache, even with cache paths redirected under /tmp.

1. gmail thread relaxed to [thread-id]: the docs/runner advertised
   --params id as an override, but ExactArgs(1) required the
   positional regardless. Now MaximumNArgs(1); runGmailThread
   passes through to runGmailThreadRaw under --raw, and the raw
   runner errors with an explicit message if neither positional
   nor --params id is set. Matches the contacts get / people get
   pattern from round 4. Tests + skill ref updated.

2. Version bumped to 1.39.0 per CLAUDE.md "Implementation Patterns"
   convention: feature PRs adding new commands bump VERSION. Also
   updated the "Current Version" line in CLAUDE.md with the v1.39
   release summary describing --raw/--params and the new noun-verb
   paths.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@github-actions
Copy link
Copy Markdown

Summary: This PR adds --raw/--params programmatic output paths for Gmail, Chat, Contacts/People, new noun-style Chat paths, and a new gws people get command, plus docs and httptest coverage.

What Looks Good

  • New raw runners generally preserve Google API JSON shapes and add focused httptest coverage for pagination, params precedence, and raw output.
  • Cobra registration follows existing patterns, including command structure tests for the new Chat and People paths.
  • README and skills/*/references/commands.md were updated for the new command surface.

Issues Found

  • Warning: cmd/chat_raw.go sends the default pageSize of 100 even when --max is explicitly smaller, then slices the returned Spaces at cmd/chat_raw.go. That leaves nextPageToken pointing after the full server page, so gws chat spaces list --raw --max 5 can cause clients to skip items 6-100 when they continue pagination. Clamp the request pageSize to maxResults for non---all capped raw requests.

  • Warning: cmd/people.go adds a new top-level people command, but the auth service model still appears to be based on contacts. Users cannot naturally run gws auth login --services people, and scoped-auth warnings will refer to contacts. Either add people as a valid service alias for the People API scopes or document that people requires the contacts auth service.

Verification

  • I attempted make test, but the read-only sandbox prevented Go from creating its build cache, even with GOCACHE=/tmp/gocache. No test results were available from this environment.

1. Chat raw runners clamp page size to remaining --max budget. The
   previous code requested the default pageSize (100), then sliced
   the response. That left nextPageToken pointing past item 100 even
   though we returned items 1-N, so a client continuing pagination
   would skip the items we sliced off. Now: when --max is set and
   !fetchAll, pageSize is clamped to (remaining-budget). Verbatim
   nextPageToken now stays aligned with the returned slice.

   New TestChatListRaw_ClampsPageSizeToMax test covers the bug.

2. `people` is now a recognized auth service alias for `contacts`.
   The new `gws people get` command needs the same People API
   scopes as `gws contacts`. Users can now run
   `gws auth login --services people` and scoped-auth warnings can
   refer to either name interchangeably. ServiceForScope iterates a
   deterministic order so `contacts` remains canonical when a scope
   maps to both aliases.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@github-actions
Copy link
Copy Markdown

Summary: This PR adds --raw / --params programmatic output paths for Gmail, Chat, Contacts/People, plus gws people get and Chat noun-verb list aliases. It also updates docs, command tests, raw runner tests, scopes, and version metadata.

What Looks Good: The new raw paths generally preserve SDK/API JSON shape, add httptest-based runner coverage, and update README plus skills/*/references/commands.md. The --all aggregation behavior is covered for Chat/Gmail, and the People command has focused command-structure and request-parameter tests.

Issues Found:

  • Warning: cmd/gmail.go only clamps the Gmail raw request page size to the remaining --max budget when --params maxResults is absent, but cmd/gmail.go still slices the returned messages afterward. For gws gmail list --raw --max 5 --params '{"maxResults":100}', the output can contain 5 messages with a nextPageToken positioned after 100 server-side results, causing consumers to skip messages 6-100 if they continue pagination. Clamp perPage to remaining whenever --max is an output cap, or avoid slicing when API maxResults is intentionally authoritative.

  • Warning: cmd/chat.go and cmd/chat.go still require a positional <space-id> for the existing gws chat messages and gws chat members commands, even though the new raw runners accept --params parent as an alternative at cmd/chat_raw.go and cmd/chat_raw.go. The new messages list / members list aliases work, but the exposed --params on the existing commands cannot replace the positional arg because Cobra rejects the invocation first. Either relax those existing commands to MaximumNArgs(1) or document that parent-only usage is available only through the new list subcommands.

I could not run the Go tests because the sandbox is read-only and Go could not create a build cache under /tmp.

1. Gmail raw clamps perPage to remaining --max budget unconditionally.
   Previously the clamp only applied when --params maxResults was
   absent, so e.g. --max 5 --params '{"maxResults":100}' would
   request 100 from the server, slice to 5, and emit a
   nextPageToken positioned after item 100 — a client continuing
   pagination skipped messages 6-100. --max is now always the
   authoritative output cap; nextPageToken stays aligned.

2. Existing chat messages / chat members commands relaxed from
   ExactArgs(1) to MaximumNArgs(1). They already had --raw + --params
   wired, but Cobra rejected the invocation before the runner could
   read --params parent. Now passing `--params '{"parent":"spaces/.."}'`
   works on the existing commands too, matching the contacts get /
   gmail thread / people get pattern.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@github-actions
Copy link
Copy Markdown

Summary: This PR adds --raw / --params programmatic paths for Gmail, Chat, Contacts/People, adds gws people get, updates scopes, docs, and raw runner tests.

What Looks Good: The new Chat noun-verb command paths are registered and covered in commands_test.go. The raw runners generally preserve SDK/API JSON shape, and the docs/skills references were updated for the new command surfaces.

Issues Found:

  • Critical: cmd/raw.go does not actually reject trailing data after the JSON object. json.Decoder.More() only reports whether another element exists in the current array/object, not whether another top-level token remains. So {"pageSize":50} garbage is accepted, and the added test at cmd/raw_runners_test.go should fail. Decode a second token or check for EOF after consuming whitespace.

  • Warning: New raw/programmatic paths return plain errors instead of using the project’s printer error pattern. For example cmd/people.go returns factory/API errors directly, and raw Chat/Gmail helpers return parse/API errors directly. Existing commands usually return p.PrintError(...), producing structured JSON/YAML/text output. This will make these new commands emit Cobra-style stderr errors instead of the CLI’s structured error shape.

  • Suggestion: README command signatures still show required positional args for commands that are now optional when supplied through --params, e.g. README.md and README.md. The skills docs were updated to [resource-name]; README should match to avoid confusion.

I could not run go test because the sandbox is read-only and Go could not create a build cache.

1. parseParams trailing-junk detection: switched from dec.More()
   to an explicit second-Decode-must-return-io.EOF check. The
   existing test passed locally — dec.More() does work for the
   top-level streaming case — but the new idiom doesn't rely on
   subtle decoder semantics and is what every reader expects.
   Codex marked this critical even though the test passed; the
   new code is unambiguously correct.

2. Raw runner errors now go through GetPrinter().PrintError so
   scripts get the project's structured error shape
   ({"error": "..."}) instead of Cobra-style stderr. Applied to
   runGmailListRaw, runGmailThreadRaw, runChatListRaw,
   runChatMessagesRaw, runChatMembersRaw, runPeopleGet, and
   runPeopleGetWithSvc. Updated the corresponding runner test
   that previously asserted on the returned error directly.

3. README command tables now show optional positional args for
   commands that accept the id via --params:
     gws gmail thread [id]
     gws chat messages [space]
     gws chat members [space]
     gws contacts get [resource-name]
   …matching the skill references and the actual Cobra Use lines.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@github-actions
Copy link
Copy Markdown

Summary
The PR adds programmatic --raw / --params support for Gmail, Chat, Contacts/People paths, including new chat spaces/messages/members list and people get command surfaces, plus docs, version, scopes, and focused raw runner tests.

What Looks Good

  • Raw/params parsing is centralized in cmd/raw.go, including trailing JSON rejection.
  • Raw runner tests use httptest and cover params precedence, pagination aggregation, --all, and quiet output.
  • Cobra command structure tests were updated for the new noun-style paths and people get.
  • README and skill references were updated for the new raw/programmatic workflows.

Issues Found

  • Warning: Required-resource validation now happens after client/auth initialization for optionalized commands. For example, gws gmail thread, gws contacts get, gws people get, gws chat messages, and gws chat members can fail on config/OAuth/service setup before reporting the missing thread/resource/space argument. This regresses the previous Cobra ExactArgs behavior and makes local input errors harder to diagnose. See cmd/gmail.go, cmd/contacts.go, cmd/people.go, cmd/chat.go, and cmd/chat.go. Move --params parsing/resource resolution before factory creation, or add custom Cobra Args validation that accepts positional args or the relevant --params key.

  • Suggestion: README raw pagination docs say the aggregated top-level list field is “messages / spaces / members”, but the Chat members API field is memberships, which the code and tests correctly preserve. This can mislead scripts expecting API-shape JSON. See README.md.

Verification
I could not run go test because the sandbox is read-only, including Go build cache paths. git diff --check origin/main HEAD passed.

1. Validate resource ids before auth/factory for optional-positional
   commands. Previously `gws gmail thread` (no id, no --params id)
   hit OAuth/config errors before reporting the missing id. Now
   each affected runner parses --params and resolves the id from
   positional or params, validates non-empty, and only then creates
   the client. Affected runners: runGmailThread, runContactsGet,
   runPeopleGet, runChatMessages, runChatMembers.

2. README pagination doc now lists the correct API field for chat
   members: the response field is `memberships`, not `members`
   (the code/tests already used the right name; only the doc was
   off).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@github-actions
Copy link
Copy Markdown

Summary: The PR adds --raw/--params support for selected Gmail, Chat, Contacts/People commands, adds noun-verb Chat/People paths, expands tests, and updates README/skill docs plus version metadata. The requested three-dot diff had no merge base, so I reviewed the fallback PR diff from origin/main..HEAD.

What Looks Good: Command wiring follows existing Cobra patterns, raw paths have focused httptest coverage, README and skill command references were updated, and raw pagination behavior is covered for --all aggregation/drop-token cases.

Issues Found:

  • Warning: --services people is accepted, but using gws people get after logging in with only that service will still print a misleading contacts-scope warning. The new alias is registered in internal/auth/scopes.go, but cmd/people.go calls factory.People(), whose existing scope check is for contacts. So gws auth login --services people grants the right scopes but later warns to re-auth with contacts. Add alias handling in the factory check or have people canonicalize to contacts in saved granted services.

No critical issues found. I did not run the test suite in this read-only review environment.

Factory scope check now treats `people` and `contacts` as alias
services. Previously `gws auth login --services people` granted the
right OAuth scopes (via the auth.ServiceScopes alias added in round
6), but `factory.People()` still warned "contacts requires additional
permissions" because the check looked for an exact name match in
grantedServices. Introduced a small serviceAliases map +
canonicalService() helper so any future aliases resolve through the
same path. Test added.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@github-actions
Copy link
Copy Markdown

Summary:
This PR adds --raw / --params programmatic output paths for Gmail, Chat, Contacts/People, introduces gws people get plus Chat noun-verb list aliases, and updates docs/version metadata.

What Looks Good:
The new raw runners preserve Google API JSON shapes, --params consistently wins over equivalent flags, and pagination aggregation drops nextPageToken under --all as documented. Command registration and flag wiring follow existing Cobra patterns, and the PR adds focused httptest coverage plus command-structure tests for the new paths.

Issues Found:
None. I did not find correctness, security, docs, or pattern-consistency issues in the PR diff.

Verification:
git diff --check passed. I could not run go test ./... because this environment is read-only and cannot create a Go build cache, even under /tmp. From code review, the PR is clean and ready to merge.

@omriariav omriariav merged commit 784bff5 into main May 14, 2026
3 checks passed
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.

Add programmatic API-shape output: --raw flag + --params passthrough

1 participant