feat(installer): add Claude Desktop and OpenCode, auto-configure by default - #40
Merged
Merged
Conversation
- Detects Claude Desktop via its app bundle (not a CLI command) and writes ~/Library/Application Support/Claude/claude_desktop_config.json. - Detects and configures OpenCode via ~/.config/opencode/opencode.json, which uses a distinct entry shape (type: "local", command as a single array combining executable and args). - Extracted the read-merge-write JSON logic shared by Cursor, Claude Desktop, and OpenCode into one write_mcp_json_config helper parameterized by config path, servers key, and entry shape, rather than duplicating it a third time. Cursor's own output is unchanged. - Extended legacy-package reference scanning to include both new config files. - Documented that ChatGPT Desktop shares Codex CLI's config.toml on the same host, so --codex already covers it. Also changes the default (no-flag) and --all behavior: auto-detect and configure every client found, silently skipping ones that aren't, without prompting. Explicit single-client flags (--claude, etc.) keep today's behavior of dying if that specific client isn't installed. Retires the interactive per-client Y/n prompt this replaces.
Covers install/uninstall/manual-configuration for both new clients, the ChatGPT-Desktop-via-Codex relationship, and the installer's new default behavior (auto-detect and configure everything found, no prompting, explicit single-client flags still fail loudly if missing).
…them write_mcp_json_config fully replaced each client's server entry on every run, so re-running the installer would silently re-enable an OpenCode server the user had explicitly disabled via enabled: false (the constructed entry always set enabled: true, and always won because it overwrote the whole object rather than merging into it). Merge onto the existing entry instead, and stop forcing an explicit enabled: true on the entries this installer constructs itself, so an absent field just falls through to OpenCode's own default instead of overriding whatever the user (or another tool) had set. Found by code review.
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.
Summary
~/Library/Application Support/Claude/claude_desktop_config.jsonin the samemcpServersshape Claude Code/Cursor use (minus thetypefield, which Claude Desktop infers from the presence ofcommand).opencodecommand, configured by writing~/.config/opencode/opencode.jsonunder a distinctmcpkey with its own entry shape (type: "local", andcommandas a single array combining the executable and its arguments, rather than separatecommand/argsfields).~/.codex/config.tomlon the same host, so--codexalready covers it when thecodexcommand is installed. Documented this relationship rather than adding a redundant path. (A narrower gap exists for users with ChatGPT Desktop but nocodexCLI binary; left out of scope for this PR since it would need a hand-rolled TOML writer for a comparatively rare case.)write_mcp_json_configshell function parameterized by config path, top-level servers key, and entry shape — added here since a third near-identical 40-line block crossed the threshold where duplicating it again stopped being the simpler option. Cursor's own output is byte-for-byte unchanged..tgzfiles after a config gets rewritten) to also read both new config files.Behavior change: auto-select by default
While implementing this, hit a real question: should
--all(and the true no-flags default) die if one of five possible clients isn't installed? That would make the common case — most people have one or two of these, not all five — fail by default. So:--all: auto-detect and configure every client found; silently skip ones that aren't. No interactive Y/n prompting either — retired theprompt_targetconfirmation step entirely, since the pipedcurl | shinstall path already always ran in exactly this way when non-interactive (no TTY), it just also happened to prompt when run interactively in a terminal. Now both cases behave the same: install what's there.--claude,--claude-desktop,--codex,--cursor,--opencode): unchanged from today — requires exactly that client and fails loudly if it's missing.Test plan
sh -n install.shnpm run typechecknpm run lintnpm test(373 tests passing — new coverage for Claude Desktop and OpenCode configuration, the auto-select-skips-undetected-clients default, explicit-flag-dies-when-missing for both new clients, and legacy-package cleanup scanning both new config files)npm run build