feat(cli): add bm cloud share command group (create/list/update/revoke)#965
Conversation
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 22901c366d
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
|
Live prod QA found that This commit resolves the workspace header client-side in the share commands:
🤖 Generated with Claude Code |
|
This is good to go, but it needs to ship in v0.next and we have a maintenance release ahead of it. |
There was a problem hiding this comment.
Pull request overview
Adds a new bm cloud share Typer subcommand group to manage public share links via the cloud /api/shares endpoints, aligning CLI capabilities with cloud share functionality requested in #880.
Changes:
- Introduces
bm cloud share create/list/update/revokecommands with workspace routing support and rich output formatting. - Registers the new
sharecommand group under existingbm cloudcommands. - Adds a dedicated test suite covering success/error paths, flag validation, workspace resolution behavior, and URL encoding.
Reviewed changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated 1 comment.
| File | Description |
|---|---|
src/basic_memory/cli/commands/cloud/shares.py |
New CLI implementation for share management (create/list/update/revoke) including workspace header routing and output formatting. |
src/basic_memory/cli/commands/cloud/__init__.py |
Registers the new share_app Typer subcommand group under bm cloud share. |
tests/cli/test_share_commands.py |
Adds comprehensive CLI tests for share commands, including workspace resolution and request payload assertions. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
|
@codex review |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 440a2aa923
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
440a2aa to
a29860c
Compare
|
@codex review |
|
recheck |
|
Codex Review: Didn't find any major issues. Breezy! Reviewed commit: ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
If Codex has suggestions, it will comment; otherwise it will react with 👍. Codex can also answer questions or update the PR. Try commenting "@codex address that feedback". |
Surface the cloud /api/shares endpoints from the CLI so users can manage
public share links for notes without leaving the terminal.
New `bm cloud share` subcommand group:
- create <project> <permalink> [--expires-at] -> POST /api/shares
- list [--project] -> GET /api/shares
- update <token> [--enable|--disable|--expires-at] -> PATCH /api/shares/{token}
- revoke <token> [--force] -> DELETE /api/shares/{token}
Reuses the existing make_api_request() helper, ConfigManager cloud_host
lookup, and SubscriptionRequired/CloudAPIError handling that snapshot.py
uses. Rich table output mirrors `bm project list`. Payloads match the
cloud CreateShareRequest/UpdateShareRequest contracts (project_name,
note_permalink, expires_at, enabled).
Adds PublicShareResponse/PublicShareListResponse schemas and unit tests
with mocked HTTP following the snapshot CLI test patterns.
Co-Authored-By: Claude <noreply@anthropic.com>
Signed-off-by: Drew Cain <groksrc@gmail.com>
…emas Address review findings on `bm cloud share`: - `create` re-wrapped the `typer.Exit(1)` from `_parse_expires_at()` as a spurious "Unexpected error: 1" trailing line because the broad `except Exception` caught it (typer.Exit subclasses Exception). Parse and validate --expires-at before entering the try block so the error surfaces as a single clean message, and add the `except typer.Exit: raise` guard for parity with `update`/`revoke`. - Strengthen test_create_share_invalid_expires_at to assert "Unexpected error" is absent, which was masking the bug. - Drop unused PublicShareResponse/PublicShareListResponse schemas; responses are parsed as raw dicts, so the schemas were dead code. Co-Authored-By: Claude <noreply@anthropic.com> Signed-off-by: Drew Cain <groksrc@gmail.com>
… project filter The `bm cloud share` commands authenticated but never sent the X-Workspace-ID header that sibling cloud calls (cloud_utils._workspace_headers) use for workspace scoping. The cloud /api/shares endpoints resolve the target tenant from that header (resolve_workspace in basic-memory-cloud deps.py), so share create/list/update/revoke for a team-workspace project were evaluated against the caller's default tenant. Resolve the workspace via resolve_configured_workspace (explicit --workspace > project's configured workspace_id > global default) and pass X-Workspace-ID on all four commands, mirroring the established cloud command pattern. Adds a --workspace option to each, matching `bm cloud pull/push`. Also URL-encode the list `--project` filter with urllib.parse.urlencode so project names containing query-reserved characters (&, +, #, spaces) reach the server as a single faithful value instead of splitting into stray query params. Extends the mocked tests to assert the header is built/routed and that a project name with special characters is percent-encoded. Co-Authored-By: Claude <noreply@anthropic.com> Signed-off-by: Drew Cain <groksrc@gmail.com>
…space Live prod QA found `bm cloud share ... --workspace <slug>` failed with an opaque 400: resolve_configured_workspace returns the explicit --workspace value verbatim, but the cloud's X-Workspace-ID resolver only accepts a workspace/tenant UUID. Users see slugs and display names (list-workspaces output, memory:// URLs), so the natural input never routed. The share commands now resolve the workspace header client-side: a UUID is forwarded verbatim (covers per-project config workspace_id and the default chain, zero extra API calls), while any other value is treated as a human identifier and mapped to the tenant UUID via a single get_available_workspaces lookup, matching with slug > tenant_id > name precedence (mirroring #979). Ambiguous and unknown identifiers fail fast with errors that name the candidate / available workspace slugs, and the list command now re-raises typer.Exit ahead of its broad handler so the resolution errors aren't re-wrapped as "Unexpected error". Co-Authored-By: Claude <noreply@anthropic.com> Signed-off-by: Drew Cain <groksrc@gmail.com>
Signed-off-by: phernandez <paul@basicmachines.co>
|
@codex review recheck |
a29860c to
9b7df0d
Compare
|
Codex Review: Didn't find any major issues. What shall we delve into next? Reviewed commit: ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
If Codex has suggestions, it will comment; otherwise it will react with 👍. Codex can also answer questions or update the PR. Try commenting "@codex address that feedback". |
Closes #880
Summary
Adds a
bm cloud sharecommand group for the cloud/api/sharesendpoints:create <project> <permalink> [--expires-at/-e]creates a public share link.list [--project/-p]lists links in a Rich table and safely encodes project filters.update <token> [--enable|--disable|--expires-at]updates link state or expiry;--expires-at noneclears it.revoke <token> [--force/-f]revokes a link, with confirmation unless--forceis passed.All four commands support explicit workspace routing by slug, display name, or tenant ID and preserve the existing configured-workspace fallback.
Design
Maintainer follow-through
main.Zsupport.2099-12-31and added a help-output regression test.Testing
uv run pytest -q tests/cli/test_share_commands.py— 31 passed.uv run ruff check src/basic_memory/cli/commands/cloud/shares.py tests/cli/test_share_commands.py— passed.uv run ty check src/basic_memory/cli/commands/cloud/shares.py tests/cli/test_share_commands.py— passed.just fast-check— passed (with the repository's existing Python 3.14 asyncio deprecation diagnostics).Files changed
src/basic_memory/cli/commands/cloud/shares.pysrc/basic_memory/cli/commands/cloud/__init__.pyshare_apptests/cli/test_share_commands.pyGenerated with Claude Code; maintainer follow-through by Basic Machines.