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
15 changes: 12 additions & 3 deletions ARCHITECTURE.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ graph TD
| `internal/proc` | `DetachTTY` — run probes without a controlling terminal; `KillGroup` — process-group SIGKILL (plain `Kill` on Windows) |
| `internal/ui` | Lip Gloss styles, `PlaceOverlay`, `StripANSI` |
| `internal/updater` | Detect the package manager that owns an installed binary and produce an update `Plan{Manager, Argv, Display}` |
| `internal/version` | Detect the installed version locally; GitHub API with a 24-hour cache; semver comparison (`IsNewer`) |
| `internal/version` | Detect the installed version locally — `InstalledVersion(t) (ver, present)`; GitHub API with a 24-hour cache; semver comparison (`IsNewer`) |

`configdir`, `launcher`, `logx`, `proc`, `ui`, `updater` and `version` sit at the bottom of the import graph:
they know nothing about the TUI (`ui`, `updater` and `version` reach only into
Expand Down Expand Up @@ -74,7 +74,10 @@ The `model` package is split across files within a single package:

Each tool has five data sources, split so local detection never waits on the network:

- **installed** — `fetchInstalledCmd`: a local subprocess (`--version`/`-V`), always fired;
- **installed** — `fetchInstalledCmd`: a local subprocess (`--version`/`-V`, with brew-directory
and `cargo install --list` fallbacks that need no subprocess of the tool itself), always
fired. It reports a version *and* whether the tool is present at all, so the card can tell
"installed, version unknown" from "not installed";
- **remote** — `fetchRemoteCmd`: a single network pass via `version.GetRepoData`
(release + repo card + languages), only when `github` is set;
- **changelog** — `fetchChangelogCmd`;
Expand Down Expand Up @@ -176,6 +179,11 @@ Go binary is not misrouted to `go install`). `update_cmd` from `meta.yaml` alway
wins and runs via `sh -c`. Detection spawns subprocesses, so it runs as a `tea.Cmd`,
never inside `Update()`.

When the tool has no binary of its own on PATH, one fallback runs before
`ErrUnknownManager`: a `Cellar/<name>`/`Caskroom/<name>` directory means brew owns
the name, so the plan is `brew upgrade <name>`. That is the `rust` case — the
formula ships `rustc` and `cargo`, so `LookPath("rust")` can only miss.

Output streaming uses the "channel + re-subscribe" idiom, with no `*tea.Program`: a
goroutine reads the merged stdout+stderr to EOF (`streamLines`, splitting on `\n`
**and** `\r` — brew/npm progress bars collapse into one updating line), then
Expand Down Expand Up @@ -280,7 +288,8 @@ rewrites the tracker wholesale. A `TestConfigDirIsolated` test in each of those
packages fails if the isolation is ever dropped.

Per-test setup still uses the internal seams: `testConfigDir`, `testCacheDir`,
`testTokenDir`, `testAPIBase`, `testBrewPrefix`, `updater`'s `testHomeDir`, and
`testTokenDir`, `testAPIBase`, `testBrewPrefix` (one copy in `version`, a second in
`updater` — each private to its package), `updater`'s `testHomeDir`, and
`model`'s `testReadmeStyle` (forces the glamour construction failure so the
plain-text fallback is covered). The races are real (mutexes in `version`, `logx`),
so tests always run with `-race`:
Expand Down
16 changes: 8 additions & 8 deletions CLAUDE.md

Large diffs are not rendered by default.

11 changes: 11 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,12 @@ Statuses: `active` (●) · `trying` (○) · `inactive` (✕) — shown on the
Legacy `forgotten` / `archived` values from `meta.yaml` are automatically read as
`inactive`; a legacy list of several tags is read as its first tag.

The `installed:` line has four states: the detected version, `detecting…` while the
local probe runs, `✓ no version` for a tool that is installed but won't report one
(a TUI app that ignores `--version`), and `✕ not installed`. The version is read from
`--version` / `-V`, and failing that from Homebrew's directory layout or
`cargo install --list` — so tools with no version CLI still resolve.

The card's links are clickable: a click on the `repo:` line opens the repository in the
browser, a click on the release URL under `[changelog]` opens that release page — the
same thing `o` and `c` do from the keyboard.
Expand Down Expand Up @@ -170,6 +176,11 @@ in the brief panel. `keeptui` detects the package manager the binary was install
- `pipx` — a venv in `~/.local/pipx/venvs/<pkg>/` → `pipx upgrade <pkg>`;
- `npm` — a global `node_modules/<pkg>` → `npm install -g <pkg>`.

If the tool has no binary of its own on `PATH`, one more check runs before giving up:
a Homebrew keg or cask named after the tool → `brew upgrade <name>`. That covers
formulae whose binaries are named differently — `rust` installs `rustc` and `cargo`,
so there is no `rust` binary to detect from.

The command is shown in the status bar for confirmation (`enter` runs it, any other
key cancels); its output streams into panel `[3] Update` in real time and the TUI
stays responsive. After a successful update the version is re-detected, the `↑`
Expand Down
Loading
Loading