pm project: `wt` first-class, CLI cleanup, per-project multi-worktree
- Schema: `repos(name, slot_uuid, branch)` → `worktrees(name, repo, slot_uuid, branch)`.
A worktree has its own name (the symlink under projects/<p>/) and a `repo` column
that's the pool key, so a project can hold multiple worktrees of the same repo.
Legacy dbs migrate in place on first open (copies name into both columns).
- CLI reshape under `pm project`:
create <project> [--wt <spec>] — create-only; `--wt` optional
delete <project> [--dry-run] — whole-project only
wt create [-p P] <spec> — add worktrees to an existing project
wt attach [-p P] (--wt <names>|--all) [--no-branch]
wt detach [-p P] (--wt <names>|--all) [--dry-run]
wt delete [-p P] (--wt <names>|--all) [--dry-run]
`-p/--project` defaults to the current project (via cwd detection).
- Spec syntax: `foo,bar:baz,qux` → wt `foo`/repo `foo`, wt `bar`/repo `baz`,
wt `qux`/repo `qux`. Rejects duplicates, empty sides of colon, extra colons.
- Impl: `project/new.py` → `create.py`; attach/detach/delete/discovery/ls/status
thread (wt, repo) pairs; forward symlinks keyed on wt, pool claims keyed on
repo. check.Finding gains `wt`; ORPHAN_OWNER/OPS_OWNED now populate `repo`
from the pool key.
- Tests: full rewrite of test_project/test_check/test_current/test_status/test_pool
for the new signatures, plus new coverage for two wts of the same repo, spec
parsing, and legacy schema migration.
stacker: full Emacs UI + --json on every stacker command
Build out interactive stacker support in the pm Emacs integration,
backed by structured CLI output.
Python:
- pm project status --json now carries the structured stacker tree per
repo (StackerRow.branches / current_branch / operation), reusing the
same branch selection the text arm renders (ls.ls_structure +
arm_branch_set). Text mode is unchanged; --json skips the text render
to stay at one prefetch per repo.
- Every `pm stacker` subcommand gains --json via a uniform envelope
(_common.emit_result): {ok, command, repo, branch, message, operation}.
message is the raw markup result; operation surfaces a paused/
conflicted op so a client can offer continue/abort. ls/config keep
their existing richer JSON.
Emacs (new pm-stacker.el + integration):
- *pm-stacker: <project>* — a foldable, multi-repo branch tree with
CLI-matching status icons, commit-group markers (count/needs-sync/
ahead), current-branch + merged styling, and a paused-op banner.
- Branch-scoped action transient (RET) covering the full verb set with
infix flags; direct keys for the common verbs. Every action runs
`pm stacker <verb> --json` and refreshes; destructive verbs confirm.
- The status buffer's Stacker section reuses the same renderer, so it's
now the same interactive tree (closes the old plain-face gap).
- Branch rows use a dedicated section class (pm-stacker-branch-section)
whose highlight covers only the heading line — so a repo heading
highlights its whole block (table-style) while a branch row (even a
parent) highlights as a single line, with folding intact.
- Faces: pm-faces-stacker-status (icon+face per status mirroring
graph.py), pm-stacker-current, pm-stacker-merged, strike markup token.
Tests: status structured-tree + --json envelope (Python); stacker tree
render, faces, RET scope, wrapper argv (Emacs). README documents the
buffer, transient, and the --json envelope.