feat: ask which agents to use on first launch - #190
Merged
Conversation
lich opened its first session on Claude Code because Claude was the only harness its author ran. A machine with Codex and nothing else met a first session that died on "claude: command not found", and the other harnesses sat off in a Settings screen nobody had been pointed at. Detection now runs before anything is shown, and the first launch opens on the providers it found: what is actually installed, a switch each, and the pick of which one new sessions spawn. The first one found arrives on, so the common case is one click. The panel is Settings > Providers verbatim, so the screen met on day one is the one to come back to. Continue writes an explicit enabled flag for every provider, including the ones the installed-only filter hid. Claude is enabled by default in readEnabled even when absent from PATH, so without that write a Codex-only machine would still be offered Claude in New Session. The gate is the stored default being empty — the one setting only a deliberate choice writes — so existing installs that never chose one see the dialog once. Nothing installed is its own shape: lich names what it looks for instead of failing inside a terminal. Also adds oh-my-pi (the omp binary, a Pi fork) to the registry, wearing lobehub's Pi mark. Verified end to end: it spawns under lich and paints a real TUI in the PTY.
…er-setup # Conflicts: # CHANGELOG.md
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
lich opened its first session on Claude Code because Claude was the only harness its author ran. A machine with Codex and nothing else met a first session that died on
claude: command not found, and the three other harnesses sat off in a Settings screen nobody had been pointed at.What changes
Detection runs before anything is shown, and the first launch opens on the providers it found — what is actually installed, a switch each, and the pick of which one new sessions spawn. The first one found arrives on, so the common case is one click on Continue. The body is
<ProvidersSettings installedOnly />, the Settings › Providers panel verbatim, so the screen a user meets on day one is the one to come back to.The dialog cannot leave without writing the choice it exists to collect: no close button,
openpinned true,onOpenChangeswallowing Escape and the backdrop.Also adds oh-my-pi to the registry — the
ompbinary, a Pi fork — wearing lobehub's Pi mark. Upstream draws that mark as two paths underfill-rule="evenodd"; concatenated they render identically under the default nonzero rule, soProviderIconkeeps its single-path shape.Three decisions worth reviewing
The gate is
provider.defaultbeing empty. It is the one setting only a deliberate choice writes, so empty means "never chose" — no new flag, no localStorage, and it lives in the DB beside the choice it guards. Consequence: an existing install that never opened Settings › Providers sees the dialog once on upgrade. That reads as correct here — the default is changing and they should see it — but it is a popup in front of people who did not ask for one. Seedingprovider.default = "claude"for existing workspaces would make it truly first-run-only.Continue writes an explicit flag for every provider, including the ones the filter hid.
readEnabledreturns true for Claude even when it is absent from PATH, so without that write a Codex-only machine would keep Claude out of the visible list and still be offered it in New Session.Only installed harnesses are listed. The question is which of your agents to use, not a catalogue of what lich supports — "Not found on PATH" rows are noise there and the useful state in Settings. With nothing installed the shape inverts: no switches at all, just the names lich looks for, because five dead toggles under a "Default provider" nobody can honour contradict the title above them.
Test plan
Backend and frontend suites cover the pure logic —
decideProviderSetuphas the wait / skip / preselect / nothing-installed cases. The frontend gate runs in node with no jsdom, so it cannot catch a render crash: the first build of this gate passed all 653 tests and painted a blank window (React #185 —setProviderEnabledemits synchronously,useSyncExternalStorere-entered the effect before anysetStatelanded, and the state guard recursed; the latch had to be a ref).So the dialog was driven headless over CDP against a fresh config directory and a controlled
PATH:provider.claude.enabled|0,provider.codex.enabled|1,provider.default|codexompspawns under lich (bun .../ompas a child) and paints a real TUI in the PTY — alternate screen, SGR mouse trackinggofmt,go vet,go test ./...,tsc,biome check,vitest,vite buildNot touched: any OS seam, so no
ci:os.Known gap
ompinstalled viabun install -glands in~/.cache/.bun/bin, which is not on PATH by default — lich will report it as "Not found on PATH" until that directory is added. That is where bun puts global binaries, not something lich can resolve.