153 Commits

Author SHA1 Message Date
Shutong Wu 07e8680df9 Merge pull request #1298 from asavs/fix/gameobject-create-component-properties
fix: make component properties reachable on manage_gameobject create
2026-08-02 16:25:25 -04:00
Shutong Wu 32428e820e Merge pull request #1302 from KamilDev/fix/resource-uri-prose
fix(server): address resources by URI in agent-facing prose
2026-08-02 12:21:12 -04:00
KamilDev 69267c536c fix(server): address resources by URI in agent-facing prose
A resource's name and its URI are deliberately different (`editor_state` vs
`mcpforunity://editor/state`), and the URI scheme is not derivable from the
name -- most resources are `category/thing` but several are flat
(`mcpforunity://instances`, `mcpforunity://menu-items`, `mcpforunity://tests`).

Several agent-facing strings still named resources without their URI, so an
agent following them built `mcpforunity://editor_state` and got a 404:

- server instructions listed resources by bare name and told the reader to
  "poll the `editor_state` resource's `isCompiling` field" (that field path is
  also wrong -- payloads are wrapped, so it is `data.compilation.is_compiling`)
- `refresh_unity`'s `wait_for_ready` parameter description referred to
  `editor_state.advice.ready_for_tools`
- the hint Unity returns in the `refresh_unity` result said "poll editor_state
  until ready_for_tools is true"

#1244 added a warning that names and URIs are not interchangeable, but left the
strings that trigger the mistake unchanged. Spell every resource reference as a
full URI instead, and correct the field paths while here.

