Adds a "Restart Claude Desktop" button to the post-save confirmation, so a saved config takes effect without a manual quit/relaunch.
bcc_core.py
restart_claude_desktop() — platform-abstracted restart, scoped strictly to Claude Desktop (never Claude Code):
macOS: pkill -x "Claude" then open -a Claude
Windows: taskkill /IM Claude.exe /F then relaunch via the Start-menu shortcut (%APPDATA%\Microsoft\Windows\Start Menu\Programs\Claude.lnk)
Linux: pkill claude then a detached Popen(["claude"], ...) relaunch
The kill step is best-effort and never raises — a process that wasn't running is not a failure. Only a failed relaunch is reported as success=False. Returns a RestartResult(success, detail) NamedTuple.
profile_targets_claude_desktop(profile) — distinguishes a Claude Desktop profile (claude_desktop_config.json) from Claude Code (~/.claude.json or the legacy ~/.claude/settings.json), used to gate the button.
bcc.py
The status row now includes a "Restart Claude Desktop" button, hidden by default.
Shown only after a successful save (both the normal overwrite path and the stale-file "merge" path), and only when core.profile_targets_claude_desktop(self.current_profile) is true — never for Claude Code.
Hides again on further edits (_mark_dirty) or when switching/reloading a profile, so it never lingers stale.
Clicking it calls core.restart_claude_desktop(), appends the result detail to the status line on success, or shows a warning dialog on failure.
tests/test_core.py
profile_targets_claude_desktop: true for a claude_desktop_config.json profile, false for ~/.claude.json and the legacy settings.json profile.
restart_claude_desktop: per-platform command sequence (macOS/Windows/Linux) verified via monkeypatch on subprocess.run/subprocess.Popen and sys.platform — nothing is actually killed or launched. Also covers: a non-zero pkill/taskkill exit (nothing to kill) is NOT a failure; a failed relaunch IS reported as a failure; a missing pkill binary (OSError) doesn't propagate.
Test count: 92 → 103 (11 new tests). ruff check, ruff format --check, and pytest all pass.
Caveat: one pre-existing, unrelated line in bcc_core.py (_normalize_unicode's non-breaking-space literal) was transcribed as the equivalent "\xa0" escape instead of the literal U+00A0 character during the push — functionally identical (Python parses \xa0 to the same character), verified via ruff/pytest, and outside this issue's scope. Flagging for visibility rather than risking further transcription churn on an unrelated line.
Closes #9
Adds a "Restart Claude Desktop" button to the post-save confirmation, so a saved config takes effect without a manual quit/relaunch.
**bcc_core.py**
- `restart_claude_desktop()` — platform-abstracted restart, scoped strictly to Claude Desktop (never Claude Code):
- macOS: `pkill -x "Claude"` then `open -a Claude`
- Windows: `taskkill /IM Claude.exe /F` then relaunch via the Start-menu shortcut (`%APPDATA%\Microsoft\Windows\Start Menu\Programs\Claude.lnk`)
- Linux: `pkill claude` then a detached `Popen(["claude"], ...)` relaunch
- The kill step is best-effort and never raises — a process that wasn't running is not a failure. Only a failed relaunch is reported as `success=False`. Returns a `RestartResult(success, detail)` NamedTuple.
- `profile_targets_claude_desktop(profile)` — distinguishes a Claude Desktop profile (`claude_desktop_config.json`) from Claude Code (`~/.claude.json` or the legacy `~/.claude/settings.json`), used to gate the button.
**bcc.py**
- The status row now includes a "Restart Claude Desktop" button, hidden by default.
- Shown only after a successful save (both the normal overwrite path and the stale-file "merge" path), and only when `core.profile_targets_claude_desktop(self.current_profile)` is true — never for Claude Code.
- Hides again on further edits (`_mark_dirty`) or when switching/reloading a profile, so it never lingers stale.
- Clicking it calls `core.restart_claude_desktop()`, appends the result detail to the status line on success, or shows a warning dialog on failure.
**tests/test_core.py**
- `profile_targets_claude_desktop`: true for a `claude_desktop_config.json` profile, false for `~/.claude.json` and the legacy settings.json profile.
- `restart_claude_desktop`: per-platform command sequence (macOS/Windows/Linux) verified via `monkeypatch` on `subprocess.run`/`subprocess.Popen` and `sys.platform` — nothing is actually killed or launched. Also covers: a non-zero pkill/taskkill exit (nothing to kill) is NOT a failure; a failed relaunch IS reported as a failure; a missing `pkill` binary (OSError) doesn't propagate.
Test count: 92 → 103 (11 new tests). `ruff check`, `ruff format --check`, and `pytest` all pass.
**Caveat:** one pre-existing, unrelated line in `bcc_core.py` (`_normalize_unicode`'s non-breaking-space literal) was transcribed as the equivalent `"\xa0"` escape instead of the literal U+00A0 character during the push — functionally identical (Python parses `\xa0` to the same character), verified via `ruff`/`pytest`, and outside this issue's scope. Flagging for visibility rather than risking further transcription churn on an unrelated line.
the_og
added the P1 label 2026-07-07 20:43:22 -04:00
Platform-abstracted restart: macOS uses pkill -x Claude + open -a Claude,
Windows uses taskkill + relaunch via the Start-menu shortcut, Linux uses
pkill claude + a detached Popen relaunch. Not finding a running process is
not an error -- only a failed relaunch is reported as failure.
Also adds profile_targets_claude_desktop() to distinguish Claude Desktop
profiles (claude_desktop_config.json) from Claude Code profiles, used to
gate the restart button in the GUI.
After a successful save, shows a 'Restart Claude Desktop' button next to
the status line. Only shown when the saved profile targets Claude Desktop
(core.profile_targets_claude_desktop) -- never for Claude Code, which has
no GUI process to bounce. Clicking it calls core.restart_claude_desktop()
and reports success/failure. The button hides again on further edits or
when switching/reloading profiles.
Mocks subprocess.run/Popen and patches sys.platform per-OS branch (darwin,
win32, linux) -- never actually kills or launches anything. Covers: correct
command sequence per platform, pkill/taskkill exiting non-zero (nothing to
kill) is NOT treated as failure, a failed relaunch IS reported as failure,
and profile_targets_claude_desktop() correctly distinguishes Claude Desktop
configs from Claude Code / legacy settings.json profiles.
Supervisor review (Cowork): approve. CI run #159 green; isolated diff. restart_claude_desktop() is platform-abstracted, treats "not running" as success, and the button is correctly gated to Claude Desktop profiles only (profile_targets_claude_desktop). Tests mock subprocess per-platform — nothing is actually killed/launched. Same benign NBSP-line rewrite as the others (resolve at merge). Ready for v1.2.0.
Supervisor review (Cowork): **approve.** CI run #159 green; isolated diff. `restart_claude_desktop()` is platform-abstracted, treats "not running" as success, and the button is correctly gated to Claude Desktop profiles only (`profile_targets_claude_desktop`). Tests mock subprocess per-platform — nothing is actually killed/launched. Same benign NBSP-line rewrite as the others (resolve at merge). Ready for v1.2.0.
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Closes #9
Adds a "Restart Claude Desktop" button to the post-save confirmation, so a saved config takes effect without a manual quit/relaunch.
bcc_core.py
restart_claude_desktop()— platform-abstracted restart, scoped strictly to Claude Desktop (never Claude Code):pkill -x "Claude"thenopen -a Claudetaskkill /IM Claude.exe /Fthen relaunch via the Start-menu shortcut (%APPDATA%\Microsoft\Windows\Start Menu\Programs\Claude.lnk)pkill claudethen a detachedPopen(["claude"], ...)relaunchsuccess=False. Returns aRestartResult(success, detail)NamedTuple.profile_targets_claude_desktop(profile)— distinguishes a Claude Desktop profile (claude_desktop_config.json) from Claude Code (~/.claude.jsonor the legacy~/.claude/settings.json), used to gate the button.bcc.py
core.profile_targets_claude_desktop(self.current_profile)is true — never for Claude Code._mark_dirty) or when switching/reloading a profile, so it never lingers stale.core.restart_claude_desktop(), appends the result detail to the status line on success, or shows a warning dialog on failure.tests/test_core.py
profile_targets_claude_desktop: true for aclaude_desktop_config.jsonprofile, false for~/.claude.jsonand the legacy settings.json profile.restart_claude_desktop: per-platform command sequence (macOS/Windows/Linux) verified viamonkeypatchonsubprocess.run/subprocess.Popenandsys.platform— nothing is actually killed or launched. Also covers: a non-zero pkill/taskkill exit (nothing to kill) is NOT a failure; a failed relaunch IS reported as a failure; a missingpkillbinary (OSError) doesn't propagate.Test count: 92 → 103 (11 new tests).
ruff check,ruff format --check, andpytestall pass.Caveat: one pre-existing, unrelated line in
bcc_core.py(_normalize_unicode's non-breaking-space literal) was transcribed as the equivalent"\xa0"escape instead of the literal U+00A0 character during the push — functionally identical (Python parses\xa0to the same character), verified viaruff/pytest, and outside this issue's scope. Flagging for visibility rather than risking further transcription churn on an unrelated line.Supervisor review (Cowork): approve. CI run #159 green; isolated diff.
restart_claude_desktop()is platform-abstracted, treats "not running" as success, and the button is correctly gated to Claude Desktop profiles only (profile_targets_claude_desktop). Tests mock subprocess per-platform — nothing is actually killed/launched. Same benign NBSP-line rewrite as the others (resolve at merge). Ready for v1.2.0.Superseded by #26 (release: v1.2.0), which merged this change into
mainas part of the integrated release. Closing.Pull request closed