fix: watch providers.jsonc for external edits so UI refreshes without restart#3233
fix: watch providers.jsonc for external edits so UI refreshes without restart#3233Neppkun wants to merge 1 commit into
Conversation
…ut restart Manual edits to ~/.mux/providers.jsonc were silently ignored by the frontend because notifyConfigChanged() was only called after API mutations. Added watchProvidersFile() to Config (fs.watch on the mux home directory, debounced 300ms) and wired it into ProviderService's constructor so external file changes propagate to all onConfigChanged subscribers automatically. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
|
@codex review |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 902766a042
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| const filename = path.basename(this.providersFile); | ||
| let debounceTimer: ReturnType<typeof setTimeout> | null = null; | ||
|
|
||
| const watcher = fs.watch(this.rootDir, (_eventType, changedFilename) => { |
There was a problem hiding this comment.
Guard providers watcher when mux home is missing
watchProvidersFile() calls fs.watch(this.rootDir, ...) unconditionally, but Config does not guarantee rootDir exists before ProviderService is constructed. On first run (or when MUX_ROOT points to a not-yet-created directory), fs.watch throws ENOENT synchronously, which aborts ProviderService construction and can crash startup before recovery logic runs.
Useful? React with 👍 / 👎.
| // Avoid noisy MaxListenersExceededWarning for normal usage. | ||
| this.emitter.setMaxListeners(50); | ||
| // Notify subscribers when providers.jsonc is edited externally (e.g. manual edits). | ||
| this.config.watchProvidersFile(() => this.notifyConfigChanged()); |
There was a problem hiding this comment.
Retain and dispose providers file watcher
The constructor starts a filesystem watch via watchProvidersFile(...) but drops the returned cleanup function. Because FSWatcher is ref'ed by default, each ProviderService instance now keeps a live watcher for the process lifetime, which can leak handles in tests/one-shot CLI flows and make transient service instances unable to fully tear down.
Useful? React with 👍 / 👎.



Summary
~/.mux/providers.jsoncnever appeared in the UI becausenotifyConfigChanged()was only called after API mutations, not on external file changesConfig.watchProvidersFile()— watches the mux home directory withfs.watch, debounced 300 ms, returns a cleanup fnProviderServiceconstructor so any external edit toproviders.jsoncimmediately propagates to allonConfigChangedfrontend subscribersRoot cause
ProviderService.list()andgetConfig()already readproviders.jsoncfresh on every call, so the backend always had the right data. The missing piece was a signal to the frontend to re-fetch.notifyConfigChanged()emits that signal — but it was only called after in-app edits, leaving manual file edits invisible until restart.Test plan
~/.mux/providers.jsoncwhile the app is running — it should appear in Settings → Providers within ~300 ms, no restart neededMaxListenersExceededWarningnoise in dev logs🤖 Generated with Claude Code