feat(cli): [project] manifest block, --takeover, groups ls owner column

Makes §7 ownership usable end to end from the CLI.

- manifest: a `[project]` block (slug + optional name), independent of the
  [app]/[group] XOR; threaded onto every apply from the repo. --dir reads it
  from the tree ROOT's picloud.toml (a [project] elsewhere is ignored with a
  note).
- client: apply_node/apply_tree carry project + takeover; the 409 branch now
  surfaces the server message verbatim (covers StateMoved AND OwnershipConflict,
  both self-contained). New groups_list_with_owner captures the owner slug.
- pic apply --takeover flag; pic groups ls gains an `owner` column (the owning
  project's slug, or — when unclaimed).
- server: /api/v1/admin/groups now returns each group flattened with its owner
  slug (via list_with_owner) — the shared Group deserialize ignores the extra
  field, so pic groups tree / the dashboard are unaffected.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
MechaCat02
2026-07-06 20:46:09 +02:00
parent 47072c481d
commit b33c87e5c4
10 changed files with 175 additions and 31 deletions

View File

@@ -246,6 +246,11 @@ struct ApplyArgs {
/// since the last `pic plan`).
#[arg(long)]
force: bool,
/// §7 multi-repo ownership: reassign a group node owned by another
/// `[project]` to this manifest's project. Requires group-admin on the
/// node; without it an apply to an owned node is refused (409).
#[arg(long)]
takeover: bool,
/// Merge the `picloud.<env>.toml` overlay (per-env slug + secrets) on
/// top of the base manifest before applying.
#[arg(long)]
@@ -1421,6 +1426,7 @@ async fn main() -> ExitCode {
args.prune,
args.yes,
args.force,
args.takeover,
args.env.as_deref(),
mode,
)
@@ -1433,6 +1439,7 @@ async fn main() -> ExitCode {
args.prune,
args.yes,
args.force,
args.takeover,
mode,
)
.await