Adds a regression test asserting that no agent-facing prose -- server
instructions, resource descriptions, tool and parameter descriptions, and
multi-word string literals under MCPForUnity/Editor -- mentions a resource by
its snake_case name without also giving that resource's URI.
2026-08-01 13:23:23 +10:00
Shutong Wu 835bfcdd06 fix: stop 34 tools forcing an approval prompt on every call (#1288)
MCP clients gate a tool behind human approval unless it is read-only or
explicitly non-destructive, and destructiveHint defaults to true when omitted.
PR #480 set only `title=` on read_console, manage_editor and set_active_instance
despite its description claiming otherwise, so the spec default supplied
destructiveHint: true and nobody noticed.

Registering all 48 tools and dumping tools/list showed 34 of them serializing as
neither read-only nor explicitly non-destructive. find_gameobjects emitted
`annotations: null` outright.

State the hints explicitly across 10 modules. Four genuinely safe tools become
destructiveHint=False; the read-only set gets explicit hints instead of relying
on defaults; manage_editor and manage_components get explicit destructiveHint=True,
which changes no behaviour but stops them depending on the implicit default that
caused this. 34 gated -> 30, and the remaining 30 all write to the project.

find_gameobjects is deliberately not readOnlyHint=True: it calls
preflight(refresh_if_dirty=True), which can trigger a domain reload, and a
read-only promise would let a client do that unattended.

Add test_tool_annotations.py as the durable guard - it requires every tool to
state title and destructiveHint, and pins the auto-approvable set so a future
edit cannot silently flip one. Verified it fails by replaying the #480 regression.

test_tool_test_symmetry.py now excludes registry-wide guards from counting as
per-tool coverage, so one such file cannot satisfy the coverage guard for every
tool it happens to mention.

Does not fix the whole report: manage_asset(action="search") stays gated because
manage_asset can also delete. A read-only find_assets tool is the follow-up.
2026-07-29 00:18:06 -04:00
asavschaeffer 503d938b4a fix: make manage_gameobject component properties reachable on create
Fixes #1297. At action:"create", component_properties was accepted and
coerced by the C# dispatcher (ManageGameObject.cs) but only ever consumed
by the "modify" handler, so it silently did nothing. Meanwhile the shape
"create" already reads directly out of each componentsToAdd entry
({typeName, properties}) was rejected before it reached Unity, because the
Python schema typed components_to_add as list[str].

- GameObjectComponentHelpers.cs: factor the componentProperties loop +
  error aggregation out of GameObjectModify.cs into a shared
  ApplyComponentProperties helper, so both actions apply it identically.
- GameObjectCreate.cs: call the new helper after components are added,
  destroying the partially-created object and returning the error if any
  property fails to set (matching how component-add failures are handled).
- GameObjectModify.cs: switch to the shared helper (behavior-preserving
  refactor, no functional change on the modify path).
- manage_gameobject.py: widen components_to_add to accept
  {"typeName": ..., "properties": {...}} objects alongside plain strings,
  matching what GameObjectCreate.cs already reads.
- Regenerated website/docs/reference/tools/core/manage_gameobject.md via
  tools/generate_docs_reference.py for the updated parameter docs.

Tested: Server/tests/test_manage_gameobject.py exercises the Python
contract end-to-end, including a real fastmcp/pydantic schema validation
run of the issue's exact repro payloads (confirmed the pre-fix
ValidationError reproduces on the unmodified file, and is gone after).
Added TestProjects/UnityMCPTests/Assets/Tests/EditMode/Tools/
ManageGameObjectCreateTests.cs coverage for the C# side, but this was not
run against a live Editor.
2026-07-28 15:59:38 -07:00
Shutong Wu 2b2ca8a6f3 feat: add a clear_stuck escape hatch to run_tests (#1272)
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.
2026-07-28 12:05:53 -04:00
Shutong Wu ea3ce5a7e0 chore(asset-gen): "Asset Gen" tool-group label + regenerate reference docs
- McpToolsSection: add the asset_gen -> "Asset Gen" group display name so
  the tool-group tab no longer falls back to the raw "Asset_gen".
- Update the asset_gen group blurb (registry + CLI) to include audio gen.
- Regenerate the tool reference docs from the Python registry: add the
  missing generate_audio.md and refresh the asset_gen landscape/index.

Claude-Session: https://claude.ai/code/session_015KYy51gwBuhDuLZXXoqc98
2026-07-13 00:29:58 -07:00
Shutong Wu 8c0a5dfe0d feat(asset-gen): model catalog + generate_audio tool + default-model wiring
Phases 2-3. Adds a curated AssetGenModelCatalog (image/3D/audio models with
price/duration/use-case metadata; defaults reference the adapter constants so the
panel default equals what an omitted model resolves to). Adds the generate_audio
MCP tool + CLI, threads a per-(kind,provider) selected-model pref so a GUI choice
becomes the default generate_* uses when no model is passed, and makes
Tripo/Meshy consume req.Model. Per-provider prefs (not per-type) so disjoint model
lists never clobber. Compiles on 2021.3 floor; Python + adapter/catalog tests green.

Claude-Session: https://claude.ai/code/session_01GCxmdd4qo7MG6J4M6WcT9Y
2026-07-12 11:20:16 -07:00
Shutong Wu 7ffc8302ee docs: distinguish omitted animation_type from explicit 'none'
CodeRabbit follow-up on #1262: the API-level default is omitting the
parameter (nothing crosses the wire); passing 'none' explicitly maps to
the same no-rig import. Say "omitted or 'none'" instead of calling
'none' the default, and regenerate the reference page.

Claude-Session: https://claude.ai/code/session_01Cya1SZmg7CJgJS61nhjLH4
2026-07-12 00:25:03 -07:00
Shutong Wu 283e393f90 docs: address PR #1262 review feedback and regenerate tool reference
Review responses (CodeRabbit + Copilot):
- Document the 'legacy' animation_type value in the C# XML summary, MCP tool
  description, param help, and CLI help (Copilot x4).
- SKILL.md: drop multi-material zones as a GLB-only trigger (both formats keep
  slots), define out_glb in the glTF branch example, document the full
  animation_type contract, probe both Principled emission socket names
  ('Emission Color' 4.x / 'Emission' 3.x), keep use_active_scene=True in the
  Notes GLB example, and distinguish FBX vertex-color data transfer from URP
  Lit shader display.
- bridge-fidelity.md: make export_apply conditional (static-only; skinned/
  shape-key meshes need False) and document export_animations' active/NLA-
  stashed semantics.

Regenerate website/docs/reference for the updated tool description — fixes the
"Check docs reference is fresh" CI failure ("differs: asset_gen/import_model_file.md").

Claude-Session: https://claude.ai/code/session_01Cya1SZmg7CJgJS61nhjLH4
2026-07-12 00:15:47 -07:00
Shutong Wu 0eee1568d8 feat(asset-gen): add animation_type rig mode to import_model_file
A rigged/animated FBX imported through import_model_file always arrived
with zero AnimationClips because the import pipeline hard-coded
ModelImporterAnimationType.None. Thread an optional animation_type param
(none|generic|humanoid|legacy) through the MCP tool, the CLI command, and
the C# pipeline so callers can surface a model's clips; the default stays
None, so existing imports are unchanged. glTF/GLB ignores the knob
(glTFast imports animation itself).

Also fold the tested Blender-handoff findings into the blender-to-unity
skill: GLB-vs-FBX fidelity guidance (with the new
references/bridge-fidelity.md matrix, force-added since .claude is
gitignored), FBX emission restoration steps, and the animation_type knob.
Sync uv.lock with the pyproject 10.0.0 version already on beta.

Claude-Session: https://claude.ai/code/session_01Cya1SZmg7CJgJS61nhjLH4
2026-07-11 22:59:48 -07:00
Shutong Wu 18c31a6977 fix(middleware): delegate active-instance persistence to FastMCP session state (#1023)
UnityInstanceMiddleware previously kept its own dict (`_active_by_key`) keyed
by `client_id | user:{user_id} | "global"`. The MCP protocol's identity is
session-based, not client-based:

  - Streamable HTTP uses `Mcp-Session-Id` per the 2025-11-25 spec
  - stdio is intrinsically 1:1 (one subprocess = one session)
  - `client_id` is the peer-declared Implementation name, which is not
    unique — two Cursor instances both report `"cursor"` and collide

The `"global"` fallback compounded this: anonymous clients all collapsed onto
one record, so client A's `set_active_instance` retargeted client B (#1023).

FastMCP already exposes session-isolated state via `ctx.set_state` /
`ctx.get_state`, prefixed by `ctx.session_id` (verified in fastmcp 3.x
`server/context.py:1181-1238` — reads `mcp-session-id` header on HTTP,
generates a per-session UUID on stdio, caches on the session object).
Switching to it removes a whole concurrency surface and closes the bug class
by construction.

Changes:
- Replace `_active_by_key + _lock + get_session_key` with two-liner
  set/get/clear_active_instance backed by `ctx.set_state` under
  `mcpforunity.active_instance`.
- `set_active_instance` tool now returns `session_id` (the real key) instead
  of the bogus `session_key` field.
- `debug_request_context` drops `derived_key` and `all_keys_in_store`
  (no global dict to enumerate; per-session reads still report
  `active_instance` and the real `session_id`).
- Drop characterization/integration tests that pinned the removed
  `client_id → key → "global"` behaviour. Add a regression test that
  proves two ctxs with private state dicts can't read each other's
  active instance.

No protocol or wire-format change. The behavior shift is invisible to
single-client setups and removes the cross-client leak for multi-client
HTTP deployments.
2026-07-04 15:34:10 -07:00
Shutong Wu a884ada409 Clarify generate image unsupported action docs 2026-06-30 10:37:05 -07:00
Shutong Wu 2efb786042 fix(asset-gen): security hardening + provider correctness + local image_path
Security review + code review of the asset-gen feature surfaced concrete issues;
this fixes them and adds regression tests (request-shaping layer, FakeHttpTransport).

Security
- SafeZipExtractor enforces an extension allowlist; ModelImportPipeline passes an
  inert model/texture allowlist so a provider archive can't drop a .cs/.dll under
  Assets/ and have the Editor compile/load it (code execution on import).
- AssetGenJobManager refuses non-http(s) download URLs before fetching
  (file:// SSRF / local-file read into the project).

Provider correctness
- Meshy image->3D polls /openapi/v1/image-to-3d/{id} (was the v2 text URL).
- Meshy text->3D honors texture=true via the preview->refine two-phase flow.
- OpenRouter image->image attaches the reference image (content image_url part).
- fal image->image uses the /edit endpoint + image_urls array; width/height
  forwarded as image_size.
- Sketchfab search forwards categories/count/cursor/downloadable; preview doc
  corrected (returns metadata, not a base64 thumbnail).
- Job import calls AssetDatabase.Refresh() before importing a freshly written file.

Local image input (image_path)
- New LocalImage helper; image_path is read and sent inline as a base64 data URI
  for Meshy / fal / OpenRouter. Tripo rejects local images with a clear error
  (needs a hosted image_url; its upload flow is not wired).

Cleanup (no behavior change)
- Shared AssetGenPaths + ProviderHttp helpers, HttpResult.Ok, MissingKeyMessage,
  cached glTFast probe, dead-field / per-frame-alloc removal, CLI _emit.

Docs: README + manual-verification updated (image_path support; transparency is
import-flag-only; width/height fal-only).

Verified: package compiles clean; Python 1306 passed / 3 skipped. Meshy refine,
fal /edit, and image_path data-URI paths are unit-tested at the request layer
only -- live smoke per provider (real keys) still pending.

Claude-Session: https://claude.ai/code/session_015DAUrMR5UaSEzEn2wNPrEP
2026-06-28 21:30:00 -07:00
Shutong Wu 125c97dd49 docs(asset-gen): import_model_file self-contained-format caveat + skill tool-name fix
Claude-Session: https://claude.ai/code/session_01NoHk4f7N1vUFs7gu817ihm
2026-06-28 19:25:21 -07:00
Shutong Wu 6dcdda115f feat(asset-gen): import_model_file MCP tool + pass-through tests 2026-06-28 19:25:21 -07:00
Shutong Wu 48863078e2 feat(asset-gen): remove Hunyuan; update to current SOTA model defaults
Drop Hunyuan (Tencent TC3-HMAC) — high effort and not testable by the maintainer:
delete HunyuanAdapter + TencentCloud3Signer (+tests), unwire from AssetGenProviders,
SecureKeyStoreConstants, the GUI provider list, and Python/CLI/README/manual-verify docs.

Refresh model defaults to current (2026) SOTA, verified against provider docs:
- fal: fal-ai/flux/dev -> fal-ai/flux-2 (FLUX.2 dev; cheaper and higher quality)
- Tripo: v2.5-20250123 -> v3.1-20260211 (current recommended model)
- Meshy: drop deprecated art_style (errors on Meshy-6); pin ai_model=meshy-6
- OpenRouter: gemini-2.5-flash-image-preview (delisted) -> gemini-2.5-flash-image

Fix two tests that asserted the now-implemented 'meshy' provider throws (repointed to the
now-removed 'hunyuan'). They were silently wrong: the headless --full runs never executed
EditMode tests (Unity -quit exits before -runTests; compile-only). A real -runTests run
now passes 62/62 AssetGen EditMode tests; Python suite 1299 passed.

Claude-Session: https://claude.ai/code/session_01Tjpb5gYgUe2AUJuRdXr7Lv
2026-06-28 19:25:21 -07:00
Shutong Wu b7652ca6fd feat(asset-gen): Python MCP tools + CLI pass-throughs (generate_model/import_model/generate_image)
Thin key-free pass-throughs in group asset_gen mirroring the C# command names:
camelCase param mapping, None-strip, async status/job_id (manage_packages shape).
CLI group 'asset-gen' registered in cli/main.py. No key/secret param exists on any
tool; tests assert sent payloads carry no key/secret/token. 34 tests pass.

Claude-Session: https://claude.ai/code/session_01Tjpb5gYgUe2AUJuRdXr7Lv
2026-06-28 19:25:20 -07:00
Shutong Wu d6604a571e feat(asset-gen): scaffold asset_gen tool group + non-secret prefs (Phase 0)
- Register 'asset_gen' tool group (off by default, parity with vfx/animation)
- EditorPrefKeys.AssetGen.* consts (non-secret config only; keys go to secure store)
- AssetGenPrefs helper (provider/format/output-root/normalize/enabled) + EditMode tests
- Python scaffold test asserts group present and disabled by default

Claude-Session: https://claude.ai/code/session_01Tjpb5gYgUe2AUJuRdXr7Lv
2026-06-28 19:25:20 -07:00
Shutong Wu 71083d2e1b fix: tighten IsInstalled default + accept parameters=None on execute_custom_tool (PR review)
Two review nits from PR #1142.

McpClientConfiguratorBase.IsInstalled defaulted to `true`, which meant
any future configurator that derives directly from the base (without
going through JsonFile/Codex/ClaudeCli) would be treated as "detected"
by ConfigureAllDetectedClients and could end up writing config files
for apps that aren't on the machine. Default to a cheap filesystem
check via ParentDirectoryExists(GetConfigPath()); the three existing
base classes that override with the same check are harmlessly redundant
now, and CLI configurators (where GetConfigPath isn't a real path) keep
their own overrides.

execute_custom_tool declared `parameters: dict[str, Any] | None = None`
in its signature but then rejected `None` at runtime with
"parameters must be an object/dictionary". For parameter-less custom
tools the type hint and the behavior contradicted each other. Coerce
`None` to an empty dict; reject only genuinely-wrong types.
2026-05-22 19:37:32 +08:00
Shutong Wu 324c484436 Merge remote-tracking branch 'upstream/beta' into fix/auto-test-multi 2026-05-22 17:17:27 +08:00
Shutong Wu c4e583fb66 fix(server): annotate execute_custom_tool parameters as dict[str, Any] (#946)
FastMCP derives the wire schema from each tool's type annotations.
execute_custom_tool declared `parameters: dict | None`, which generates
a permissive schema some strict clients (Roo Code, certain VSCode MCP
adapters) reject during tool discovery — the tool then appears missing
even though everything else is healthy.

Switch to `dict[str, Any] | None` so the generated schema includes
proper additionalProperties bounds. The four other files cited in #946
(custom_tool_service, manage_components, manage_material, manage_texture)
were already parametrised in prior commits; execute_custom_tool was the
last remaining MCP-exposed tool with a bare `dict` annotation.
2026-05-22 13:28:25 +08:00
Warlander 0c2e275d9d Cleanup before the PR 2026-05-06 00:16:57 +02:00
Warlander e192f216a5 Allow global custom tool registration even when project-scoped tools are enabled 2026-05-06 00:04:00 +02:00
Shutong Wu 99a4687948 Merge pull request #1097 from Scriptwonder/chore/unity-version-compat-2026-04-27
Update0503
2026-05-03 20:05:24 -04:00
Shutong Wu 1b095fb301 PatchFix 2026-05-03 19:50:52 -04:00
Shutong Wu 1fba42998c Update0503
1.Add Compat based scripts revolving around UnityCompatShims.cs, that will document our current API Compatibility changes in several files.
2.Add custom screenshot folder selection
2026-05-03 18:16:10 -04:00
PaulLubos e8e3b45882 Address code review: input validation and tests
- Clamp initTimeoutMs in StartJob: negative values → 0, cap at 600s
- Python: reject init_timeout <= 0 with explicit error before calling Unity
- Add 3 C# EditMode tests for per-job InitTimeoutMs behavior
  (custom timeout, default timeout auto-fail, persist/restore)
- Add 4 Python tests for init_timeout forwarding and validation

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-29 08:29:34 +02:00
PaulLubos 8d51737f97 Add configurable init_timeout for PlayMode test initialization
PlayMode tests require entering play mode which triggers a domain reload.
On large projects this can take >15s, causing the hardcoded 15s init
timeout to auto-fail the test job before tests actually start.

This adds an `init_timeout` parameter to `run_tests` that flows through
the Python server → C# RunTests handler → TestJobManager. When set, the
per-job timeout overrides the 15s default. The value is persisted across
domain reloads via SessionState.

Changes:
- Python: Add `init_timeout` param to `run_tests()` function signature
- C# RunTests: Read `initTimeout` param and pass to `StartJob()`
- C# TestJobManager: Per-job `InitTimeoutMs` field with fallback to
  `DefaultInitializationTimeoutMs` (15s), persisted in SessionState

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-29 08:29:34 +02:00
Song b83470b190 docs(camera): clarify screenshot camera param behavior and UI capture limitation
Clarify screenshot camera param behavior and UI capture limitation

Corrects misleading "Defaults to Camera.main" in the camera parameter description

and adds explicit warnings that specifying a camera excludes Screen Space - Overlay

canvases from the capture.
2026-04-14 16:33:56 +08:00
Shutong Wu 97a418e01d bug-fix-and-component-index-update
1. Fix the bug mentioned in #956 and add index mentioned in #1014
2026-04-03 23:39:11 -04:00
Shutong Wu af37bccc3d Fix 2026-04-02 23:49:08 -04:00
Shutong Wu c76d0bb281 Fix on #837 2026-04-02 23:23:07 -04:00
Shutong Wu 97a61efdec Merge pull request #1001 from zaferdace/feat/execute-code
feat: add execute_code tool for running arbitrary C# in Unity Editor
2026-04-01 15:41:36 -04:00
Shutong Wu fa0c6d123a Update with Roslyn as optional execute_code usage, and UX update 2026-04-01 14:21:09 -04:00
Shutong Wu 2e3e65ed65 Merge pull request #1005 from Sibirius/feature/manage-gameobject-is-static
feat(manage_gameobject): add is_static parameter to modify action
2026-04-01 01:12:11 -04:00
Shutong Wu 8b913ed84e Doc change 2026-04-01 00:07:38 -04:00
Shutong Wu c41d365354 Update 2026-03-31 12:24:07 -04:00
Sebastian Muehr 11c128e118 feat(manage_gameobject): add is_static parameter to modify action
manage_gameobject already serializes isStatic in read output
(GameObjectSerializer, GameObjectResource) but the modify action
had no parameter to write it.

This adds is_static (bool) across all three layers:
- C#: GameObjectModify.cs calls GameObjectUtility.SetStaticEditorFlags()
- Python MCP tool: manage_gameobject.py with coerce_bool normalization
- Python CLI: gameobject.py with --static/--no-static flag

When true, all static flags are set; when false, all are cleared.
Omitting the parameter is a no-op (fully backwards compatible).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-30 22:38:35 +02:00
zaferdace d2847a960b fix: address review feedback from Sourcery and CodeRabbit
- Fix off-by-one in WrapperLineOffset (9 → 10)
- Cache resolved assembly paths in static field for performance
- Add encoding="utf-8" to CLI file read
- Add group="scripting_ext" to Python tool decorator

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-29 17:11:54 +01:00
zaferdace c18ee94da8 feat: add execute_code tool for running arbitrary C# in Unity Editor
Adds a built-in `execute_code` tool that compiles and runs C# code
inside the Unity Editor via CSharpCodeProvider. No external dependencies
(Roslyn not required), no script files created.

## Actions
- `execute` — compile and run C# method body, return result
- `get_history` — list past executions with previews
- `replay` — re-run a history entry with original settings
- `clear_history` — clear execution history

## Safety
- `safety_checks` (default: true) blocks known dangerous patterns
  (File.Delete, Process.Start, AssetDatabase.DeleteAsset, infinite loops)
- Clearly documented as pattern-based blocklist, NOT a security sandbox
- `destructiveHint=True` annotation for MCP clients

## Features
- In-memory compilation with all loaded assembly references
- User-friendly error line numbers (wrapper offset subtracted)
- Execution history (max 50 entries) with code preview truncation
- Replay preserves original safety_checks setting
- CLI commands: `code execute`, `code history`, `code replay`, `code clear-history`

## Files
- C#: `MCPForUnity/Editor/Tools/ExecuteCode.cs` (329 lines)
- Python: `Server/src/services/tools/execute_code.py` (85 lines)
- CLI: `Server/src/cli/commands/code.py` (+89 lines)
- Tests: `Server/tests/test_execute_code.py` (17 tests, all passing)
- Manifest: added `execute_code` entry

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-29 16:20:28 +01:00
Shutong Wu f4e98d8a4f feat(profiler): rewrite Python MCP tool with 14 actions across 4 groups
Replaces the old 5-action read-only profiler with a comprehensive tool
covering session control, generic counter reads, memory snapshots, and
Frame Debugger. Adds "profiling" as a new opt-in tool group.
2026-03-28 21:55:49 -04:00
zaferdace c0a2a2d0aa fix: update physics counter names in manage_profiler description 2026-03-28 21:37:55 -04:00
zaferdace 0011a7a5ee feat: add manage_profiler tool for CPU timing, GC alloc, and animation profiling
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-28 21:37:55 -04:00
Shutong Wu e2903a7005 Merge pull request #990 from zaferdace/feat/save-prefab-stage
feat(manage_editor): add save_prefab_stage action
2026-03-28 00:31:56 -04:00
Shutong Wu 242548b93b docs: mention save_prefab_stage in resource docs and skill reference 2026-03-28 00:10:33 -04:00
Shutong Wu da1b700041 Merge branch 'CoplayDev:beta' into pr-980 2026-03-27 00:52:16 -04:00
zaferdace fea9ab8b5a feat(manage_editor): add save_prefab_stage action
Adds save_prefab_stage to manage_editor to complete the prefab stage
workflow alongside the existing open_prefab_stage and close_prefab_stage.

- C#: SavePrefabStage() uses EditorSceneManager.MarkSceneDirty +
  SaveScene on the prefab stage scene, returns ErrorResponse when no
  stage is open or save fails
- Python: adds save_prefab_stage to action Literal and tool description
- Tests: 3 new tests covering forwarding, description, and clean params

open_prefab_stage was already merged in #968. This PR only adds
save_prefab_stage.
2026-03-26 07:02:26 +00:00
Shutong Wu 23dd9d4416 Merge branch 'CoplayDev:beta' into beta 2026-03-25 13:01:10 -04:00
zaferdace dc871b98c1 feat: add CLI command and fix key mapping for set_import_settings
- Add 'set-import-settings' CLI command with --texture-type, --sprite-mode,
  --as-sprite, --max-size, --compression, --generate-mipmaps flags
- Add 'set_import_settings' to Python MCP server action enum
- Fix C# key mapping: accept both 'spriteSettings' (from Python server)
  and 'as_sprite' (direct param) for sprite configuration
- Same fix for 'importSettings' / 'import_settings' keys
2026-03-25 10:21:24 +00:00