mando-cli: v2 State Flow Integration

Path Update

All src/v2/ paths referenced below were flattened to src/ root on 2026-04-09. E.g. src/v2/workspace/state.rs is now src/workspace/state.rs.

Overview

Connected init, pull, and override commands to .bessstate.json persistence layer. Previously these commands existed but weren’t integrated with the v2 state system.

ProjectStateManager Changes

Switched internal HashMap<Project, Arc<ProjectState>> to RwLock<HashMap<...>> for async mutation.

New methods:

  • init_project(project, path) — registers a cloned project
  • set_override(project, entry) — persists an OverrideEntry
  • clear_override(project, branch) — removes an override
  • active_override(project) — reads current active override
  • save() — serializes all state to .bessstate.json

All existing methods (for_project, for_dir, load_via) became async.

Command Integration

InitCommand — writes .bessstate.json after cloning, creating per-project state entries so the workspace is discoverable on subsequent runs.

OverrideCommand — persists OverrideEntry (worktree_path, branch, created_at) to state on create, removes it on --clear.

PullCommand — checks active_override() per project. If overridden, pulls from worktree path using override branch. Shows “(override: branch)” in output.

Bootstrap (main.rs)

Now tries ProjectStateManager::for_root() first (reads .bessstate.json), falls back to init_default_for() if no state file.

Key Design Decision

Commands that only need git operations (pull, override) use ctx.state.path instead of ctx.projects()?.abs_path. This avoids requiring the full MandoWorkspaceProject load (which needs bess.yaml in each project dir) for operations that just need the workspace root path.

Files Changed

FileChange
src/v2/workspace/state.rsRwLock, mutation methods, save()
src/v2/commands/init.rsWrite state after clone
src/v2/commands/override_cmd.rsPersist/clear overrides in state
src/v2/commands/pull.rsOverride-aware pulling
src/v2/commands/status.rsAsync for_project calls
src/main.rsTry for_root before init_default_for

E2E Tests

Shell-based e2e tests in tests/e2e/:

  • test_status.sh — 10 assertions
  • test_pull.sh — 11 assertions
  • test_override.sh — 17 assertions
  • test_init.sh — 2 assertions (glab-gated)
  • run_all.sh — runs all suites

See also: