Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 37 additions & 0 deletions PROJECTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -227,3 +227,40 @@ See `docs/superpowers/specs/2026-05-29-release-please-commitlint-design.md`.

### Manual Steps (maintainer)
- Add `RELEASE_PLEASE_APP_ID` + `RELEASE_PLEASE_PRIVATE_KEY` (GitHub App) or `RELEASE_PLEASE_APP_TOKEN` (PAT) secrets.

---

## [x] Project P10: CLI ergonomics refactor (v0.5.0)
**Goal**: Make the CLI more ergonomic without breaking the existing flat-flag
interface. Three additive layers, shipped in order:
1. **Declarative clap constraints** — replace hand-rolled flag-combination
checks with clap `group`/`requires`, so impossible combinations fail at parse
time with consistent messages.
2. **Subcommands** — `toggle`/`scan`/`check`/`list`/`insert`/`remove` expose
only the flags that apply to each operation. *Additive*: the legacy flat
flags remain; each subcommand translates to the equivalent legacy argv and is
re-parsed through the same pipeline, so the two forms cannot drift. The legacy
form emits a TTY-only deprecation nudge.
3. **stdin/stdout filter** — accept `-`/stdin and write to stdout so `togl`
composes as a Unix filter.

**Out of Scope**
- Removing the flat-flag interface (deprecate only; removal is a future major).
- A `recover` subcommand (the rare `--recover` path stays flat-flag only).

### Tests & Tasks
- [x] [P10-T01] Option 2: `operation` arg-group + `requires` constraints in `cli.rs`
- [x] [P10-T02] Option 1: `Commands` subcommand enum + `GlobalArgs` flatten struct
- [x] [P10-T03] Option 1: `Commands::to_legacy_argv` translation (clap owns defaults)
- [x] [P10-T04] Option 1: `main()` subcommand bridge + TTY-only deprecation notice
- [x] [P10-TS01] Parity tests: each subcommand ≡ its flat-flag form (incl. a
defaulted `--remove-mode` case to guard default drift); scoping + help/man render
- [x] [P10-T05] Option 3: stdin/stdout filter mode (`-`/`--stdin`/`--stdout`,
writer ops only; rejection set for `--json`/`--atomic`/`--backup`/etc.)
- [x] [P10-TS02] Option 3: stdin≡file parity + no-op byte-identity (trailing
newline both ways) + rejection-set tests

### Automated Verification
- `cargo test` green (all parity + existing suites)
- `cargo clippy --all-targets -- -D warnings` clean
- `togl --help` / `--man` / `--completions` render the subcommands under the aliased bin name
48 changes: 48 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,24 @@ toggle -S debug --force on -R src/
toggle --scan -R src/
```

## Subcommands

Every operation is also available as a subcommand that exposes only the flags
relevant to it. The subcommands are equivalent to the flat flags below (they run
through the same engine), but are easier to discover and harder to misuse:

| Subcommand | Flat-flag equivalent |
|---|---|
| `toggle <paths> -S id` | `toggle <paths> -S id` |
| `toggle scan -R src/` | `toggle --scan -R src/` |
| `toggle check -R src/` | `toggle --scan --check -R src/` |
| `toggle list src/` | `toggle --list-sections src/` |
| `toggle insert main.py -S id -l 10:20` | `toggle --insert -S id -l 10:20 main.py` |
| `toggle remove main.py -S id` | `toggle --remove -S id main.py` |

Run `toggle <subcommand> --help` to see its scoped flags. The flat-flag form
still works and is supported, but is deprecated in favor of the subcommands.
Comment on lines +48 to +49

## Section markers

Wrap any block in a paired marker comment that the tool can find:
Expand Down Expand Up @@ -106,6 +124,36 @@ toggle --scan -R src/ --json
`--check` exits non-zero on any error finding (unclosed markers, duplicate
IDs); warnings (variant gaps, pair-count mismatches) do not fail the run.

## Filter mode (stdin → stdout)

The writer operations (`toggle`, `insert`, `remove`) can read from stdin and
write the transformed result to stdout, leaving any file untouched — so `toggle`
composes in a pipeline. Use a `-` path, or the `--stdin` / `--stdout` aliases:

```bash
# stdin → stdout: read stdin, write the result to stdout
cat main.py | toggle - -S featureX

# Equivalent spellings for stdin → stdout
toggle --stdin -S featureX < main.py
toggle --stdout -S featureX < main.py

# file → stdout: transform a real file, print the result, leave the file on disk
# untouched (the prettier / clang-format model; great for editor integration).
toggle main.py --stdout -S featureX

# Works with the subcommands too
toggle remove --stdin -S featureX < main.py
toggle insert main.py --stdout -S featureX -l 10:20 > wrapped.py
```

With `file --stdout`, the comment style is resolved from the file's real
extension. Piped (stdin) input has no extension, so it defaults to `#` (Python);
pass `--comment-style` for other languages. Filter mode is always a single
stream to stdout and never modifies a file, so it does not accept multiple
files, directories, `--json`, `--atomic`, `--backup`, `--dry-run`,
`--interactive`, or `-R`.

## Atomic multi-file mode

```bash
Expand Down
Loading
Loading