§7 M3 (part 3) — the ownership track becomes inspectable, completing M1–M3. - server: GET /api/v1/admin/projects (projects_api) lists every project + its owned-group count (projects repo list_with_counts, one GROUP BY); behind the /admin middleware, like the groups list. - CLI: pic projects ls (cmds/projects.rs + client projects_list); the apply_ownership plan-preview journey now also asserts projects ls (plat owns exactly 1 group; teamb listed). - docs: design §7 + CLAUDE.md record M3 shipped and the whole §7 multi-repo ownership track (M1 claim · M2 attach ceiling · M3 preview + projects ls) COMPLETE; deferred = structural-divergence + declarative tree shape + per-env approval gating. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
30 lines
972 B
Rust
30 lines
972 B
Rust
//! `pic projects` — read-only view of §7 multi-repo ownership projects.
|
|
//!
|
|
//! A project is the repo-root that declaratively owns a slice of the group
|
|
//! tree. Ownership is CLAIMED by `pic apply` (first apply with a `[project]`
|
|
//! slug registers it); this command only lists what exists.
|
|
|
|
use anyhow::Result;
|
|
|
|
use crate::client::Client;
|
|
use crate::config;
|
|
use crate::output::{OutputMode, Table};
|
|
|
|
/// `pic projects ls` — every project + how many group nodes it owns.
|
|
pub async fn ls(mode: OutputMode) -> Result<()> {
|
|
let creds = config::resolve()?;
|
|
let client = Client::from_creds(&creds)?;
|
|
let projects = client.projects_list().await?;
|
|
let mut table = Table::new(["slug", "name", "owned_groups", "created_at"]);
|
|
for p in &projects {
|
|
table.row([
|
|
p.slug.clone(),
|
|
p.name.clone(),
|
|
p.owned_groups.to_string(),
|
|
p.created_at.to_rfc3339(),
|
|
]);
|
|
}
|
|
table.print(mode);
|
|
Ok(())
|
|
}
|