Repository navigation
Conversation
Adds `source-coop product`, the first gh-style command group from #21, over the `/api/v1/products` endpoints from source-cooperative/source.coop#651. A small API client sends the request and turns the API's `{"error": {code, message, field_errors}}` body into a message; the CLI does no validation of its own. Requests carry the login session's access token (or `SOURCE_TOKEN`, if set), and run signed out without one, which is enough to read public products. `create` and `edit` take fields from flags, from a JSON file (`--from-file`), or both. When stdin and stderr are terminals, whatever is still missing is prompted for with defaults: a title from the product ID, the data connections the account can use, and the visibilities the chosen one allows. `edit` with no flags prompts from the product's current values and sends only what changed. `delete` asks whether to keep the data and for the name to be typed back; without a terminal it needs `--yes`. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017poyHYEyxWEJct9X8Q71qF
When the API rejects a field and someone is at the terminal, the CLI shows why and asks for just that field again, keeping every other answer, then resends; the API stays the only judge. A rejection naming a field nobody can be asked for is an error, as before. Descriptions can be written in `$VISUAL`/`$EDITOR`, gh's way: Enter keeps, `e` opens the editor, anything else is the text. `edit` with no flags first asks which fields to change. `list` prints a header and aligned columns on a terminal, and tab-separated rows when piped. `create` and `edit` print the product URL on stdout and their message on stderr. A request that gets no response now says why (DNS, TLS, refused connection), not just which URL. `source-coop api PATH` sends any `/api/v1` request as the signed-in user, with gh-style `-X`, `-f`, `-F` and `--input`, prints the response, and exits non-zero on an error status. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017poyHYEyxWEJct9X8Q71qF
alukach
force-pushed
the
feat/product-commands
branch
from
October 9, 2026 19:38
0102eef to
bbe48fe
Compare
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.
Part of #21, stacked on the login-session PR. Builds on the product endpoints in source-cooperative/source.coop#651.
source-coop product list | view | create | edit | deleteover/api/v1/products. As #21 asks, the CLI checks nothing itself and shows the API's errors field by field.SOURCE_TOKENif set. Without either they run signed out, which is enough to read public products, and a 401 says to runsource-coop login.listfollows paging up to-L(default 30). Reads take--json, andview --webopens the product page.createandedittake fields as flags, from a JSON object with-F/--from-file(-for stdin), or both, with flags winning.SOURCE_PROMPT_DISABLEDis unset), the CLI asks for whatever is still missing:create: a title defaulting to one made from the ID, a data connection from those the account can use, and only the visibilities that connection allows.$VISUAL/$EDITORby answeringe, as in gh.editwith no flags: asks which fields to change, and starts each from its current value.delete: asks whether to keep the data, then for the product name typed back. Without a terminal it needs--yes.listprints a header and aligned columns on a terminal, and tab-separated rows without a header when piped.createandeditprint the product URL on stdout and their message on stderr.source-coop api PATHsends any/api/v1request as the signed-in user, for whatever the other commands don't cover yet:-Xfor the method,-f key=valuefor a string,-F key=valuefor a JSON boolean, null or number, and--input FILE.Follow-ups, not in this PR:
--jq./data-connectionsroute itself, and doesn't know about connections that require an account flag.Deploying: needs the login-session PR, and source.coop#651 deployed. See the runbook in {{CLI_LOGIN_PR}}, steps 4 and 6.
Testing
cargo fmt --check,cargo clippy --all-targets -- -D warningsandcargo test(58 passed) all pass.apitests run against wiremock, using the request shapes from #651's routes. They include asking again for just the rejected field, a rejection of another field staying an error, the field picker, the piped table format, andapi's query and body handling.product listandapisent the session's refreshed access token.apiexited 1 on a 404.Related
🤖 Generated with Claude Code
https://claude.ai/code/session_017poyHYEyxWEJct9X8Q71qF