Files
flow/docs/refactor-plan.md

181 lines
7.6 KiB
Markdown

# Flow CLI Refactor Status
> Based on code review (2026-03-22), architecture discussion, and the current implementation.
> Spec: `docs/superpowers/specs/2026-03-16-flow-architecture-redesign.md`
## Current State
The action-runtime rewrite is implemented. `cli.py` is a thin Typer adapter, `flow.app` owns
application orchestration, domain modules keep pure planning and resolution logic, and
executor-managed mutations are represented as action plans before they reach runtime adapters.
The old structural problems from the original codebase (duplicated flows, monkeypatching, dead
modules, singleton-style runtime access) have been removed from the active command paths. The
remaining refactor work is deferred cleanup, not a blocker for the action-centered architecture.
---
## Command Surface
This is the implemented command surface.
```
flow remote enter <target> # Host only. SSH+tmux into VM.
flow remote list # List configured targets.
flow dev create <name> -i <image> # VM only. Create+start container.
flow dev attach <name> # Attach to container tmux session.
flow dev exec <name> [cmd...] # Run command in container.
flow dev enter <name> # Interactive shell in container.
flow dev list # List dev containers.
flow dev stop <name> # Stop container.
flow dev rm <name> # Remove container.
flow dev respawn <name> # Respawn tmux panes.
flow dotfiles init --repo <url> # Clone dotfiles repo + all module repos.
flow dotfiles link [--profile p] # Reconcile symlinks (creates, fixes broken, removes stale).
flow dotfiles unlink [packages...] # Remove managed symlinks.
flow dotfiles status [packages...] # Show packages, link health, module info.
flow dotfiles edit <package> # Pull -> $EDITOR -> commit+push.
flow dotfiles repos list # List ALL managed repos (dotfiles + modules).
flow dotfiles repos status [--repo=x] # Git status for one or all repos.
flow dotfiles repos pull [--repo=x] [--dry-run]
flow dotfiles repos push [--repo=x] [--dry-run]
flow setup run [profile|--profile p] [--dry-run] [--var KEY=VALUE]
flow setup list # List profiles.
flow setup show <profile> # Show profile plan.
flow packages install [name...] [--profile p] [--dry-run]
flow packages list [--all] # List packages.
flow packages remove <name...> [--dry-run]
flow projects check [--fetch] # VM only. Git health across ~/projects.
flow projects fetch # Fetch all project remotes.
flow projects summary # Quick status overview.
```
### Aliases
- `dotfiles` -> `dot`
- `packages` -> `package`, `pkg`
- `projects` -> `project`; `flow sync` -> `flow projects check --fetch`
- `setup` -> `bootstrap`, `provision`
- `remote enter` -> `enter`
- `dev attach` -> `dev connect`
- `dev rm` -> `dev remove`
- `dotfiles repos` -> `dotfiles repo`
### Global flags
- `--version`
- `--quiet` / `-q`
- `--no-color`
### Commands Removed During Refactor
| Removed | Reason |
|---------|--------|
| `dotfiles sync` | Redundant: `repos pull` + `link` |
| `dotfiles relink` | Redundant: `link` is idempotent |
| `dotfiles undo` | Redundant: `unlink` is the inverse of `link` |
| `dotfiles clean` | Folded into `link` (reconciliation handles broken symlinks) |
| `dotfiles modules list` | Replaced by `dotfiles repos list` |
| `dotfiles modules sync` | Replaced by `dotfiles repos pull` |
## Action-Centered Architecture
The runtime boundary is `flow.actions`.
- `ActionPlan` is the unit of execution. It can contain high-level `DomainAction` entries and direct
`PrimitiveAction` entries.
- `DomainAction` records intent from a domain such as dotfiles, packages, repos, remote targets,
containers, completion, or setup.
- `expand_actions()` converts domain actions into primitive actions. Some domains supply already
expanded primitive plans when the service has concrete runtime arguments.
- `PrimitiveAction` is the canonical executor input for filesystem, process, git, download,
archive, container, and tmux operations.
- `ActionExecutor` owns dry-run output, append-only JSONL audit logging, rollback stack management,
rollback barriers, and dispatch into `SystemRuntime`.
App use-cases construct plans and pass them to the executor for action-backed commands. Direct
runtime calls are limited to explicit interactive boundaries such as attaching to tmux or entering a
container shell. Domain modules stay free of I/O where the current implementation has pure
resolution/planning functions.
Rollback is best-effort and explicit. Actions default to `rollbackable`; external boundaries such
as shell commands, remote sessions, and non-reversible git/container operations use `barrier` or
`none` policies.
## Key Design Decision: Modules Are Repos
The `_module.yaml` files define external git repos that provide content for dotfiles packages.
These module repos are **not** git submodules -- they are regular git clones managed by flow.
The dotfiles repo itself is also a git clone managed by flow. So **all managed git repos** (the
dotfiles repo + every module repo) share the same abstraction and the same commands.
`dotfiles repos` is the single entry point for all repo operations. There is no separate
`dotfiles modules` subcommand group. The `--repo=<name>` flag filters to a specific repo when
needed (dotfiles repo is named `dotfiles`, module repos are named by their package, e.g. `nvim`).
---
## Completed Work
### Unified Repos Abstraction
`RepoInfo` with `module_ref` is the canonical repo model. `_discover_repos()` finds the dotfiles
repo and module repos, and `repos list/status/pull/push` iterate that single collection with an
optional `--repo` filter. `dotfiles init` uses the same pull-or-clone flow.
### Command Trimming
Removed redundant dotfiles commands:
- `dotfiles sync`: use `dotfiles repos pull` plus `dotfiles link`
- `dotfiles relink`: `dotfiles link` is idempotent
- `dotfiles undo`: use `dotfiles unlink`
- `dotfiles clean`: broken symlink repair is part of link planning
- `dotfiles modules list/sync`: use `dotfiles repos list/pull`
### Feature Completion
- `dotfiles edit`: pull -> `$EDITOR`/`$VISUAL` -> scoped `git add` -> commit+push, with
`--no-commit` to skip auto-commit/push.
- `dotfiles status`: module info, link health, and package filtering.
- `dotfiles repos list`: all managed repos with name, type, local path, and clone status.
- `--no-color`: global flag added to `cli.py`.
- `--dry-run`: supported by dotfiles link/unlink, repos pull/push, packages install, setup run,
remote enter, and dev create.
### Improvements Over Spec
These are correct deviations -- the implementation improved on the spec:
- `adapters/containers.py` + `adapters/tmux.py` extracted as adapters (spec had them inline)
- `core/config_parse.py` + `core/yaml.py` extracted for config parsing
- `SystemRuntime` extended with containers, tmux, download, and archive runtime fields
- `flow.actions` extracted as the canonical execution layer instead of leaving mutation dispatch in
individual app use-cases
---
## CI
The GitHub Actions workflow is split into two jobs:
- `unit`: installs dependencies and runs `pytest tests/ -v --ignore=tests/e2e`
- `e2e`: verifies Docker is available, sets `FLOW_RUN_E2E=1`, and runs `pytest tests/e2e/ -v`
---
## Optional Future Work
These are optional refinements, not blockers for the action-centered rewrite.
### Global `--dry-run`
If per-command `--dry-run` becomes a maintenance burden, promote to a global flag in `cli.py`.