Adds `bm cloud push` and `bm cloud pull` as git-style, fail-safe transfer
primitives that are usable on Team workspaces (issue #858), and restricts the
destructive `bm cloud sync` mirror to Personal workspaces.
Why
- `bm cloud sync` is a destructive local->cloud mirror; on a shared Team bucket
it can delete a teammate's files. The only pull path was two-way `bisync`,
which is already Personal-only (#849).
- Teams need a safe way to fetch teammates' notes and add their own without one
stale local tree becoming authoritative for shared cloud state.
What
- push = `rclone copy` local->cloud, pull = `rclone copy` cloud->local. Both are
additive (never delete on the destination), so neither can damage shared state.
- Conflicts (a file that differs on both sides) abort by default and list the
paths, like git refusing to clobber local changes / rejecting a stale push.
`--on-conflict {fail|keep-local|keep-cloud|keep-both}` lets the user decide;
no vague --force, no silent winner.
- `sync` now requires a Personal workspace; its guard and the bisync guard point
Team users at push/pull.
Limitations (surfaced in --help and command output, tracked by #862):
- No sync baseline yet, so deletions are not propagated and every divergence is
treated as a conflict rather than auto-resolved. Real three-way merge needs
the per-client manifest + Tigris snapshot baseline designed in #862.
Implementation
- rclone_commands.py: shared `_build_transfer_cmd`/`_transfer_endpoints`;
refactor `project_sync` onto them (no behavior change); add `project_diff`
(conflict detection via `rclone check --combined`), `project_copy`,
`project_copy_file`, and `project_transfer` (strategy dispatch).
- project_sync.py: new `push`/`pull` commands (ungated, Team-safe) with
`--on-conflict`/`--dry-run`; gate `sync` to Personal via a per-command guard
message.
- Tests at the rclone-argv and CLI-command levels; existing sync/bisync tests
updated for the new gating and messages.
Signed-off-by: phernandez <paul@basicmachines.co>
`bm cloud login` only caught SubscriptionRequiredError after the
post-login `/proxy/health` subscription check. OAuth succeeds and tokens
are saved, but if that check returns anything else — a 5xx while the
tenant instance is still provisioning, a 403/401 whose body doesn't match
the subscription_required shape, or a transport error — make_api_request
raises a generic CloudAPIError that escaped uncaught, dumping a raw
httpx.raise_for_status traceback. Users read this as "login failed" even
though authentication actually worked.
Add a CloudAPIError handler that prints a clean, actionable message and
exits non-zero. make_api_request wraps every httpx error (status and
transport) in CloudAPIError, so the single handler covers them all.
Fixes#863.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Signed-off-by: phernandez <paul@basicmachines.co>
Add configurable cache_dir, threads, and parallel settings for FastEmbed
to support cloud deployments where defaults fail. Cache embedding providers
at the process level to avoid re-creating heavy ONNX model instances.
- Add semantic_embedding_cache_dir, semantic_embedding_threads, and
semantic_embedding_parallel config fields
- Thread-safe provider cache with double-checked locking in factory
- Forward runtime knobs through to TextEmbedding and embed() calls
- Fix if/elif chain in factory for correct error handling
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Signed-off-by: phernandez <paul@basicmachines.co>
Thread constructor no longer receives daemon=True, update mock
signatures to match. Also assert on the new "type": "event" field.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Signed-off-by: phernandez <paul@basicmachines.co>
- Simplify `bm cloud status` output: remove verbose health check details
(status/version/timestamp), show simple "Cloud connected" / "Cloud not
connected" message instead
- Improve `bm reindex --project` error for cloud projects: distinguish
between "project not found" and "project is cloud-only" with a helpful
message explaining reindexing is a local operation
- Improve `bm project list` cloud error message: show the actual error
and soften the credentials suggestion
- Add tests for cloud status command (5 tests)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Signed-off-by: phernandez <paul@basicmachines.co>
- Wrap isatty() in _is_interactive_session() with try/except ValueError
so MCP stdio transport shutdown no longer produces noisy tracebacks
- Check both search_vector_chunks AND search_vector_embeddings exist
before running JOIN queries in get_embedding_status(), fixing
OperationalError when only the chunks table is present
- Add test for closed-stream scenario
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Signed-off-by: phernandez <paul@basicmachines.co>