Skip to content

fix: repair dead camera CLI, add run_tests clear_stuck (#1272), refresh uv.lock - #1293

Merged
Scriptwonder merged 5 commits into
CoplayDev:betafrom
Scriptwonder:fix/server-cli-run-tests-and-camera
Jul 28, 2026
Merged

fix: repair dead camera CLI, add run_tests clear_stuck (#1272), refresh uv.lock#1293
Scriptwonder merged 5 commits into
CoplayDev:betafrom
Scriptwonder:fix/server-cli-run-tests-and-camera

Conversation

@Scriptwonder

@Scriptwonder Scriptwonder commented Jul 28, 2026

Copy link
Copy Markdown
Collaborator

Three small, independent Server/ fixes, kept as three separate commits so they can be reviewed — or dropped — individually.


1. fix: the camera CLI is completely dead at beta HEAD

run_command's signature is run_command(tool, params, config). All 18 call sites in Server/src/cli/commands/camera.py pass run_command(config, "manage_camera", params) — arguments inverted. Every single unity-mcp camera subcommand fails.

This was not caught because Server/tests/test_cli.py asserted against call_args[0][2], which encoded the bug rather than detecting it. The test now asserts the tool name at [0][0] and params at [0][1], so the inversion cannot come back silently.

Found during triage, not attached to an existing issue.

2. feat: clear_stuck escape hatch for run_tests (fixes #1272)

A test job orphaned by a domain reload leaves TestRunStatus pinned with a CurrentJobId that blocks every subsequent run, with no client-side way to release it.

Adds clear_stuck to the run_tests MCP tool and --clear-stuck to the editor CLI, for parity.

Both short-circuit ahead of the init_timeout validation and preflight. That ordering is deliberate and is the whole point: preflight's requires_no_tests=True gate would otherwise reject the very call that exists to clear the orphaned job blocking it.

Reproduced live — an orphan showed TestRunStatus.IsRunning = False with CurrentJobId still set, and ClearStuckJob() returned cleared=True.

Four tests cover it: the flag is forwarded alone as {"clear_stuck": True}, preflight is bypassed (monkeypatched to raise), an invalid init_timeout is ignored on the clear path, and the normal path still preflights.

3. chore: refresh uv.lock

The lockfile pinned mcpforunityserver = 10.0.0 while pyproject.toml declared 10.1.0, and no workflow runs uv lock. Every contributor's first uv run therefore dirtied their working tree with an unrelated lockfile diff.

Worth considering a CI check so this cannot drift again.


Tests

cd Server && uv run pytest tests/1334 passed, 3 skipped.

No Unity-side changes in this PR.

Summary by CodeRabbit

  • New Features
    • Added a --clear-stuck option to the editor test command to clear an orphaned running Unity test job instead of starting a new run.
  • Bug Fixes
    • Improved camera CLI command dispatch to use the correct argument ordering and consistent output formatting across all camera operations.
  • Tests
    • Added integration coverage for clear_stuck to verify Unity requests, preflight bypass, and standard behavior when the option is not provided.
  • Documentation
    • Updated the run_tests tool reference to document the new clear_stuck parameter.

All 18 call sites passed run_command(config, "manage_camera", params) while
the signature is run_command(tool, params, config), so the entire
`unity-mcp camera` command group was dead at beta HEAD.

test_cli.py asserted against call_args[0][2], which encoded the bug rather
than catching it; it now asserts the tool name at [0][0] and params at [0][1].
A test job orphaned by a domain reload leaves TestRunStatus pinned with a
CurrentJobId that blocks every subsequent run, and there was no way to clear
it from the client side.

Add clear_stuck to the run_tests MCP tool and --clear-stuck to the editor CLI.
Both short-circuit ahead of the init_timeout validation and preflight, because
neither applies to clearing and preflight's requires_no_tests gate would reject
the very call that exists to release it.
The lockfile pinned mcpforunityserver 10.0.0 while pyproject.toml declared
10.1.0, and no workflow runs `uv lock`, so every contributor's first `uv run`
dirtied their working tree.
Copilot AI review requested due to automatic review settings July 28, 2026 16:19
@coderabbitai

coderabbitai Bot commented Jul 28, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 0d6a5c65-bb27-4208-b024-b51fdec417c9

📥 Commits

Reviewing files that changed from the base of the PR and between 172d3e2 and e2aacdf.

📒 Files selected for processing (3)
  • Server/src/cli/commands/camera.py
  • Server/tests/test_cli.py
  • website/docs/reference/tools/testing/run_tests.md
🚧 Files skipped from review as they are similar to previous changes (2)
  • Server/src/cli/commands/camera.py
  • Server/tests/test_cli.py

📝 Walkthrough

Walkthrough

Camera CLI commands now use the updated run_command signature and output formatting. The editor tests command adds --clear-stuck, and the test service forwards this request directly to Unity before normal validation and preflight.

Changes

Camera command dispatch

Layer / File(s) Summary
Update camera command dispatch
Server/src/cli/commands/camera.py, Server/tests/test_cli.py
Camera queries, controls, extensions, screenshots, and related assertions use command-name-first dispatch and explicit formatted output.

Stuck test recovery

Layer / File(s) Summary
Expose clear-stuck CLI operation
Server/src/cli/commands/editor.py
The editor tests command accepts --clear-stuck, forwards it to run_tests, formats the result, and exits without starting or polling a test run.
Forward and validate stuck-job clearing
Server/src/services/tools/run_tests.py, Server/tests/integration/test_run_tests_async.py, website/docs/reference/tools/testing/run_tests.md
run_tests sends {"clear_stuck": True} to Unity before timeout validation and preflight; tests cover forwarding, short-circuiting, invalid timeout handling, and the default preflight path, while documentation lists the new parameter.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Sequence Diagram(s)

sequenceDiagram
  participant CLI
  participant run_tests
  participant Unity
  CLI->>run_tests: request clear_stuck=True
  run_tests->>Unity: send run_tests with clear_stuck=True
  Unity-->>run_tests: cleared-job response
  run_tests-->>CLI: formatted result
Loading

Possibly related PRs

Suggested labels: bug

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Out of Scope Changes check ⚠️ Warning Camera CLI fixes and uv.lock refresh are unrelated to #1272's clear_stuck recovery objective. Split the camera CLI and lockfile updates into separate PRs, or add linked issues that explicitly cover those changes.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title matches the PR's main changes: camera CLI fix, run_tests clear_stuck, and lockfile refresh.
Description check ✅ Passed The description is detailed and covers the changes, tests, and related issue, though not in the exact template.
Linked Issues check ✅ Passed The PR exposes clear_stuck through run_tests and the editor CLI, matching #1272's recovery objective.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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.

@codecov-commenter

codecov-commenter commented Jul 28, 2026

Copy link
Copy Markdown

⚠️ Please install the 'codecov app svg image' to ensure uploads and comments are reliably processed by Codecov.

Codecov Report

❌ Patch coverage is 25.00000% with 36 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
Server/src/cli/commands/camera.py 11.11% 32 Missing ⚠️
Server/src/cli/commands/editor.py 50.00% 3 Missing ⚠️
Server/src/services/tools/run_tests.py 83.33% 1 Missing ⚠️

📢 Thoughts on this report? Let us know!

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

This PR delivers three independent fixes in the Python Server/ portion of MCP for Unity: (1) repairs broken camera CLI invocation of run_command, (2) exposes a clear_stuck escape hatch for run_tests to unblock orphaned test jobs (issue #1272), and (3) refreshes uv.lock to match the declared server version.

Changes:

  • Fix unity-mcp camera ... subcommands by correcting run_command(command_type, params, config) argument ordering and strengthening the camera CLI test assertion.
  • Add clear_stuck support to the run_tests MCP tool and the editor CLI (unity-mcp editor tests --clear-stuck), with integration tests verifying forwarding + preflight bypass behavior.
  • Update Server/uv.lock to align the locked mcpforunityserver version with pyproject.toml.

Reviewed changes

Copilot reviewed 5 out of 6 changed files in this pull request and generated 1 comment.

Show a summary per file
File Description
Server/uv.lock Updates locked package version for mcpforunityserver to 10.1.0.
Server/tests/test_cli.py Adjusts camera CLI test assertions to validate the correct run_command argument order.
Server/tests/integration/test_run_tests_async.py Adds async integration tests covering run_tests(clear_stuck=True) forwarding and preflight bypass.
Server/src/services/tools/run_tests.py Adds clear_stuck parameter with deliberate short-circuit before validation/preflight.
Server/src/cli/commands/editor.py Adds --clear-stuck flag to editor tests CLI command with early-return forwarding.
Server/src/cli/commands/camera.py Fixes run_command argument order for all camera CLI subcommands.
Comments suppressed due to low confidence (17)

Server/src/cli/commands/camera.py:69

  • format_output(...) returns a string but this command doesn't print it, so unity-mcp camera list produces no output. Also format_output expects a format type string; passing CLIConfig ignores config.format.
    result = run_command("manage_camera", {"action": "list_cameras"}, config)
    format_output(result, config)

Server/src/cli/commands/camera.py:83

  • format_output(...) returns a string but this command doesn't print it, so unity-mcp camera brain-status produces no output. Also format_output expects a format type string; passing CLIConfig ignores config.format.
    result = run_command("manage_camera", {"action": "get_brain_status"}, config)
    format_output(result, config)

Server/src/cli/commands/camera.py:129

  • This command formats the response but never prints it (format_output returns a string), so users see no output. It also passes CLIConfig as the format_type argument, which ignores config.format.
    result = run_command("manage_camera", params, config)
    format_output(result, config)

Server/src/cli/commands/camera.py:159

  • This command formats the response but never prints it (format_output returns a string), so users see no output. It also passes CLIConfig as the format_type argument, which ignores config.format.
    result = run_command("manage_camera", params, config)
    format_output(result, config)

Server/src/cli/commands/camera.py:193

  • This command formats the response but never prints it (format_output returns a string), so users see no output. It also passes CLIConfig as the format_type argument, which ignores config.format.
    result = run_command("manage_camera", params, config)
    format_output(result, config)

Server/src/cli/commands/camera.py:232

  • This command formats the response but never prints it (format_output returns a string), so users see no output. It also passes CLIConfig as the format_type argument, which ignores config.format.
    result = run_command("manage_camera", params, config)
    format_output(result, config)

Server/src/cli/commands/camera.py:255

  • This command formats the response but never prints it (format_output returns a string), so users see no output. It also passes CLIConfig as the format_type argument, which ignores config.format.
    result = run_command("manage_camera", params, config)
    format_output(result, config)

Server/src/cli/commands/camera.py:290

  • This command formats the response but never prints it (format_output returns a string), so users see no output. It also passes CLIConfig as the format_type argument, which ignores config.format.
    result = run_command("manage_camera", params, config)
    format_output(result, config)

Server/src/cli/commands/camera.py:320

  • This command formats the response but never prints it (format_output returns a string), so users see no output. It also passes CLIConfig as the format_type argument, which ignores config.format.
    result = run_command("manage_camera", params, config)
    format_output(result, config)

Server/src/cli/commands/camera.py:350

  • This command formats the response but never prints it (format_output returns a string), so users see no output. It also passes CLIConfig as the format_type argument, which ignores config.format.
    result = run_command("manage_camera", params, config)
    format_output(result, config)

Server/src/cli/commands/camera.py:383

  • This command formats the response but never prints it (format_output returns a string), so users see no output. It also passes CLIConfig as the format_type argument, which ignores config.format.
    result = run_command("manage_camera", params, config)
    format_output(result, config)

Server/src/cli/commands/camera.py:406

  • This command formats the response but never prints it (format_output returns a string), so users see no output. It also passes CLIConfig as the format_type argument, which ignores config.format.
    result = run_command("manage_camera", params, config)
    format_output(result, config)

Server/src/cli/commands/camera.py:436

  • This command formats the response but never prints it (format_output returns a string), so users see no output. It also passes CLIConfig as the format_type argument, which ignores config.format.
    result = run_command("manage_camera", params, config)
    format_output(result, config)

Server/src/cli/commands/camera.py:457

  • This command formats the response but never prints it (format_output returns a string), so users see no output. It also passes CLIConfig as the format_type argument, which ignores config.format.
    result = run_command("manage_camera", params, config)
    format_output(result, config)

Server/src/cli/commands/camera.py:471

  • format_output(...) returns a string but this command doesn't print it, so unity-mcp camera release produces no output. Also format_output expects a format type string; passing CLIConfig ignores config.format.
    result = run_command("manage_camera", {"action": "release_override"}, config)
    format_output(result, config)

Server/src/cli/commands/camera.py:527

  • This command formats the response but never prints it (format_output returns a string), so users see no output. It also passes CLIConfig as the format_type argument, which ignores config.format.
    result = run_command("manage_camera", params, config)
    format_output(result, config)

Server/src/cli/commands/camera.py:554

  • This command formats the response but never prints it (format_output returns a string), so users see no output. It also passes CLIConfig as the format_type argument, which ignores config.format.
    result = run_command("manage_camera", params, config)
    format_output(result, config)

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread Server/src/cli/commands/camera.py Outdated
Comment on lines 54 to 55
result = run_command("manage_camera", {"action": "ping"}, config)
format_output(result, config)
Generated by tools/generate_docs_reference.py; the "Check docs reference is
fresh" CI job flagged testing/run_tests.md as stale after clear_stuck was added.
Follow-up to the inverted-argument fix in this branch: repairing the
run_command call order was necessary but not sufficient, and the group was
still effectively dead.

format_output(data, format_type: str = "text") returns a string. All 18 call
sites called format_output(result, config) and dropped the return value, so
every `unity-mcp camera` subcommand printed nothing at all. Passing the whole
CLIConfig where a format string was expected also meant the branch always fell
through to text, silently ignoring --format/UNITY_MCP_FORMAT.

Use click.echo(format_output(result, config.format)), matching every other
command module.

Adds two regression tests: one asserting the group emits non-empty output, one
asserting --format json yields parseable JSON. Both fail without this change.

Reported by Copilot on CoplayDev#1293.
@Scriptwonder
Scriptwonder merged commit 5496c12 into CoplayDev:beta Jul 28, 2026
@Scriptwonder
Scriptwonder deleted the fix/server-cli-run-tests-and-camera branch July 28, 2026 18:40
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]: Orphaned test job after domain reload permanently blocks run_tests; clear_stuck is not exposed

3 participants