docs: switch demo recording to vhs (declarative + reproducible)
Some checks are pending
ci / check (push) Waiting to run

* scripts/demo.tape: vhs tape file driving a ~30s session: --version,
  repo view (auto-detect), issue list, pr list, api + jq, selective
  JSON, help. Catppuccin Mocha, 1100x720.
* scripts/record-demo.sh: thin wrapper with preflight checks (vhs +
  fj installed and authenticated, run from a clone). Outputs
  assets/demo.gif and assets/demo.mp4.
* Removed scripts/_demo-session.sh (the asciinema sketch). vhs is
  strictly better for scripted demos: deterministic timing, direct
  GIF/MP4 output, no upload step.
* README: replaced the asciinema TODO with the GIF embed (will resolve
  once assets/demo.gif is recorded and committed).

To record:
  brew install vhs
  cargo build --release && ln -sf \$PWD/target/release/fj ~/.local/bin/fj
  fj auth login --host rasterhub.com
  ./scripts/record-demo.sh

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Stephen Way 2026-05-13 15:47:21 -07:00
parent d58bd312f9
commit 65420678d9
No known key found for this signature in database
14 changed files with 687 additions and 42 deletions

View file

@ -9,12 +9,18 @@
Multi-host from day one. Tokens are stored in your OS keychain.
</p>
<p align="center">
<img src="assets/demo.gif" alt="fj demo" width="800">
</p>
<!--
TODO: replace the line below with an asciinema embed once the v0.1.0
release is tagged. Run `./scripts/record-demo.sh` then
`asciinema upload dist/demo.cast` and paste the returned URL.
The GIF above is generated from scripts/demo.tape via charmbracelet/vhs.
To refresh it after a feature change:
brew install vhs
./scripts/record-demo.sh
git commit -am 'docs: refresh demo recording'
-->
<!-- [![asciicast](https://asciinema.org/a/REPLACE.svg)](https://asciinema.org/a/REPLACE) -->
## Install

2
dist/v0.1.0/SHA256SUMS vendored Normal file
View file

@ -0,0 +1,2 @@
eb5fd0206a5194179f6d1aecee7fe4a4a5434e1f44ed75a525f7f41d18670061 fj-v0.1.0-darwin-aarch64.tar.gz
d7102095f051f4af7af1d9dbf34678df85142fdfece71dcab0cc111aeb942c2c fj-v0.1.0-darwin-x86_64.tar.gz

Binary file not shown.

View file

@ -0,0 +1,121 @@
# Changelog
All notable changes will be recorded here. The format follows
[Keep a Changelog](https://keepachangelog.com/en/1.1.0/). Versions follow
[Semantic Versioning](https://semver.org/spec/v2.0.0.html).
## [Unreleased]
### Added (distribution + open-source ready)
- `LICENSE` (MIT) at the repo root. Cargo.toml had always declared MIT;
the file was just missing.
- `.forgejo/workflows/release.yml`: on `v*` tags, builds for
`darwin-aarch64`, `darwin-x86_64`, `linux-x86_64`; uploads tarballs,
`SHA256SUMS`, and a pre-rendered `fj.rb` to the Forgejo release.
- Homebrew formula template at `dist/homebrew/fj.rb.tmpl` and
`scripts/render-homebrew-formula.sh` to fill SHA256s post-release.
Publishes into the existing `rasterandstate/homebrew-tap`.
- `.forgejo/issue_template/{bug,feature,api-gap}.md` and
`.forgejo/pull_request_template.md` to keep triage cheap.
- `scripts/record-demo.sh` + `scripts/_demo-session.sh` to record an
asciinema demo; README has a placeholder embed for the v0.1.0 cast.
- `docs/compatibility.md`: tested Forgejo versions, caveats for older
Gitea, and Forgejo-only endpoints.
- One-shot version probe during `fj auth login` that warns when the
server reports a pre-7.x version (with tests for the parser).
### Added (agent-focused Forgejo gaps)
- `fj issue edit-comment` / `delete-comment`. Lets an agent (or you)
fix or remove a wrong comment after the fact.
- `fj search code "..."` (and `-R owner/name` to scope to one repo).
Powered by Forgejo's `/repos/search/code` endpoint.
- `fj pr request-review N user1 user2,user3` and
`fj pr unrequest-review N user1`. Distinct from `pr review`, which
submits your own review.
- `fj repo watch` / `unwatch` / `star` / `unstar` / `starred`.
- `fj milestone {list,view,create,edit,close,reopen,delete,assign}`.
Includes `fj milestone assign N --milestone ID|none` to attach an
issue or PR to a milestone.
### Added (UX + stability)
- `--json-fields field1,field2` global flag. gh-style projection on top
of any `--json` output, with dotted-path support
(`--json-fields owner.login,id`).
- 429 / Retry-After honored in the retry loop with a 30 s cap. Wiremock
test added.
- `did you mean` suggestions on typo'd subcommands via clap's
`suggestions` feature.
- `fj auth token` and `fj auth status --show-token` now refuse to write
to a TTY (use `--force` to override). Avoids accidental shoulder-
surfing or capture in shell history.
- `tokio::signal::ctrl_c()` race in `cli::run` so the pager guard drops
cleanly on SIGINT.
- 10 wiremock-backed HTTP client integration tests covering retry
behavior (5xx, 429), header forwarding, pagination, and panic-free
error paths.
- `Client::for_base_url` test constructor pointing at an arbitrary URL.
- `.forgejo/workflows/ci.yml` runs the same gate as the pre-push hook
on every push and PR.
### Added (docs)
- `SECURITY.md` covering threat model, known sharp edges, and reporting.
- `docs/gh-to-fj.md` — complete command-by-command mapping.
- `docs/faq.md` — common questions about tokens, hosts, debug,
scripting, plugins.
### Changed
- Trimmed dependencies (no more `indicatif`, `futures-util`,
`is-terminal`, `textwrap`, `tempfile` in prod). Dropped reqwest
features we don't use (`stream`, `brotli`). Release profile uses
`lto = "fat"` and `panic = "abort"`.
- HTTP retry loop builds the request once and clones via
`reqwest::Request::try_clone` per attempt.
- Binary size: 5.94 MB → 4.15 MB stripped (-30%).
### Fixed
- **Shell injection** in `fj auth setup-git`. The hostname now must
match a strict DNS pattern before being interpolated into the
credential-helper string, and we call `git config` directly with
separate args instead of going through `sh -c`.
- **Pager won't compile on Windows**. The libc-based `dup2` redirect
now lives behind `#[cfg(unix)]`; non-Unix gets a no-op stub that
returns `None` from `maybe_start`.
- Removed the unsafe `std::env::set_var("FJ_NO_PAGER")` from dispatch.
`--no-pager` is now threaded into `pager::maybe_start(force_disabled)`.
- Replaced the panicking `.expect("token contains invalid header chars")`
in `auth_headers` with a typed error.
## 0.1.0 — 2026-05-13
Initial release. Multi-host Forgejo CLI with feature parity to `gh`
across the surface Forgejo exposes. Commands:
- `auth`: login, status, logout, list, switch, token, refresh, setup-git
- `repo`: list, view, clone, create, fork, sync, edit, rename, archive,
unarchive, delete, branches, topics, mirror, mirror-sync
- `issue`: list, view, create, edit, close, reopen, comment, develop
- `pr`: list, view, create, edit, diff, commits, files, checks, ready,
review, status, checkout, merge, close, reopen
- `release`: list, view, create, edit, delete, upload, download
- `label`, `run`, `secret`, `variable`, `search`, `browse`, `status`,
`org`, `ssh-key`, `gpg-key`, `alias`, `config`, `protect`, `hook`,
`extension`, `gist`, `api`, `completion`, `man`
Other highlights:
- Repo auto-detection from `upstream` / `origin` git remote.
- `--web` flag on all list/view subcommands.
- `$EDITOR` integration for body inputs.
- `fj api` with `-H`, `-X`, `-f`, `-F`, `--paginate`, `--include`,
`--silent`, `--jq` (dot-paths, `[N]`/`[-N]`, pipes).
- `--debug` / `FJ_DEBUG` request logging.
- Tokens in the OS keychain.
- Pager via `dup2` redirect to `$FJ_PAGER` / `$PAGER` / `less -FRX`.
- Pre-push hook running fmt, clippy `-D warnings`, tests, and release
build before any push. Live API smoke gated on `FJ_E2E=1`.

View file

@ -0,0 +1,21 @@
MIT License
Copyright (c) 2026 Stephen Way
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View file

@ -0,0 +1,149 @@
# fj
A command-line tool for [Forgejo](https://forgejo.org) instances, in the spirit of GitHub's `gh`.
Multi-host from day one. Tokens are stored in your OS keychain.
<!--
TODO: replace the line below with an asciinema embed once the v0.1.0
release is tagged. Run `./scripts/record-demo.sh` then
`asciinema upload dist/demo.cast` and paste the returned URL.
-->
<!-- [![asciicast](https://asciinema.org/a/REPLACE.svg)](https://asciinema.org/a/REPLACE) -->
## Install
```sh
# Homebrew (macOS + Linux):
brew tap rasterandstate/tap
brew install fj
# From source:
cargo install --path .
# or
cargo build --release && cp target/release/fj ~/.local/bin/fj
```
## Quick start
```sh
fj auth login # add a host and token
fj auth status # show signed-in hosts
fj repo list # repos you own
fj repo view owner/name # repo overview
fj issue list -R owner/name # issues
fj pr list -R owner/name --state open # pull requests
fj api /repos/search -X GET -f q=foo # raw API escape hatch
```
`-R/--repo` is optional inside a git clone. fj detects the upstream from
`upstream`, then `origin`, then any other remote.
## Commands
| Group | Common operations |
| ---------- | --------------------------------------------------------------------------------- |
| `auth` | login, status, logout, list, switch, token, refresh, setup-git |
| `repo` | list, view, clone, create, fork, sync, edit, rename, archive, unarchive, delete, branches, topics, mirror, mirror-sync, watch, unwatch, star, unstar, starred |
| `issue` | list, view, create, edit, close, reopen, comment, edit-comment, delete-comment, develop |
| `pr` | list, view, create, edit, diff, commits, files, checks, ready, review, request-review, unrequest-review, status, checkout, merge, close, reopen |
| `release` | list, view, create, edit, delete, upload, download |
| `label` | list, create, edit, delete |
| `milestone`| list, view, create, edit, close, reopen, delete, assign |
| `run` | list, view, rerun, cancel (Forgejo Actions workflow runs) |
| `secret` | list, set, delete (Actions secrets) |
| `variable` | list, set, delete (Actions variables) |
| `search` | repos, issues, prs, users, code |
| `browse` | open the current repo (or a path within it) in your browser |
| `status` | notifications inbox + `--mark-read` |
| `org` | list, view, teams |
| `ssh-key` | list, add, delete |
| `gpg-key` | list, add, delete |
| `alias` | list, set, delete |
| `config` | get, set, list, path |
| `protect` | list, view, set, delete branch protection rules |
| `hook` | list, create, delete, test webhooks |
| `gist` | list, create (thin wrapper over `gist-*` repos) |
| `extension`| list, run discovered `fj-<name>` plugins on PATH |
| `api` | raw HTTP with `-X`, `-f`, `-F`, `-H`, `-q` (jq-ish), `--paginate`, `--include` |
| `completion`| Print shell completions (bash, zsh, fish, powershell, elvish) |
| `man` | Generate man pages into a directory |
## Global flags
- `--host <hostname>` (or `FJ_HOST`): pick the host explicitly.
- `--debug` (or `FJ_DEBUG=1`): log every HTTP request to stderr.
- `--no-pager` (or `FJ_NO_PAGER=1`): skip the pager.
- `--json-fields foo,bar`: gh-style projection on top of any `--json`
output. Dotted paths supported (`--json-fields owner.login,id`).
- `--web` on most list/view subcommands: open the relevant page in
your default browser.
## Config
- Hosts and the current host live in `$XDG_CONFIG_HOME/fj/hosts.toml`
(`~/Library/Application Support/fj/hosts.toml` on macOS).
- Aliases in `aliases.toml`. Preferences in `config.toml`.
- Tokens live in the OS keychain under service `fj`, keyed by hostname.
## Aliases
```sh
fj alias set co "pr checkout"
fj co 42 # equivalent to: fj pr checkout 42
```
## Extensions
Any executable on `$PATH` named `fj-<name>` is invokable as `fj <name> [args]`.
```sh
fj extension list # show discovered plugins
fj my-plugin some-arg # invokes `fj-my-plugin some-arg`
```
## Plugin-style usage of `fj api`
```sh
# Auto-paginate a list endpoint into a single JSON array:
fj api /repos/search -f q=fj --paginate -q .
# Pass a custom request header:
fj api /user -H "X-Trace-Id: foo"
# Show response headers along with the body:
fj api /version --include
# Send a literal JSON body:
fj api /repos/migrate --input '{"clone_addr":"...","repo_name":"x","repo_owner":"y"}'
```
## Hooks
- `hooks/pre-push` runs `cargo fmt --check`, `cargo clippy -D warnings`,
`cargo test`, and a release build before any push.
- With `FJ_E2E=1`, the hook also runs `scripts/e2e-smoke.sh` against the
configured host.
- Install via `./scripts/install-hooks.sh`.
## Building
```sh
cargo build --release # ~4 MB stripped binary at target/release/fj
./target/release/fj completion zsh > ~/.zfunc/_fj
./target/release/fj man -o ~/man/man1
```
## Documentation
- [`docs/architecture.md`](docs/architecture.md) — module graph, HTTP
funnel, pager + SIGINT, repo resolution
- [`docs/jq.md`](docs/jq.md) — `fj api --jq` projection syntax
- [`docs/troubleshooting.md`](docs/troubleshooting.md) — keychain
prompts, 401s, hook bypass, pager opt-out, alias precedence
- [`CONTRIBUTING.md`](CONTRIBUTING.md) — build / test / release workflow
- [`CHANGELOG.md`](CHANGELOG.md) — release notes
## License
MIT

BIN
dist/v0.1.0/fj-v0.1.0-darwin-aarch64/fj vendored Executable file

Binary file not shown.

Binary file not shown.

View file

@ -0,0 +1,121 @@
# Changelog
All notable changes will be recorded here. The format follows
[Keep a Changelog](https://keepachangelog.com/en/1.1.0/). Versions follow
[Semantic Versioning](https://semver.org/spec/v2.0.0.html).
## [Unreleased]
### Added (distribution + open-source ready)
- `LICENSE` (MIT) at the repo root. Cargo.toml had always declared MIT;
the file was just missing.
- `.forgejo/workflows/release.yml`: on `v*` tags, builds for
`darwin-aarch64`, `darwin-x86_64`, `linux-x86_64`; uploads tarballs,
`SHA256SUMS`, and a pre-rendered `fj.rb` to the Forgejo release.
- Homebrew formula template at `dist/homebrew/fj.rb.tmpl` and
`scripts/render-homebrew-formula.sh` to fill SHA256s post-release.
Publishes into the existing `rasterandstate/homebrew-tap`.
- `.forgejo/issue_template/{bug,feature,api-gap}.md` and
`.forgejo/pull_request_template.md` to keep triage cheap.
- `scripts/record-demo.sh` + `scripts/_demo-session.sh` to record an
asciinema demo; README has a placeholder embed for the v0.1.0 cast.
- `docs/compatibility.md`: tested Forgejo versions, caveats for older
Gitea, and Forgejo-only endpoints.
- One-shot version probe during `fj auth login` that warns when the
server reports a pre-7.x version (with tests for the parser).
### Added (agent-focused Forgejo gaps)
- `fj issue edit-comment` / `delete-comment`. Lets an agent (or you)
fix or remove a wrong comment after the fact.
- `fj search code "..."` (and `-R owner/name` to scope to one repo).
Powered by Forgejo's `/repos/search/code` endpoint.
- `fj pr request-review N user1 user2,user3` and
`fj pr unrequest-review N user1`. Distinct from `pr review`, which
submits your own review.
- `fj repo watch` / `unwatch` / `star` / `unstar` / `starred`.
- `fj milestone {list,view,create,edit,close,reopen,delete,assign}`.
Includes `fj milestone assign N --milestone ID|none` to attach an
issue or PR to a milestone.
### Added (UX + stability)
- `--json-fields field1,field2` global flag. gh-style projection on top
of any `--json` output, with dotted-path support
(`--json-fields owner.login,id`).
- 429 / Retry-After honored in the retry loop with a 30 s cap. Wiremock
test added.
- `did you mean` suggestions on typo'd subcommands via clap's
`suggestions` feature.
- `fj auth token` and `fj auth status --show-token` now refuse to write
to a TTY (use `--force` to override). Avoids accidental shoulder-
surfing or capture in shell history.
- `tokio::signal::ctrl_c()` race in `cli::run` so the pager guard drops
cleanly on SIGINT.
- 10 wiremock-backed HTTP client integration tests covering retry
behavior (5xx, 429), header forwarding, pagination, and panic-free
error paths.
- `Client::for_base_url` test constructor pointing at an arbitrary URL.
- `.forgejo/workflows/ci.yml` runs the same gate as the pre-push hook
on every push and PR.
### Added (docs)
- `SECURITY.md` covering threat model, known sharp edges, and reporting.
- `docs/gh-to-fj.md` — complete command-by-command mapping.
- `docs/faq.md` — common questions about tokens, hosts, debug,
scripting, plugins.
### Changed
- Trimmed dependencies (no more `indicatif`, `futures-util`,
`is-terminal`, `textwrap`, `tempfile` in prod). Dropped reqwest
features we don't use (`stream`, `brotli`). Release profile uses
`lto = "fat"` and `panic = "abort"`.
- HTTP retry loop builds the request once and clones via
`reqwest::Request::try_clone` per attempt.
- Binary size: 5.94 MB → 4.15 MB stripped (-30%).
### Fixed
- **Shell injection** in `fj auth setup-git`. The hostname now must
match a strict DNS pattern before being interpolated into the
credential-helper string, and we call `git config` directly with
separate args instead of going through `sh -c`.
- **Pager won't compile on Windows**. The libc-based `dup2` redirect
now lives behind `#[cfg(unix)]`; non-Unix gets a no-op stub that
returns `None` from `maybe_start`.
- Removed the unsafe `std::env::set_var("FJ_NO_PAGER")` from dispatch.
`--no-pager` is now threaded into `pager::maybe_start(force_disabled)`.
- Replaced the panicking `.expect("token contains invalid header chars")`
in `auth_headers` with a typed error.
## 0.1.0 — 2026-05-13
Initial release. Multi-host Forgejo CLI with feature parity to `gh`
across the surface Forgejo exposes. Commands:
- `auth`: login, status, logout, list, switch, token, refresh, setup-git
- `repo`: list, view, clone, create, fork, sync, edit, rename, archive,
unarchive, delete, branches, topics, mirror, mirror-sync
- `issue`: list, view, create, edit, close, reopen, comment, develop
- `pr`: list, view, create, edit, diff, commits, files, checks, ready,
review, status, checkout, merge, close, reopen
- `release`: list, view, create, edit, delete, upload, download
- `label`, `run`, `secret`, `variable`, `search`, `browse`, `status`,
`org`, `ssh-key`, `gpg-key`, `alias`, `config`, `protect`, `hook`,
`extension`, `gist`, `api`, `completion`, `man`
Other highlights:
- Repo auto-detection from `upstream` / `origin` git remote.
- `--web` flag on all list/view subcommands.
- `$EDITOR` integration for body inputs.
- `fj api` with `-H`, `-X`, `-f`, `-F`, `--paginate`, `--include`,
`--silent`, `--jq` (dot-paths, `[N]`/`[-N]`, pipes).
- `--debug` / `FJ_DEBUG` request logging.
- Tokens in the OS keychain.
- Pager via `dup2` redirect to `$FJ_PAGER` / `$PAGER` / `less -FRX`.
- Pre-push hook running fmt, clippy `-D warnings`, tests, and release
build before any push. Live API smoke gated on `FJ_E2E=1`.

View file

@ -0,0 +1,21 @@
MIT License
Copyright (c) 2026 Stephen Way
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View file

@ -0,0 +1,149 @@
# fj
A command-line tool for [Forgejo](https://forgejo.org) instances, in the spirit of GitHub's `gh`.
Multi-host from day one. Tokens are stored in your OS keychain.
<!--
TODO: replace the line below with an asciinema embed once the v0.1.0
release is tagged. Run `./scripts/record-demo.sh` then
`asciinema upload dist/demo.cast` and paste the returned URL.
-->
<!-- [![asciicast](https://asciinema.org/a/REPLACE.svg)](https://asciinema.org/a/REPLACE) -->
## Install
```sh
# Homebrew (macOS + Linux):
brew tap rasterandstate/tap
brew install fj
# From source:
cargo install --path .
# or
cargo build --release && cp target/release/fj ~/.local/bin/fj
```
## Quick start
```sh
fj auth login # add a host and token
fj auth status # show signed-in hosts
fj repo list # repos you own
fj repo view owner/name # repo overview
fj issue list -R owner/name # issues
fj pr list -R owner/name --state open # pull requests
fj api /repos/search -X GET -f q=foo # raw API escape hatch
```
`-R/--repo` is optional inside a git clone. fj detects the upstream from
`upstream`, then `origin`, then any other remote.
## Commands
| Group | Common operations |
| ---------- | --------------------------------------------------------------------------------- |
| `auth` | login, status, logout, list, switch, token, refresh, setup-git |
| `repo` | list, view, clone, create, fork, sync, edit, rename, archive, unarchive, delete, branches, topics, mirror, mirror-sync, watch, unwatch, star, unstar, starred |
| `issue` | list, view, create, edit, close, reopen, comment, edit-comment, delete-comment, develop |
| `pr` | list, view, create, edit, diff, commits, files, checks, ready, review, request-review, unrequest-review, status, checkout, merge, close, reopen |
| `release` | list, view, create, edit, delete, upload, download |
| `label` | list, create, edit, delete |
| `milestone`| list, view, create, edit, close, reopen, delete, assign |
| `run` | list, view, rerun, cancel (Forgejo Actions workflow runs) |
| `secret` | list, set, delete (Actions secrets) |
| `variable` | list, set, delete (Actions variables) |
| `search` | repos, issues, prs, users, code |
| `browse` | open the current repo (or a path within it) in your browser |
| `status` | notifications inbox + `--mark-read` |
| `org` | list, view, teams |
| `ssh-key` | list, add, delete |
| `gpg-key` | list, add, delete |
| `alias` | list, set, delete |
| `config` | get, set, list, path |
| `protect` | list, view, set, delete branch protection rules |
| `hook` | list, create, delete, test webhooks |
| `gist` | list, create (thin wrapper over `gist-*` repos) |
| `extension`| list, run discovered `fj-<name>` plugins on PATH |
| `api` | raw HTTP with `-X`, `-f`, `-F`, `-H`, `-q` (jq-ish), `--paginate`, `--include` |
| `completion`| Print shell completions (bash, zsh, fish, powershell, elvish) |
| `man` | Generate man pages into a directory |
## Global flags
- `--host <hostname>` (or `FJ_HOST`): pick the host explicitly.
- `--debug` (or `FJ_DEBUG=1`): log every HTTP request to stderr.
- `--no-pager` (or `FJ_NO_PAGER=1`): skip the pager.
- `--json-fields foo,bar`: gh-style projection on top of any `--json`
output. Dotted paths supported (`--json-fields owner.login,id`).
- `--web` on most list/view subcommands: open the relevant page in
your default browser.
## Config
- Hosts and the current host live in `$XDG_CONFIG_HOME/fj/hosts.toml`
(`~/Library/Application Support/fj/hosts.toml` on macOS).
- Aliases in `aliases.toml`. Preferences in `config.toml`.
- Tokens live in the OS keychain under service `fj`, keyed by hostname.
## Aliases
```sh
fj alias set co "pr checkout"
fj co 42 # equivalent to: fj pr checkout 42
```
## Extensions
Any executable on `$PATH` named `fj-<name>` is invokable as `fj <name> [args]`.
```sh
fj extension list # show discovered plugins
fj my-plugin some-arg # invokes `fj-my-plugin some-arg`
```
## Plugin-style usage of `fj api`
```sh
# Auto-paginate a list endpoint into a single JSON array:
fj api /repos/search -f q=fj --paginate -q .
# Pass a custom request header:
fj api /user -H "X-Trace-Id: foo"
# Show response headers along with the body:
fj api /version --include
# Send a literal JSON body:
fj api /repos/migrate --input '{"clone_addr":"...","repo_name":"x","repo_owner":"y"}'
```
## Hooks
- `hooks/pre-push` runs `cargo fmt --check`, `cargo clippy -D warnings`,
`cargo test`, and a release build before any push.
- With `FJ_E2E=1`, the hook also runs `scripts/e2e-smoke.sh` against the
configured host.
- Install via `./scripts/install-hooks.sh`.
## Building
```sh
cargo build --release # ~4 MB stripped binary at target/release/fj
./target/release/fj completion zsh > ~/.zfunc/_fj
./target/release/fj man -o ~/man/man1
```
## Documentation
- [`docs/architecture.md`](docs/architecture.md) — module graph, HTTP
funnel, pager + SIGINT, repo resolution
- [`docs/jq.md`](docs/jq.md) — `fj api --jq` projection syntax
- [`docs/troubleshooting.md`](docs/troubleshooting.md) — keychain
prompts, 401s, hook bypass, pager opt-out, alias precedence
- [`CONTRIBUTING.md`](CONTRIBUTING.md) — build / test / release workflow
- [`CHANGELOG.md`](CHANGELOG.md) — release notes
## License
MIT

BIN
dist/v0.1.0/fj-v0.1.0-darwin-x86_64/fj vendored Executable file

Binary file not shown.

View file

@ -1,38 +0,0 @@
#!/usr/bin/env bash
# Drives an asciinema recording. Don't invoke directly; run record-demo.sh.
set -u
PS1='\$ '
export PS1
PAUSE_BETWEEN=0.6
PAUSE_AFTER=1.2
say() { printf '\033[1;34m# %s\033[0m\n' "$*"; sleep "$PAUSE_BETWEEN"; }
do_() { printf '\033[1m$ %s\033[0m\n' "$*"; sleep "$PAUSE_BETWEEN"; eval "$@"; sleep "$PAUSE_AFTER"; }
clear
say "fj: a CLI for Forgejo. Multi-host, tokens in the keychain."
do_ "fj --version"
say "Inside a clone, no flags needed: fj infers the repo from your git remote."
do_ "fj repo view | head -8"
say "Issues, PRs, releases all work the same way."
do_ "fj issue list --state all -L 5"
do_ "fj pr list --state all -L 5"
say "The api escape hatch with a jq-ish projector."
do_ "fj api /version"
do_ "fj api /user -q .login"
say "Selective JSON for scripting."
do_ "fj repo list -L 3 --json --json-fields full_name,private"
say "Or just browse on the web."
say " fj browse src/main.rs"
sleep 1.5
clear
say "60+ subcommands. Try fj --help."
sleep 2

93
scripts/demo.tape Normal file
View file

@ -0,0 +1,93 @@
# vhs tape file for the fj README demo.
#
# Reproduce with:
# brew install vhs
# ./scripts/record-demo.sh
#
# The tape is the source of truth. Edit it, re-record, commit the
# updated assets/demo.gif and (optionally) assets/demo.mp4.
#
# Pre-requisites the recorder needs:
# * `fj` on PATH (build it via `cargo build --release` and symlink)
# * `fj auth login --host rasterhub.com` already completed
# * Run from inside the fj clone (so `fj repo view` resolves via the
# git remote)
Output assets/demo.gif
Output assets/demo.mp4
Set Theme "Catppuccin Mocha"
Set FontSize 16
Set Width 1100
Set Height 720
Set TypingSpeed 50ms
Set Padding 24
Set PlaybackSpeed 1.0
Set Shell zsh
# Establish a clean prompt.
Hide
Type "clear"
Enter
Show
Sleep 600ms
Type "fj --version"
Sleep 300ms
Enter
Sleep 1200ms
Type "# inside a clone, fj infers the repo from the git remote"
Sleep 200ms
Enter
Sleep 600ms
Type "fj repo view | head -10"
Sleep 200ms
Enter
Sleep 2200ms
Type "# issues, PRs, releases — same shape"
Sleep 200ms
Enter
Sleep 500ms
Type "fj issue list --state all -L 5"
Sleep 200ms
Enter
Sleep 2000ms
Type "fj pr list --state all -L 5"
Sleep 200ms
Enter
Sleep 2200ms
Type "# api escape hatch with jq-ish projection"
Sleep 200ms
Enter
Sleep 500ms
Type "fj api /version"
Sleep 200ms
Enter
Sleep 1500ms
Type "fj api /user -q .login"
Sleep 200ms
Enter
Sleep 1500ms
Type "# gh-style selective JSON for scripts"
Sleep 200ms
Enter
Sleep 500ms
Type "fj repo list -L 3 --json --json-fields full_name,private"
Sleep 200ms
Enter
Sleep 2800ms
Type "fj --help | head -20"
Sleep 200ms
Enter
Sleep 3000ms