Skip to content

Fix focus nudge launching Electron instead of restoring VS Code on macOS#783

Merged
dsarno merged 2 commits intoCoplayDev:betafrom
dsarno:fix/focus-nudge-electron-bundle-id
Feb 19, 2026
Merged

Fix focus nudge launching Electron instead of restoring VS Code on macOS#783
dsarno merged 2 commits intoCoplayDev:betafrom
dsarno:fix/focus-nudge-electron-bundle-id

Conversation

@dsarno
Copy link
Collaborator

@dsarno dsarno commented Feb 19, 2026

Summary

  • Fixes the macOS focus-restore bug where tell application "Electron" launches a standalone Electron instance instead of returning to VS Code ([Bug] Get Test Job launching Electron #699)
  • Now captures bundle identifier (e.g. com.microsoft.VSCode) alongside process name when saving the frontmost app
  • Uses tell application id "<bundle_id>" to activate for precise focus restore, falling back to name-based activation if bundle ID fails
  • Windows/Linux unaffected — they use window titles and window IDs respectively, not process names

Test plan

  • Live-tested AppleScript captures both process name and bundle_id
  • Bundle ID activation works (tell application id "com.apple.Terminal" to activate)
  • Bug scenario: generic name "Electron" + correct bundle_id → bundle_id takes priority
  • Bad bundle_id gracefully falls back to name-based activation
  • Full nudge cycle: Unity focus + restore returns to correct app via bundle_id
  • 685 Python tests pass
  • 666 Unity tests pass (EditMode + PlayMode, including all normally-skipped explicit tests)

Fixes #699

🤖 Generated with Claude Code

Summary by Sourcery

Improve cross-platform focus restoration by tracking richer frontmost app metadata and preferring precise activation on macOS.

New Features:

  • Capture and propagate structured frontmost application info, including optional macOS bundle identifiers, through the focus nudge pipeline.

Bug Fixes:

  • Fix macOS focus restore incorrectly launching a generic Electron app instead of returning to the original VS Code instance by preferring bundle identifier–based activation when available.

Enhancements:

  • Unify frontmost application handling across macOS, Windows, and Linux via a shared app info data structure.
  • Improve Unity focus nudge logic to work with the new structured app info while preserving multi-instance support.

Summary by CodeRabbit

  • New Features
    • macOS focus can now prefer application bundle identifier when available for more accurate activation.
  • Bug Fixes
    • More reliable app focus restoration and switching across macOS, Windows, and Linux.
    • Improved handling for multi-instance applications (e.g., Unity projects).
    • Consistent name-based comparisons to avoid incorrect focus changes.

The focus restore used process name (e.g. "Electron") which caused macOS
to launch a standalone Electron instance instead of returning to VS Code.
Now captures bundle identifier and uses `tell application id` for precise
activation, falling back to name-based activation if bundle ID fails.

Fixes CoplayDev#699

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@sourcery-ai
Copy link
Contributor

sourcery-ai bot commented Feb 19, 2026

Reviewer's Guide

Refactors focus tracking to carry structured frontmost app info (including macOS bundle IDs) through the nudge pipeline and updates macOS focus-restore to prefer bundle-id-based activation, fixing the Electron/VS Code mis-focus while keeping Windows/Linux behavior intact.

Sequence diagram for macOS Unity focus nudge with bundle_id-based restore

sequenceDiagram
    actor User
    participant UnityEditor as UnityEditor
    participant FocusNudge as nudge_unity_focus
    participant FrontApp as _get_frontmost_app
    participant MacFront as _get_frontmost_app_macos
    participant FocusApp as _focus_app
    participant FocusMac as _focus_app_macos
    participant AppleScript as osascript

    User->>UnityEditor: Perform action requiring focus nudge
    UnityEditor->>FocusNudge: nudge_unity_focus(unity_project_path)

    FocusNudge->>FrontApp: _get_frontmost_app()
    FrontApp->>MacFront: _get_frontmost_app_macos()
    MacFront->>AppleScript: osascript System Events query
    AppleScript-->>MacFront: procName|bundleID
    MacFront-->>FrontApp: _FrontmostAppInfo(name, bundle_id)
    FrontApp-->>FocusNudge: original_app

    FocusNudge->>FocusApp: _focus_app("Unity", unity_project_path)
    FocusApp->>FocusMac: _focus_app_macos(app_name="Unity", unity_project_path, bundle_id=None)
    FocusMac->>AppleScript: Unity PID based activation
    AppleScript-->>FocusMac: success
    FocusMac-->>FocusApp: True
    FocusApp-->>FocusNudge: True

    FocusNudge->>FrontApp: _get_frontmost_app()
    FrontApp-->>FocusNudge: current_app _FrontmostAppInfo

    FocusNudge-->>FocusNudge: wait focus_duration_s

    FocusNudge->>FocusApp: _focus_app(original_app)
    FocusApp-->>FocusNudge: platform route by system
    FocusApp->>FocusMac: _focus_app_macos(app_name=original_app.name, unity_project_path=None, bundle_id=original_app.bundle_id)
    alt bundle_id present
        FocusMac->>AppleScript: tell application id bundle_id to activate
        AppleScript-->>FocusMac: success
        FocusMac-->>FocusApp: True
    else bundle_id missing or failed
        FocusMac->>AppleScript: tell application original_app.name to activate
        AppleScript-->>FocusMac: success or failure
        FocusMac-->>FocusApp: result
    end
    FocusApp-->>FocusNudge: True or False
    FocusNudge-->>UnityEditor: nudge complete
Loading

Class diagram for focus_nudge frontmost app handling and macOS focus restore

classDiagram
    class _FrontmostAppInfo {
        +str name
        +str bundle_id
        +__str__() str
    }

    class FocusNudgeModule {
        +_parse_env_float(env_var, default) float
        +_is_available() bool
        +reset_nudge_backoff() void
        +_get_frontmost_app_macos() _FrontmostAppInfo
        +_get_frontmost_app_windows() _FrontmostAppInfo
        +_get_frontmost_app_linux() _FrontmostAppInfo
        +_get_frontmost_app() _FrontmostAppInfo
        +_focus_app_macos(app_name, unity_project_path, bundle_id) bool
        +_focus_app_windows(window_title) bool
        +_focus_app_linux(window_id) bool
        +_focus_app(app_info, unity_project_path) bool
        +_find_unity_pid_by_project_path(project_path) int
        +_focus_any_unity_macos() bool
        +nudge_unity_focus(unity_project_path, focus_duration_s) bool
    }

    _FrontmostAppInfo <.. FocusNudgeModule : used by

    FocusNudgeModule ..> _FrontmostAppInfo : returns
    FocusNudgeModule ..> _FrontmostAppInfo : wraps string into

    class MacOSPath {
        +_get_frontmost_app_macos() _FrontmostAppInfo
        +_focus_app_macos(app_name, unity_project_path, bundle_id) bool
    }

    class WindowsPath {
        +_get_frontmost_app_windows() _FrontmostAppInfo
        +_focus_app_windows(window_title) bool
    }

    class LinuxPath {
        +_get_frontmost_app_linux() _FrontmostAppInfo
        +_focus_app_linux(window_id) bool
    }

    FocusNudgeModule ..> MacOSPath : delegates on Darwin
    FocusNudgeModule ..> WindowsPath : delegates on Windows
    FocusNudgeModule ..> LinuxPath : delegates on Linux

    MacOSPath ..> _FrontmostAppInfo : constructs
    WindowsPath ..> _FrontmostAppInfo : constructs
    LinuxPath ..> _FrontmostAppInfo : constructs
Loading

File-Level Changes

Change Details Files
Introduce a structured frontmost-app representation and propagate it through platform-specific getters and focus logic.
  • Add _FrontmostAppInfo dataclass to hold app name and optional bundle_id with a string representation returning the name.
  • Change _get_frontmost_app_macos/_windows/_linux to return _FrontmostAppInfo instead of a bare string and wrap existing outputs accordingly.
  • Update _get_frontmost_app and _focus_app to use _FrontmostAppInfo, including a compatibility path when a plain string is passed in.
Server/src/utils/focus_nudge.py
Enhance macOS focus detection and restore to use bundle identifiers, fixing mis-targeting when the process name is a generic value like 'Electron'.
  • Extend the macOS AppleScript to fetch both process name and bundle identifier, parse the combined output, and construct _FrontmostAppInfo with name and bundle_id.
  • Update _focus_app_macos signature to accept an optional bundle_id and prefer bundle-id-based AppleScript activation, with a logged fallback to name-based activation if bundle ID fails.
  • Wire bundle_id from _FrontmostAppInfo into _focus_app_macos via _focus_app so that non-Unity apps are restored using tell application id where possible.
Server/src/utils/focus_nudge.py
Adapt Unity nudge flow to work with the new _FrontmostAppInfo while preserving platform behavior.
  • Adjust Unity-focused checks in nudge_unity_focus to reference original_app.name/current_app.name and compare against the string 'Unity'.
  • Ensure final focus restoration passes the _FrontmostAppInfo instance back into _focus_app so the original app is restored correctly across platforms.
Server/src/utils/focus_nudge.py

Assessment against linked issues

Issue Objective Addressed Explanation
#699 On macOS, prevent the focus-restore logic from launching a standalone Electron instance when returning focus (so VS Code is restored instead of a generic Electron app).
#699 Preserve correct focus-nudge behavior across platforms while enhancing macOS to restore focus precisely to the original application used to start the tests.

Possibly linked issues


Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Feb 19, 2026

📝 Walkthrough

Walkthrough

Introduces _FrontmostAppInfo dataclass (name, optional macOS bundle_id). All platform frontmost-app getters now return this type. Focus logic normalizes inputs, prefers macOS bundle_id activation when available, and uses app_info.name for comparisons and cross-platform activation calls.

Changes

Cohort / File(s) Summary
Focus app handling
Server/src/utils/focus_nudge.py
Added _FrontmostAppInfo dataclass (name: str, `bundle_id: str

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Poem

🐰 I hopped through names and bundle IDs bright,
I wrapped each frontmost app snug and tight,
On macOS I nudge by bundle when known,
On other lands by name it's shown,
Focus finds home — a gentle, precise flight.

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately describes the main fix: resolving a macOS focus-restore bug where Electron launches incorrectly instead of returning to VS Code, which is the primary objective of this PR.
Description check ✅ Passed The PR description comprehensively covers the problem, solution approach, and testing validation. It includes a clear summary, test plan with checkmarks, and covers the core fix of using bundle IDs for macOS focus restoration.
Linked Issues check ✅ Passed The PR successfully addresses issue #699 by capturing bundle identifiers alongside process names and preferring bundle-id activation on macOS, directly fixing the Electron launch bug when checking test results.
Out of Scope Changes check ✅ Passed All changes are scoped to the focus nudge module and directly support fixing the macOS Electron launch issue. The refactoring to use _FrontmostAppInfo is necessary infrastructure for capturing bundle IDs across platforms.
Docstring Coverage ✅ Passed Docstring coverage is 92.86% which is sufficient. The required threshold is 80.00%.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Contributor

@sourcery-ai sourcery-ai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey - I've found 2 issues, and left some high level feedback:

  • When parsing the procName|bundleID AppleScript output in _get_frontmost_app_macos, consider using a delimiter that cannot appear in app names (or escaping) to avoid edge cases where a process name might contain | and break the split logic.
  • In _focus_app_macos, when bundle ID activation fails, it could be helpful to log result.stdout/result.stderr at debug level along with the bundle ID to make diagnosing future activation failures easier.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- When parsing the `procName|bundleID` AppleScript output in `_get_frontmost_app_macos`, consider using a delimiter that cannot appear in app names (or escaping) to avoid edge cases where a process name might contain `|` and break the split logic.
- In `_focus_app_macos`, when bundle ID activation fails, it could be helpful to log `result.stdout`/`result.stderr` at debug level along with the bundle ID to make diagnosing future activation failures easier.

## Individual Comments

### Comment 1
<location> `Server/src/utils/focus_nudge.py:157-162` </location>
<code_context>
         )
         if result.returncode == 0:
-            return result.stdout.strip()
+            output = result.stdout.strip()
+            parts = output.split("|", 1)
+            name = parts[0]
+            bundle_id = parts[1] if len(parts) > 1 and parts[1] else None
</code_context>

<issue_to_address>
**suggestion:** Handle 'missing value' bundle identifier explicitly to avoid using it as a real bundle_id

For some macOS processes, the front process bundle identifier can be the literal string `"missing value"`. In that case `parts[1]` is truthy, so `bundle_id` becomes `"missing value"` and you end up calling `tell application id "missing value"`, which will always fail. Consider normalizing this case (e.g., mapping `"missing value"` or similar placeholder values to `None`) so the code skips the bundle-id path and uses the name-based fallback instead.

```suggestion
        if result.returncode == 0:
            output = result.stdout.strip()
            parts = output.split("|", 1)
            name = parts[0]
            bundle_id: str | None = None
            if len(parts) > 1:
                raw_bundle_id = parts[1].strip()
                # Some processes report the literal string "missing value" as a bundle ID;
                # treat this as an absent bundle identifier so we fall back to name-based handling.
                if raw_bundle_id and raw_bundle_id.lower() != "missing value":
                    bundle_id = raw_bundle_id
            return _FrontmostAppInfo(name=name, bundle_id=bundle_id)
```
</issue_to_address>

### Comment 2
<location> `Server/src/utils/focus_nudge.py:303-305` </location>
<code_context>
+            # For non-Unity apps, prefer bundle_id to avoid the Electron bug:
+            # VS Code's process name is "Electron", and `tell application "Electron"`
+            # can launch a standalone Electron instance instead of returning to VS Code.
+            if bundle_id:
+                escaped_bundle_id = bundle_id.replace('"', '\\"')
+                result = subprocess.run(
+                    ["osascript", "-e", f'tell application id "{escaped_bundle_id}" to activate'],
+                    capture_output=True,
+                    text=True,
+                    timeout=5,
+                )
+                if result.returncode == 0:
+                    return True
+                logger.debug(f"Bundle ID activation failed for {bundle_id}, falling back to name")
</code_context>

<issue_to_address>
**suggestion:** Log AppleScript stderr when bundle_id activation fails to aid debugging

Since we already capture `stderr`, consider logging `result.stderr` at debug level when bundle-id activation fails. That would preserve current behavior while greatly improving diagnosability of AppleScript/permission issues.

```suggestion
                if result.returncode == 0:
                    return True
                logger.debug(f"Bundle ID activation failed for {bundle_id}, falling back to name")
                if result.stderr:
                    logger.debug(
                        "AppleScript stderr for bundle ID %s activation: %s",
                        bundle_id,
                        result.stderr.strip(),
                    )
```
</issue_to_address>

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Nitpick comments (1)
Server/src/utils/focus_nudge.py (1)

592-596: Redundant guard — original_app is always non-None and never "Unity" at this point.

original_app is guaranteed non-None (early return at lines 557–559). original_app.name == "Unity" is also impossible here because line 562 already returns False when "Unity" in original_app.name. The entire condition is dead code.

♻️ Proposed cleanup
-    if original_app and original_app.name != "Unity":
+    if original_app.name != "Unity":  # always True; kept for explicitness
         if _focus_app(original_app):

Or simply remove the check entirely if desired:

-    if original_app and original_app.name != "Unity":
-        if _focus_app(original_app):
-            logger.info(f"Returned focus to {original_app} after {focus_duration_s:.1f}s Unity focus")
-        else:
-            logger.warning(f"Failed to return focus to {original_app}")
+    if _focus_app(original_app):
+        logger.info(f"Returned focus to {original_app} after {focus_duration_s:.1f}s Unity focus")
+    else:
+        logger.warning(f"Failed to return focus to {original_app}")
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@Server/src/utils/focus_nudge.py` around lines 592 - 596, The condition
checking "if original_app and original_app.name != 'Unity'" is redundant because
original_app is already guaranteed non-None and not Unity; remove that guard and
directly call _focus_app(original_app) and log using logger.info/logger.warning
with focus_duration_s and original_app as before (i.e., replace the entire outer
if with a direct call to _focus_app(original_app) and the subsequent logging
branches referencing focus_duration_s, _focus_app, and logger).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@Server/src/utils/focus_nudge.py`:
- Around line 146-162: The AppleScript can return `missing value` for `bundle
identifier` which causes osascript to error before Python sees output; update
the AppleScript string in _get_frontmost_app_macos so it guards/coerces bundle
identifier to text (e.g., check `if bundle identifier of frontProc is missing
value then set bundleID to "" else set bundleID to bundle identifier of
frontProc` or use a try/coerce) so osascript always returns a string
"procName|bundleID"; keep the Python parsing that converts empty bundleID to
None and return _FrontmostAppInfo(name=name, bundle_id=bundle_id).
- Around line 295-298: The AppleScript string escaping in focus_nudge.py is
incorrect and Ruff S603/S607 are false positives; change the Python-style escape
(\" ) to AppleScript escaping by replacing any internal double-quote with two
double-quotes ("" ) when building escaped_bundle_id and escaped_app_name, and
add a local linter suppression (e.g., # noqa: S603 S607) on the subprocess.run
calls that invoke osascript since they pass an argv list (not shell=True) and
bundle_id/app_name come from the OS; update the code paths that set
escaped_bundle_id and escaped_app_name and annotate the subprocess.run lines
that call osascript to suppress the warning.

---

Nitpick comments:
In `@Server/src/utils/focus_nudge.py`:
- Around line 592-596: The condition checking "if original_app and
original_app.name != 'Unity'" is redundant because original_app is already
guaranteed non-None and not Unity; remove that guard and directly call
_focus_app(original_app) and log using logger.info/logger.warning with
focus_duration_s and original_app as before (i.e., replace the entire outer if
with a direct call to _focus_app(original_app) and the subsequent logging
branches referencing focus_duration_s, _focus_app, and logger).

…g, improve logging

- Guard AppleScript against `missing value` bundle identifier that would crash
  osascript and silently disable the entire nudge cycle (CodeRabbit)
- Also filter "missing value" string on the Python side as belt-and-suspenders
  (Sourcery)
- Fix AppleScript string escaping: use "" (AppleScript convention) not \"
  (Python convention) for both bundle_id and app_name (CodeRabbit)
- Log AppleScript stderr when bundle_id activation fails (Sourcery)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (2)
Server/src/utils/focus_nudge.py (2)

279-285: Pre-existing: bundle identifier not guarded against missing value in the Unity PID activation path — inconsistent with the defensive fix introduced elsewhere in this PR.

Line 280:

set bundleID to bundle identifier of targetProc

If bundle identifier returns missing value (unlikely for Unity, but possible for a stripped or unsigned build), tell application id bundleID to activate on line 284 raises an AppleScript runtime error, subprocess.run returns non-zero, and _focus_app_macos returns False — silently failing to nudge Unity.

The same pattern was fixed in _get_frontmost_app_macos (lines 150–153). Applying the same guard here for consistency:

♻️ Proposed fix — guard bundleID against `missing value`
 tell application "System Events"
     set targetProc to first process whose unix id is {pid}
     set frontmost of targetProc to true
 
     -- Get bundle identifier to activate the app properly
-    set bundleID to bundle identifier of targetProc
+    set bundleID to ""
+    try
+        set bID to bundle identifier of targetProc
+        if bID is not missing value then set bundleID to bID
+    end try
 end tell
 
--- Activate using bundle identifier (ensures Unity wakes up and starts processing)
-tell application id bundleID to activate
+-- Activate: prefer bundle ID, fall back to name
+if bundleID is not "" then
+    tell application id bundleID to activate
+else
+    tell application "Unity" to activate
+end if
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@Server/src/utils/focus_nudge.py` around lines 279 - 285, In _focus_app_macos,
guard the AppleScript result for bundleID (set bundleID to bundle identifier of
targetProc) against returning 'missing value' just like _get_frontmost_app_macos
does: after retrieving bundleID, check if it's missing/None/empty and handle by
skipping the "tell application id bundleID to activate" step (and return False
or fall back) so we don't call AppleScript with a missing bundle identifier;
reference the variables bundleID and targetProc and the function
_focus_app_macos when making this change.

605-609: Redundant if original_app guard.

At this point original_app is guaranteed non-None — the early return at lines 570–572 exits the function if it is None. The if original_app condition is always True here.

🧹 Proposed cleanup
-    if original_app and original_app.name != "Unity":
+    if original_app.name != "Unity":
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@Server/src/utils/focus_nudge.py` around lines 605 - 609, The redundant guard
"if original_app" is unnecessary because original_app is guaranteed non-None
earlier; remove that condition and directly check the app name and call
_focus_app. Update the block to: if original_app.name != "Unity": if
_focus_app(original_app): logger.info(...) else: logger.warning(...),
referencing original_app, _focus_app, and logger to locate and change the code.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Duplicate comments:
In `@Server/src/utils/focus_nudge.py`:
- Around line 144-156: Add Ruff suppressions for the false-positive
shell-injection warnings on the osascript subprocess calls: annotate the
subprocess invocations that pass ["osascript", ...] (the call that builds and
runs the AppleScript returning procName & "|" & bundleID and the other osascript
calls referenced around the later occurrences) with "# noqa: S603,S607". Keep
the list-style invocation (shell=False) and do not change logic; the noqa should
be placed on the lines with the subprocess call expressions so Ruff ignores
S603/S607 for those specific osascript usages (bundleID/bundle_id is sourced
from System Events and _is_available() already checks osascript on PATH).

---

Nitpick comments:
In `@Server/src/utils/focus_nudge.py`:
- Around line 279-285: In _focus_app_macos, guard the AppleScript result for
bundleID (set bundleID to bundle identifier of targetProc) against returning
'missing value' just like _get_frontmost_app_macos does: after retrieving
bundleID, check if it's missing/None/empty and handle by skipping the "tell
application id bundleID to activate" step (and return False or fall back) so we
don't call AppleScript with a missing bundle identifier; reference the variables
bundleID and targetProc and the function _focus_app_macos when making this
change.
- Around line 605-609: The redundant guard "if original_app" is unnecessary
because original_app is guaranteed non-None earlier; remove that condition and
directly check the app name and call _focus_app. Update the block to: if
original_app.name != "Unity": if _focus_app(original_app): logger.info(...)
else: logger.warning(...), referencing original_app, _focus_app, and logger to
locate and change the code.

@dsarno dsarno merged commit 9493c5f into CoplayDev:beta Feb 19, 2026
2 checks passed
msanatan pushed a commit to msanatan/unity-mcp that referenced this pull request Feb 25, 2026
…cOS (CoplayDev#783)

* Fix focus nudge launching Electron instead of restoring VS Code on macOS

The focus restore used process name (e.g. "Electron") which caused macOS
to launch a standalone Electron instance instead of returning to VS Code.
Now captures bundle identifier and uses `tell application id` for precise
activation, falling back to name-based activation if bundle ID fails.

Fixes CoplayDev#699

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* Address review feedback: guard AppleScript missing value, fix escaping, improve logging

- Guard AppleScript against `missing value` bundle identifier that would crash
  osascript and silently disable the entire nudge cycle (CodeRabbit)
- Also filter "missing value" string on the Python side as belt-and-suspenders
  (Sourcery)
- Fix AppleScript string escaping: use "" (AppleScript convention) not \"
  (Python convention) for both bundle_id and app_name (CodeRabbit)
- Log AppleScript stderr when bundle_id activation fails (Sourcery)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
msanatan pushed a commit to msanatan/unity-mcp that referenced this pull request Feb 25, 2026
…cOS (CoplayDev#783)

* Fix focus nudge launching Electron instead of restoring VS Code on macOS

The focus restore used process name (e.g. "Electron") which caused macOS
to launch a standalone Electron instance instead of returning to VS Code.
Now captures bundle identifier and uses `tell application id` for precise
activation, falling back to name-based activation if bundle ID fails.

Fixes CoplayDev#699

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* Address review feedback: guard AppleScript missing value, fix escaping, improve logging

- Guard AppleScript against `missing value` bundle identifier that would crash
  osascript and silently disable the entire nudge cycle (CodeRabbit)
- Also filter "missing value" string on the Python side as belt-and-suspenders
  (Sourcery)
- Fix AppleScript string escaping: use "" (AppleScript convention) not \"
  (Python convention) for both bundle_id and app_name (CodeRabbit)
- Log AppleScript stderr when bundle_id activation fails (Sourcery)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug] Get Test Job launching Electron

1 participant