181 lines
7.6 KiB
Markdown
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`.
|