unity-mcp/UnityMcpBridge/Editor/Tools/ManageScript.cs

2625 lines
119 KiB
C#
Raw Normal View History

2025-03-31 03:58:01 +08:00
using System;
using System.IO;
using System.Linq;
Claude‑friendly edit tools + framed transport + live Unity NL test framework (#243) * CI: gate desktop-parity on Anthropic key; pass anthropic_api_key like NL suite * Add quickprobe prompt and CI workflow (mcp-quickprobe.md, unity-mcp-quickprobe.yml) * strictier tool use to prevent subagent spawning and force mcp tools * update workflow filesto reduce likelihood of subagent spawning * improve permissions for claude agent, fix mcpbridge timeout/token issue * increase max turns to 10 * ci: align NL suite to new permissions schema; prevent subagent drift * ci: NL suite -> mini prompt for e2e; add full NL/T prompt; server: ctx optional + project_root fallback; workflows: set UNITY_PROJECT_ROOT for CI * ci: add checks:write; revert local project hardcodes (manifest, ProjectVersion.txt) * tools: text-edit routing fixes (anchor_insert via text, CRLF calc); prompts: mini NL/T clarifications * ci: use absolute UNITY_PROJECT_ROOT; prompts target TestProjects; server: accept relative UNITY_PROJECT_ROOT and bare spec URI * ci: ignore Unity test project's packages-lock.json; remove from repo to avoid absolute paths * CI: start persistent Unity Editor for MCP (guarded by license) + allow batch-mode bridge via UNITY_MCP_ALLOW_BATCH * CI: hide license and pass via env to docker; fix invalid ref format * CI: readiness probe uses handshake on Unity MCP port (deterministic) * CI: fix YAML; use TCP handshake readiness probe (FRAMING=1) * CI: prime Unity license via game-ci; mount ULF into container; extend readiness timeout * CI: use ULF write + mount for Unity licensing; remove serial/email/pass from container * CI: entitlement activation (UNITY_SERIAL=''); verify host ULF cache; keep mount * CI: write ULF from secret and verify; drop entitlement activation step * CI: detect any licensing path; GameCI prime; status dir env; log+probe readiness; fix YAML * CI: add GameCI license prime; conditional ULF write; one-shot license validation; explicit status dir + license env * CI: fix YAML (inline python), add Anthropic key detect via GITHUB_ENV; ready to run happy path * CI: mount Unity token/ulf/cache dirs into container to share host license; create dirs before start * CI: fix YAML indentation; write ULF on host; activate in container with shared mounts; mount .config and .cache too * CI: gate Claude via outputs; mount all Unity license dirs; fix inline probe python; stabilize licensing flow * CI: normalize detect to step outputs; ensure license dirs mounted and validated; fix indentation * Bridge: honor UNITY_MCP_STATUS_DIR for heartbeat/status file (CI-friendly) * CI: guard project path for activation/start; align tool allowlist; run MCP server with python; tighten secret scoping * CI: finalize Unity licensing mounts + status dir; mode-detect (ULF/EBL); readiness logs+probe; Claude gating via outputs * CI: fix YAML probe (inline python -c) and finalize happy-path Unity licensing and MCP/Claude wiring * CI: inline python probe; unify Unity image and cache mounts; ready to test * CI: fix docker run IMAGE placement; ignore cache find perms; keep same editor image * CI: pass -manualLicenseFile to persistent Editor; keep mounts and single image * CI: mount full GameCI cache to /root in persistent Unity; set HOME=/root; add optional license check * CI: make -manualLicenseFile conditional; keep full /root mount and license check * CI: set HOME=/github/home; mount GameCI cache there; adjust manualLicenseFile path; expand license check * CI: EBL sign-in for persistent Unity (email/password/serial); revert HOME=/root and full /root mount; keep conditional manualLicenseFile and improved readiness * CI: run full NL/T suite prompt (nl-unity-suite-full.md) instead of mini * NL/T: require unified diffs + explicit verdicts in JUnit; CI: remove short sanity step, publish JUnit, upload artifacts * NL/T prompt: require CDATA wrapping for JUnit XML fields; guidance for splitting embedded ]]>; keep VERDICT in CDATA only * CI: remove in-container license check step; keep readiness and full suite * NL/T prompt: add version header, stricter JUnit schema, hashing/normalization, anchors, statuses, atomic semantics, tool logging * CI: increase Claude NL/T suite timeout to 30 minutes * CI: pre-create reports dir and result files to avoid tool approval prompts * CI: skip wait if container not running; skip Editor start if project missing; broaden MCP deps detection; expand allowed tools * fixies to harden ManageScript * CI: sanitize NL/T markdown report to avoid NUL/encoding issues * revert breaking yyaml changes * CI: prime license, robust Unity start/wait, sanitize markdown via heredoc * Resolve merge: accept upstream renames/installer (fix/installer-cleanup-v2) and keep local framing/script-editing - Restored upstream server.py, EditorWindow, uv.lock\n- Preserved ManageScript editing/validation; switched to atomic write + debounced refresh\n- Updated tools/__init__.py to keep script_edits/resources and adopt new logger name\n- All Python tests via uv: 7 passed, 6 skipped, 9 xpassed; Unity compile OK * Fix Claude Desktop config path and atomic write issues - Fix macOS path for Claude Desktop config: use ~/Library/Application Support/Claude/ instead of ~/.config/Claude/ - Improve atomic write pattern with backup/restore safety - Replace File.Replace() with File.Move() for better macOS compatibility - Add proper error handling and cleanup for file operations - Resolves issue where installer couldn't find Claude Desktop config on macOS * Editor: use macConfigPath on macOS for MCP client config writes (Claude Desktop, etc.). Fallback to linuxConfigPath only if mac path missing. * Models: add macConfigPath to McpClient for macOS config path selection (fixes CS1061 in editor window). * Editor: on macOS, prefer macConfigPath in ManualConfigEditorWindow (fallback to linux path); Linux/Windows unchanged. * Fix McpClient: align with upstream/main, prep for framing split * NL suite: shard workflow; tighten bridge readiness; add MCP preflight; use env-based shard vars * NL suite: fix shard step indentation; move shard vars to env; remove invalid inputs * MCP clients: split VSCode Copilot config paths into macConfigPath and linuxConfigPath * Unity bridge: clean stale status; bind host; robust wait probe with IPv4/IPv6 + diagnostics * CI: use MCPForUnity.Editor.MCPForUnityBridge.StartAutoConnect as executeMethod * Action wiring: inline mcpServers in settings for all shards; remove redundant .claude/mcp.json step * CI: embed mcpServers in settings for all shards; fix startup sanity step; lint clean * CI: pin claude-code-base-action to e6f32c8; use claude_args --mcp-config; switch to allowed_tools; ensure MCP config per step * CI: unpin claude-code-base-action to @beta (commit ref not found) * CI: align with claude-code-base-action @beta; pass MCP via claude_args and allowedTools * Editor: Fix apply_text_edits heuristic when edits shift positions; recompute method span on candidate text with fallback delta adjustment * CI: unify MCP wiring across workflows; write .claude/mcp.json; switch to claude_args with --mcp-config/--allowedTools; remove unsupported inputs * CI: collapse NL suite shards into a single run to avoid repeated test execution * CI: minimize allowedTools for NL suite to essential Unity MCP + Bash("git:*") + Write * CI: mkdir -p reports before run; remove unsupported --timeout-minutes from claude_args * CI: broaden allowedTools to include find_in_file and mcp__unity__* * CI: enable use_node_cache and switch NL suite model to claude-3-7-haiku-20250219 * CI: disable use_node_cache to avoid setup-node lockfile error * CI: set NL suite model to claude-3-haiku-20240307 * CI: cap Haiku output with --max-tokens 2048 for NL suite * CI: switch to claude-3-7-sonnet-latest and remove unsupported --max-tokens * CI: update allowedTools to Bash(*) and explicit Unity MCP tool list * CI: update NL suite workflow (latest tweaks) * Tests: tighten NL suite prompt for logging, hash discipline, stale retry, evidence windows, diff cap, and VERDICT line * Add disallowed tools to NL suite workflow * docs: clarify stale write retry * Add fallback JUnit report and adjust publisher * Indent fallback JUnit XML in workflow * fix: correct fallback JUnit report generation * Update mcp-quickprobe.md Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> * Update mcp-quickprobe.md Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> * Update Response.cs Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> * Update MCPForUnityBridge.cs Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> * fix: correct McpTypes reference * Add directory existence checks for symlink and XDG paths * fix: only set installation flag after successful server install * Update resource_tools.py Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> * fix: respect mac config paths * Use File.Replace for atomic config write * Remove unused imports in manage_script * bump server version * Tests: update NL suite prompt and workflows; remove deprecated smoke/desktop-parity; quickprobe tidy * Editor: atomic config write via File.Replace fallback; remove redundant backups and racey exists checks * CI: harden NL suite - idempotent docker, gate on unity_ok, safer port probe, least-priv perms * Editor: make atomic config write restoration safe (flag writeDone; copy-overwrite restore; cleanup in finally) * CI: fix fallback JUnit heredoc by using printf lines (no EOF delimiter issues) * CI: switch NL suite to mini prompt; mini prompt honors / and NL discipline * CI: replace claude_args with allowed_tools/model/mcp_config per action schema * CI: expand UNITY_PROJECT_ROOT via in MCP config heredoc * EditorWindow: add cross-platform fallback for File.Replace; macOS-insensitive PathsEqual; safer uv resolve; honor macConfigPath * CI: strengthen JUnit publishing for NL mini suite (normalize, debug list, publish both, fail_on_parse_error) * CI: set job-wide JUNIT_OUT/MD_OUT; normalization uses env; publish references env and ungroup reports * CI: publish a single normalized JUnit (reports/junit-for-actions.xml); fallback writes same; avoid checkName/reportPaths mismatch * CI: align mini prompt report filenames; redact Unity log tail in diagnostics * chore: sync workflow and mini prompt; redacted logs; JUnit normalization/publish tweaks * CI: redact sensitive tokens in Stop Unity; docs: CI usage + edit tools * prompts: update nl-unity-suite-full (mini-style setup + reporting discipline); remove obsolete prompts * CI: harden NL workflows (timeout_minutes, robust normalization); prompts: unify JUnit suite name and reporting discipline * prompts: add guarded write pattern (LF hash, stale_file retry) to full suite * prompts: enforce continue-on-failure, driver flow, and status handling in full suite * Make test list more explicit in prompt. Get rid of old test prompts for hygeine. * prompts: add stale fast-retry (server hash) + in-memory buf guidance * CI: standardize JUNIT_OUT to reports/junit-nl-suite.xml; fix artifact upload indentation; prompt copy cleanups * prompts: reporting discipline — append-only fragments, batch writes, no model round-trip * prompts: stale fast-retry preference, buffer/sha carry, snapshot revert, essential logging * workflows(nl-suite): precreate report skeletons, assemble junit, synthesize markdown; restrict allowed_tools to append-only Bash + MCP tools * thsis too * Update README-DEV.md Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update .github/workflows/claude-nl-suite-mini.yml Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update .github/workflows/claude-nl-suite.yml Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * workflows(nl-mini): fix YAML indentation/trailing spaces under with: and cleanup heredoc spacing * workflows(nl-suite): fix indentation on docker logs redaction line (YAML lint) * Add write to allowlist * nl-suite: harden reporting discipline (fragment-only writes, forbid alt paths); workflow: clean stray junit-*updated*.xml * nl-suite: enforce end-of-suite single Write (no bash redirection); workflow: restrict allowed_tools to Write+MCP only * prompts(nl-full): end-of-suite results must be valid XML with single <cases> root and only <testcase> children; no raw text outside CDATA * workflows(nl-suite): make Claude step non-fatal; tolerant normalizer extracts <testcase> via regex on bad fragments * nl-suite: fix stale classname to UnityMCP.NL-T in mini fallback; prompt: require re-read after every revert; correct PLAN/PROGRESS to 15 * nl-suite: fix fallback JUnit classname to UnityMCP.NL-T; prompt: forbid create_script and env/mkdir checks, enforce single baseline-byte revert flow and post-revert re-read; add corruption-handling guidance * prompts(nl-full): after each write re-read raw bytes to refresh pre_sha; prefer script_apply_edits for anchors; avoid header/using changes * prompts(nl-full): canonicalize outputs to /; allow small fragment appends via Write or Bash(printf/echo); forbid wrappers and full-file round-trips * prompts(nl-full): finalize markdown formatting for guarded write, execution order, specs, status * workflows(nl-suite, mini): header/lint fixes and constrained Bash append path; align allowed_tools * prompts(nl-full): format Fast Restore, Guarded Write, Execution, Specs, Status as proper markdown lists and code fences * workflows(nl-suite): keep header tidy and append-path alignment with prompt * minor fix * workflows(nl-suite): fix indentation and dispatch; align allowed_tools and revert helper * prompts(nl-full): switch to read_resource for buf/sha; re-read only when needed; convert 'Print this once' to heading; note snapshot helper creates parent dirs * workflows(nl-suite): normalize step removes bootstrap when real testcases present; recompute tests/failures * workflows(nl-suite): enrich Markdown summary by extracting per-test <system-out> blocks (truncated) * clarify prompt resilience instructions * ci(nl-suite): revert prompt and workflow to known-good e0f8a72 for green run; remove extra MD details * ci(nl-suite): minimal fixes — no-mkdir guard in prompt; drop bootstrap and recompute JUnit counts * ci(nl-suite): richer JUnit→Markdown report (per-test system-out) * Small guard to incorret asset read call. * ci(nl-suite): refine MD builder — unescape XML entities, safe code fences, PASS/FAIL badges * Update UnityMcpBridge/UnityMcpServer~/src/tools/resource_tools.py Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update UnityMcpBridge/UnityMcpServer~/src/unity_connection.py Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update UnityMcpBridge/UnityMcpServer~/src/tools/manage_script_edits.py Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update .github/scripts/mark_skipped.py Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update .github/scripts/mark_skipped.py Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update .github/scripts/mark_skipped.py Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> * server(manage_script): robust URI handling — percent-decode file://, normalize, strip host/leading slashes, return Assets-relative if present * Update .claude/prompts/nl-unity-suite-full.md Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> * tests(framing): reduce handshake poll window, nonblocking peek to avoid disconnect race; still enforce pre-handshake data drop * tests(manage_script): add _split_uri tests for unity://path, file:// URLs (decoded/Assets-relative), and plain paths * server+tests: fix handshake syntax error; robust file:// URI normalization in manage_script; add _split_uri tests; adjust stdout scan to ignore venv/site-packages * bridge(framing): accept zero-length frames (treat as empty keepalive) * tests(logging): use errors='replace' on decode fallback to avoid silent drops * resources(list): restrict to Assets/, resolve symlinks, enforce .cs; add traversal/outside-path tests * Update .claude/prompts/nl-unity-suite-full.md Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update UnityMcpBridge/UnityMcpServer~/src/unity_connection.py Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * misc: framing keepalive (zero-length), regex preview consistency, resource.list hardening, URI parsing, legacy update routing, test cleanups * docs(tools): richer MCP tool descriptions; tests accept decorator kwargs; resource URI parsing hardened * Update .claude/prompts/nl-unity-suite-full.md Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update UnityMcpBridge/UnityMcpServer~/src/tools/resource_tools.py Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update UnityMcpBridge/UnityMcpServer~/src/unity_connection.py Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * net+docs: hard-reject zero-length frames; TCP_NODELAY on connect; Assets detection case-insensitive; NL prompt statuses aligned * prompt(nl-suite): constrain Write destinations under reports/, forbid traversal * prompt+net: harden Write path rules; use monotonic deadline and plain-text advisory for non-framed peers * unity_connection: restore recv timeout via try/finally; make global connection getter thread-safe with module lock and double-checked init * NL/T prompt: pin structured edit ops for T-D/T-E; add schema-error guarded write behavior; keep existing path/URI and revert rules * unity_connection: add FRAMED_MAX; use ValueError for framed length violations; lower framed receive log to debug; serialize connect() with per-instance lock * ManageScript: use UTF8Encoding(without BOM) for atomic writes in ApplyTextEdits/EditScript to align with Create/Update and avoid BOM-related diffs/hash mismatches * NL/T prompt: make helper deletion regex multiline-safe ((?ms) so ^ anchors line starts) * ManageScript: emit structured overlap status {status:"overlap"} for overlapping edit ranges in apply_text_edits and edit paths * NL/T prompt: clarify fallback vs failure — fallback only for unsupported/missing_field; treat bad_request as failure; note unsupported after fallback as failure * NL/T prompt: pin deterministic overlap probe (apply_text_edits two ranges from same snapshot); gate too_large behind RUN_TOO_LARGE env hint * TB update * NL/T prompt: harden Output Rules — constrain Bash(printf|echo) to stdout-only; forbid redirection/here-docs/tee; only scripts/nlt-revert.sh may mutate FS * Prompt: enumerate allowed script_apply_edits ops; add manage_editor/read_console guidance; fix T‑F atomic batch to single script_apply_edits. ManageScript: regex timeout for diagnostics; symlink ancestor guard; complete allowed-modes list. * Fixes * ManageScript: add rich overlap diagnostics (conflicts + hint) for both text range and structured batch paths * ManageScript: return structured {status:"validation_failed"} diagnostics in create/update/edits and validate before commit * ManageScript: echo canonical uri in responses (create/read/update/apply_text_edits/structured edits) to reinforce resource identity * improve clarity of capabilities message * Framing: allow zero-length frames on both ends (C# bridge, Python server). Prompt: harden T-F to single text-range apply_text_edits batch (descending order, one snapshot). URI: normalize file:// outside Assets by stripping leading slash. * ManageScript: include new sha256 in success payload for apply_text_edits; harden TryResolveUnderAssets by rejecting symlinked ancestors up to Assets/. * remove claudetest dir * manage_script_edits: normalize method-anchored anchor_insert to insert_method (map text->replacement); improves CI compatibility for T‑A/T‑E without changing Editor behavior. * tighten testing protocol around mkdir * manage_script: validate create_script inputs (Assets/.cs/name/no traversal); add Assets/ guard to delete_script; validate level+Assets in validate_script; make legacy manage_script optional params; harden legacy update routing with base64 reuse and payload size preflight. * Tighten prompt for testing * Update .claude/prompts/nl-unity-suite-full.md Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update .claude/prompts/nl-unity-suite-full.md Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update UnityMcpBridge/Editor/Tools/ManageScript.cs Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * manage_script_edits: honor ignore_case on anchor_insert and regex_replace in both direct and text-conversion paths (MULTILINE|IGNORECASE). * remove extra file * workflow: use python3 for inline scripts and port detection on ubuntu-latest. * Tighten prompt + manage_script * Update UnityMcpBridge/UnityMcpServer~/src/tools/manage_script_edits.py Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update UnityMcpBridge/UnityMcpServer~/src/tools/manage_script_edits.py Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update .claude/prompts/nl-unity-suite-full.md Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update UnityMcpBridge/Editor/Tools/ManageScript.cs Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update .claude/prompts/nl-unity-suite-full.md Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * manage_script: improve file:// UNC handling; preserve POSIX absolute semantics internally; keep test-expected slash stripping for non-Assets paths. * ManageScript.cs: add TimeSpan timeouts to all Regex uses (IsMatch/Match/new Regex) and keep CultureInvariant/Multiline options; reduces risk of catastrophic backtracking stalls. * workflow: ensure reports/ exists in markdown build step to avoid FileNotFoundError when writing MD_OUT. * fix brace * manage_script_edits: expand backrefs for regex_replace in preview->text conversion and translate to \g<n> in local apply; keeps previews and actual edits consistent. * anchor_insert: default to position=after, normalize surrounding newlines in Python conversion paths; C# path ensures trailing newline and skips duplicate insertion within class. * feat(mcp): add get_sha tool; apply_text_edits normalization+overlap preflight+strict; no-op evidence in C#; update NL suite prompt; add unit tests * feat(frames): accept zero-length heartbeat frames in client; add heartbeat test * feat(edits): guard destructive regex_replace with structural preflight; add robust tests; prompt uses delete_method for temp helper * feat(frames): bound heartbeat loop with timeout/threshold; align zero-length response with C#; update test * SDK hardening: atomic multi-span text edits; stop forcing sequential for structured ops; forward options on apply_text_edits; add validate=relaxed support and scoped checks; update NL/T prompt; add tests for options forwarding, relaxed mode, and atomic batches * Router: default applyMode=atomic for multi-span apply_text_edits; add tests * CI prompt: pass options.validate=relaxed for T-B/C; options.applyMode=atomic for T-F; emphasize always writing testcase and restoring on errors * Validation & DX: add validate=syntax (scoped), standardize evidence windows; early regex compile with hints; debug_preview for apply_text_edits * Update UnityMcpBridge/Editor/Windows/MCPForUnityEditorWindow.cs Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * NL/T suite-driven edits: LongUnityScriptClaudeTest, bridge helpers, server_version; prepare framing tests * Fix duplicate macConfigPath field in McpClient to resolve CS0102 * Editor threading: run EnsureServerInstalled on main thread; marshal EditorPrefs/DeleteKey + logging via delayCall * Docs(apply_text_edits): strengthen guidance on 1-based positions, verify-before-edit, and recommend anchors/structured edits * Docs(script_apply_edits): add safety guidance (anchors, method ops, validators) and recommended practices * Framed VerifyBridgePing in editor window; docs hardening for apply_text_edits and script_apply_edits --------- Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
2025-08-31 00:55:38 +08:00
using System.Collections.Generic;
using System.Text.RegularExpressions;
using Newtonsoft.Json.Linq;
using UnityEditor;
using UnityEngine;
Rename namespace and public facing plugin output from "Unity MCP" to "MCP for Unity" (#225) * refactor: rename namespace from UnityMcpBridge to MCPForUnity across all files See thread in #6, we can't use Unity MCP because it violates their trademark. That name makes us look affiliated. We can use MCP for Unity * Change package display name, menu item and menu titles These are front facing so has to change for Unity asset store review * Misc name changes in logs and comments for better consistency * chore: update editor window title from 'MCP Editor' to 'MCP for Unity' * refactor: update branding from UNITY-MCP to MCP-FOR-UNITY across all log messages and warnings * chore: rename Unity MCP to MCP For Unity across all files and bump version to 2.1.2 * docs: update restore script title to clarify Unity MCP naming * Fix usage instructions * chore: update log messages to use MCP For Unity branding instead of UnityMCP * Add a README inside plugin, required for distributing via the asset store * docs: update Unity port description and fix typo in troubleshooting section * Address Rabbit feedback * Update Editor prefs to use new name Prevents overlap with other Unity MCPs, happy to revert if it's too much * refactor: rename server logger and identifier from unity-mcp-server to mcp-for-unity-server * Standardize casing of renamed project to "MCP for Unity", as it is on the asset store * Remove unused folder * refactor: rename Unity MCP to MCP for Unity across codebase * Update dangling references * docs: update product name from UnityMCP to MCP for Unity in README * Update log and comments for new name
2025-08-21 03:59:49 +08:00
using MCPForUnity.Editor.Helpers;
Claude‑friendly edit tools + framed transport + live Unity NL test framework (#243) * CI: gate desktop-parity on Anthropic key; pass anthropic_api_key like NL suite * Add quickprobe prompt and CI workflow (mcp-quickprobe.md, unity-mcp-quickprobe.yml) * strictier tool use to prevent subagent spawning and force mcp tools * update workflow filesto reduce likelihood of subagent spawning * improve permissions for claude agent, fix mcpbridge timeout/token issue * increase max turns to 10 * ci: align NL suite to new permissions schema; prevent subagent drift * ci: NL suite -> mini prompt for e2e; add full NL/T prompt; server: ctx optional + project_root fallback; workflows: set UNITY_PROJECT_ROOT for CI * ci: add checks:write; revert local project hardcodes (manifest, ProjectVersion.txt) * tools: text-edit routing fixes (anchor_insert via text, CRLF calc); prompts: mini NL/T clarifications * ci: use absolute UNITY_PROJECT_ROOT; prompts target TestProjects; server: accept relative UNITY_PROJECT_ROOT and bare spec URI * ci: ignore Unity test project's packages-lock.json; remove from repo to avoid absolute paths * CI: start persistent Unity Editor for MCP (guarded by license) + allow batch-mode bridge via UNITY_MCP_ALLOW_BATCH * CI: hide license and pass via env to docker; fix invalid ref format * CI: readiness probe uses handshake on Unity MCP port (deterministic) * CI: fix YAML; use TCP handshake readiness probe (FRAMING=1) * CI: prime Unity license via game-ci; mount ULF into container; extend readiness timeout * CI: use ULF write + mount for Unity licensing; remove serial/email/pass from container * CI: entitlement activation (UNITY_SERIAL=''); verify host ULF cache; keep mount * CI: write ULF from secret and verify; drop entitlement activation step * CI: detect any licensing path; GameCI prime; status dir env; log+probe readiness; fix YAML * CI: add GameCI license prime; conditional ULF write; one-shot license validation; explicit status dir + license env * CI: fix YAML (inline python), add Anthropic key detect via GITHUB_ENV; ready to run happy path * CI: mount Unity token/ulf/cache dirs into container to share host license; create dirs before start * CI: fix YAML indentation; write ULF on host; activate in container with shared mounts; mount .config and .cache too * CI: gate Claude via outputs; mount all Unity license dirs; fix inline probe python; stabilize licensing flow * CI: normalize detect to step outputs; ensure license dirs mounted and validated; fix indentation * Bridge: honor UNITY_MCP_STATUS_DIR for heartbeat/status file (CI-friendly) * CI: guard project path for activation/start; align tool allowlist; run MCP server with python; tighten secret scoping * CI: finalize Unity licensing mounts + status dir; mode-detect (ULF/EBL); readiness logs+probe; Claude gating via outputs * CI: fix YAML probe (inline python -c) and finalize happy-path Unity licensing and MCP/Claude wiring * CI: inline python probe; unify Unity image and cache mounts; ready to test * CI: fix docker run IMAGE placement; ignore cache find perms; keep same editor image * CI: pass -manualLicenseFile to persistent Editor; keep mounts and single image * CI: mount full GameCI cache to /root in persistent Unity; set HOME=/root; add optional license check * CI: make -manualLicenseFile conditional; keep full /root mount and license check * CI: set HOME=/github/home; mount GameCI cache there; adjust manualLicenseFile path; expand license check * CI: EBL sign-in for persistent Unity (email/password/serial); revert HOME=/root and full /root mount; keep conditional manualLicenseFile and improved readiness * CI: run full NL/T suite prompt (nl-unity-suite-full.md) instead of mini * NL/T: require unified diffs + explicit verdicts in JUnit; CI: remove short sanity step, publish JUnit, upload artifacts * NL/T prompt: require CDATA wrapping for JUnit XML fields; guidance for splitting embedded ]]>; keep VERDICT in CDATA only * CI: remove in-container license check step; keep readiness and full suite * NL/T prompt: add version header, stricter JUnit schema, hashing/normalization, anchors, statuses, atomic semantics, tool logging * CI: increase Claude NL/T suite timeout to 30 minutes * CI: pre-create reports dir and result files to avoid tool approval prompts * CI: skip wait if container not running; skip Editor start if project missing; broaden MCP deps detection; expand allowed tools * fixies to harden ManageScript * CI: sanitize NL/T markdown report to avoid NUL/encoding issues * revert breaking yyaml changes * CI: prime license, robust Unity start/wait, sanitize markdown via heredoc * Resolve merge: accept upstream renames/installer (fix/installer-cleanup-v2) and keep local framing/script-editing - Restored upstream server.py, EditorWindow, uv.lock\n- Preserved ManageScript editing/validation; switched to atomic write + debounced refresh\n- Updated tools/__init__.py to keep script_edits/resources and adopt new logger name\n- All Python tests via uv: 7 passed, 6 skipped, 9 xpassed; Unity compile OK * Fix Claude Desktop config path and atomic write issues - Fix macOS path for Claude Desktop config: use ~/Library/Application Support/Claude/ instead of ~/.config/Claude/ - Improve atomic write pattern with backup/restore safety - Replace File.Replace() with File.Move() for better macOS compatibility - Add proper error handling and cleanup for file operations - Resolves issue where installer couldn't find Claude Desktop config on macOS * Editor: use macConfigPath on macOS for MCP client config writes (Claude Desktop, etc.). Fallback to linuxConfigPath only if mac path missing. * Models: add macConfigPath to McpClient for macOS config path selection (fixes CS1061 in editor window). * Editor: on macOS, prefer macConfigPath in ManualConfigEditorWindow (fallback to linux path); Linux/Windows unchanged. * Fix McpClient: align with upstream/main, prep for framing split * NL suite: shard workflow; tighten bridge readiness; add MCP preflight; use env-based shard vars * NL suite: fix shard step indentation; move shard vars to env; remove invalid inputs * MCP clients: split VSCode Copilot config paths into macConfigPath and linuxConfigPath * Unity bridge: clean stale status; bind host; robust wait probe with IPv4/IPv6 + diagnostics * CI: use MCPForUnity.Editor.MCPForUnityBridge.StartAutoConnect as executeMethod * Action wiring: inline mcpServers in settings for all shards; remove redundant .claude/mcp.json step * CI: embed mcpServers in settings for all shards; fix startup sanity step; lint clean * CI: pin claude-code-base-action to e6f32c8; use claude_args --mcp-config; switch to allowed_tools; ensure MCP config per step * CI: unpin claude-code-base-action to @beta (commit ref not found) * CI: align with claude-code-base-action @beta; pass MCP via claude_args and allowedTools * Editor: Fix apply_text_edits heuristic when edits shift positions; recompute method span on candidate text with fallback delta adjustment * CI: unify MCP wiring across workflows; write .claude/mcp.json; switch to claude_args with --mcp-config/--allowedTools; remove unsupported inputs * CI: collapse NL suite shards into a single run to avoid repeated test execution * CI: minimize allowedTools for NL suite to essential Unity MCP + Bash("git:*") + Write * CI: mkdir -p reports before run; remove unsupported --timeout-minutes from claude_args * CI: broaden allowedTools to include find_in_file and mcp__unity__* * CI: enable use_node_cache and switch NL suite model to claude-3-7-haiku-20250219 * CI: disable use_node_cache to avoid setup-node lockfile error * CI: set NL suite model to claude-3-haiku-20240307 * CI: cap Haiku output with --max-tokens 2048 for NL suite * CI: switch to claude-3-7-sonnet-latest and remove unsupported --max-tokens * CI: update allowedTools to Bash(*) and explicit Unity MCP tool list * CI: update NL suite workflow (latest tweaks) * Tests: tighten NL suite prompt for logging, hash discipline, stale retry, evidence windows, diff cap, and VERDICT line * Add disallowed tools to NL suite workflow * docs: clarify stale write retry * Add fallback JUnit report and adjust publisher * Indent fallback JUnit XML in workflow * fix: correct fallback JUnit report generation * Update mcp-quickprobe.md Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> * Update mcp-quickprobe.md Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> * Update Response.cs Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> * Update MCPForUnityBridge.cs Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> * fix: correct McpTypes reference * Add directory existence checks for symlink and XDG paths * fix: only set installation flag after successful server install * Update resource_tools.py Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> * fix: respect mac config paths * Use File.Replace for atomic config write * Remove unused imports in manage_script * bump server version * Tests: update NL suite prompt and workflows; remove deprecated smoke/desktop-parity; quickprobe tidy * Editor: atomic config write via File.Replace fallback; remove redundant backups and racey exists checks * CI: harden NL suite - idempotent docker, gate on unity_ok, safer port probe, least-priv perms * Editor: make atomic config write restoration safe (flag writeDone; copy-overwrite restore; cleanup in finally) * CI: fix fallback JUnit heredoc by using printf lines (no EOF delimiter issues) * CI: switch NL suite to mini prompt; mini prompt honors / and NL discipline * CI: replace claude_args with allowed_tools/model/mcp_config per action schema * CI: expand UNITY_PROJECT_ROOT via in MCP config heredoc * EditorWindow: add cross-platform fallback for File.Replace; macOS-insensitive PathsEqual; safer uv resolve; honor macConfigPath * CI: strengthen JUnit publishing for NL mini suite (normalize, debug list, publish both, fail_on_parse_error) * CI: set job-wide JUNIT_OUT/MD_OUT; normalization uses env; publish references env and ungroup reports * CI: publish a single normalized JUnit (reports/junit-for-actions.xml); fallback writes same; avoid checkName/reportPaths mismatch * CI: align mini prompt report filenames; redact Unity log tail in diagnostics * chore: sync workflow and mini prompt; redacted logs; JUnit normalization/publish tweaks * CI: redact sensitive tokens in Stop Unity; docs: CI usage + edit tools * prompts: update nl-unity-suite-full (mini-style setup + reporting discipline); remove obsolete prompts * CI: harden NL workflows (timeout_minutes, robust normalization); prompts: unify JUnit suite name and reporting discipline * prompts: add guarded write pattern (LF hash, stale_file retry) to full suite * prompts: enforce continue-on-failure, driver flow, and status handling in full suite * Make test list more explicit in prompt. Get rid of old test prompts for hygeine. * prompts: add stale fast-retry (server hash) + in-memory buf guidance * CI: standardize JUNIT_OUT to reports/junit-nl-suite.xml; fix artifact upload indentation; prompt copy cleanups * prompts: reporting discipline — append-only fragments, batch writes, no model round-trip * prompts: stale fast-retry preference, buffer/sha carry, snapshot revert, essential logging * workflows(nl-suite): precreate report skeletons, assemble junit, synthesize markdown; restrict allowed_tools to append-only Bash + MCP tools * thsis too * Update README-DEV.md Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update .github/workflows/claude-nl-suite-mini.yml Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update .github/workflows/claude-nl-suite.yml Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * workflows(nl-mini): fix YAML indentation/trailing spaces under with: and cleanup heredoc spacing * workflows(nl-suite): fix indentation on docker logs redaction line (YAML lint) * Add write to allowlist * nl-suite: harden reporting discipline (fragment-only writes, forbid alt paths); workflow: clean stray junit-*updated*.xml * nl-suite: enforce end-of-suite single Write (no bash redirection); workflow: restrict allowed_tools to Write+MCP only * prompts(nl-full): end-of-suite results must be valid XML with single <cases> root and only <testcase> children; no raw text outside CDATA * workflows(nl-suite): make Claude step non-fatal; tolerant normalizer extracts <testcase> via regex on bad fragments * nl-suite: fix stale classname to UnityMCP.NL-T in mini fallback; prompt: require re-read after every revert; correct PLAN/PROGRESS to 15 * nl-suite: fix fallback JUnit classname to UnityMCP.NL-T; prompt: forbid create_script and env/mkdir checks, enforce single baseline-byte revert flow and post-revert re-read; add corruption-handling guidance * prompts(nl-full): after each write re-read raw bytes to refresh pre_sha; prefer script_apply_edits for anchors; avoid header/using changes * prompts(nl-full): canonicalize outputs to /; allow small fragment appends via Write or Bash(printf/echo); forbid wrappers and full-file round-trips * prompts(nl-full): finalize markdown formatting for guarded write, execution order, specs, status * workflows(nl-suite, mini): header/lint fixes and constrained Bash append path; align allowed_tools * prompts(nl-full): format Fast Restore, Guarded Write, Execution, Specs, Status as proper markdown lists and code fences * workflows(nl-suite): keep header tidy and append-path alignment with prompt * minor fix * workflows(nl-suite): fix indentation and dispatch; align allowed_tools and revert helper * prompts(nl-full): switch to read_resource for buf/sha; re-read only when needed; convert 'Print this once' to heading; note snapshot helper creates parent dirs * workflows(nl-suite): normalize step removes bootstrap when real testcases present; recompute tests/failures * workflows(nl-suite): enrich Markdown summary by extracting per-test <system-out> blocks (truncated) * clarify prompt resilience instructions * ci(nl-suite): revert prompt and workflow to known-good e0f8a72 for green run; remove extra MD details * ci(nl-suite): minimal fixes — no-mkdir guard in prompt; drop bootstrap and recompute JUnit counts * ci(nl-suite): richer JUnit→Markdown report (per-test system-out) * Small guard to incorret asset read call. * ci(nl-suite): refine MD builder — unescape XML entities, safe code fences, PASS/FAIL badges * Update UnityMcpBridge/UnityMcpServer~/src/tools/resource_tools.py Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update UnityMcpBridge/UnityMcpServer~/src/unity_connection.py Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update UnityMcpBridge/UnityMcpServer~/src/tools/manage_script_edits.py Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update .github/scripts/mark_skipped.py Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update .github/scripts/mark_skipped.py Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update .github/scripts/mark_skipped.py Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> * server(manage_script): robust URI handling — percent-decode file://, normalize, strip host/leading slashes, return Assets-relative if present * Update .claude/prompts/nl-unity-suite-full.md Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> * tests(framing): reduce handshake poll window, nonblocking peek to avoid disconnect race; still enforce pre-handshake data drop * tests(manage_script): add _split_uri tests for unity://path, file:// URLs (decoded/Assets-relative), and plain paths * server+tests: fix handshake syntax error; robust file:// URI normalization in manage_script; add _split_uri tests; adjust stdout scan to ignore venv/site-packages * bridge(framing): accept zero-length frames (treat as empty keepalive) * tests(logging): use errors='replace' on decode fallback to avoid silent drops * resources(list): restrict to Assets/, resolve symlinks, enforce .cs; add traversal/outside-path tests * Update .claude/prompts/nl-unity-suite-full.md Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update UnityMcpBridge/UnityMcpServer~/src/unity_connection.py Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * misc: framing keepalive (zero-length), regex preview consistency, resource.list hardening, URI parsing, legacy update routing, test cleanups * docs(tools): richer MCP tool descriptions; tests accept decorator kwargs; resource URI parsing hardened * Update .claude/prompts/nl-unity-suite-full.md Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update UnityMcpBridge/UnityMcpServer~/src/tools/resource_tools.py Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update UnityMcpBridge/UnityMcpServer~/src/unity_connection.py Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * net+docs: hard-reject zero-length frames; TCP_NODELAY on connect; Assets detection case-insensitive; NL prompt statuses aligned * prompt(nl-suite): constrain Write destinations under reports/, forbid traversal * prompt+net: harden Write path rules; use monotonic deadline and plain-text advisory for non-framed peers * unity_connection: restore recv timeout via try/finally; make global connection getter thread-safe with module lock and double-checked init * NL/T prompt: pin structured edit ops for T-D/T-E; add schema-error guarded write behavior; keep existing path/URI and revert rules * unity_connection: add FRAMED_MAX; use ValueError for framed length violations; lower framed receive log to debug; serialize connect() with per-instance lock * ManageScript: use UTF8Encoding(without BOM) for atomic writes in ApplyTextEdits/EditScript to align with Create/Update and avoid BOM-related diffs/hash mismatches * NL/T prompt: make helper deletion regex multiline-safe ((?ms) so ^ anchors line starts) * ManageScript: emit structured overlap status {status:"overlap"} for overlapping edit ranges in apply_text_edits and edit paths * NL/T prompt: clarify fallback vs failure — fallback only for unsupported/missing_field; treat bad_request as failure; note unsupported after fallback as failure * NL/T prompt: pin deterministic overlap probe (apply_text_edits two ranges from same snapshot); gate too_large behind RUN_TOO_LARGE env hint * TB update * NL/T prompt: harden Output Rules — constrain Bash(printf|echo) to stdout-only; forbid redirection/here-docs/tee; only scripts/nlt-revert.sh may mutate FS * Prompt: enumerate allowed script_apply_edits ops; add manage_editor/read_console guidance; fix T‑F atomic batch to single script_apply_edits. ManageScript: regex timeout for diagnostics; symlink ancestor guard; complete allowed-modes list. * Fixes * ManageScript: add rich overlap diagnostics (conflicts + hint) for both text range and structured batch paths * ManageScript: return structured {status:"validation_failed"} diagnostics in create/update/edits and validate before commit * ManageScript: echo canonical uri in responses (create/read/update/apply_text_edits/structured edits) to reinforce resource identity * improve clarity of capabilities message * Framing: allow zero-length frames on both ends (C# bridge, Python server). Prompt: harden T-F to single text-range apply_text_edits batch (descending order, one snapshot). URI: normalize file:// outside Assets by stripping leading slash. * ManageScript: include new sha256 in success payload for apply_text_edits; harden TryResolveUnderAssets by rejecting symlinked ancestors up to Assets/. * remove claudetest dir * manage_script_edits: normalize method-anchored anchor_insert to insert_method (map text->replacement); improves CI compatibility for T‑A/T‑E without changing Editor behavior. * tighten testing protocol around mkdir * manage_script: validate create_script inputs (Assets/.cs/name/no traversal); add Assets/ guard to delete_script; validate level+Assets in validate_script; make legacy manage_script optional params; harden legacy update routing with base64 reuse and payload size preflight. * Tighten prompt for testing * Update .claude/prompts/nl-unity-suite-full.md Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update .claude/prompts/nl-unity-suite-full.md Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update UnityMcpBridge/Editor/Tools/ManageScript.cs Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * manage_script_edits: honor ignore_case on anchor_insert and regex_replace in both direct and text-conversion paths (MULTILINE|IGNORECASE). * remove extra file * workflow: use python3 for inline scripts and port detection on ubuntu-latest. * Tighten prompt + manage_script * Update UnityMcpBridge/UnityMcpServer~/src/tools/manage_script_edits.py Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update UnityMcpBridge/UnityMcpServer~/src/tools/manage_script_edits.py Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update .claude/prompts/nl-unity-suite-full.md Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update UnityMcpBridge/Editor/Tools/ManageScript.cs Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update .claude/prompts/nl-unity-suite-full.md Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * manage_script: improve file:// UNC handling; preserve POSIX absolute semantics internally; keep test-expected slash stripping for non-Assets paths. * ManageScript.cs: add TimeSpan timeouts to all Regex uses (IsMatch/Match/new Regex) and keep CultureInvariant/Multiline options; reduces risk of catastrophic backtracking stalls. * workflow: ensure reports/ exists in markdown build step to avoid FileNotFoundError when writing MD_OUT. * fix brace * manage_script_edits: expand backrefs for regex_replace in preview->text conversion and translate to \g<n> in local apply; keeps previews and actual edits consistent. * anchor_insert: default to position=after, normalize surrounding newlines in Python conversion paths; C# path ensures trailing newline and skips duplicate insertion within class. * feat(mcp): add get_sha tool; apply_text_edits normalization+overlap preflight+strict; no-op evidence in C#; update NL suite prompt; add unit tests * feat(frames): accept zero-length heartbeat frames in client; add heartbeat test * feat(edits): guard destructive regex_replace with structural preflight; add robust tests; prompt uses delete_method for temp helper * feat(frames): bound heartbeat loop with timeout/threshold; align zero-length response with C#; update test * SDK hardening: atomic multi-span text edits; stop forcing sequential for structured ops; forward options on apply_text_edits; add validate=relaxed support and scoped checks; update NL/T prompt; add tests for options forwarding, relaxed mode, and atomic batches * Router: default applyMode=atomic for multi-span apply_text_edits; add tests * CI prompt: pass options.validate=relaxed for T-B/C; options.applyMode=atomic for T-F; emphasize always writing testcase and restoring on errors * Validation & DX: add validate=syntax (scoped), standardize evidence windows; early regex compile with hints; debug_preview for apply_text_edits * Update UnityMcpBridge/Editor/Windows/MCPForUnityEditorWindow.cs Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * NL/T suite-driven edits: LongUnityScriptClaudeTest, bridge helpers, server_version; prepare framing tests * Fix duplicate macConfigPath field in McpClient to resolve CS0102 * Editor threading: run EnsureServerInstalled on main thread; marshal EditorPrefs/DeleteKey + logging via delayCall * Docs(apply_text_edits): strengthen guidance on 1-based positions, verify-before-edit, and recommend anchors/structured edits * Docs(script_apply_edits): add safety guidance (anchors, method ops, validators) and recommended practices * Framed VerifyBridgePing in editor window; docs hardening for apply_text_edits and script_apply_edits --------- Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
2025-08-31 00:55:38 +08:00
using System.Threading;
using System.Security.Cryptography;
2025-03-31 03:58:01 +08:00
#if USE_ROSLYN
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
Claude‑friendly edit tools + framed transport + live Unity NL test framework (#243) * CI: gate desktop-parity on Anthropic key; pass anthropic_api_key like NL suite * Add quickprobe prompt and CI workflow (mcp-quickprobe.md, unity-mcp-quickprobe.yml) * strictier tool use to prevent subagent spawning and force mcp tools * update workflow filesto reduce likelihood of subagent spawning * improve permissions for claude agent, fix mcpbridge timeout/token issue * increase max turns to 10 * ci: align NL suite to new permissions schema; prevent subagent drift * ci: NL suite -> mini prompt for e2e; add full NL/T prompt; server: ctx optional + project_root fallback; workflows: set UNITY_PROJECT_ROOT for CI * ci: add checks:write; revert local project hardcodes (manifest, ProjectVersion.txt) * tools: text-edit routing fixes (anchor_insert via text, CRLF calc); prompts: mini NL/T clarifications * ci: use absolute UNITY_PROJECT_ROOT; prompts target TestProjects; server: accept relative UNITY_PROJECT_ROOT and bare spec URI * ci: ignore Unity test project's packages-lock.json; remove from repo to avoid absolute paths * CI: start persistent Unity Editor for MCP (guarded by license) + allow batch-mode bridge via UNITY_MCP_ALLOW_BATCH * CI: hide license and pass via env to docker; fix invalid ref format * CI: readiness probe uses handshake on Unity MCP port (deterministic) * CI: fix YAML; use TCP handshake readiness probe (FRAMING=1) * CI: prime Unity license via game-ci; mount ULF into container; extend readiness timeout * CI: use ULF write + mount for Unity licensing; remove serial/email/pass from container * CI: entitlement activation (UNITY_SERIAL=''); verify host ULF cache; keep mount * CI: write ULF from secret and verify; drop entitlement activation step * CI: detect any licensing path; GameCI prime; status dir env; log+probe readiness; fix YAML * CI: add GameCI license prime; conditional ULF write; one-shot license validation; explicit status dir + license env * CI: fix YAML (inline python), add Anthropic key detect via GITHUB_ENV; ready to run happy path * CI: mount Unity token/ulf/cache dirs into container to share host license; create dirs before start * CI: fix YAML indentation; write ULF on host; activate in container with shared mounts; mount .config and .cache too * CI: gate Claude via outputs; mount all Unity license dirs; fix inline probe python; stabilize licensing flow * CI: normalize detect to step outputs; ensure license dirs mounted and validated; fix indentation * Bridge: honor UNITY_MCP_STATUS_DIR for heartbeat/status file (CI-friendly) * CI: guard project path for activation/start; align tool allowlist; run MCP server with python; tighten secret scoping * CI: finalize Unity licensing mounts + status dir; mode-detect (ULF/EBL); readiness logs+probe; Claude gating via outputs * CI: fix YAML probe (inline python -c) and finalize happy-path Unity licensing and MCP/Claude wiring * CI: inline python probe; unify Unity image and cache mounts; ready to test * CI: fix docker run IMAGE placement; ignore cache find perms; keep same editor image * CI: pass -manualLicenseFile to persistent Editor; keep mounts and single image * CI: mount full GameCI cache to /root in persistent Unity; set HOME=/root; add optional license check * CI: make -manualLicenseFile conditional; keep full /root mount and license check * CI: set HOME=/github/home; mount GameCI cache there; adjust manualLicenseFile path; expand license check * CI: EBL sign-in for persistent Unity (email/password/serial); revert HOME=/root and full /root mount; keep conditional manualLicenseFile and improved readiness * CI: run full NL/T suite prompt (nl-unity-suite-full.md) instead of mini * NL/T: require unified diffs + explicit verdicts in JUnit; CI: remove short sanity step, publish JUnit, upload artifacts * NL/T prompt: require CDATA wrapping for JUnit XML fields; guidance for splitting embedded ]]>; keep VERDICT in CDATA only * CI: remove in-container license check step; keep readiness and full suite * NL/T prompt: add version header, stricter JUnit schema, hashing/normalization, anchors, statuses, atomic semantics, tool logging * CI: increase Claude NL/T suite timeout to 30 minutes * CI: pre-create reports dir and result files to avoid tool approval prompts * CI: skip wait if container not running; skip Editor start if project missing; broaden MCP deps detection; expand allowed tools * fixies to harden ManageScript * CI: sanitize NL/T markdown report to avoid NUL/encoding issues * revert breaking yyaml changes * CI: prime license, robust Unity start/wait, sanitize markdown via heredoc * Resolve merge: accept upstream renames/installer (fix/installer-cleanup-v2) and keep local framing/script-editing - Restored upstream server.py, EditorWindow, uv.lock\n- Preserved ManageScript editing/validation; switched to atomic write + debounced refresh\n- Updated tools/__init__.py to keep script_edits/resources and adopt new logger name\n- All Python tests via uv: 7 passed, 6 skipped, 9 xpassed; Unity compile OK * Fix Claude Desktop config path and atomic write issues - Fix macOS path for Claude Desktop config: use ~/Library/Application Support/Claude/ instead of ~/.config/Claude/ - Improve atomic write pattern with backup/restore safety - Replace File.Replace() with File.Move() for better macOS compatibility - Add proper error handling and cleanup for file operations - Resolves issue where installer couldn't find Claude Desktop config on macOS * Editor: use macConfigPath on macOS for MCP client config writes (Claude Desktop, etc.). Fallback to linuxConfigPath only if mac path missing. * Models: add macConfigPath to McpClient for macOS config path selection (fixes CS1061 in editor window). * Editor: on macOS, prefer macConfigPath in ManualConfigEditorWindow (fallback to linux path); Linux/Windows unchanged. * Fix McpClient: align with upstream/main, prep for framing split * NL suite: shard workflow; tighten bridge readiness; add MCP preflight; use env-based shard vars * NL suite: fix shard step indentation; move shard vars to env; remove invalid inputs * MCP clients: split VSCode Copilot config paths into macConfigPath and linuxConfigPath * Unity bridge: clean stale status; bind host; robust wait probe with IPv4/IPv6 + diagnostics * CI: use MCPForUnity.Editor.MCPForUnityBridge.StartAutoConnect as executeMethod * Action wiring: inline mcpServers in settings for all shards; remove redundant .claude/mcp.json step * CI: embed mcpServers in settings for all shards; fix startup sanity step; lint clean * CI: pin claude-code-base-action to e6f32c8; use claude_args --mcp-config; switch to allowed_tools; ensure MCP config per step * CI: unpin claude-code-base-action to @beta (commit ref not found) * CI: align with claude-code-base-action @beta; pass MCP via claude_args and allowedTools * Editor: Fix apply_text_edits heuristic when edits shift positions; recompute method span on candidate text with fallback delta adjustment * CI: unify MCP wiring across workflows; write .claude/mcp.json; switch to claude_args with --mcp-config/--allowedTools; remove unsupported inputs * CI: collapse NL suite shards into a single run to avoid repeated test execution * CI: minimize allowedTools for NL suite to essential Unity MCP + Bash("git:*") + Write * CI: mkdir -p reports before run; remove unsupported --timeout-minutes from claude_args * CI: broaden allowedTools to include find_in_file and mcp__unity__* * CI: enable use_node_cache and switch NL suite model to claude-3-7-haiku-20250219 * CI: disable use_node_cache to avoid setup-node lockfile error * CI: set NL suite model to claude-3-haiku-20240307 * CI: cap Haiku output with --max-tokens 2048 for NL suite * CI: switch to claude-3-7-sonnet-latest and remove unsupported --max-tokens * CI: update allowedTools to Bash(*) and explicit Unity MCP tool list * CI: update NL suite workflow (latest tweaks) * Tests: tighten NL suite prompt for logging, hash discipline, stale retry, evidence windows, diff cap, and VERDICT line * Add disallowed tools to NL suite workflow * docs: clarify stale write retry * Add fallback JUnit report and adjust publisher * Indent fallback JUnit XML in workflow * fix: correct fallback JUnit report generation * Update mcp-quickprobe.md Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> * Update mcp-quickprobe.md Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> * Update Response.cs Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> * Update MCPForUnityBridge.cs Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> * fix: correct McpTypes reference * Add directory existence checks for symlink and XDG paths * fix: only set installation flag after successful server install * Update resource_tools.py Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> * fix: respect mac config paths * Use File.Replace for atomic config write * Remove unused imports in manage_script * bump server version * Tests: update NL suite prompt and workflows; remove deprecated smoke/desktop-parity; quickprobe tidy * Editor: atomic config write via File.Replace fallback; remove redundant backups and racey exists checks * CI: harden NL suite - idempotent docker, gate on unity_ok, safer port probe, least-priv perms * Editor: make atomic config write restoration safe (flag writeDone; copy-overwrite restore; cleanup in finally) * CI: fix fallback JUnit heredoc by using printf lines (no EOF delimiter issues) * CI: switch NL suite to mini prompt; mini prompt honors / and NL discipline * CI: replace claude_args with allowed_tools/model/mcp_config per action schema * CI: expand UNITY_PROJECT_ROOT via in MCP config heredoc * EditorWindow: add cross-platform fallback for File.Replace; macOS-insensitive PathsEqual; safer uv resolve; honor macConfigPath * CI: strengthen JUnit publishing for NL mini suite (normalize, debug list, publish both, fail_on_parse_error) * CI: set job-wide JUNIT_OUT/MD_OUT; normalization uses env; publish references env and ungroup reports * CI: publish a single normalized JUnit (reports/junit-for-actions.xml); fallback writes same; avoid checkName/reportPaths mismatch * CI: align mini prompt report filenames; redact Unity log tail in diagnostics * chore: sync workflow and mini prompt; redacted logs; JUnit normalization/publish tweaks * CI: redact sensitive tokens in Stop Unity; docs: CI usage + edit tools * prompts: update nl-unity-suite-full (mini-style setup + reporting discipline); remove obsolete prompts * CI: harden NL workflows (timeout_minutes, robust normalization); prompts: unify JUnit suite name and reporting discipline * prompts: add guarded write pattern (LF hash, stale_file retry) to full suite * prompts: enforce continue-on-failure, driver flow, and status handling in full suite * Make test list more explicit in prompt. Get rid of old test prompts for hygeine. * prompts: add stale fast-retry (server hash) + in-memory buf guidance * CI: standardize JUNIT_OUT to reports/junit-nl-suite.xml; fix artifact upload indentation; prompt copy cleanups * prompts: reporting discipline — append-only fragments, batch writes, no model round-trip * prompts: stale fast-retry preference, buffer/sha carry, snapshot revert, essential logging * workflows(nl-suite): precreate report skeletons, assemble junit, synthesize markdown; restrict allowed_tools to append-only Bash + MCP tools * thsis too * Update README-DEV.md Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update .github/workflows/claude-nl-suite-mini.yml Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update .github/workflows/claude-nl-suite.yml Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * workflows(nl-mini): fix YAML indentation/trailing spaces under with: and cleanup heredoc spacing * workflows(nl-suite): fix indentation on docker logs redaction line (YAML lint) * Add write to allowlist * nl-suite: harden reporting discipline (fragment-only writes, forbid alt paths); workflow: clean stray junit-*updated*.xml * nl-suite: enforce end-of-suite single Write (no bash redirection); workflow: restrict allowed_tools to Write+MCP only * prompts(nl-full): end-of-suite results must be valid XML with single <cases> root and only <testcase> children; no raw text outside CDATA * workflows(nl-suite): make Claude step non-fatal; tolerant normalizer extracts <testcase> via regex on bad fragments * nl-suite: fix stale classname to UnityMCP.NL-T in mini fallback; prompt: require re-read after every revert; correct PLAN/PROGRESS to 15 * nl-suite: fix fallback JUnit classname to UnityMCP.NL-T; prompt: forbid create_script and env/mkdir checks, enforce single baseline-byte revert flow and post-revert re-read; add corruption-handling guidance * prompts(nl-full): after each write re-read raw bytes to refresh pre_sha; prefer script_apply_edits for anchors; avoid header/using changes * prompts(nl-full): canonicalize outputs to /; allow small fragment appends via Write or Bash(printf/echo); forbid wrappers and full-file round-trips * prompts(nl-full): finalize markdown formatting for guarded write, execution order, specs, status * workflows(nl-suite, mini): header/lint fixes and constrained Bash append path; align allowed_tools * prompts(nl-full): format Fast Restore, Guarded Write, Execution, Specs, Status as proper markdown lists and code fences * workflows(nl-suite): keep header tidy and append-path alignment with prompt * minor fix * workflows(nl-suite): fix indentation and dispatch; align allowed_tools and revert helper * prompts(nl-full): switch to read_resource for buf/sha; re-read only when needed; convert 'Print this once' to heading; note snapshot helper creates parent dirs * workflows(nl-suite): normalize step removes bootstrap when real testcases present; recompute tests/failures * workflows(nl-suite): enrich Markdown summary by extracting per-test <system-out> blocks (truncated) * clarify prompt resilience instructions * ci(nl-suite): revert prompt and workflow to known-good e0f8a72 for green run; remove extra MD details * ci(nl-suite): minimal fixes — no-mkdir guard in prompt; drop bootstrap and recompute JUnit counts * ci(nl-suite): richer JUnit→Markdown report (per-test system-out) * Small guard to incorret asset read call. * ci(nl-suite): refine MD builder — unescape XML entities, safe code fences, PASS/FAIL badges * Update UnityMcpBridge/UnityMcpServer~/src/tools/resource_tools.py Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update UnityMcpBridge/UnityMcpServer~/src/unity_connection.py Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update UnityMcpBridge/UnityMcpServer~/src/tools/manage_script_edits.py Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update .github/scripts/mark_skipped.py Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update .github/scripts/mark_skipped.py Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update .github/scripts/mark_skipped.py Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> * server(manage_script): robust URI handling — percent-decode file://, normalize, strip host/leading slashes, return Assets-relative if present * Update .claude/prompts/nl-unity-suite-full.md Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> * tests(framing): reduce handshake poll window, nonblocking peek to avoid disconnect race; still enforce pre-handshake data drop * tests(manage_script): add _split_uri tests for unity://path, file:// URLs (decoded/Assets-relative), and plain paths * server+tests: fix handshake syntax error; robust file:// URI normalization in manage_script; add _split_uri tests; adjust stdout scan to ignore venv/site-packages * bridge(framing): accept zero-length frames (treat as empty keepalive) * tests(logging): use errors='replace' on decode fallback to avoid silent drops * resources(list): restrict to Assets/, resolve symlinks, enforce .cs; add traversal/outside-path tests * Update .claude/prompts/nl-unity-suite-full.md Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update UnityMcpBridge/UnityMcpServer~/src/unity_connection.py Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * misc: framing keepalive (zero-length), regex preview consistency, resource.list hardening, URI parsing, legacy update routing, test cleanups * docs(tools): richer MCP tool descriptions; tests accept decorator kwargs; resource URI parsing hardened * Update .claude/prompts/nl-unity-suite-full.md Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update UnityMcpBridge/UnityMcpServer~/src/tools/resource_tools.py Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update UnityMcpBridge/UnityMcpServer~/src/unity_connection.py Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * net+docs: hard-reject zero-length frames; TCP_NODELAY on connect; Assets detection case-insensitive; NL prompt statuses aligned * prompt(nl-suite): constrain Write destinations under reports/, forbid traversal * prompt+net: harden Write path rules; use monotonic deadline and plain-text advisory for non-framed peers * unity_connection: restore recv timeout via try/finally; make global connection getter thread-safe with module lock and double-checked init * NL/T prompt: pin structured edit ops for T-D/T-E; add schema-error guarded write behavior; keep existing path/URI and revert rules * unity_connection: add FRAMED_MAX; use ValueError for framed length violations; lower framed receive log to debug; serialize connect() with per-instance lock * ManageScript: use UTF8Encoding(without BOM) for atomic writes in ApplyTextEdits/EditScript to align with Create/Update and avoid BOM-related diffs/hash mismatches * NL/T prompt: make helper deletion regex multiline-safe ((?ms) so ^ anchors line starts) * ManageScript: emit structured overlap status {status:"overlap"} for overlapping edit ranges in apply_text_edits and edit paths * NL/T prompt: clarify fallback vs failure — fallback only for unsupported/missing_field; treat bad_request as failure; note unsupported after fallback as failure * NL/T prompt: pin deterministic overlap probe (apply_text_edits two ranges from same snapshot); gate too_large behind RUN_TOO_LARGE env hint * TB update * NL/T prompt: harden Output Rules — constrain Bash(printf|echo) to stdout-only; forbid redirection/here-docs/tee; only scripts/nlt-revert.sh may mutate FS * Prompt: enumerate allowed script_apply_edits ops; add manage_editor/read_console guidance; fix T‑F atomic batch to single script_apply_edits. ManageScript: regex timeout for diagnostics; symlink ancestor guard; complete allowed-modes list. * Fixes * ManageScript: add rich overlap diagnostics (conflicts + hint) for both text range and structured batch paths * ManageScript: return structured {status:"validation_failed"} diagnostics in create/update/edits and validate before commit * ManageScript: echo canonical uri in responses (create/read/update/apply_text_edits/structured edits) to reinforce resource identity * improve clarity of capabilities message * Framing: allow zero-length frames on both ends (C# bridge, Python server). Prompt: harden T-F to single text-range apply_text_edits batch (descending order, one snapshot). URI: normalize file:// outside Assets by stripping leading slash. * ManageScript: include new sha256 in success payload for apply_text_edits; harden TryResolveUnderAssets by rejecting symlinked ancestors up to Assets/. * remove claudetest dir * manage_script_edits: normalize method-anchored anchor_insert to insert_method (map text->replacement); improves CI compatibility for T‑A/T‑E without changing Editor behavior. * tighten testing protocol around mkdir * manage_script: validate create_script inputs (Assets/.cs/name/no traversal); add Assets/ guard to delete_script; validate level+Assets in validate_script; make legacy manage_script optional params; harden legacy update routing with base64 reuse and payload size preflight. * Tighten prompt for testing * Update .claude/prompts/nl-unity-suite-full.md Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update .claude/prompts/nl-unity-suite-full.md Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update UnityMcpBridge/Editor/Tools/ManageScript.cs Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * manage_script_edits: honor ignore_case on anchor_insert and regex_replace in both direct and text-conversion paths (MULTILINE|IGNORECASE). * remove extra file * workflow: use python3 for inline scripts and port detection on ubuntu-latest. * Tighten prompt + manage_script * Update UnityMcpBridge/UnityMcpServer~/src/tools/manage_script_edits.py Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update UnityMcpBridge/UnityMcpServer~/src/tools/manage_script_edits.py Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update .claude/prompts/nl-unity-suite-full.md Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update UnityMcpBridge/Editor/Tools/ManageScript.cs Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update .claude/prompts/nl-unity-suite-full.md Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * manage_script: improve file:// UNC handling; preserve POSIX absolute semantics internally; keep test-expected slash stripping for non-Assets paths. * ManageScript.cs: add TimeSpan timeouts to all Regex uses (IsMatch/Match/new Regex) and keep CultureInvariant/Multiline options; reduces risk of catastrophic backtracking stalls. * workflow: ensure reports/ exists in markdown build step to avoid FileNotFoundError when writing MD_OUT. * fix brace * manage_script_edits: expand backrefs for regex_replace in preview->text conversion and translate to \g<n> in local apply; keeps previews and actual edits consistent. * anchor_insert: default to position=after, normalize surrounding newlines in Python conversion paths; C# path ensures trailing newline and skips duplicate insertion within class. * feat(mcp): add get_sha tool; apply_text_edits normalization+overlap preflight+strict; no-op evidence in C#; update NL suite prompt; add unit tests * feat(frames): accept zero-length heartbeat frames in client; add heartbeat test * feat(edits): guard destructive regex_replace with structural preflight; add robust tests; prompt uses delete_method for temp helper * feat(frames): bound heartbeat loop with timeout/threshold; align zero-length response with C#; update test * SDK hardening: atomic multi-span text edits; stop forcing sequential for structured ops; forward options on apply_text_edits; add validate=relaxed support and scoped checks; update NL/T prompt; add tests for options forwarding, relaxed mode, and atomic batches * Router: default applyMode=atomic for multi-span apply_text_edits; add tests * CI prompt: pass options.validate=relaxed for T-B/C; options.applyMode=atomic for T-F; emphasize always writing testcase and restoring on errors * Validation & DX: add validate=syntax (scoped), standardize evidence windows; early regex compile with hints; debug_preview for apply_text_edits * Update UnityMcpBridge/Editor/Windows/MCPForUnityEditorWindow.cs Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * NL/T suite-driven edits: LongUnityScriptClaudeTest, bridge helpers, server_version; prepare framing tests * Fix duplicate macConfigPath field in McpClient to resolve CS0102 * Editor threading: run EnsureServerInstalled on main thread; marshal EditorPrefs/DeleteKey + logging via delayCall * Docs(apply_text_edits): strengthen guidance on 1-based positions, verify-before-edit, and recommend anchors/structured edits * Docs(script_apply_edits): add safety guidance (anchors, method ops, validators) and recommended practices * Framed VerifyBridgePing in editor window; docs hardening for apply_text_edits and script_apply_edits --------- Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
2025-08-31 00:55:38 +08:00
using Microsoft.CodeAnalysis.Formatting;
#endif
#if UNITY_EDITOR
using UnityEditor.Compilation;
#endif
Rename namespace and public facing plugin output from "Unity MCP" to "MCP for Unity" (#225) * refactor: rename namespace from UnityMcpBridge to MCPForUnity across all files See thread in #6, we can't use Unity MCP because it violates their trademark. That name makes us look affiliated. We can use MCP for Unity * Change package display name, menu item and menu titles These are front facing so has to change for Unity asset store review * Misc name changes in logs and comments for better consistency * chore: update editor window title from 'MCP Editor' to 'MCP for Unity' * refactor: update branding from UNITY-MCP to MCP-FOR-UNITY across all log messages and warnings * chore: rename Unity MCP to MCP For Unity across all files and bump version to 2.1.2 * docs: update restore script title to clarify Unity MCP naming * Fix usage instructions * chore: update log messages to use MCP For Unity branding instead of UnityMCP * Add a README inside plugin, required for distributing via the asset store * docs: update Unity port description and fix typo in troubleshooting section * Address Rabbit feedback * Update Editor prefs to use new name Prevents overlap with other Unity MCPs, happy to revert if it's too much * refactor: rename server logger and identifier from unity-mcp-server to mcp-for-unity-server * Standardize casing of renamed project to "MCP for Unity", as it is on the asset store * Remove unused folder * refactor: rename Unity MCP to MCP for Unity across codebase * Update dangling references * docs: update product name from UnityMCP to MCP for Unity in README * Update log and comments for new name
2025-08-21 03:59:49 +08:00
namespace MCPForUnity.Editor.Tools
2025-03-31 03:58:01 +08:00
{
/// <summary>
/// Handles CRUD operations for C# scripts within the Unity project.
///
/// ROSLYN INSTALLATION GUIDE:
/// To enable advanced syntax validation with Roslyn compiler services:
///
/// 1. Install Microsoft.CodeAnalysis.CSharp NuGet package:
/// - Open Package Manager in Unity
/// - Follow the instruction on https://github.com/GlitchEnzo/NuGetForUnity
///
/// 2. Open NuGet Package Manager and Install Microsoft.CodeAnalysis.CSharp:
///
/// 3. Alternative: Manual DLL installation:
/// - Download Microsoft.CodeAnalysis.CSharp.dll and dependencies
/// - Place in Assets/Plugins/ folder
/// - Ensure .NET compatibility settings are correct
///
/// 4. Define USE_ROSLYN symbol:
/// - Go to Player Settings > Scripting Define Symbols
/// - Add "USE_ROSLYN" to enable Roslyn-based validation
///
/// 5. Restart Unity after installation
///
/// Note: Without Roslyn, the system falls back to basic structural validation.
/// Roslyn provides full C# compiler diagnostics with line numbers and detailed error messages.
2025-03-31 03:58:01 +08:00
/// </summary>
public static class ManageScript
{
Claude‑friendly edit tools + framed transport + live Unity NL test framework (#243) * CI: gate desktop-parity on Anthropic key; pass anthropic_api_key like NL suite * Add quickprobe prompt and CI workflow (mcp-quickprobe.md, unity-mcp-quickprobe.yml) * strictier tool use to prevent subagent spawning and force mcp tools * update workflow filesto reduce likelihood of subagent spawning * improve permissions for claude agent, fix mcpbridge timeout/token issue * increase max turns to 10 * ci: align NL suite to new permissions schema; prevent subagent drift * ci: NL suite -> mini prompt for e2e; add full NL/T prompt; server: ctx optional + project_root fallback; workflows: set UNITY_PROJECT_ROOT for CI * ci: add checks:write; revert local project hardcodes (manifest, ProjectVersion.txt) * tools: text-edit routing fixes (anchor_insert via text, CRLF calc); prompts: mini NL/T clarifications * ci: use absolute UNITY_PROJECT_ROOT; prompts target TestProjects; server: accept relative UNITY_PROJECT_ROOT and bare spec URI * ci: ignore Unity test project's packages-lock.json; remove from repo to avoid absolute paths * CI: start persistent Unity Editor for MCP (guarded by license) + allow batch-mode bridge via UNITY_MCP_ALLOW_BATCH * CI: hide license and pass via env to docker; fix invalid ref format * CI: readiness probe uses handshake on Unity MCP port (deterministic) * CI: fix YAML; use TCP handshake readiness probe (FRAMING=1) * CI: prime Unity license via game-ci; mount ULF into container; extend readiness timeout * CI: use ULF write + mount for Unity licensing; remove serial/email/pass from container * CI: entitlement activation (UNITY_SERIAL=''); verify host ULF cache; keep mount * CI: write ULF from secret and verify; drop entitlement activation step * CI: detect any licensing path; GameCI prime; status dir env; log+probe readiness; fix YAML * CI: add GameCI license prime; conditional ULF write; one-shot license validation; explicit status dir + license env * CI: fix YAML (inline python), add Anthropic key detect via GITHUB_ENV; ready to run happy path * CI: mount Unity token/ulf/cache dirs into container to share host license; create dirs before start * CI: fix YAML indentation; write ULF on host; activate in container with shared mounts; mount .config and .cache too * CI: gate Claude via outputs; mount all Unity license dirs; fix inline probe python; stabilize licensing flow * CI: normalize detect to step outputs; ensure license dirs mounted and validated; fix indentation * Bridge: honor UNITY_MCP_STATUS_DIR for heartbeat/status file (CI-friendly) * CI: guard project path for activation/start; align tool allowlist; run MCP server with python; tighten secret scoping * CI: finalize Unity licensing mounts + status dir; mode-detect (ULF/EBL); readiness logs+probe; Claude gating via outputs * CI: fix YAML probe (inline python -c) and finalize happy-path Unity licensing and MCP/Claude wiring * CI: inline python probe; unify Unity image and cache mounts; ready to test * CI: fix docker run IMAGE placement; ignore cache find perms; keep same editor image * CI: pass -manualLicenseFile to persistent Editor; keep mounts and single image * CI: mount full GameCI cache to /root in persistent Unity; set HOME=/root; add optional license check * CI: make -manualLicenseFile conditional; keep full /root mount and license check * CI: set HOME=/github/home; mount GameCI cache there; adjust manualLicenseFile path; expand license check * CI: EBL sign-in for persistent Unity (email/password/serial); revert HOME=/root and full /root mount; keep conditional manualLicenseFile and improved readiness * CI: run full NL/T suite prompt (nl-unity-suite-full.md) instead of mini * NL/T: require unified diffs + explicit verdicts in JUnit; CI: remove short sanity step, publish JUnit, upload artifacts * NL/T prompt: require CDATA wrapping for JUnit XML fields; guidance for splitting embedded ]]>; keep VERDICT in CDATA only * CI: remove in-container license check step; keep readiness and full suite * NL/T prompt: add version header, stricter JUnit schema, hashing/normalization, anchors, statuses, atomic semantics, tool logging * CI: increase Claude NL/T suite timeout to 30 minutes * CI: pre-create reports dir and result files to avoid tool approval prompts * CI: skip wait if container not running; skip Editor start if project missing; broaden MCP deps detection; expand allowed tools * fixies to harden ManageScript * CI: sanitize NL/T markdown report to avoid NUL/encoding issues * revert breaking yyaml changes * CI: prime license, robust Unity start/wait, sanitize markdown via heredoc * Resolve merge: accept upstream renames/installer (fix/installer-cleanup-v2) and keep local framing/script-editing - Restored upstream server.py, EditorWindow, uv.lock\n- Preserved ManageScript editing/validation; switched to atomic write + debounced refresh\n- Updated tools/__init__.py to keep script_edits/resources and adopt new logger name\n- All Python tests via uv: 7 passed, 6 skipped, 9 xpassed; Unity compile OK * Fix Claude Desktop config path and atomic write issues - Fix macOS path for Claude Desktop config: use ~/Library/Application Support/Claude/ instead of ~/.config/Claude/ - Improve atomic write pattern with backup/restore safety - Replace File.Replace() with File.Move() for better macOS compatibility - Add proper error handling and cleanup for file operations - Resolves issue where installer couldn't find Claude Desktop config on macOS * Editor: use macConfigPath on macOS for MCP client config writes (Claude Desktop, etc.). Fallback to linuxConfigPath only if mac path missing. * Models: add macConfigPath to McpClient for macOS config path selection (fixes CS1061 in editor window). * Editor: on macOS, prefer macConfigPath in ManualConfigEditorWindow (fallback to linux path); Linux/Windows unchanged. * Fix McpClient: align with upstream/main, prep for framing split * NL suite: shard workflow; tighten bridge readiness; add MCP preflight; use env-based shard vars * NL suite: fix shard step indentation; move shard vars to env; remove invalid inputs * MCP clients: split VSCode Copilot config paths into macConfigPath and linuxConfigPath * Unity bridge: clean stale status; bind host; robust wait probe with IPv4/IPv6 + diagnostics * CI: use MCPForUnity.Editor.MCPForUnityBridge.StartAutoConnect as executeMethod * Action wiring: inline mcpServers in settings for all shards; remove redundant .claude/mcp.json step * CI: embed mcpServers in settings for all shards; fix startup sanity step; lint clean * CI: pin claude-code-base-action to e6f32c8; use claude_args --mcp-config; switch to allowed_tools; ensure MCP config per step * CI: unpin claude-code-base-action to @beta (commit ref not found) * CI: align with claude-code-base-action @beta; pass MCP via claude_args and allowedTools * Editor: Fix apply_text_edits heuristic when edits shift positions; recompute method span on candidate text with fallback delta adjustment * CI: unify MCP wiring across workflows; write .claude/mcp.json; switch to claude_args with --mcp-config/--allowedTools; remove unsupported inputs * CI: collapse NL suite shards into a single run to avoid repeated test execution * CI: minimize allowedTools for NL suite to essential Unity MCP + Bash("git:*") + Write * CI: mkdir -p reports before run; remove unsupported --timeout-minutes from claude_args * CI: broaden allowedTools to include find_in_file and mcp__unity__* * CI: enable use_node_cache and switch NL suite model to claude-3-7-haiku-20250219 * CI: disable use_node_cache to avoid setup-node lockfile error * CI: set NL suite model to claude-3-haiku-20240307 * CI: cap Haiku output with --max-tokens 2048 for NL suite * CI: switch to claude-3-7-sonnet-latest and remove unsupported --max-tokens * CI: update allowedTools to Bash(*) and explicit Unity MCP tool list * CI: update NL suite workflow (latest tweaks) * Tests: tighten NL suite prompt for logging, hash discipline, stale retry, evidence windows, diff cap, and VERDICT line * Add disallowed tools to NL suite workflow * docs: clarify stale write retry * Add fallback JUnit report and adjust publisher * Indent fallback JUnit XML in workflow * fix: correct fallback JUnit report generation * Update mcp-quickprobe.md Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> * Update mcp-quickprobe.md Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> * Update Response.cs Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> * Update MCPForUnityBridge.cs Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> * fix: correct McpTypes reference * Add directory existence checks for symlink and XDG paths * fix: only set installation flag after successful server install * Update resource_tools.py Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> * fix: respect mac config paths * Use File.Replace for atomic config write * Remove unused imports in manage_script * bump server version * Tests: update NL suite prompt and workflows; remove deprecated smoke/desktop-parity; quickprobe tidy * Editor: atomic config write via File.Replace fallback; remove redundant backups and racey exists checks * CI: harden NL suite - idempotent docker, gate on unity_ok, safer port probe, least-priv perms * Editor: make atomic config write restoration safe (flag writeDone; copy-overwrite restore; cleanup in finally) * CI: fix fallback JUnit heredoc by using printf lines (no EOF delimiter issues) * CI: switch NL suite to mini prompt; mini prompt honors / and NL discipline * CI: replace claude_args with allowed_tools/model/mcp_config per action schema * CI: expand UNITY_PROJECT_ROOT via in MCP config heredoc * EditorWindow: add cross-platform fallback for File.Replace; macOS-insensitive PathsEqual; safer uv resolve; honor macConfigPath * CI: strengthen JUnit publishing for NL mini suite (normalize, debug list, publish both, fail_on_parse_error) * CI: set job-wide JUNIT_OUT/MD_OUT; normalization uses env; publish references env and ungroup reports * CI: publish a single normalized JUnit (reports/junit-for-actions.xml); fallback writes same; avoid checkName/reportPaths mismatch * CI: align mini prompt report filenames; redact Unity log tail in diagnostics * chore: sync workflow and mini prompt; redacted logs; JUnit normalization/publish tweaks * CI: redact sensitive tokens in Stop Unity; docs: CI usage + edit tools * prompts: update nl-unity-suite-full (mini-style setup + reporting discipline); remove obsolete prompts * CI: harden NL workflows (timeout_minutes, robust normalization); prompts: unify JUnit suite name and reporting discipline * prompts: add guarded write pattern (LF hash, stale_file retry) to full suite * prompts: enforce continue-on-failure, driver flow, and status handling in full suite * Make test list more explicit in prompt. Get rid of old test prompts for hygeine. * prompts: add stale fast-retry (server hash) + in-memory buf guidance * CI: standardize JUNIT_OUT to reports/junit-nl-suite.xml; fix artifact upload indentation; prompt copy cleanups * prompts: reporting discipline — append-only fragments, batch writes, no model round-trip * prompts: stale fast-retry preference, buffer/sha carry, snapshot revert, essential logging * workflows(nl-suite): precreate report skeletons, assemble junit, synthesize markdown; restrict allowed_tools to append-only Bash + MCP tools * thsis too * Update README-DEV.md Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update .github/workflows/claude-nl-suite-mini.yml Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update .github/workflows/claude-nl-suite.yml Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * workflows(nl-mini): fix YAML indentation/trailing spaces under with: and cleanup heredoc spacing * workflows(nl-suite): fix indentation on docker logs redaction line (YAML lint) * Add write to allowlist * nl-suite: harden reporting discipline (fragment-only writes, forbid alt paths); workflow: clean stray junit-*updated*.xml * nl-suite: enforce end-of-suite single Write (no bash redirection); workflow: restrict allowed_tools to Write+MCP only * prompts(nl-full): end-of-suite results must be valid XML with single <cases> root and only <testcase> children; no raw text outside CDATA * workflows(nl-suite): make Claude step non-fatal; tolerant normalizer extracts <testcase> via regex on bad fragments * nl-suite: fix stale classname to UnityMCP.NL-T in mini fallback; prompt: require re-read after every revert; correct PLAN/PROGRESS to 15 * nl-suite: fix fallback JUnit classname to UnityMCP.NL-T; prompt: forbid create_script and env/mkdir checks, enforce single baseline-byte revert flow and post-revert re-read; add corruption-handling guidance * prompts(nl-full): after each write re-read raw bytes to refresh pre_sha; prefer script_apply_edits for anchors; avoid header/using changes * prompts(nl-full): canonicalize outputs to /; allow small fragment appends via Write or Bash(printf/echo); forbid wrappers and full-file round-trips * prompts(nl-full): finalize markdown formatting for guarded write, execution order, specs, status * workflows(nl-suite, mini): header/lint fixes and constrained Bash append path; align allowed_tools * prompts(nl-full): format Fast Restore, Guarded Write, Execution, Specs, Status as proper markdown lists and code fences * workflows(nl-suite): keep header tidy and append-path alignment with prompt * minor fix * workflows(nl-suite): fix indentation and dispatch; align allowed_tools and revert helper * prompts(nl-full): switch to read_resource for buf/sha; re-read only when needed; convert 'Print this once' to heading; note snapshot helper creates parent dirs * workflows(nl-suite): normalize step removes bootstrap when real testcases present; recompute tests/failures * workflows(nl-suite): enrich Markdown summary by extracting per-test <system-out> blocks (truncated) * clarify prompt resilience instructions * ci(nl-suite): revert prompt and workflow to known-good e0f8a72 for green run; remove extra MD details * ci(nl-suite): minimal fixes — no-mkdir guard in prompt; drop bootstrap and recompute JUnit counts * ci(nl-suite): richer JUnit→Markdown report (per-test system-out) * Small guard to incorret asset read call. * ci(nl-suite): refine MD builder — unescape XML entities, safe code fences, PASS/FAIL badges * Update UnityMcpBridge/UnityMcpServer~/src/tools/resource_tools.py Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update UnityMcpBridge/UnityMcpServer~/src/unity_connection.py Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update UnityMcpBridge/UnityMcpServer~/src/tools/manage_script_edits.py Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update .github/scripts/mark_skipped.py Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update .github/scripts/mark_skipped.py Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update .github/scripts/mark_skipped.py Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> * server(manage_script): robust URI handling — percent-decode file://, normalize, strip host/leading slashes, return Assets-relative if present * Update .claude/prompts/nl-unity-suite-full.md Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> * tests(framing): reduce handshake poll window, nonblocking peek to avoid disconnect race; still enforce pre-handshake data drop * tests(manage_script): add _split_uri tests for unity://path, file:// URLs (decoded/Assets-relative), and plain paths * server+tests: fix handshake syntax error; robust file:// URI normalization in manage_script; add _split_uri tests; adjust stdout scan to ignore venv/site-packages * bridge(framing): accept zero-length frames (treat as empty keepalive) * tests(logging): use errors='replace' on decode fallback to avoid silent drops * resources(list): restrict to Assets/, resolve symlinks, enforce .cs; add traversal/outside-path tests * Update .claude/prompts/nl-unity-suite-full.md Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update UnityMcpBridge/UnityMcpServer~/src/unity_connection.py Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * misc: framing keepalive (zero-length), regex preview consistency, resource.list hardening, URI parsing, legacy update routing, test cleanups * docs(tools): richer MCP tool descriptions; tests accept decorator kwargs; resource URI parsing hardened * Update .claude/prompts/nl-unity-suite-full.md Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update UnityMcpBridge/UnityMcpServer~/src/tools/resource_tools.py Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update UnityMcpBridge/UnityMcpServer~/src/unity_connection.py Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * net+docs: hard-reject zero-length frames; TCP_NODELAY on connect; Assets detection case-insensitive; NL prompt statuses aligned * prompt(nl-suite): constrain Write destinations under reports/, forbid traversal * prompt+net: harden Write path rules; use monotonic deadline and plain-text advisory for non-framed peers * unity_connection: restore recv timeout via try/finally; make global connection getter thread-safe with module lock and double-checked init * NL/T prompt: pin structured edit ops for T-D/T-E; add schema-error guarded write behavior; keep existing path/URI and revert rules * unity_connection: add FRAMED_MAX; use ValueError for framed length violations; lower framed receive log to debug; serialize connect() with per-instance lock * ManageScript: use UTF8Encoding(without BOM) for atomic writes in ApplyTextEdits/EditScript to align with Create/Update and avoid BOM-related diffs/hash mismatches * NL/T prompt: make helper deletion regex multiline-safe ((?ms) so ^ anchors line starts) * ManageScript: emit structured overlap status {status:"overlap"} for overlapping edit ranges in apply_text_edits and edit paths * NL/T prompt: clarify fallback vs failure — fallback only for unsupported/missing_field; treat bad_request as failure; note unsupported after fallback as failure * NL/T prompt: pin deterministic overlap probe (apply_text_edits two ranges from same snapshot); gate too_large behind RUN_TOO_LARGE env hint * TB update * NL/T prompt: harden Output Rules — constrain Bash(printf|echo) to stdout-only; forbid redirection/here-docs/tee; only scripts/nlt-revert.sh may mutate FS * Prompt: enumerate allowed script_apply_edits ops; add manage_editor/read_console guidance; fix T‑F atomic batch to single script_apply_edits. ManageScript: regex timeout for diagnostics; symlink ancestor guard; complete allowed-modes list. * Fixes * ManageScript: add rich overlap diagnostics (conflicts + hint) for both text range and structured batch paths * ManageScript: return structured {status:"validation_failed"} diagnostics in create/update/edits and validate before commit * ManageScript: echo canonical uri in responses (create/read/update/apply_text_edits/structured edits) to reinforce resource identity * improve clarity of capabilities message * Framing: allow zero-length frames on both ends (C# bridge, Python server). Prompt: harden T-F to single text-range apply_text_edits batch (descending order, one snapshot). URI: normalize file:// outside Assets by stripping leading slash. * ManageScript: include new sha256 in success payload for apply_text_edits; harden TryResolveUnderAssets by rejecting symlinked ancestors up to Assets/. * remove claudetest dir * manage_script_edits: normalize method-anchored anchor_insert to insert_method (map text->replacement); improves CI compatibility for T‑A/T‑E without changing Editor behavior. * tighten testing protocol around mkdir * manage_script: validate create_script inputs (Assets/.cs/name/no traversal); add Assets/ guard to delete_script; validate level+Assets in validate_script; make legacy manage_script optional params; harden legacy update routing with base64 reuse and payload size preflight. * Tighten prompt for testing * Update .claude/prompts/nl-unity-suite-full.md Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update .claude/prompts/nl-unity-suite-full.md Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update UnityMcpBridge/Editor/Tools/ManageScript.cs Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * manage_script_edits: honor ignore_case on anchor_insert and regex_replace in both direct and text-conversion paths (MULTILINE|IGNORECASE). * remove extra file * workflow: use python3 for inline scripts and port detection on ubuntu-latest. * Tighten prompt + manage_script * Update UnityMcpBridge/UnityMcpServer~/src/tools/manage_script_edits.py Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update UnityMcpBridge/UnityMcpServer~/src/tools/manage_script_edits.py Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update .claude/prompts/nl-unity-suite-full.md Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update UnityMcpBridge/Editor/Tools/ManageScript.cs Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update .claude/prompts/nl-unity-suite-full.md Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * manage_script: improve file:// UNC handling; preserve POSIX absolute semantics internally; keep test-expected slash stripping for non-Assets paths. * ManageScript.cs: add TimeSpan timeouts to all Regex uses (IsMatch/Match/new Regex) and keep CultureInvariant/Multiline options; reduces risk of catastrophic backtracking stalls. * workflow: ensure reports/ exists in markdown build step to avoid FileNotFoundError when writing MD_OUT. * fix brace * manage_script_edits: expand backrefs for regex_replace in preview->text conversion and translate to \g<n> in local apply; keeps previews and actual edits consistent. * anchor_insert: default to position=after, normalize surrounding newlines in Python conversion paths; C# path ensures trailing newline and skips duplicate insertion within class. * feat(mcp): add get_sha tool; apply_text_edits normalization+overlap preflight+strict; no-op evidence in C#; update NL suite prompt; add unit tests * feat(frames): accept zero-length heartbeat frames in client; add heartbeat test * feat(edits): guard destructive regex_replace with structural preflight; add robust tests; prompt uses delete_method for temp helper * feat(frames): bound heartbeat loop with timeout/threshold; align zero-length response with C#; update test * SDK hardening: atomic multi-span text edits; stop forcing sequential for structured ops; forward options on apply_text_edits; add validate=relaxed support and scoped checks; update NL/T prompt; add tests for options forwarding, relaxed mode, and atomic batches * Router: default applyMode=atomic for multi-span apply_text_edits; add tests * CI prompt: pass options.validate=relaxed for T-B/C; options.applyMode=atomic for T-F; emphasize always writing testcase and restoring on errors * Validation & DX: add validate=syntax (scoped), standardize evidence windows; early regex compile with hints; debug_preview for apply_text_edits * Update UnityMcpBridge/Editor/Windows/MCPForUnityEditorWindow.cs Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * NL/T suite-driven edits: LongUnityScriptClaudeTest, bridge helpers, server_version; prepare framing tests * Fix duplicate macConfigPath field in McpClient to resolve CS0102 * Editor threading: run EnsureServerInstalled on main thread; marshal EditorPrefs/DeleteKey + logging via delayCall * Docs(apply_text_edits): strengthen guidance on 1-based positions, verify-before-edit, and recommend anchors/structured edits * Docs(script_apply_edits): add safety guidance (anchors, method ops, validators) and recommended practices * Framed VerifyBridgePing in editor window; docs hardening for apply_text_edits and script_apply_edits --------- Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
2025-08-31 00:55:38 +08:00
/// <summary>
/// Resolves a directory under Assets/, preventing traversal and escaping.
/// Returns fullPathDir on disk and canonical 'Assets/...' relative path.
/// </summary>
private static bool TryResolveUnderAssets(string relDir, out string fullPathDir, out string relPathSafe)
{
string assets = Application.dataPath.Replace('\\', '/');
// Normalize caller path: allow both "Scripts/..." and "Assets/Scripts/..."
string rel = (relDir ?? "Scripts").Replace('\\', '/').Trim();
if (string.IsNullOrEmpty(rel)) rel = "Scripts";
if (rel.StartsWith("Assets/", StringComparison.OrdinalIgnoreCase)) rel = rel.Substring(7);
rel = rel.TrimStart('/');
string targetDir = Path.Combine(assets, rel).Replace('\\', '/');
string full = Path.GetFullPath(targetDir).Replace('\\', '/');
bool underAssets = full.StartsWith(assets + "/", StringComparison.OrdinalIgnoreCase)
|| string.Equals(full, assets, StringComparison.OrdinalIgnoreCase);
if (!underAssets)
{
fullPathDir = null;
relPathSafe = null;
return false;
}
// Best-effort symlink guard: if the directory OR ANY ANCESTOR (up to Assets/) is a reparse point/symlink, reject
try
{
var di = new DirectoryInfo(full);
while (di != null)
{
if (di.Exists && (di.Attributes & FileAttributes.ReparsePoint) != 0)
{
fullPathDir = null;
relPathSafe = null;
return false;
}
var atAssets = string.Equals(
di.FullName.Replace('\\','/'),
assets,
StringComparison.OrdinalIgnoreCase
);
if (atAssets) break;
di = di.Parent;
}
}
catch { /* best effort; proceed */ }
fullPathDir = full;
string tail = full.Length > assets.Length ? full.Substring(assets.Length).TrimStart('/') : string.Empty;
relPathSafe = ("Assets/" + tail).TrimEnd('/');
return true;
}
2025-03-31 03:58:01 +08:00
/// <summary>
/// Main handler for script management actions.
/// </summary>
public static object HandleCommand(JObject @params)
{
// Extract parameters
string action = @params["action"]?.ToString().ToLower();
string name = @params["name"]?.ToString();
string path = @params["path"]?.ToString(); // Relative to Assets/
string contents = null;
// Check if we have base64 encoded contents
bool contentsEncoded = @params["contentsEncoded"]?.ToObject<bool>() ?? false;
if (contentsEncoded && @params["encodedContents"] != null)
{
try
{
contents = DecodeBase64(@params["encodedContents"].ToString());
}
catch (Exception e)
{
return Response.Error($"Failed to decode script contents: {e.Message}");
}
}
else
{
contents = @params["contents"]?.ToString();
}
2025-03-31 03:58:01 +08:00
string scriptType = @params["scriptType"]?.ToString(); // For templates/validation
string namespaceName = @params["namespace"]?.ToString(); // For organizing code
// Validate required parameters
if (string.IsNullOrEmpty(action))
{
return Response.Error("Action parameter is required.");
}
if (string.IsNullOrEmpty(name))
{
return Response.Error("Name parameter is required.");
}
// Basic name validation (alphanumeric, underscores, cannot start with number)
Claude‑friendly edit tools + framed transport + live Unity NL test framework (#243) * CI: gate desktop-parity on Anthropic key; pass anthropic_api_key like NL suite * Add quickprobe prompt and CI workflow (mcp-quickprobe.md, unity-mcp-quickprobe.yml) * strictier tool use to prevent subagent spawning and force mcp tools * update workflow filesto reduce likelihood of subagent spawning * improve permissions for claude agent, fix mcpbridge timeout/token issue * increase max turns to 10 * ci: align NL suite to new permissions schema; prevent subagent drift * ci: NL suite -> mini prompt for e2e; add full NL/T prompt; server: ctx optional + project_root fallback; workflows: set UNITY_PROJECT_ROOT for CI * ci: add checks:write; revert local project hardcodes (manifest, ProjectVersion.txt) * tools: text-edit routing fixes (anchor_insert via text, CRLF calc); prompts: mini NL/T clarifications * ci: use absolute UNITY_PROJECT_ROOT; prompts target TestProjects; server: accept relative UNITY_PROJECT_ROOT and bare spec URI * ci: ignore Unity test project's packages-lock.json; remove from repo to avoid absolute paths * CI: start persistent Unity Editor for MCP (guarded by license) + allow batch-mode bridge via UNITY_MCP_ALLOW_BATCH * CI: hide license and pass via env to docker; fix invalid ref format * CI: readiness probe uses handshake on Unity MCP port (deterministic) * CI: fix YAML; use TCP handshake readiness probe (FRAMING=1) * CI: prime Unity license via game-ci; mount ULF into container; extend readiness timeout * CI: use ULF write + mount for Unity licensing; remove serial/email/pass from container * CI: entitlement activation (UNITY_SERIAL=''); verify host ULF cache; keep mount * CI: write ULF from secret and verify; drop entitlement activation step * CI: detect any licensing path; GameCI prime; status dir env; log+probe readiness; fix YAML * CI: add GameCI license prime; conditional ULF write; one-shot license validation; explicit status dir + license env * CI: fix YAML (inline python), add Anthropic key detect via GITHUB_ENV; ready to run happy path * CI: mount Unity token/ulf/cache dirs into container to share host license; create dirs before start * CI: fix YAML indentation; write ULF on host; activate in container with shared mounts; mount .config and .cache too * CI: gate Claude via outputs; mount all Unity license dirs; fix inline probe python; stabilize licensing flow * CI: normalize detect to step outputs; ensure license dirs mounted and validated; fix indentation * Bridge: honor UNITY_MCP_STATUS_DIR for heartbeat/status file (CI-friendly) * CI: guard project path for activation/start; align tool allowlist; run MCP server with python; tighten secret scoping * CI: finalize Unity licensing mounts + status dir; mode-detect (ULF/EBL); readiness logs+probe; Claude gating via outputs * CI: fix YAML probe (inline python -c) and finalize happy-path Unity licensing and MCP/Claude wiring * CI: inline python probe; unify Unity image and cache mounts; ready to test * CI: fix docker run IMAGE placement; ignore cache find perms; keep same editor image * CI: pass -manualLicenseFile to persistent Editor; keep mounts and single image * CI: mount full GameCI cache to /root in persistent Unity; set HOME=/root; add optional license check * CI: make -manualLicenseFile conditional; keep full /root mount and license check * CI: set HOME=/github/home; mount GameCI cache there; adjust manualLicenseFile path; expand license check * CI: EBL sign-in for persistent Unity (email/password/serial); revert HOME=/root and full /root mount; keep conditional manualLicenseFile and improved readiness * CI: run full NL/T suite prompt (nl-unity-suite-full.md) instead of mini * NL/T: require unified diffs + explicit verdicts in JUnit; CI: remove short sanity step, publish JUnit, upload artifacts * NL/T prompt: require CDATA wrapping for JUnit XML fields; guidance for splitting embedded ]]>; keep VERDICT in CDATA only * CI: remove in-container license check step; keep readiness and full suite * NL/T prompt: add version header, stricter JUnit schema, hashing/normalization, anchors, statuses, atomic semantics, tool logging * CI: increase Claude NL/T suite timeout to 30 minutes * CI: pre-create reports dir and result files to avoid tool approval prompts * CI: skip wait if container not running; skip Editor start if project missing; broaden MCP deps detection; expand allowed tools * fixies to harden ManageScript * CI: sanitize NL/T markdown report to avoid NUL/encoding issues * revert breaking yyaml changes * CI: prime license, robust Unity start/wait, sanitize markdown via heredoc * Resolve merge: accept upstream renames/installer (fix/installer-cleanup-v2) and keep local framing/script-editing - Restored upstream server.py, EditorWindow, uv.lock\n- Preserved ManageScript editing/validation; switched to atomic write + debounced refresh\n- Updated tools/__init__.py to keep script_edits/resources and adopt new logger name\n- All Python tests via uv: 7 passed, 6 skipped, 9 xpassed; Unity compile OK * Fix Claude Desktop config path and atomic write issues - Fix macOS path for Claude Desktop config: use ~/Library/Application Support/Claude/ instead of ~/.config/Claude/ - Improve atomic write pattern with backup/restore safety - Replace File.Replace() with File.Move() for better macOS compatibility - Add proper error handling and cleanup for file operations - Resolves issue where installer couldn't find Claude Desktop config on macOS * Editor: use macConfigPath on macOS for MCP client config writes (Claude Desktop, etc.). Fallback to linuxConfigPath only if mac path missing. * Models: add macConfigPath to McpClient for macOS config path selection (fixes CS1061 in editor window). * Editor: on macOS, prefer macConfigPath in ManualConfigEditorWindow (fallback to linux path); Linux/Windows unchanged. * Fix McpClient: align with upstream/main, prep for framing split * NL suite: shard workflow; tighten bridge readiness; add MCP preflight; use env-based shard vars * NL suite: fix shard step indentation; move shard vars to env; remove invalid inputs * MCP clients: split VSCode Copilot config paths into macConfigPath and linuxConfigPath * Unity bridge: clean stale status; bind host; robust wait probe with IPv4/IPv6 + diagnostics * CI: use MCPForUnity.Editor.MCPForUnityBridge.StartAutoConnect as executeMethod * Action wiring: inline mcpServers in settings for all shards; remove redundant .claude/mcp.json step * CI: embed mcpServers in settings for all shards; fix startup sanity step; lint clean * CI: pin claude-code-base-action to e6f32c8; use claude_args --mcp-config; switch to allowed_tools; ensure MCP config per step * CI: unpin claude-code-base-action to @beta (commit ref not found) * CI: align with claude-code-base-action @beta; pass MCP via claude_args and allowedTools * Editor: Fix apply_text_edits heuristic when edits shift positions; recompute method span on candidate text with fallback delta adjustment * CI: unify MCP wiring across workflows; write .claude/mcp.json; switch to claude_args with --mcp-config/--allowedTools; remove unsupported inputs * CI: collapse NL suite shards into a single run to avoid repeated test execution * CI: minimize allowedTools for NL suite to essential Unity MCP + Bash("git:*") + Write * CI: mkdir -p reports before run; remove unsupported --timeout-minutes from claude_args * CI: broaden allowedTools to include find_in_file and mcp__unity__* * CI: enable use_node_cache and switch NL suite model to claude-3-7-haiku-20250219 * CI: disable use_node_cache to avoid setup-node lockfile error * CI: set NL suite model to claude-3-haiku-20240307 * CI: cap Haiku output with --max-tokens 2048 for NL suite * CI: switch to claude-3-7-sonnet-latest and remove unsupported --max-tokens * CI: update allowedTools to Bash(*) and explicit Unity MCP tool list * CI: update NL suite workflow (latest tweaks) * Tests: tighten NL suite prompt for logging, hash discipline, stale retry, evidence windows, diff cap, and VERDICT line * Add disallowed tools to NL suite workflow * docs: clarify stale write retry * Add fallback JUnit report and adjust publisher * Indent fallback JUnit XML in workflow * fix: correct fallback JUnit report generation * Update mcp-quickprobe.md Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> * Update mcp-quickprobe.md Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> * Update Response.cs Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> * Update MCPForUnityBridge.cs Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> * fix: correct McpTypes reference * Add directory existence checks for symlink and XDG paths * fix: only set installation flag after successful server install * Update resource_tools.py Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> * fix: respect mac config paths * Use File.Replace for atomic config write * Remove unused imports in manage_script * bump server version * Tests: update NL suite prompt and workflows; remove deprecated smoke/desktop-parity; quickprobe tidy * Editor: atomic config write via File.Replace fallback; remove redundant backups and racey exists checks * CI: harden NL suite - idempotent docker, gate on unity_ok, safer port probe, least-priv perms * Editor: make atomic config write restoration safe (flag writeDone; copy-overwrite restore; cleanup in finally) * CI: fix fallback JUnit heredoc by using printf lines (no EOF delimiter issues) * CI: switch NL suite to mini prompt; mini prompt honors / and NL discipline * CI: replace claude_args with allowed_tools/model/mcp_config per action schema * CI: expand UNITY_PROJECT_ROOT via in MCP config heredoc * EditorWindow: add cross-platform fallback for File.Replace; macOS-insensitive PathsEqual; safer uv resolve; honor macConfigPath * CI: strengthen JUnit publishing for NL mini suite (normalize, debug list, publish both, fail_on_parse_error) * CI: set job-wide JUNIT_OUT/MD_OUT; normalization uses env; publish references env and ungroup reports * CI: publish a single normalized JUnit (reports/junit-for-actions.xml); fallback writes same; avoid checkName/reportPaths mismatch * CI: align mini prompt report filenames; redact Unity log tail in diagnostics * chore: sync workflow and mini prompt; redacted logs; JUnit normalization/publish tweaks * CI: redact sensitive tokens in Stop Unity; docs: CI usage + edit tools * prompts: update nl-unity-suite-full (mini-style setup + reporting discipline); remove obsolete prompts * CI: harden NL workflows (timeout_minutes, robust normalization); prompts: unify JUnit suite name and reporting discipline * prompts: add guarded write pattern (LF hash, stale_file retry) to full suite * prompts: enforce continue-on-failure, driver flow, and status handling in full suite * Make test list more explicit in prompt. Get rid of old test prompts for hygeine. * prompts: add stale fast-retry (server hash) + in-memory buf guidance * CI: standardize JUNIT_OUT to reports/junit-nl-suite.xml; fix artifact upload indentation; prompt copy cleanups * prompts: reporting discipline — append-only fragments, batch writes, no model round-trip * prompts: stale fast-retry preference, buffer/sha carry, snapshot revert, essential logging * workflows(nl-suite): precreate report skeletons, assemble junit, synthesize markdown; restrict allowed_tools to append-only Bash + MCP tools * thsis too * Update README-DEV.md Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update .github/workflows/claude-nl-suite-mini.yml Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update .github/workflows/claude-nl-suite.yml Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * workflows(nl-mini): fix YAML indentation/trailing spaces under with: and cleanup heredoc spacing * workflows(nl-suite): fix indentation on docker logs redaction line (YAML lint) * Add write to allowlist * nl-suite: harden reporting discipline (fragment-only writes, forbid alt paths); workflow: clean stray junit-*updated*.xml * nl-suite: enforce end-of-suite single Write (no bash redirection); workflow: restrict allowed_tools to Write+MCP only * prompts(nl-full): end-of-suite results must be valid XML with single <cases> root and only <testcase> children; no raw text outside CDATA * workflows(nl-suite): make Claude step non-fatal; tolerant normalizer extracts <testcase> via regex on bad fragments * nl-suite: fix stale classname to UnityMCP.NL-T in mini fallback; prompt: require re-read after every revert; correct PLAN/PROGRESS to 15 * nl-suite: fix fallback JUnit classname to UnityMCP.NL-T; prompt: forbid create_script and env/mkdir checks, enforce single baseline-byte revert flow and post-revert re-read; add corruption-handling guidance * prompts(nl-full): after each write re-read raw bytes to refresh pre_sha; prefer script_apply_edits for anchors; avoid header/using changes * prompts(nl-full): canonicalize outputs to /; allow small fragment appends via Write or Bash(printf/echo); forbid wrappers and full-file round-trips * prompts(nl-full): finalize markdown formatting for guarded write, execution order, specs, status * workflows(nl-suite, mini): header/lint fixes and constrained Bash append path; align allowed_tools * prompts(nl-full): format Fast Restore, Guarded Write, Execution, Specs, Status as proper markdown lists and code fences * workflows(nl-suite): keep header tidy and append-path alignment with prompt * minor fix * workflows(nl-suite): fix indentation and dispatch; align allowed_tools and revert helper * prompts(nl-full): switch to read_resource for buf/sha; re-read only when needed; convert 'Print this once' to heading; note snapshot helper creates parent dirs * workflows(nl-suite): normalize step removes bootstrap when real testcases present; recompute tests/failures * workflows(nl-suite): enrich Markdown summary by extracting per-test <system-out> blocks (truncated) * clarify prompt resilience instructions * ci(nl-suite): revert prompt and workflow to known-good e0f8a72 for green run; remove extra MD details * ci(nl-suite): minimal fixes — no-mkdir guard in prompt; drop bootstrap and recompute JUnit counts * ci(nl-suite): richer JUnit→Markdown report (per-test system-out) * Small guard to incorret asset read call. * ci(nl-suite): refine MD builder — unescape XML entities, safe code fences, PASS/FAIL badges * Update UnityMcpBridge/UnityMcpServer~/src/tools/resource_tools.py Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update UnityMcpBridge/UnityMcpServer~/src/unity_connection.py Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update UnityMcpBridge/UnityMcpServer~/src/tools/manage_script_edits.py Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update .github/scripts/mark_skipped.py Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update .github/scripts/mark_skipped.py Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update .github/scripts/mark_skipped.py Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> * server(manage_script): robust URI handling — percent-decode file://, normalize, strip host/leading slashes, return Assets-relative if present * Update .claude/prompts/nl-unity-suite-full.md Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> * tests(framing): reduce handshake poll window, nonblocking peek to avoid disconnect race; still enforce pre-handshake data drop * tests(manage_script): add _split_uri tests for unity://path, file:// URLs (decoded/Assets-relative), and plain paths * server+tests: fix handshake syntax error; robust file:// URI normalization in manage_script; add _split_uri tests; adjust stdout scan to ignore venv/site-packages * bridge(framing): accept zero-length frames (treat as empty keepalive) * tests(logging): use errors='replace' on decode fallback to avoid silent drops * resources(list): restrict to Assets/, resolve symlinks, enforce .cs; add traversal/outside-path tests * Update .claude/prompts/nl-unity-suite-full.md Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update UnityMcpBridge/UnityMcpServer~/src/unity_connection.py Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * misc: framing keepalive (zero-length), regex preview consistency, resource.list hardening, URI parsing, legacy update routing, test cleanups * docs(tools): richer MCP tool descriptions; tests accept decorator kwargs; resource URI parsing hardened * Update .claude/prompts/nl-unity-suite-full.md Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update UnityMcpBridge/UnityMcpServer~/src/tools/resource_tools.py Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update UnityMcpBridge/UnityMcpServer~/src/unity_connection.py Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * net+docs: hard-reject zero-length frames; TCP_NODELAY on connect; Assets detection case-insensitive; NL prompt statuses aligned * prompt(nl-suite): constrain Write destinations under reports/, forbid traversal * prompt+net: harden Write path rules; use monotonic deadline and plain-text advisory for non-framed peers * unity_connection: restore recv timeout via try/finally; make global connection getter thread-safe with module lock and double-checked init * NL/T prompt: pin structured edit ops for T-D/T-E; add schema-error guarded write behavior; keep existing path/URI and revert rules * unity_connection: add FRAMED_MAX; use ValueError for framed length violations; lower framed receive log to debug; serialize connect() with per-instance lock * ManageScript: use UTF8Encoding(without BOM) for atomic writes in ApplyTextEdits/EditScript to align with Create/Update and avoid BOM-related diffs/hash mismatches * NL/T prompt: make helper deletion regex multiline-safe ((?ms) so ^ anchors line starts) * ManageScript: emit structured overlap status {status:"overlap"} for overlapping edit ranges in apply_text_edits and edit paths * NL/T prompt: clarify fallback vs failure — fallback only for unsupported/missing_field; treat bad_request as failure; note unsupported after fallback as failure * NL/T prompt: pin deterministic overlap probe (apply_text_edits two ranges from same snapshot); gate too_large behind RUN_TOO_LARGE env hint * TB update * NL/T prompt: harden Output Rules — constrain Bash(printf|echo) to stdout-only; forbid redirection/here-docs/tee; only scripts/nlt-revert.sh may mutate FS * Prompt: enumerate allowed script_apply_edits ops; add manage_editor/read_console guidance; fix T‑F atomic batch to single script_apply_edits. ManageScript: regex timeout for diagnostics; symlink ancestor guard; complete allowed-modes list. * Fixes * ManageScript: add rich overlap diagnostics (conflicts + hint) for both text range and structured batch paths * ManageScript: return structured {status:"validation_failed"} diagnostics in create/update/edits and validate before commit * ManageScript: echo canonical uri in responses (create/read/update/apply_text_edits/structured edits) to reinforce resource identity * improve clarity of capabilities message * Framing: allow zero-length frames on both ends (C# bridge, Python server). Prompt: harden T-F to single text-range apply_text_edits batch (descending order, one snapshot). URI: normalize file:// outside Assets by stripping leading slash. * ManageScript: include new sha256 in success payload for apply_text_edits; harden TryResolveUnderAssets by rejecting symlinked ancestors up to Assets/. * remove claudetest dir * manage_script_edits: normalize method-anchored anchor_insert to insert_method (map text->replacement); improves CI compatibility for T‑A/T‑E without changing Editor behavior. * tighten testing protocol around mkdir * manage_script: validate create_script inputs (Assets/.cs/name/no traversal); add Assets/ guard to delete_script; validate level+Assets in validate_script; make legacy manage_script optional params; harden legacy update routing with base64 reuse and payload size preflight. * Tighten prompt for testing * Update .claude/prompts/nl-unity-suite-full.md Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update .claude/prompts/nl-unity-suite-full.md Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update UnityMcpBridge/Editor/Tools/ManageScript.cs Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * manage_script_edits: honor ignore_case on anchor_insert and regex_replace in both direct and text-conversion paths (MULTILINE|IGNORECASE). * remove extra file * workflow: use python3 for inline scripts and port detection on ubuntu-latest. * Tighten prompt + manage_script * Update UnityMcpBridge/UnityMcpServer~/src/tools/manage_script_edits.py Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update UnityMcpBridge/UnityMcpServer~/src/tools/manage_script_edits.py Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update .claude/prompts/nl-unity-suite-full.md Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update UnityMcpBridge/Editor/Tools/ManageScript.cs Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update .claude/prompts/nl-unity-suite-full.md Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * manage_script: improve file:// UNC handling; preserve POSIX absolute semantics internally; keep test-expected slash stripping for non-Assets paths. * ManageScript.cs: add TimeSpan timeouts to all Regex uses (IsMatch/Match/new Regex) and keep CultureInvariant/Multiline options; reduces risk of catastrophic backtracking stalls. * workflow: ensure reports/ exists in markdown build step to avoid FileNotFoundError when writing MD_OUT. * fix brace * manage_script_edits: expand backrefs for regex_replace in preview->text conversion and translate to \g<n> in local apply; keeps previews and actual edits consistent. * anchor_insert: default to position=after, normalize surrounding newlines in Python conversion paths; C# path ensures trailing newline and skips duplicate insertion within class. * feat(mcp): add get_sha tool; apply_text_edits normalization+overlap preflight+strict; no-op evidence in C#; update NL suite prompt; add unit tests * feat(frames): accept zero-length heartbeat frames in client; add heartbeat test * feat(edits): guard destructive regex_replace with structural preflight; add robust tests; prompt uses delete_method for temp helper * feat(frames): bound heartbeat loop with timeout/threshold; align zero-length response with C#; update test * SDK hardening: atomic multi-span text edits; stop forcing sequential for structured ops; forward options on apply_text_edits; add validate=relaxed support and scoped checks; update NL/T prompt; add tests for options forwarding, relaxed mode, and atomic batches * Router: default applyMode=atomic for multi-span apply_text_edits; add tests * CI prompt: pass options.validate=relaxed for T-B/C; options.applyMode=atomic for T-F; emphasize always writing testcase and restoring on errors * Validation & DX: add validate=syntax (scoped), standardize evidence windows; early regex compile with hints; debug_preview for apply_text_edits * Update UnityMcpBridge/Editor/Windows/MCPForUnityEditorWindow.cs Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * NL/T suite-driven edits: LongUnityScriptClaudeTest, bridge helpers, server_version; prepare framing tests * Fix duplicate macConfigPath field in McpClient to resolve CS0102 * Editor threading: run EnsureServerInstalled on main thread; marshal EditorPrefs/DeleteKey + logging via delayCall * Docs(apply_text_edits): strengthen guidance on 1-based positions, verify-before-edit, and recommend anchors/structured edits * Docs(script_apply_edits): add safety guidance (anchors, method ops, validators) and recommended practices * Framed VerifyBridgePing in editor window; docs hardening for apply_text_edits and script_apply_edits --------- Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
2025-08-31 00:55:38 +08:00
if (!Regex.IsMatch(name, @"^[a-zA-Z_][a-zA-Z0-9_]*$", RegexOptions.CultureInvariant, TimeSpan.FromSeconds(2)))
2025-03-31 03:58:01 +08:00
{
return Response.Error(
$"Invalid script name: '{name}'. Use only letters, numbers, underscores, and don't start with a number."
);
2025-03-31 03:58:01 +08:00
}
Claude‑friendly edit tools + framed transport + live Unity NL test framework (#243) * CI: gate desktop-parity on Anthropic key; pass anthropic_api_key like NL suite * Add quickprobe prompt and CI workflow (mcp-quickprobe.md, unity-mcp-quickprobe.yml) * strictier tool use to prevent subagent spawning and force mcp tools * update workflow filesto reduce likelihood of subagent spawning * improve permissions for claude agent, fix mcpbridge timeout/token issue * increase max turns to 10 * ci: align NL suite to new permissions schema; prevent subagent drift * ci: NL suite -> mini prompt for e2e; add full NL/T prompt; server: ctx optional + project_root fallback; workflows: set UNITY_PROJECT_ROOT for CI * ci: add checks:write; revert local project hardcodes (manifest, ProjectVersion.txt) * tools: text-edit routing fixes (anchor_insert via text, CRLF calc); prompts: mini NL/T clarifications * ci: use absolute UNITY_PROJECT_ROOT; prompts target TestProjects; server: accept relative UNITY_PROJECT_ROOT and bare spec URI * ci: ignore Unity test project's packages-lock.json; remove from repo to avoid absolute paths * CI: start persistent Unity Editor for MCP (guarded by license) + allow batch-mode bridge via UNITY_MCP_ALLOW_BATCH * CI: hide license and pass via env to docker; fix invalid ref format * CI: readiness probe uses handshake on Unity MCP port (deterministic) * CI: fix YAML; use TCP handshake readiness probe (FRAMING=1) * CI: prime Unity license via game-ci; mount ULF into container; extend readiness timeout * CI: use ULF write + mount for Unity licensing; remove serial/email/pass from container * CI: entitlement activation (UNITY_SERIAL=''); verify host ULF cache; keep mount * CI: write ULF from secret and verify; drop entitlement activation step * CI: detect any licensing path; GameCI prime; status dir env; log+probe readiness; fix YAML * CI: add GameCI license prime; conditional ULF write; one-shot license validation; explicit status dir + license env * CI: fix YAML (inline python), add Anthropic key detect via GITHUB_ENV; ready to run happy path * CI: mount Unity token/ulf/cache dirs into container to share host license; create dirs before start * CI: fix YAML indentation; write ULF on host; activate in container with shared mounts; mount .config and .cache too * CI: gate Claude via outputs; mount all Unity license dirs; fix inline probe python; stabilize licensing flow * CI: normalize detect to step outputs; ensure license dirs mounted and validated; fix indentation * Bridge: honor UNITY_MCP_STATUS_DIR for heartbeat/status file (CI-friendly) * CI: guard project path for activation/start; align tool allowlist; run MCP server with python; tighten secret scoping * CI: finalize Unity licensing mounts + status dir; mode-detect (ULF/EBL); readiness logs+probe; Claude gating via outputs * CI: fix YAML probe (inline python -c) and finalize happy-path Unity licensing and MCP/Claude wiring * CI: inline python probe; unify Unity image and cache mounts; ready to test * CI: fix docker run IMAGE placement; ignore cache find perms; keep same editor image * CI: pass -manualLicenseFile to persistent Editor; keep mounts and single image * CI: mount full GameCI cache to /root in persistent Unity; set HOME=/root; add optional license check * CI: make -manualLicenseFile conditional; keep full /root mount and license check * CI: set HOME=/github/home; mount GameCI cache there; adjust manualLicenseFile path; expand license check * CI: EBL sign-in for persistent Unity (email/password/serial); revert HOME=/root and full /root mount; keep conditional manualLicenseFile and improved readiness * CI: run full NL/T suite prompt (nl-unity-suite-full.md) instead of mini * NL/T: require unified diffs + explicit verdicts in JUnit; CI: remove short sanity step, publish JUnit, upload artifacts * NL/T prompt: require CDATA wrapping for JUnit XML fields; guidance for splitting embedded ]]>; keep VERDICT in CDATA only * CI: remove in-container license check step; keep readiness and full suite * NL/T prompt: add version header, stricter JUnit schema, hashing/normalization, anchors, statuses, atomic semantics, tool logging * CI: increase Claude NL/T suite timeout to 30 minutes * CI: pre-create reports dir and result files to avoid tool approval prompts * CI: skip wait if container not running; skip Editor start if project missing; broaden MCP deps detection; expand allowed tools * fixies to harden ManageScript * CI: sanitize NL/T markdown report to avoid NUL/encoding issues * revert breaking yyaml changes * CI: prime license, robust Unity start/wait, sanitize markdown via heredoc * Resolve merge: accept upstream renames/installer (fix/installer-cleanup-v2) and keep local framing/script-editing - Restored upstream server.py, EditorWindow, uv.lock\n- Preserved ManageScript editing/validation; switched to atomic write + debounced refresh\n- Updated tools/__init__.py to keep script_edits/resources and adopt new logger name\n- All Python tests via uv: 7 passed, 6 skipped, 9 xpassed; Unity compile OK * Fix Claude Desktop config path and atomic write issues - Fix macOS path for Claude Desktop config: use ~/Library/Application Support/Claude/ instead of ~/.config/Claude/ - Improve atomic write pattern with backup/restore safety - Replace File.Replace() with File.Move() for better macOS compatibility - Add proper error handling and cleanup for file operations - Resolves issue where installer couldn't find Claude Desktop config on macOS * Editor: use macConfigPath on macOS for MCP client config writes (Claude Desktop, etc.). Fallback to linuxConfigPath only if mac path missing. * Models: add macConfigPath to McpClient for macOS config path selection (fixes CS1061 in editor window). * Editor: on macOS, prefer macConfigPath in ManualConfigEditorWindow (fallback to linux path); Linux/Windows unchanged. * Fix McpClient: align with upstream/main, prep for framing split * NL suite: shard workflow; tighten bridge readiness; add MCP preflight; use env-based shard vars * NL suite: fix shard step indentation; move shard vars to env; remove invalid inputs * MCP clients: split VSCode Copilot config paths into macConfigPath and linuxConfigPath * Unity bridge: clean stale status; bind host; robust wait probe with IPv4/IPv6 + diagnostics * CI: use MCPForUnity.Editor.MCPForUnityBridge.StartAutoConnect as executeMethod * Action wiring: inline mcpServers in settings for all shards; remove redundant .claude/mcp.json step * CI: embed mcpServers in settings for all shards; fix startup sanity step; lint clean * CI: pin claude-code-base-action to e6f32c8; use claude_args --mcp-config; switch to allowed_tools; ensure MCP config per step * CI: unpin claude-code-base-action to @beta (commit ref not found) * CI: align with claude-code-base-action @beta; pass MCP via claude_args and allowedTools * Editor: Fix apply_text_edits heuristic when edits shift positions; recompute method span on candidate text with fallback delta adjustment * CI: unify MCP wiring across workflows; write .claude/mcp.json; switch to claude_args with --mcp-config/--allowedTools; remove unsupported inputs * CI: collapse NL suite shards into a single run to avoid repeated test execution * CI: minimize allowedTools for NL suite to essential Unity MCP + Bash("git:*") + Write * CI: mkdir -p reports before run; remove unsupported --timeout-minutes from claude_args * CI: broaden allowedTools to include find_in_file and mcp__unity__* * CI: enable use_node_cache and switch NL suite model to claude-3-7-haiku-20250219 * CI: disable use_node_cache to avoid setup-node lockfile error * CI: set NL suite model to claude-3-haiku-20240307 * CI: cap Haiku output with --max-tokens 2048 for NL suite * CI: switch to claude-3-7-sonnet-latest and remove unsupported --max-tokens * CI: update allowedTools to Bash(*) and explicit Unity MCP tool list * CI: update NL suite workflow (latest tweaks) * Tests: tighten NL suite prompt for logging, hash discipline, stale retry, evidence windows, diff cap, and VERDICT line * Add disallowed tools to NL suite workflow * docs: clarify stale write retry * Add fallback JUnit report and adjust publisher * Indent fallback JUnit XML in workflow * fix: correct fallback JUnit report generation * Update mcp-quickprobe.md Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> * Update mcp-quickprobe.md Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> * Update Response.cs Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> * Update MCPForUnityBridge.cs Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> * fix: correct McpTypes reference * Add directory existence checks for symlink and XDG paths * fix: only set installation flag after successful server install * Update resource_tools.py Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> * fix: respect mac config paths * Use File.Replace for atomic config write * Remove unused imports in manage_script * bump server version * Tests: update NL suite prompt and workflows; remove deprecated smoke/desktop-parity; quickprobe tidy * Editor: atomic config write via File.Replace fallback; remove redundant backups and racey exists checks * CI: harden NL suite - idempotent docker, gate on unity_ok, safer port probe, least-priv perms * Editor: make atomic config write restoration safe (flag writeDone; copy-overwrite restore; cleanup in finally) * CI: fix fallback JUnit heredoc by using printf lines (no EOF delimiter issues) * CI: switch NL suite to mini prompt; mini prompt honors / and NL discipline * CI: replace claude_args with allowed_tools/model/mcp_config per action schema * CI: expand UNITY_PROJECT_ROOT via in MCP config heredoc * EditorWindow: add cross-platform fallback for File.Replace; macOS-insensitive PathsEqual; safer uv resolve; honor macConfigPath * CI: strengthen JUnit publishing for NL mini suite (normalize, debug list, publish both, fail_on_parse_error) * CI: set job-wide JUNIT_OUT/MD_OUT; normalization uses env; publish references env and ungroup reports * CI: publish a single normalized JUnit (reports/junit-for-actions.xml); fallback writes same; avoid checkName/reportPaths mismatch * CI: align mini prompt report filenames; redact Unity log tail in diagnostics * chore: sync workflow and mini prompt; redacted logs; JUnit normalization/publish tweaks * CI: redact sensitive tokens in Stop Unity; docs: CI usage + edit tools * prompts: update nl-unity-suite-full (mini-style setup + reporting discipline); remove obsolete prompts * CI: harden NL workflows (timeout_minutes, robust normalization); prompts: unify JUnit suite name and reporting discipline * prompts: add guarded write pattern (LF hash, stale_file retry) to full suite * prompts: enforce continue-on-failure, driver flow, and status handling in full suite * Make test list more explicit in prompt. Get rid of old test prompts for hygeine. * prompts: add stale fast-retry (server hash) + in-memory buf guidance * CI: standardize JUNIT_OUT to reports/junit-nl-suite.xml; fix artifact upload indentation; prompt copy cleanups * prompts: reporting discipline — append-only fragments, batch writes, no model round-trip * prompts: stale fast-retry preference, buffer/sha carry, snapshot revert, essential logging * workflows(nl-suite): precreate report skeletons, assemble junit, synthesize markdown; restrict allowed_tools to append-only Bash + MCP tools * thsis too * Update README-DEV.md Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update .github/workflows/claude-nl-suite-mini.yml Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update .github/workflows/claude-nl-suite.yml Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * workflows(nl-mini): fix YAML indentation/trailing spaces under with: and cleanup heredoc spacing * workflows(nl-suite): fix indentation on docker logs redaction line (YAML lint) * Add write to allowlist * nl-suite: harden reporting discipline (fragment-only writes, forbid alt paths); workflow: clean stray junit-*updated*.xml * nl-suite: enforce end-of-suite single Write (no bash redirection); workflow: restrict allowed_tools to Write+MCP only * prompts(nl-full): end-of-suite results must be valid XML with single <cases> root and only <testcase> children; no raw text outside CDATA * workflows(nl-suite): make Claude step non-fatal; tolerant normalizer extracts <testcase> via regex on bad fragments * nl-suite: fix stale classname to UnityMCP.NL-T in mini fallback; prompt: require re-read after every revert; correct PLAN/PROGRESS to 15 * nl-suite: fix fallback JUnit classname to UnityMCP.NL-T; prompt: forbid create_script and env/mkdir checks, enforce single baseline-byte revert flow and post-revert re-read; add corruption-handling guidance * prompts(nl-full): after each write re-read raw bytes to refresh pre_sha; prefer script_apply_edits for anchors; avoid header/using changes * prompts(nl-full): canonicalize outputs to /; allow small fragment appends via Write or Bash(printf/echo); forbid wrappers and full-file round-trips * prompts(nl-full): finalize markdown formatting for guarded write, execution order, specs, status * workflows(nl-suite, mini): header/lint fixes and constrained Bash append path; align allowed_tools * prompts(nl-full): format Fast Restore, Guarded Write, Execution, Specs, Status as proper markdown lists and code fences * workflows(nl-suite): keep header tidy and append-path alignment with prompt * minor fix * workflows(nl-suite): fix indentation and dispatch; align allowed_tools and revert helper * prompts(nl-full): switch to read_resource for buf/sha; re-read only when needed; convert 'Print this once' to heading; note snapshot helper creates parent dirs * workflows(nl-suite): normalize step removes bootstrap when real testcases present; recompute tests/failures * workflows(nl-suite): enrich Markdown summary by extracting per-test <system-out> blocks (truncated) * clarify prompt resilience instructions * ci(nl-suite): revert prompt and workflow to known-good e0f8a72 for green run; remove extra MD details * ci(nl-suite): minimal fixes — no-mkdir guard in prompt; drop bootstrap and recompute JUnit counts * ci(nl-suite): richer JUnit→Markdown report (per-test system-out) * Small guard to incorret asset read call. * ci(nl-suite): refine MD builder — unescape XML entities, safe code fences, PASS/FAIL badges * Update UnityMcpBridge/UnityMcpServer~/src/tools/resource_tools.py Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update UnityMcpBridge/UnityMcpServer~/src/unity_connection.py Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update UnityMcpBridge/UnityMcpServer~/src/tools/manage_script_edits.py Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update .github/scripts/mark_skipped.py Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update .github/scripts/mark_skipped.py Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update .github/scripts/mark_skipped.py Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> * server(manage_script): robust URI handling — percent-decode file://, normalize, strip host/leading slashes, return Assets-relative if present * Update .claude/prompts/nl-unity-suite-full.md Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> * tests(framing): reduce handshake poll window, nonblocking peek to avoid disconnect race; still enforce pre-handshake data drop * tests(manage_script): add _split_uri tests for unity://path, file:// URLs (decoded/Assets-relative), and plain paths * server+tests: fix handshake syntax error; robust file:// URI normalization in manage_script; add _split_uri tests; adjust stdout scan to ignore venv/site-packages * bridge(framing): accept zero-length frames (treat as empty keepalive) * tests(logging): use errors='replace' on decode fallback to avoid silent drops * resources(list): restrict to Assets/, resolve symlinks, enforce .cs; add traversal/outside-path tests * Update .claude/prompts/nl-unity-suite-full.md Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update UnityMcpBridge/UnityMcpServer~/src/unity_connection.py Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * misc: framing keepalive (zero-length), regex preview consistency, resource.list hardening, URI parsing, legacy update routing, test cleanups * docs(tools): richer MCP tool descriptions; tests accept decorator kwargs; resource URI parsing hardened * Update .claude/prompts/nl-unity-suite-full.md Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update UnityMcpBridge/UnityMcpServer~/src/tools/resource_tools.py Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update UnityMcpBridge/UnityMcpServer~/src/unity_connection.py Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * net+docs: hard-reject zero-length frames; TCP_NODELAY on connect; Assets detection case-insensitive; NL prompt statuses aligned * prompt(nl-suite): constrain Write destinations under reports/, forbid traversal * prompt+net: harden Write path rules; use monotonic deadline and plain-text advisory for non-framed peers * unity_connection: restore recv timeout via try/finally; make global connection getter thread-safe with module lock and double-checked init * NL/T prompt: pin structured edit ops for T-D/T-E; add schema-error guarded write behavior; keep existing path/URI and revert rules * unity_connection: add FRAMED_MAX; use ValueError for framed length violations; lower framed receive log to debug; serialize connect() with per-instance lock * ManageScript: use UTF8Encoding(without BOM) for atomic writes in ApplyTextEdits/EditScript to align with Create/Update and avoid BOM-related diffs/hash mismatches * NL/T prompt: make helper deletion regex multiline-safe ((?ms) so ^ anchors line starts) * ManageScript: emit structured overlap status {status:"overlap"} for overlapping edit ranges in apply_text_edits and edit paths * NL/T prompt: clarify fallback vs failure — fallback only for unsupported/missing_field; treat bad_request as failure; note unsupported after fallback as failure * NL/T prompt: pin deterministic overlap probe (apply_text_edits two ranges from same snapshot); gate too_large behind RUN_TOO_LARGE env hint * TB update * NL/T prompt: harden Output Rules — constrain Bash(printf|echo) to stdout-only; forbid redirection/here-docs/tee; only scripts/nlt-revert.sh may mutate FS * Prompt: enumerate allowed script_apply_edits ops; add manage_editor/read_console guidance; fix T‑F atomic batch to single script_apply_edits. ManageScript: regex timeout for diagnostics; symlink ancestor guard; complete allowed-modes list. * Fixes * ManageScript: add rich overlap diagnostics (conflicts + hint) for both text range and structured batch paths * ManageScript: return structured {status:"validation_failed"} diagnostics in create/update/edits and validate before commit * ManageScript: echo canonical uri in responses (create/read/update/apply_text_edits/structured edits) to reinforce resource identity * improve clarity of capabilities message * Framing: allow zero-length frames on both ends (C# bridge, Python server). Prompt: harden T-F to single text-range apply_text_edits batch (descending order, one snapshot). URI: normalize file:// outside Assets by stripping leading slash. * ManageScript: include new sha256 in success payload for apply_text_edits; harden TryResolveUnderAssets by rejecting symlinked ancestors up to Assets/. * remove claudetest dir * manage_script_edits: normalize method-anchored anchor_insert to insert_method (map text->replacement); improves CI compatibility for T‑A/T‑E without changing Editor behavior. * tighten testing protocol around mkdir * manage_script: validate create_script inputs (Assets/.cs/name/no traversal); add Assets/ guard to delete_script; validate level+Assets in validate_script; make legacy manage_script optional params; harden legacy update routing with base64 reuse and payload size preflight. * Tighten prompt for testing * Update .claude/prompts/nl-unity-suite-full.md Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update .claude/prompts/nl-unity-suite-full.md Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update UnityMcpBridge/Editor/Tools/ManageScript.cs Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * manage_script_edits: honor ignore_case on anchor_insert and regex_replace in both direct and text-conversion paths (MULTILINE|IGNORECASE). * remove extra file * workflow: use python3 for inline scripts and port detection on ubuntu-latest. * Tighten prompt + manage_script * Update UnityMcpBridge/UnityMcpServer~/src/tools/manage_script_edits.py Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update UnityMcpBridge/UnityMcpServer~/src/tools/manage_script_edits.py Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update .claude/prompts/nl-unity-suite-full.md Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update UnityMcpBridge/Editor/Tools/ManageScript.cs Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update .claude/prompts/nl-unity-suite-full.md Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * manage_script: improve file:// UNC handling; preserve POSIX absolute semantics internally; keep test-expected slash stripping for non-Assets paths. * ManageScript.cs: add TimeSpan timeouts to all Regex uses (IsMatch/Match/new Regex) and keep CultureInvariant/Multiline options; reduces risk of catastrophic backtracking stalls. * workflow: ensure reports/ exists in markdown build step to avoid FileNotFoundError when writing MD_OUT. * fix brace * manage_script_edits: expand backrefs for regex_replace in preview->text conversion and translate to \g<n> in local apply; keeps previews and actual edits consistent. * anchor_insert: default to position=after, normalize surrounding newlines in Python conversion paths; C# path ensures trailing newline and skips duplicate insertion within class. * feat(mcp): add get_sha tool; apply_text_edits normalization+overlap preflight+strict; no-op evidence in C#; update NL suite prompt; add unit tests * feat(frames): accept zero-length heartbeat frames in client; add heartbeat test * feat(edits): guard destructive regex_replace with structural preflight; add robust tests; prompt uses delete_method for temp helper * feat(frames): bound heartbeat loop with timeout/threshold; align zero-length response with C#; update test * SDK hardening: atomic multi-span text edits; stop forcing sequential for structured ops; forward options on apply_text_edits; add validate=relaxed support and scoped checks; update NL/T prompt; add tests for options forwarding, relaxed mode, and atomic batches * Router: default applyMode=atomic for multi-span apply_text_edits; add tests * CI prompt: pass options.validate=relaxed for T-B/C; options.applyMode=atomic for T-F; emphasize always writing testcase and restoring on errors * Validation & DX: add validate=syntax (scoped), standardize evidence windows; early regex compile with hints; debug_preview for apply_text_edits * Update UnityMcpBridge/Editor/Windows/MCPForUnityEditorWindow.cs Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * NL/T suite-driven edits: LongUnityScriptClaudeTest, bridge helpers, server_version; prepare framing tests * Fix duplicate macConfigPath field in McpClient to resolve CS0102 * Editor threading: run EnsureServerInstalled on main thread; marshal EditorPrefs/DeleteKey + logging via delayCall * Docs(apply_text_edits): strengthen guidance on 1-based positions, verify-before-edit, and recommend anchors/structured edits * Docs(script_apply_edits): add safety guidance (anchors, method ops, validators) and recommended practices * Framed VerifyBridgePing in editor window; docs hardening for apply_text_edits and script_apply_edits --------- Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
2025-08-31 00:55:38 +08:00
// Resolve and harden target directory under Assets/
if (!TryResolveUnderAssets(path, out string fullPathDir, out string relPathSafeDir))
{
Claude‑friendly edit tools + framed transport + live Unity NL test framework (#243) * CI: gate desktop-parity on Anthropic key; pass anthropic_api_key like NL suite * Add quickprobe prompt and CI workflow (mcp-quickprobe.md, unity-mcp-quickprobe.yml) * strictier tool use to prevent subagent spawning and force mcp tools * update workflow filesto reduce likelihood of subagent spawning * improve permissions for claude agent, fix mcpbridge timeout/token issue * increase max turns to 10 * ci: align NL suite to new permissions schema; prevent subagent drift * ci: NL suite -> mini prompt for e2e; add full NL/T prompt; server: ctx optional + project_root fallback; workflows: set UNITY_PROJECT_ROOT for CI * ci: add checks:write; revert local project hardcodes (manifest, ProjectVersion.txt) * tools: text-edit routing fixes (anchor_insert via text, CRLF calc); prompts: mini NL/T clarifications * ci: use absolute UNITY_PROJECT_ROOT; prompts target TestProjects; server: accept relative UNITY_PROJECT_ROOT and bare spec URI * ci: ignore Unity test project's packages-lock.json; remove from repo to avoid absolute paths * CI: start persistent Unity Editor for MCP (guarded by license) + allow batch-mode bridge via UNITY_MCP_ALLOW_BATCH * CI: hide license and pass via env to docker; fix invalid ref format * CI: readiness probe uses handshake on Unity MCP port (deterministic) * CI: fix YAML; use TCP handshake readiness probe (FRAMING=1) * CI: prime Unity license via game-ci; mount ULF into container; extend readiness timeout * CI: use ULF write + mount for Unity licensing; remove serial/email/pass from container * CI: entitlement activation (UNITY_SERIAL=''); verify host ULF cache; keep mount * CI: write ULF from secret and verify; drop entitlement activation step * CI: detect any licensing path; GameCI prime; status dir env; log+probe readiness; fix YAML * CI: add GameCI license prime; conditional ULF write; one-shot license validation; explicit status dir + license env * CI: fix YAML (inline python), add Anthropic key detect via GITHUB_ENV; ready to run happy path * CI: mount Unity token/ulf/cache dirs into container to share host license; create dirs before start * CI: fix YAML indentation; write ULF on host; activate in container with shared mounts; mount .config and .cache too * CI: gate Claude via outputs; mount all Unity license dirs; fix inline probe python; stabilize licensing flow * CI: normalize detect to step outputs; ensure license dirs mounted and validated; fix indentation * Bridge: honor UNITY_MCP_STATUS_DIR for heartbeat/status file (CI-friendly) * CI: guard project path for activation/start; align tool allowlist; run MCP server with python; tighten secret scoping * CI: finalize Unity licensing mounts + status dir; mode-detect (ULF/EBL); readiness logs+probe; Claude gating via outputs * CI: fix YAML probe (inline python -c) and finalize happy-path Unity licensing and MCP/Claude wiring * CI: inline python probe; unify Unity image and cache mounts; ready to test * CI: fix docker run IMAGE placement; ignore cache find perms; keep same editor image * CI: pass -manualLicenseFile to persistent Editor; keep mounts and single image * CI: mount full GameCI cache to /root in persistent Unity; set HOME=/root; add optional license check * CI: make -manualLicenseFile conditional; keep full /root mount and license check * CI: set HOME=/github/home; mount GameCI cache there; adjust manualLicenseFile path; expand license check * CI: EBL sign-in for persistent Unity (email/password/serial); revert HOME=/root and full /root mount; keep conditional manualLicenseFile and improved readiness * CI: run full NL/T suite prompt (nl-unity-suite-full.md) instead of mini * NL/T: require unified diffs + explicit verdicts in JUnit; CI: remove short sanity step, publish JUnit, upload artifacts * NL/T prompt: require CDATA wrapping for JUnit XML fields; guidance for splitting embedded ]]>; keep VERDICT in CDATA only * CI: remove in-container license check step; keep readiness and full suite * NL/T prompt: add version header, stricter JUnit schema, hashing/normalization, anchors, statuses, atomic semantics, tool logging * CI: increase Claude NL/T suite timeout to 30 minutes * CI: pre-create reports dir and result files to avoid tool approval prompts * CI: skip wait if container not running; skip Editor start if project missing; broaden MCP deps detection; expand allowed tools * fixies to harden ManageScript * CI: sanitize NL/T markdown report to avoid NUL/encoding issues * revert breaking yyaml changes * CI: prime license, robust Unity start/wait, sanitize markdown via heredoc * Resolve merge: accept upstream renames/installer (fix/installer-cleanup-v2) and keep local framing/script-editing - Restored upstream server.py, EditorWindow, uv.lock\n- Preserved ManageScript editing/validation; switched to atomic write + debounced refresh\n- Updated tools/__init__.py to keep script_edits/resources and adopt new logger name\n- All Python tests via uv: 7 passed, 6 skipped, 9 xpassed; Unity compile OK * Fix Claude Desktop config path and atomic write issues - Fix macOS path for Claude Desktop config: use ~/Library/Application Support/Claude/ instead of ~/.config/Claude/ - Improve atomic write pattern with backup/restore safety - Replace File.Replace() with File.Move() for better macOS compatibility - Add proper error handling and cleanup for file operations - Resolves issue where installer couldn't find Claude Desktop config on macOS * Editor: use macConfigPath on macOS for MCP client config writes (Claude Desktop, etc.). Fallback to linuxConfigPath only if mac path missing. * Models: add macConfigPath to McpClient for macOS config path selection (fixes CS1061 in editor window). * Editor: on macOS, prefer macConfigPath in ManualConfigEditorWindow (fallback to linux path); Linux/Windows unchanged. * Fix McpClient: align with upstream/main, prep for framing split * NL suite: shard workflow; tighten bridge readiness; add MCP preflight; use env-based shard vars * NL suite: fix shard step indentation; move shard vars to env; remove invalid inputs * MCP clients: split VSCode Copilot config paths into macConfigPath and linuxConfigPath * Unity bridge: clean stale status; bind host; robust wait probe with IPv4/IPv6 + diagnostics * CI: use MCPForUnity.Editor.MCPForUnityBridge.StartAutoConnect as executeMethod * Action wiring: inline mcpServers in settings for all shards; remove redundant .claude/mcp.json step * CI: embed mcpServers in settings for all shards; fix startup sanity step; lint clean * CI: pin claude-code-base-action to e6f32c8; use claude_args --mcp-config; switch to allowed_tools; ensure MCP config per step * CI: unpin claude-code-base-action to @beta (commit ref not found) * CI: align with claude-code-base-action @beta; pass MCP via claude_args and allowedTools * Editor: Fix apply_text_edits heuristic when edits shift positions; recompute method span on candidate text with fallback delta adjustment * CI: unify MCP wiring across workflows; write .claude/mcp.json; switch to claude_args with --mcp-config/--allowedTools; remove unsupported inputs * CI: collapse NL suite shards into a single run to avoid repeated test execution * CI: minimize allowedTools for NL suite to essential Unity MCP + Bash("git:*") + Write * CI: mkdir -p reports before run; remove unsupported --timeout-minutes from claude_args * CI: broaden allowedTools to include find_in_file and mcp__unity__* * CI: enable use_node_cache and switch NL suite model to claude-3-7-haiku-20250219 * CI: disable use_node_cache to avoid setup-node lockfile error * CI: set NL suite model to claude-3-haiku-20240307 * CI: cap Haiku output with --max-tokens 2048 for NL suite * CI: switch to claude-3-7-sonnet-latest and remove unsupported --max-tokens * CI: update allowedTools to Bash(*) and explicit Unity MCP tool list * CI: update NL suite workflow (latest tweaks) * Tests: tighten NL suite prompt for logging, hash discipline, stale retry, evidence windows, diff cap, and VERDICT line * Add disallowed tools to NL suite workflow * docs: clarify stale write retry * Add fallback JUnit report and adjust publisher * Indent fallback JUnit XML in workflow * fix: correct fallback JUnit report generation * Update mcp-quickprobe.md Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> * Update mcp-quickprobe.md Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> * Update Response.cs Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> * Update MCPForUnityBridge.cs Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> * fix: correct McpTypes reference * Add directory existence checks for symlink and XDG paths * fix: only set installation flag after successful server install * Update resource_tools.py Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> * fix: respect mac config paths * Use File.Replace for atomic config write * Remove unused imports in manage_script * bump server version * Tests: update NL suite prompt and workflows; remove deprecated smoke/desktop-parity; quickprobe tidy * Editor: atomic config write via File.Replace fallback; remove redundant backups and racey exists checks * CI: harden NL suite - idempotent docker, gate on unity_ok, safer port probe, least-priv perms * Editor: make atomic config write restoration safe (flag writeDone; copy-overwrite restore; cleanup in finally) * CI: fix fallback JUnit heredoc by using printf lines (no EOF delimiter issues) * CI: switch NL suite to mini prompt; mini prompt honors / and NL discipline * CI: replace claude_args with allowed_tools/model/mcp_config per action schema * CI: expand UNITY_PROJECT_ROOT via in MCP config heredoc * EditorWindow: add cross-platform fallback for File.Replace; macOS-insensitive PathsEqual; safer uv resolve; honor macConfigPath * CI: strengthen JUnit publishing for NL mini suite (normalize, debug list, publish both, fail_on_parse_error) * CI: set job-wide JUNIT_OUT/MD_OUT; normalization uses env; publish references env and ungroup reports * CI: publish a single normalized JUnit (reports/junit-for-actions.xml); fallback writes same; avoid checkName/reportPaths mismatch * CI: align mini prompt report filenames; redact Unity log tail in diagnostics * chore: sync workflow and mini prompt; redacted logs; JUnit normalization/publish tweaks * CI: redact sensitive tokens in Stop Unity; docs: CI usage + edit tools * prompts: update nl-unity-suite-full (mini-style setup + reporting discipline); remove obsolete prompts * CI: harden NL workflows (timeout_minutes, robust normalization); prompts: unify JUnit suite name and reporting discipline * prompts: add guarded write pattern (LF hash, stale_file retry) to full suite * prompts: enforce continue-on-failure, driver flow, and status handling in full suite * Make test list more explicit in prompt. Get rid of old test prompts for hygeine. * prompts: add stale fast-retry (server hash) + in-memory buf guidance * CI: standardize JUNIT_OUT to reports/junit-nl-suite.xml; fix artifact upload indentation; prompt copy cleanups * prompts: reporting discipline — append-only fragments, batch writes, no model round-trip * prompts: stale fast-retry preference, buffer/sha carry, snapshot revert, essential logging * workflows(nl-suite): precreate report skeletons, assemble junit, synthesize markdown; restrict allowed_tools to append-only Bash + MCP tools * thsis too * Update README-DEV.md Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update .github/workflows/claude-nl-suite-mini.yml Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update .github/workflows/claude-nl-suite.yml Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * workflows(nl-mini): fix YAML indentation/trailing spaces under with: and cleanup heredoc spacing * workflows(nl-suite): fix indentation on docker logs redaction line (YAML lint) * Add write to allowlist * nl-suite: harden reporting discipline (fragment-only writes, forbid alt paths); workflow: clean stray junit-*updated*.xml * nl-suite: enforce end-of-suite single Write (no bash redirection); workflow: restrict allowed_tools to Write+MCP only * prompts(nl-full): end-of-suite results must be valid XML with single <cases> root and only <testcase> children; no raw text outside CDATA * workflows(nl-suite): make Claude step non-fatal; tolerant normalizer extracts <testcase> via regex on bad fragments * nl-suite: fix stale classname to UnityMCP.NL-T in mini fallback; prompt: require re-read after every revert; correct PLAN/PROGRESS to 15 * nl-suite: fix fallback JUnit classname to UnityMCP.NL-T; prompt: forbid create_script and env/mkdir checks, enforce single baseline-byte revert flow and post-revert re-read; add corruption-handling guidance * prompts(nl-full): after each write re-read raw bytes to refresh pre_sha; prefer script_apply_edits for anchors; avoid header/using changes * prompts(nl-full): canonicalize outputs to /; allow small fragment appends via Write or Bash(printf/echo); forbid wrappers and full-file round-trips * prompts(nl-full): finalize markdown formatting for guarded write, execution order, specs, status * workflows(nl-suite, mini): header/lint fixes and constrained Bash append path; align allowed_tools * prompts(nl-full): format Fast Restore, Guarded Write, Execution, Specs, Status as proper markdown lists and code fences * workflows(nl-suite): keep header tidy and append-path alignment with prompt * minor fix * workflows(nl-suite): fix indentation and dispatch; align allowed_tools and revert helper * prompts(nl-full): switch to read_resource for buf/sha; re-read only when needed; convert 'Print this once' to heading; note snapshot helper creates parent dirs * workflows(nl-suite): normalize step removes bootstrap when real testcases present; recompute tests/failures * workflows(nl-suite): enrich Markdown summary by extracting per-test <system-out> blocks (truncated) * clarify prompt resilience instructions * ci(nl-suite): revert prompt and workflow to known-good e0f8a72 for green run; remove extra MD details * ci(nl-suite): minimal fixes — no-mkdir guard in prompt; drop bootstrap and recompute JUnit counts * ci(nl-suite): richer JUnit→Markdown report (per-test system-out) * Small guard to incorret asset read call. * ci(nl-suite): refine MD builder — unescape XML entities, safe code fences, PASS/FAIL badges * Update UnityMcpBridge/UnityMcpServer~/src/tools/resource_tools.py Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update UnityMcpBridge/UnityMcpServer~/src/unity_connection.py Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update UnityMcpBridge/UnityMcpServer~/src/tools/manage_script_edits.py Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update .github/scripts/mark_skipped.py Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update .github/scripts/mark_skipped.py Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update .github/scripts/mark_skipped.py Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> * server(manage_script): robust URI handling — percent-decode file://, normalize, strip host/leading slashes, return Assets-relative if present * Update .claude/prompts/nl-unity-suite-full.md Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> * tests(framing): reduce handshake poll window, nonblocking peek to avoid disconnect race; still enforce pre-handshake data drop * tests(manage_script): add _split_uri tests for unity://path, file:// URLs (decoded/Assets-relative), and plain paths * server+tests: fix handshake syntax error; robust file:// URI normalization in manage_script; add _split_uri tests; adjust stdout scan to ignore venv/site-packages * bridge(framing): accept zero-length frames (treat as empty keepalive) * tests(logging): use errors='replace' on decode fallback to avoid silent drops * resources(list): restrict to Assets/, resolve symlinks, enforce .cs; add traversal/outside-path tests * Update .claude/prompts/nl-unity-suite-full.md Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update UnityMcpBridge/UnityMcpServer~/src/unity_connection.py Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * misc: framing keepalive (zero-length), regex preview consistency, resource.list hardening, URI parsing, legacy update routing, test cleanups * docs(tools): richer MCP tool descriptions; tests accept decorator kwargs; resource URI parsing hardened * Update .claude/prompts/nl-unity-suite-full.md Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update UnityMcpBridge/UnityMcpServer~/src/tools/resource_tools.py Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update UnityMcpBridge/UnityMcpServer~/src/unity_connection.py Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * net+docs: hard-reject zero-length frames; TCP_NODELAY on connect; Assets detection case-insensitive; NL prompt statuses aligned * prompt(nl-suite): constrain Write destinations under reports/, forbid traversal * prompt+net: harden Write path rules; use monotonic deadline and plain-text advisory for non-framed peers * unity_connection: restore recv timeout via try/finally; make global connection getter thread-safe with module lock and double-checked init * NL/T prompt: pin structured edit ops for T-D/T-E; add schema-error guarded write behavior; keep existing path/URI and revert rules * unity_connection: add FRAMED_MAX; use ValueError for framed length violations; lower framed receive log to debug; serialize connect() with per-instance lock * ManageScript: use UTF8Encoding(without BOM) for atomic writes in ApplyTextEdits/EditScript to align with Create/Update and avoid BOM-related diffs/hash mismatches * NL/T prompt: make helper deletion regex multiline-safe ((?ms) so ^ anchors line starts) * ManageScript: emit structured overlap status {status:"overlap"} for overlapping edit ranges in apply_text_edits and edit paths * NL/T prompt: clarify fallback vs failure — fallback only for unsupported/missing_field; treat bad_request as failure; note unsupported after fallback as failure * NL/T prompt: pin deterministic overlap probe (apply_text_edits two ranges from same snapshot); gate too_large behind RUN_TOO_LARGE env hint * TB update * NL/T prompt: harden Output Rules — constrain Bash(printf|echo) to stdout-only; forbid redirection/here-docs/tee; only scripts/nlt-revert.sh may mutate FS * Prompt: enumerate allowed script_apply_edits ops; add manage_editor/read_console guidance; fix T‑F atomic batch to single script_apply_edits. ManageScript: regex timeout for diagnostics; symlink ancestor guard; complete allowed-modes list. * Fixes * ManageScript: add rich overlap diagnostics (conflicts + hint) for both text range and structured batch paths * ManageScript: return structured {status:"validation_failed"} diagnostics in create/update/edits and validate before commit * ManageScript: echo canonical uri in responses (create/read/update/apply_text_edits/structured edits) to reinforce resource identity * improve clarity of capabilities message * Framing: allow zero-length frames on both ends (C# bridge, Python server). Prompt: harden T-F to single text-range apply_text_edits batch (descending order, one snapshot). URI: normalize file:// outside Assets by stripping leading slash. * ManageScript: include new sha256 in success payload for apply_text_edits; harden TryResolveUnderAssets by rejecting symlinked ancestors up to Assets/. * remove claudetest dir * manage_script_edits: normalize method-anchored anchor_insert to insert_method (map text->replacement); improves CI compatibility for T‑A/T‑E without changing Editor behavior. * tighten testing protocol around mkdir * manage_script: validate create_script inputs (Assets/.cs/name/no traversal); add Assets/ guard to delete_script; validate level+Assets in validate_script; make legacy manage_script optional params; harden legacy update routing with base64 reuse and payload size preflight. * Tighten prompt for testing * Update .claude/prompts/nl-unity-suite-full.md Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update .claude/prompts/nl-unity-suite-full.md Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update UnityMcpBridge/Editor/Tools/ManageScript.cs Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * manage_script_edits: honor ignore_case on anchor_insert and regex_replace in both direct and text-conversion paths (MULTILINE|IGNORECASE). * remove extra file * workflow: use python3 for inline scripts and port detection on ubuntu-latest. * Tighten prompt + manage_script * Update UnityMcpBridge/UnityMcpServer~/src/tools/manage_script_edits.py Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update UnityMcpBridge/UnityMcpServer~/src/tools/manage_script_edits.py Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update .claude/prompts/nl-unity-suite-full.md Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update UnityMcpBridge/Editor/Tools/ManageScript.cs Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update .claude/prompts/nl-unity-suite-full.md Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * manage_script: improve file:// UNC handling; preserve POSIX absolute semantics internally; keep test-expected slash stripping for non-Assets paths. * ManageScript.cs: add TimeSpan timeouts to all Regex uses (IsMatch/Match/new Regex) and keep CultureInvariant/Multiline options; reduces risk of catastrophic backtracking stalls. * workflow: ensure reports/ exists in markdown build step to avoid FileNotFoundError when writing MD_OUT. * fix brace * manage_script_edits: expand backrefs for regex_replace in preview->text conversion and translate to \g<n> in local apply; keeps previews and actual edits consistent. * anchor_insert: default to position=after, normalize surrounding newlines in Python conversion paths; C# path ensures trailing newline and skips duplicate insertion within class. * feat(mcp): add get_sha tool; apply_text_edits normalization+overlap preflight+strict; no-op evidence in C#; update NL suite prompt; add unit tests * feat(frames): accept zero-length heartbeat frames in client; add heartbeat test * feat(edits): guard destructive regex_replace with structural preflight; add robust tests; prompt uses delete_method for temp helper * feat(frames): bound heartbeat loop with timeout/threshold; align zero-length response with C#; update test * SDK hardening: atomic multi-span text edits; stop forcing sequential for structured ops; forward options on apply_text_edits; add validate=relaxed support and scoped checks; update NL/T prompt; add tests for options forwarding, relaxed mode, and atomic batches * Router: default applyMode=atomic for multi-span apply_text_edits; add tests * CI prompt: pass options.validate=relaxed for T-B/C; options.applyMode=atomic for T-F; emphasize always writing testcase and restoring on errors * Validation & DX: add validate=syntax (scoped), standardize evidence windows; early regex compile with hints; debug_preview for apply_text_edits * Update UnityMcpBridge/Editor/Windows/MCPForUnityEditorWindow.cs Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * NL/T suite-driven edits: LongUnityScriptClaudeTest, bridge helpers, server_version; prepare framing tests * Fix duplicate macConfigPath field in McpClient to resolve CS0102 * Editor threading: run EnsureServerInstalled on main thread; marshal EditorPrefs/DeleteKey + logging via delayCall * Docs(apply_text_edits): strengthen guidance on 1-based positions, verify-before-edit, and recommend anchors/structured edits * Docs(script_apply_edits): add safety guidance (anchors, method ops, validators) and recommended practices * Framed VerifyBridgePing in editor window; docs hardening for apply_text_edits and script_apply_edits --------- Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
2025-08-31 00:55:38 +08:00
return Response.Error($"Invalid path. Target directory must be within 'Assets/'. Provided: '{(path ?? "(null)")}'");
2025-03-31 22:49:35 +08:00
}
2025-03-31 03:58:01 +08:00
Claude‑friendly edit tools + framed transport + live Unity NL test framework (#243) * CI: gate desktop-parity on Anthropic key; pass anthropic_api_key like NL suite * Add quickprobe prompt and CI workflow (mcp-quickprobe.md, unity-mcp-quickprobe.yml) * strictier tool use to prevent subagent spawning and force mcp tools * update workflow filesto reduce likelihood of subagent spawning * improve permissions for claude agent, fix mcpbridge timeout/token issue * increase max turns to 10 * ci: align NL suite to new permissions schema; prevent subagent drift * ci: NL suite -> mini prompt for e2e; add full NL/T prompt; server: ctx optional + project_root fallback; workflows: set UNITY_PROJECT_ROOT for CI * ci: add checks:write; revert local project hardcodes (manifest, ProjectVersion.txt) * tools: text-edit routing fixes (anchor_insert via text, CRLF calc); prompts: mini NL/T clarifications * ci: use absolute UNITY_PROJECT_ROOT; prompts target TestProjects; server: accept relative UNITY_PROJECT_ROOT and bare spec URI * ci: ignore Unity test project's packages-lock.json; remove from repo to avoid absolute paths * CI: start persistent Unity Editor for MCP (guarded by license) + allow batch-mode bridge via UNITY_MCP_ALLOW_BATCH * CI: hide license and pass via env to docker; fix invalid ref format * CI: readiness probe uses handshake on Unity MCP port (deterministic) * CI: fix YAML; use TCP handshake readiness probe (FRAMING=1) * CI: prime Unity license via game-ci; mount ULF into container; extend readiness timeout * CI: use ULF write + mount for Unity licensing; remove serial/email/pass from container * CI: entitlement activation (UNITY_SERIAL=''); verify host ULF cache; keep mount * CI: write ULF from secret and verify; drop entitlement activation step * CI: detect any licensing path; GameCI prime; status dir env; log+probe readiness; fix YAML * CI: add GameCI license prime; conditional ULF write; one-shot license validation; explicit status dir + license env * CI: fix YAML (inline python), add Anthropic key detect via GITHUB_ENV; ready to run happy path * CI: mount Unity token/ulf/cache dirs into container to share host license; create dirs before start * CI: fix YAML indentation; write ULF on host; activate in container with shared mounts; mount .config and .cache too * CI: gate Claude via outputs; mount all Unity license dirs; fix inline probe python; stabilize licensing flow * CI: normalize detect to step outputs; ensure license dirs mounted and validated; fix indentation * Bridge: honor UNITY_MCP_STATUS_DIR for heartbeat/status file (CI-friendly) * CI: guard project path for activation/start; align tool allowlist; run MCP server with python; tighten secret scoping * CI: finalize Unity licensing mounts + status dir; mode-detect (ULF/EBL); readiness logs+probe; Claude gating via outputs * CI: fix YAML probe (inline python -c) and finalize happy-path Unity licensing and MCP/Claude wiring * CI: inline python probe; unify Unity image and cache mounts; ready to test * CI: fix docker run IMAGE placement; ignore cache find perms; keep same editor image * CI: pass -manualLicenseFile to persistent Editor; keep mounts and single image * CI: mount full GameCI cache to /root in persistent Unity; set HOME=/root; add optional license check * CI: make -manualLicenseFile conditional; keep full /root mount and license check * CI: set HOME=/github/home; mount GameCI cache there; adjust manualLicenseFile path; expand license check * CI: EBL sign-in for persistent Unity (email/password/serial); revert HOME=/root and full /root mount; keep conditional manualLicenseFile and improved readiness * CI: run full NL/T suite prompt (nl-unity-suite-full.md) instead of mini * NL/T: require unified diffs + explicit verdicts in JUnit; CI: remove short sanity step, publish JUnit, upload artifacts * NL/T prompt: require CDATA wrapping for JUnit XML fields; guidance for splitting embedded ]]>; keep VERDICT in CDATA only * CI: remove in-container license check step; keep readiness and full suite * NL/T prompt: add version header, stricter JUnit schema, hashing/normalization, anchors, statuses, atomic semantics, tool logging * CI: increase Claude NL/T suite timeout to 30 minutes * CI: pre-create reports dir and result files to avoid tool approval prompts * CI: skip wait if container not running; skip Editor start if project missing; broaden MCP deps detection; expand allowed tools * fixies to harden ManageScript * CI: sanitize NL/T markdown report to avoid NUL/encoding issues * revert breaking yyaml changes * CI: prime license, robust Unity start/wait, sanitize markdown via heredoc * Resolve merge: accept upstream renames/installer (fix/installer-cleanup-v2) and keep local framing/script-editing - Restored upstream server.py, EditorWindow, uv.lock\n- Preserved ManageScript editing/validation; switched to atomic write + debounced refresh\n- Updated tools/__init__.py to keep script_edits/resources and adopt new logger name\n- All Python tests via uv: 7 passed, 6 skipped, 9 xpassed; Unity compile OK * Fix Claude Desktop config path and atomic write issues - Fix macOS path for Claude Desktop config: use ~/Library/Application Support/Claude/ instead of ~/.config/Claude/ - Improve atomic write pattern with backup/restore safety - Replace File.Replace() with File.Move() for better macOS compatibility - Add proper error handling and cleanup for file operations - Resolves issue where installer couldn't find Claude Desktop config on macOS * Editor: use macConfigPath on macOS for MCP client config writes (Claude Desktop, etc.). Fallback to linuxConfigPath only if mac path missing. * Models: add macConfigPath to McpClient for macOS config path selection (fixes CS1061 in editor window). * Editor: on macOS, prefer macConfigPath in ManualConfigEditorWindow (fallback to linux path); Linux/Windows unchanged. * Fix McpClient: align with upstream/main, prep for framing split * NL suite: shard workflow; tighten bridge readiness; add MCP preflight; use env-based shard vars * NL suite: fix shard step indentation; move shard vars to env; remove invalid inputs * MCP clients: split VSCode Copilot config paths into macConfigPath and linuxConfigPath * Unity bridge: clean stale status; bind host; robust wait probe with IPv4/IPv6 + diagnostics * CI: use MCPForUnity.Editor.MCPForUnityBridge.StartAutoConnect as executeMethod * Action wiring: inline mcpServers in settings for all shards; remove redundant .claude/mcp.json step * CI: embed mcpServers in settings for all shards; fix startup sanity step; lint clean * CI: pin claude-code-base-action to e6f32c8; use claude_args --mcp-config; switch to allowed_tools; ensure MCP config per step * CI: unpin claude-code-base-action to @beta (commit ref not found) * CI: align with claude-code-base-action @beta; pass MCP via claude_args and allowedTools * Editor: Fix apply_text_edits heuristic when edits shift positions; recompute method span on candidate text with fallback delta adjustment * CI: unify MCP wiring across workflows; write .claude/mcp.json; switch to claude_args with --mcp-config/--allowedTools; remove unsupported inputs * CI: collapse NL suite shards into a single run to avoid repeated test execution * CI: minimize allowedTools for NL suite to essential Unity MCP + Bash("git:*") + Write * CI: mkdir -p reports before run; remove unsupported --timeout-minutes from claude_args * CI: broaden allowedTools to include find_in_file and mcp__unity__* * CI: enable use_node_cache and switch NL suite model to claude-3-7-haiku-20250219 * CI: disable use_node_cache to avoid setup-node lockfile error * CI: set NL suite model to claude-3-haiku-20240307 * CI: cap Haiku output with --max-tokens 2048 for NL suite * CI: switch to claude-3-7-sonnet-latest and remove unsupported --max-tokens * CI: update allowedTools to Bash(*) and explicit Unity MCP tool list * CI: update NL suite workflow (latest tweaks) * Tests: tighten NL suite prompt for logging, hash discipline, stale retry, evidence windows, diff cap, and VERDICT line * Add disallowed tools to NL suite workflow * docs: clarify stale write retry * Add fallback JUnit report and adjust publisher * Indent fallback JUnit XML in workflow * fix: correct fallback JUnit report generation * Update mcp-quickprobe.md Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> * Update mcp-quickprobe.md Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> * Update Response.cs Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> * Update MCPForUnityBridge.cs Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> * fix: correct McpTypes reference * Add directory existence checks for symlink and XDG paths * fix: only set installation flag after successful server install * Update resource_tools.py Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> * fix: respect mac config paths * Use File.Replace for atomic config write * Remove unused imports in manage_script * bump server version * Tests: update NL suite prompt and workflows; remove deprecated smoke/desktop-parity; quickprobe tidy * Editor: atomic config write via File.Replace fallback; remove redundant backups and racey exists checks * CI: harden NL suite - idempotent docker, gate on unity_ok, safer port probe, least-priv perms * Editor: make atomic config write restoration safe (flag writeDone; copy-overwrite restore; cleanup in finally) * CI: fix fallback JUnit heredoc by using printf lines (no EOF delimiter issues) * CI: switch NL suite to mini prompt; mini prompt honors / and NL discipline * CI: replace claude_args with allowed_tools/model/mcp_config per action schema * CI: expand UNITY_PROJECT_ROOT via in MCP config heredoc * EditorWindow: add cross-platform fallback for File.Replace; macOS-insensitive PathsEqual; safer uv resolve; honor macConfigPath * CI: strengthen JUnit publishing for NL mini suite (normalize, debug list, publish both, fail_on_parse_error) * CI: set job-wide JUNIT_OUT/MD_OUT; normalization uses env; publish references env and ungroup reports * CI: publish a single normalized JUnit (reports/junit-for-actions.xml); fallback writes same; avoid checkName/reportPaths mismatch * CI: align mini prompt report filenames; redact Unity log tail in diagnostics * chore: sync workflow and mini prompt; redacted logs; JUnit normalization/publish tweaks * CI: redact sensitive tokens in Stop Unity; docs: CI usage + edit tools * prompts: update nl-unity-suite-full (mini-style setup + reporting discipline); remove obsolete prompts * CI: harden NL workflows (timeout_minutes, robust normalization); prompts: unify JUnit suite name and reporting discipline * prompts: add guarded write pattern (LF hash, stale_file retry) to full suite * prompts: enforce continue-on-failure, driver flow, and status handling in full suite * Make test list more explicit in prompt. Get rid of old test prompts for hygeine. * prompts: add stale fast-retry (server hash) + in-memory buf guidance * CI: standardize JUNIT_OUT to reports/junit-nl-suite.xml; fix artifact upload indentation; prompt copy cleanups * prompts: reporting discipline — append-only fragments, batch writes, no model round-trip * prompts: stale fast-retry preference, buffer/sha carry, snapshot revert, essential logging * workflows(nl-suite): precreate report skeletons, assemble junit, synthesize markdown; restrict allowed_tools to append-only Bash + MCP tools * thsis too * Update README-DEV.md Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update .github/workflows/claude-nl-suite-mini.yml Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update .github/workflows/claude-nl-suite.yml Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * workflows(nl-mini): fix YAML indentation/trailing spaces under with: and cleanup heredoc spacing * workflows(nl-suite): fix indentation on docker logs redaction line (YAML lint) * Add write to allowlist * nl-suite: harden reporting discipline (fragment-only writes, forbid alt paths); workflow: clean stray junit-*updated*.xml * nl-suite: enforce end-of-suite single Write (no bash redirection); workflow: restrict allowed_tools to Write+MCP only * prompts(nl-full): end-of-suite results must be valid XML with single <cases> root and only <testcase> children; no raw text outside CDATA * workflows(nl-suite): make Claude step non-fatal; tolerant normalizer extracts <testcase> via regex on bad fragments * nl-suite: fix stale classname to UnityMCP.NL-T in mini fallback; prompt: require re-read after every revert; correct PLAN/PROGRESS to 15 * nl-suite: fix fallback JUnit classname to UnityMCP.NL-T; prompt: forbid create_script and env/mkdir checks, enforce single baseline-byte revert flow and post-revert re-read; add corruption-handling guidance * prompts(nl-full): after each write re-read raw bytes to refresh pre_sha; prefer script_apply_edits for anchors; avoid header/using changes * prompts(nl-full): canonicalize outputs to /; allow small fragment appends via Write or Bash(printf/echo); forbid wrappers and full-file round-trips * prompts(nl-full): finalize markdown formatting for guarded write, execution order, specs, status * workflows(nl-suite, mini): header/lint fixes and constrained Bash append path; align allowed_tools * prompts(nl-full): format Fast Restore, Guarded Write, Execution, Specs, Status as proper markdown lists and code fences * workflows(nl-suite): keep header tidy and append-path alignment with prompt * minor fix * workflows(nl-suite): fix indentation and dispatch; align allowed_tools and revert helper * prompts(nl-full): switch to read_resource for buf/sha; re-read only when needed; convert 'Print this once' to heading; note snapshot helper creates parent dirs * workflows(nl-suite): normalize step removes bootstrap when real testcases present; recompute tests/failures * workflows(nl-suite): enrich Markdown summary by extracting per-test <system-out> blocks (truncated) * clarify prompt resilience instructions * ci(nl-suite): revert prompt and workflow to known-good e0f8a72 for green run; remove extra MD details * ci(nl-suite): minimal fixes — no-mkdir guard in prompt; drop bootstrap and recompute JUnit counts * ci(nl-suite): richer JUnit→Markdown report (per-test system-out) * Small guard to incorret asset read call. * ci(nl-suite): refine MD builder — unescape XML entities, safe code fences, PASS/FAIL badges * Update UnityMcpBridge/UnityMcpServer~/src/tools/resource_tools.py Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update UnityMcpBridge/UnityMcpServer~/src/unity_connection.py Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update UnityMcpBridge/UnityMcpServer~/src/tools/manage_script_edits.py Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update .github/scripts/mark_skipped.py Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update .github/scripts/mark_skipped.py Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update .github/scripts/mark_skipped.py Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> * server(manage_script): robust URI handling — percent-decode file://, normalize, strip host/leading slashes, return Assets-relative if present * Update .claude/prompts/nl-unity-suite-full.md Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> * tests(framing): reduce handshake poll window, nonblocking peek to avoid disconnect race; still enforce pre-handshake data drop * tests(manage_script): add _split_uri tests for unity://path, file:// URLs (decoded/Assets-relative), and plain paths * server+tests: fix handshake syntax error; robust file:// URI normalization in manage_script; add _split_uri tests; adjust stdout scan to ignore venv/site-packages * bridge(framing): accept zero-length frames (treat as empty keepalive) * tests(logging): use errors='replace' on decode fallback to avoid silent drops * resources(list): restrict to Assets/, resolve symlinks, enforce .cs; add traversal/outside-path tests * Update .claude/prompts/nl-unity-suite-full.md Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update UnityMcpBridge/UnityMcpServer~/src/unity_connection.py Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * misc: framing keepalive (zero-length), regex preview consistency, resource.list hardening, URI parsing, legacy update routing, test cleanups * docs(tools): richer MCP tool descriptions; tests accept decorator kwargs; resource URI parsing hardened * Update .claude/prompts/nl-unity-suite-full.md Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update UnityMcpBridge/UnityMcpServer~/src/tools/resource_tools.py Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update UnityMcpBridge/UnityMcpServer~/src/unity_connection.py Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * net+docs: hard-reject zero-length frames; TCP_NODELAY on connect; Assets detection case-insensitive; NL prompt statuses aligned * prompt(nl-suite): constrain Write destinations under reports/, forbid traversal * prompt+net: harden Write path rules; use monotonic deadline and plain-text advisory for non-framed peers * unity_connection: restore recv timeout via try/finally; make global connection getter thread-safe with module lock and double-checked init * NL/T prompt: pin structured edit ops for T-D/T-E; add schema-error guarded write behavior; keep existing path/URI and revert rules * unity_connection: add FRAMED_MAX; use ValueError for framed length violations; lower framed receive log to debug; serialize connect() with per-instance lock * ManageScript: use UTF8Encoding(without BOM) for atomic writes in ApplyTextEdits/EditScript to align with Create/Update and avoid BOM-related diffs/hash mismatches * NL/T prompt: make helper deletion regex multiline-safe ((?ms) so ^ anchors line starts) * ManageScript: emit structured overlap status {status:"overlap"} for overlapping edit ranges in apply_text_edits and edit paths * NL/T prompt: clarify fallback vs failure — fallback only for unsupported/missing_field; treat bad_request as failure; note unsupported after fallback as failure * NL/T prompt: pin deterministic overlap probe (apply_text_edits two ranges from same snapshot); gate too_large behind RUN_TOO_LARGE env hint * TB update * NL/T prompt: harden Output Rules — constrain Bash(printf|echo) to stdout-only; forbid redirection/here-docs/tee; only scripts/nlt-revert.sh may mutate FS * Prompt: enumerate allowed script_apply_edits ops; add manage_editor/read_console guidance; fix T‑F atomic batch to single script_apply_edits. ManageScript: regex timeout for diagnostics; symlink ancestor guard; complete allowed-modes list. * Fixes * ManageScript: add rich overlap diagnostics (conflicts + hint) for both text range and structured batch paths * ManageScript: return structured {status:"validation_failed"} diagnostics in create/update/edits and validate before commit * ManageScript: echo canonical uri in responses (create/read/update/apply_text_edits/structured edits) to reinforce resource identity * improve clarity of capabilities message * Framing: allow zero-length frames on both ends (C# bridge, Python server). Prompt: harden T-F to single text-range apply_text_edits batch (descending order, one snapshot). URI: normalize file:// outside Assets by stripping leading slash. * ManageScript: include new sha256 in success payload for apply_text_edits; harden TryResolveUnderAssets by rejecting symlinked ancestors up to Assets/. * remove claudetest dir * manage_script_edits: normalize method-anchored anchor_insert to insert_method (map text->replacement); improves CI compatibility for T‑A/T‑E without changing Editor behavior. * tighten testing protocol around mkdir * manage_script: validate create_script inputs (Assets/.cs/name/no traversal); add Assets/ guard to delete_script; validate level+Assets in validate_script; make legacy manage_script optional params; harden legacy update routing with base64 reuse and payload size preflight. * Tighten prompt for testing * Update .claude/prompts/nl-unity-suite-full.md Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update .claude/prompts/nl-unity-suite-full.md Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update UnityMcpBridge/Editor/Tools/ManageScript.cs Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * manage_script_edits: honor ignore_case on anchor_insert and regex_replace in both direct and text-conversion paths (MULTILINE|IGNORECASE). * remove extra file * workflow: use python3 for inline scripts and port detection on ubuntu-latest. * Tighten prompt + manage_script * Update UnityMcpBridge/UnityMcpServer~/src/tools/manage_script_edits.py Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update UnityMcpBridge/UnityMcpServer~/src/tools/manage_script_edits.py Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update .claude/prompts/nl-unity-suite-full.md Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update UnityMcpBridge/Editor/Tools/ManageScript.cs Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update .claude/prompts/nl-unity-suite-full.md Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * manage_script: improve file:// UNC handling; preserve POSIX absolute semantics internally; keep test-expected slash stripping for non-Assets paths. * ManageScript.cs: add TimeSpan timeouts to all Regex uses (IsMatch/Match/new Regex) and keep CultureInvariant/Multiline options; reduces risk of catastrophic backtracking stalls. * workflow: ensure reports/ exists in markdown build step to avoid FileNotFoundError when writing MD_OUT. * fix brace * manage_script_edits: expand backrefs for regex_replace in preview->text conversion and translate to \g<n> in local apply; keeps previews and actual edits consistent. * anchor_insert: default to position=after, normalize surrounding newlines in Python conversion paths; C# path ensures trailing newline and skips duplicate insertion within class. * feat(mcp): add get_sha tool; apply_text_edits normalization+overlap preflight+strict; no-op evidence in C#; update NL suite prompt; add unit tests * feat(frames): accept zero-length heartbeat frames in client; add heartbeat test * feat(edits): guard destructive regex_replace with structural preflight; add robust tests; prompt uses delete_method for temp helper * feat(frames): bound heartbeat loop with timeout/threshold; align zero-length response with C#; update test * SDK hardening: atomic multi-span text edits; stop forcing sequential for structured ops; forward options on apply_text_edits; add validate=relaxed support and scoped checks; update NL/T prompt; add tests for options forwarding, relaxed mode, and atomic batches * Router: default applyMode=atomic for multi-span apply_text_edits; add tests * CI prompt: pass options.validate=relaxed for T-B/C; options.applyMode=atomic for T-F; emphasize always writing testcase and restoring on errors * Validation & DX: add validate=syntax (scoped), standardize evidence windows; early regex compile with hints; debug_preview for apply_text_edits * Update UnityMcpBridge/Editor/Windows/MCPForUnityEditorWindow.cs Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * NL/T suite-driven edits: LongUnityScriptClaudeTest, bridge helpers, server_version; prepare framing tests * Fix duplicate macConfigPath field in McpClient to resolve CS0102 * Editor threading: run EnsureServerInstalled on main thread; marshal EditorPrefs/DeleteKey + logging via delayCall * Docs(apply_text_edits): strengthen guidance on 1-based positions, verify-before-edit, and recommend anchors/structured edits * Docs(script_apply_edits): add safety guidance (anchors, method ops, validators) and recommended practices * Framed VerifyBridgePing in editor window; docs hardening for apply_text_edits and script_apply_edits --------- Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
2025-08-31 00:55:38 +08:00
// Construct file paths
2025-03-31 03:58:01 +08:00
string scriptFileName = $"{name}.cs";
string fullPath = Path.Combine(fullPathDir, scriptFileName);
Claude‑friendly edit tools + framed transport + live Unity NL test framework (#243) * CI: gate desktop-parity on Anthropic key; pass anthropic_api_key like NL suite * Add quickprobe prompt and CI workflow (mcp-quickprobe.md, unity-mcp-quickprobe.yml) * strictier tool use to prevent subagent spawning and force mcp tools * update workflow filesto reduce likelihood of subagent spawning * improve permissions for claude agent, fix mcpbridge timeout/token issue * increase max turns to 10 * ci: align NL suite to new permissions schema; prevent subagent drift * ci: NL suite -> mini prompt for e2e; add full NL/T prompt; server: ctx optional + project_root fallback; workflows: set UNITY_PROJECT_ROOT for CI * ci: add checks:write; revert local project hardcodes (manifest, ProjectVersion.txt) * tools: text-edit routing fixes (anchor_insert via text, CRLF calc); prompts: mini NL/T clarifications * ci: use absolute UNITY_PROJECT_ROOT; prompts target TestProjects; server: accept relative UNITY_PROJECT_ROOT and bare spec URI * ci: ignore Unity test project's packages-lock.json; remove from repo to avoid absolute paths * CI: start persistent Unity Editor for MCP (guarded by license) + allow batch-mode bridge via UNITY_MCP_ALLOW_BATCH * CI: hide license and pass via env to docker; fix invalid ref format * CI: readiness probe uses handshake on Unity MCP port (deterministic) * CI: fix YAML; use TCP handshake readiness probe (FRAMING=1) * CI: prime Unity license via game-ci; mount ULF into container; extend readiness timeout * CI: use ULF write + mount for Unity licensing; remove serial/email/pass from container * CI: entitlement activation (UNITY_SERIAL=''); verify host ULF cache; keep mount * CI: write ULF from secret and verify; drop entitlement activation step * CI: detect any licensing path; GameCI prime; status dir env; log+probe readiness; fix YAML * CI: add GameCI license prime; conditional ULF write; one-shot license validation; explicit status dir + license env * CI: fix YAML (inline python), add Anthropic key detect via GITHUB_ENV; ready to run happy path * CI: mount Unity token/ulf/cache dirs into container to share host license; create dirs before start * CI: fix YAML indentation; write ULF on host; activate in container with shared mounts; mount .config and .cache too * CI: gate Claude via outputs; mount all Unity license dirs; fix inline probe python; stabilize licensing flow * CI: normalize detect to step outputs; ensure license dirs mounted and validated; fix indentation * Bridge: honor UNITY_MCP_STATUS_DIR for heartbeat/status file (CI-friendly) * CI: guard project path for activation/start; align tool allowlist; run MCP server with python; tighten secret scoping * CI: finalize Unity licensing mounts + status dir; mode-detect (ULF/EBL); readiness logs+probe; Claude gating via outputs * CI: fix YAML probe (inline python -c) and finalize happy-path Unity licensing and MCP/Claude wiring * CI: inline python probe; unify Unity image and cache mounts; ready to test * CI: fix docker run IMAGE placement; ignore cache find perms; keep same editor image * CI: pass -manualLicenseFile to persistent Editor; keep mounts and single image * CI: mount full GameCI cache to /root in persistent Unity; set HOME=/root; add optional license check * CI: make -manualLicenseFile conditional; keep full /root mount and license check * CI: set HOME=/github/home; mount GameCI cache there; adjust manualLicenseFile path; expand license check * CI: EBL sign-in for persistent Unity (email/password/serial); revert HOME=/root and full /root mount; keep conditional manualLicenseFile and improved readiness * CI: run full NL/T suite prompt (nl-unity-suite-full.md) instead of mini * NL/T: require unified diffs + explicit verdicts in JUnit; CI: remove short sanity step, publish JUnit, upload artifacts * NL/T prompt: require CDATA wrapping for JUnit XML fields; guidance for splitting embedded ]]>; keep VERDICT in CDATA only * CI: remove in-container license check step; keep readiness and full suite * NL/T prompt: add version header, stricter JUnit schema, hashing/normalization, anchors, statuses, atomic semantics, tool logging * CI: increase Claude NL/T suite timeout to 30 minutes * CI: pre-create reports dir and result files to avoid tool approval prompts * CI: skip wait if container not running; skip Editor start if project missing; broaden MCP deps detection; expand allowed tools * fixies to harden ManageScript * CI: sanitize NL/T markdown report to avoid NUL/encoding issues * revert breaking yyaml changes * CI: prime license, robust Unity start/wait, sanitize markdown via heredoc * Resolve merge: accept upstream renames/installer (fix/installer-cleanup-v2) and keep local framing/script-editing - Restored upstream server.py, EditorWindow, uv.lock\n- Preserved ManageScript editing/validation; switched to atomic write + debounced refresh\n- Updated tools/__init__.py to keep script_edits/resources and adopt new logger name\n- All Python tests via uv: 7 passed, 6 skipped, 9 xpassed; Unity compile OK * Fix Claude Desktop config path and atomic write issues - Fix macOS path for Claude Desktop config: use ~/Library/Application Support/Claude/ instead of ~/.config/Claude/ - Improve atomic write pattern with backup/restore safety - Replace File.Replace() with File.Move() for better macOS compatibility - Add proper error handling and cleanup for file operations - Resolves issue where installer couldn't find Claude Desktop config on macOS * Editor: use macConfigPath on macOS for MCP client config writes (Claude Desktop, etc.). Fallback to linuxConfigPath only if mac path missing. * Models: add macConfigPath to McpClient for macOS config path selection (fixes CS1061 in editor window). * Editor: on macOS, prefer macConfigPath in ManualConfigEditorWindow (fallback to linux path); Linux/Windows unchanged. * Fix McpClient: align with upstream/main, prep for framing split * NL suite: shard workflow; tighten bridge readiness; add MCP preflight; use env-based shard vars * NL suite: fix shard step indentation; move shard vars to env; remove invalid inputs * MCP clients: split VSCode Copilot config paths into macConfigPath and linuxConfigPath * Unity bridge: clean stale status; bind host; robust wait probe with IPv4/IPv6 + diagnostics * CI: use MCPForUnity.Editor.MCPForUnityBridge.StartAutoConnect as executeMethod * Action wiring: inline mcpServers in settings for all shards; remove redundant .claude/mcp.json step * CI: embed mcpServers in settings for all shards; fix startup sanity step; lint clean * CI: pin claude-code-base-action to e6f32c8; use claude_args --mcp-config; switch to allowed_tools; ensure MCP config per step * CI: unpin claude-code-base-action to @beta (commit ref not found) * CI: align with claude-code-base-action @beta; pass MCP via claude_args and allowedTools * Editor: Fix apply_text_edits heuristic when edits shift positions; recompute method span on candidate text with fallback delta adjustment * CI: unify MCP wiring across workflows; write .claude/mcp.json; switch to claude_args with --mcp-config/--allowedTools; remove unsupported inputs * CI: collapse NL suite shards into a single run to avoid repeated test execution * CI: minimize allowedTools for NL suite to essential Unity MCP + Bash("git:*") + Write * CI: mkdir -p reports before run; remove unsupported --timeout-minutes from claude_args * CI: broaden allowedTools to include find_in_file and mcp__unity__* * CI: enable use_node_cache and switch NL suite model to claude-3-7-haiku-20250219 * CI: disable use_node_cache to avoid setup-node lockfile error * CI: set NL suite model to claude-3-haiku-20240307 * CI: cap Haiku output with --max-tokens 2048 for NL suite * CI: switch to claude-3-7-sonnet-latest and remove unsupported --max-tokens * CI: update allowedTools to Bash(*) and explicit Unity MCP tool list * CI: update NL suite workflow (latest tweaks) * Tests: tighten NL suite prompt for logging, hash discipline, stale retry, evidence windows, diff cap, and VERDICT line * Add disallowed tools to NL suite workflow * docs: clarify stale write retry * Add fallback JUnit report and adjust publisher * Indent fallback JUnit XML in workflow * fix: correct fallback JUnit report generation * Update mcp-quickprobe.md Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> * Update mcp-quickprobe.md Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> * Update Response.cs Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> * Update MCPForUnityBridge.cs Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> * fix: correct McpTypes reference * Add directory existence checks for symlink and XDG paths * fix: only set installation flag after successful server install * Update resource_tools.py Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> * fix: respect mac config paths * Use File.Replace for atomic config write * Remove unused imports in manage_script * bump server version * Tests: update NL suite prompt and workflows; remove deprecated smoke/desktop-parity; quickprobe tidy * Editor: atomic config write via File.Replace fallback; remove redundant backups and racey exists checks * CI: harden NL suite - idempotent docker, gate on unity_ok, safer port probe, least-priv perms * Editor: make atomic config write restoration safe (flag writeDone; copy-overwrite restore; cleanup in finally) * CI: fix fallback JUnit heredoc by using printf lines (no EOF delimiter issues) * CI: switch NL suite to mini prompt; mini prompt honors / and NL discipline * CI: replace claude_args with allowed_tools/model/mcp_config per action schema * CI: expand UNITY_PROJECT_ROOT via in MCP config heredoc * EditorWindow: add cross-platform fallback for File.Replace; macOS-insensitive PathsEqual; safer uv resolve; honor macConfigPath * CI: strengthen JUnit publishing for NL mini suite (normalize, debug list, publish both, fail_on_parse_error) * CI: set job-wide JUNIT_OUT/MD_OUT; normalization uses env; publish references env and ungroup reports * CI: publish a single normalized JUnit (reports/junit-for-actions.xml); fallback writes same; avoid checkName/reportPaths mismatch * CI: align mini prompt report filenames; redact Unity log tail in diagnostics * chore: sync workflow and mini prompt; redacted logs; JUnit normalization/publish tweaks * CI: redact sensitive tokens in Stop Unity; docs: CI usage + edit tools * prompts: update nl-unity-suite-full (mini-style setup + reporting discipline); remove obsolete prompts * CI: harden NL workflows (timeout_minutes, robust normalization); prompts: unify JUnit suite name and reporting discipline * prompts: add guarded write pattern (LF hash, stale_file retry) to full suite * prompts: enforce continue-on-failure, driver flow, and status handling in full suite * Make test list more explicit in prompt. Get rid of old test prompts for hygeine. * prompts: add stale fast-retry (server hash) + in-memory buf guidance * CI: standardize JUNIT_OUT to reports/junit-nl-suite.xml; fix artifact upload indentation; prompt copy cleanups * prompts: reporting discipline — append-only fragments, batch writes, no model round-trip * prompts: stale fast-retry preference, buffer/sha carry, snapshot revert, essential logging * workflows(nl-suite): precreate report skeletons, assemble junit, synthesize markdown; restrict allowed_tools to append-only Bash + MCP tools * thsis too * Update README-DEV.md Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update .github/workflows/claude-nl-suite-mini.yml Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update .github/workflows/claude-nl-suite.yml Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * workflows(nl-mini): fix YAML indentation/trailing spaces under with: and cleanup heredoc spacing * workflows(nl-suite): fix indentation on docker logs redaction line (YAML lint) * Add write to allowlist * nl-suite: harden reporting discipline (fragment-only writes, forbid alt paths); workflow: clean stray junit-*updated*.xml * nl-suite: enforce end-of-suite single Write (no bash redirection); workflow: restrict allowed_tools to Write+MCP only * prompts(nl-full): end-of-suite results must be valid XML with single <cases> root and only <testcase> children; no raw text outside CDATA * workflows(nl-suite): make Claude step non-fatal; tolerant normalizer extracts <testcase> via regex on bad fragments * nl-suite: fix stale classname to UnityMCP.NL-T in mini fallback; prompt: require re-read after every revert; correct PLAN/PROGRESS to 15 * nl-suite: fix fallback JUnit classname to UnityMCP.NL-T; prompt: forbid create_script and env/mkdir checks, enforce single baseline-byte revert flow and post-revert re-read; add corruption-handling guidance * prompts(nl-full): after each write re-read raw bytes to refresh pre_sha; prefer script_apply_edits for anchors; avoid header/using changes * prompts(nl-full): canonicalize outputs to /; allow small fragment appends via Write or Bash(printf/echo); forbid wrappers and full-file round-trips * prompts(nl-full): finalize markdown formatting for guarded write, execution order, specs, status * workflows(nl-suite, mini): header/lint fixes and constrained Bash append path; align allowed_tools * prompts(nl-full): format Fast Restore, Guarded Write, Execution, Specs, Status as proper markdown lists and code fences * workflows(nl-suite): keep header tidy and append-path alignment with prompt * minor fix * workflows(nl-suite): fix indentation and dispatch; align allowed_tools and revert helper * prompts(nl-full): switch to read_resource for buf/sha; re-read only when needed; convert 'Print this once' to heading; note snapshot helper creates parent dirs * workflows(nl-suite): normalize step removes bootstrap when real testcases present; recompute tests/failures * workflows(nl-suite): enrich Markdown summary by extracting per-test <system-out> blocks (truncated) * clarify prompt resilience instructions * ci(nl-suite): revert prompt and workflow to known-good e0f8a72 for green run; remove extra MD details * ci(nl-suite): minimal fixes — no-mkdir guard in prompt; drop bootstrap and recompute JUnit counts * ci(nl-suite): richer JUnit→Markdown report (per-test system-out) * Small guard to incorret asset read call. * ci(nl-suite): refine MD builder — unescape XML entities, safe code fences, PASS/FAIL badges * Update UnityMcpBridge/UnityMcpServer~/src/tools/resource_tools.py Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update UnityMcpBridge/UnityMcpServer~/src/unity_connection.py Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update UnityMcpBridge/UnityMcpServer~/src/tools/manage_script_edits.py Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update .github/scripts/mark_skipped.py Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update .github/scripts/mark_skipped.py Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update .github/scripts/mark_skipped.py Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> * server(manage_script): robust URI handling — percent-decode file://, normalize, strip host/leading slashes, return Assets-relative if present * Update .claude/prompts/nl-unity-suite-full.md Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> * tests(framing): reduce handshake poll window, nonblocking peek to avoid disconnect race; still enforce pre-handshake data drop * tests(manage_script): add _split_uri tests for unity://path, file:// URLs (decoded/Assets-relative), and plain paths * server+tests: fix handshake syntax error; robust file:// URI normalization in manage_script; add _split_uri tests; adjust stdout scan to ignore venv/site-packages * bridge(framing): accept zero-length frames (treat as empty keepalive) * tests(logging): use errors='replace' on decode fallback to avoid silent drops * resources(list): restrict to Assets/, resolve symlinks, enforce .cs; add traversal/outside-path tests * Update .claude/prompts/nl-unity-suite-full.md Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update UnityMcpBridge/UnityMcpServer~/src/unity_connection.py Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * misc: framing keepalive (zero-length), regex preview consistency, resource.list hardening, URI parsing, legacy update routing, test cleanups * docs(tools): richer MCP tool descriptions; tests accept decorator kwargs; resource URI parsing hardened * Update .claude/prompts/nl-unity-suite-full.md Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update UnityMcpBridge/UnityMcpServer~/src/tools/resource_tools.py Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update UnityMcpBridge/UnityMcpServer~/src/unity_connection.py Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * net+docs: hard-reject zero-length frames; TCP_NODELAY on connect; Assets detection case-insensitive; NL prompt statuses aligned * prompt(nl-suite): constrain Write destinations under reports/, forbid traversal * prompt+net: harden Write path rules; use monotonic deadline and plain-text advisory for non-framed peers * unity_connection: restore recv timeout via try/finally; make global connection getter thread-safe with module lock and double-checked init * NL/T prompt: pin structured edit ops for T-D/T-E; add schema-error guarded write behavior; keep existing path/URI and revert rules * unity_connection: add FRAMED_MAX; use ValueError for framed length violations; lower framed receive log to debug; serialize connect() with per-instance lock * ManageScript: use UTF8Encoding(without BOM) for atomic writes in ApplyTextEdits/EditScript to align with Create/Update and avoid BOM-related diffs/hash mismatches * NL/T prompt: make helper deletion regex multiline-safe ((?ms) so ^ anchors line starts) * ManageScript: emit structured overlap status {status:"overlap"} for overlapping edit ranges in apply_text_edits and edit paths * NL/T prompt: clarify fallback vs failure — fallback only for unsupported/missing_field; treat bad_request as failure; note unsupported after fallback as failure * NL/T prompt: pin deterministic overlap probe (apply_text_edits two ranges from same snapshot); gate too_large behind RUN_TOO_LARGE env hint * TB update * NL/T prompt: harden Output Rules — constrain Bash(printf|echo) to stdout-only; forbid redirection/here-docs/tee; only scripts/nlt-revert.sh may mutate FS * Prompt: enumerate allowed script_apply_edits ops; add manage_editor/read_console guidance; fix T‑F atomic batch to single script_apply_edits. ManageScript: regex timeout for diagnostics; symlink ancestor guard; complete allowed-modes list. * Fixes * ManageScript: add rich overlap diagnostics (conflicts + hint) for both text range and structured batch paths * ManageScript: return structured {status:"validation_failed"} diagnostics in create/update/edits and validate before commit * ManageScript: echo canonical uri in responses (create/read/update/apply_text_edits/structured edits) to reinforce resource identity * improve clarity of capabilities message * Framing: allow zero-length frames on both ends (C# bridge, Python server). Prompt: harden T-F to single text-range apply_text_edits batch (descending order, one snapshot). URI: normalize file:// outside Assets by stripping leading slash. * ManageScript: include new sha256 in success payload for apply_text_edits; harden TryResolveUnderAssets by rejecting symlinked ancestors up to Assets/. * remove claudetest dir * manage_script_edits: normalize method-anchored anchor_insert to insert_method (map text->replacement); improves CI compatibility for T‑A/T‑E without changing Editor behavior. * tighten testing protocol around mkdir * manage_script: validate create_script inputs (Assets/.cs/name/no traversal); add Assets/ guard to delete_script; validate level+Assets in validate_script; make legacy manage_script optional params; harden legacy update routing with base64 reuse and payload size preflight. * Tighten prompt for testing * Update .claude/prompts/nl-unity-suite-full.md Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update .claude/prompts/nl-unity-suite-full.md Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update UnityMcpBridge/Editor/Tools/ManageScript.cs Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * manage_script_edits: honor ignore_case on anchor_insert and regex_replace in both direct and text-conversion paths (MULTILINE|IGNORECASE). * remove extra file * workflow: use python3 for inline scripts and port detection on ubuntu-latest. * Tighten prompt + manage_script * Update UnityMcpBridge/UnityMcpServer~/src/tools/manage_script_edits.py Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update UnityMcpBridge/UnityMcpServer~/src/tools/manage_script_edits.py Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update .claude/prompts/nl-unity-suite-full.md Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update UnityMcpBridge/Editor/Tools/ManageScript.cs Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update .claude/prompts/nl-unity-suite-full.md Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * manage_script: improve file:// UNC handling; preserve POSIX absolute semantics internally; keep test-expected slash stripping for non-Assets paths. * ManageScript.cs: add TimeSpan timeouts to all Regex uses (IsMatch/Match/new Regex) and keep CultureInvariant/Multiline options; reduces risk of catastrophic backtracking stalls. * workflow: ensure reports/ exists in markdown build step to avoid FileNotFoundError when writing MD_OUT. * fix brace * manage_script_edits: expand backrefs for regex_replace in preview->text conversion and translate to \g<n> in local apply; keeps previews and actual edits consistent. * anchor_insert: default to position=after, normalize surrounding newlines in Python conversion paths; C# path ensures trailing newline and skips duplicate insertion within class. * feat(mcp): add get_sha tool; apply_text_edits normalization+overlap preflight+strict; no-op evidence in C#; update NL suite prompt; add unit tests * feat(frames): accept zero-length heartbeat frames in client; add heartbeat test * feat(edits): guard destructive regex_replace with structural preflight; add robust tests; prompt uses delete_method for temp helper * feat(frames): bound heartbeat loop with timeout/threshold; align zero-length response with C#; update test * SDK hardening: atomic multi-span text edits; stop forcing sequential for structured ops; forward options on apply_text_edits; add validate=relaxed support and scoped checks; update NL/T prompt; add tests for options forwarding, relaxed mode, and atomic batches * Router: default applyMode=atomic for multi-span apply_text_edits; add tests * CI prompt: pass options.validate=relaxed for T-B/C; options.applyMode=atomic for T-F; emphasize always writing testcase and restoring on errors * Validation & DX: add validate=syntax (scoped), standardize evidence windows; early regex compile with hints; debug_preview for apply_text_edits * Update UnityMcpBridge/Editor/Windows/MCPForUnityEditorWindow.cs Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * NL/T suite-driven edits: LongUnityScriptClaudeTest, bridge helpers, server_version; prepare framing tests * Fix duplicate macConfigPath field in McpClient to resolve CS0102 * Editor threading: run EnsureServerInstalled on main thread; marshal EditorPrefs/DeleteKey + logging via delayCall * Docs(apply_text_edits): strengthen guidance on 1-based positions, verify-before-edit, and recommend anchors/structured edits * Docs(script_apply_edits): add safety guidance (anchors, method ops, validators) and recommended practices * Framed VerifyBridgePing in editor window; docs hardening for apply_text_edits and script_apply_edits --------- Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
2025-08-31 00:55:38 +08:00
string relativePath = Path.Combine(relPathSafeDir, scriptFileName).Replace('\\', '/');
2025-03-31 03:58:01 +08:00
// Ensure the target directory exists for create/update
if (action == "create" || action == "update")
{
try
{
Directory.CreateDirectory(fullPathDir);
}
catch (Exception e)
{
return Response.Error(
$"Could not create directory '{fullPathDir}': {e.Message}"
);
2025-03-31 03:58:01 +08:00
}
}
2025-03-31 03:58:01 +08:00
// Route to specific action handlers
switch (action)
{
case "create":
return CreateScript(
fullPath,
relativePath,
name,
contents,
scriptType,
namespaceName
);
2025-03-31 03:58:01 +08:00
case "read":
Claude‑friendly edit tools + framed transport + live Unity NL test framework (#243) * CI: gate desktop-parity on Anthropic key; pass anthropic_api_key like NL suite * Add quickprobe prompt and CI workflow (mcp-quickprobe.md, unity-mcp-quickprobe.yml) * strictier tool use to prevent subagent spawning and force mcp tools * update workflow filesto reduce likelihood of subagent spawning * improve permissions for claude agent, fix mcpbridge timeout/token issue * increase max turns to 10 * ci: align NL suite to new permissions schema; prevent subagent drift * ci: NL suite -> mini prompt for e2e; add full NL/T prompt; server: ctx optional + project_root fallback; workflows: set UNITY_PROJECT_ROOT for CI * ci: add checks:write; revert local project hardcodes (manifest, ProjectVersion.txt) * tools: text-edit routing fixes (anchor_insert via text, CRLF calc); prompts: mini NL/T clarifications * ci: use absolute UNITY_PROJECT_ROOT; prompts target TestProjects; server: accept relative UNITY_PROJECT_ROOT and bare spec URI * ci: ignore Unity test project's packages-lock.json; remove from repo to avoid absolute paths * CI: start persistent Unity Editor for MCP (guarded by license) + allow batch-mode bridge via UNITY_MCP_ALLOW_BATCH * CI: hide license and pass via env to docker; fix invalid ref format * CI: readiness probe uses handshake on Unity MCP port (deterministic) * CI: fix YAML; use TCP handshake readiness probe (FRAMING=1) * CI: prime Unity license via game-ci; mount ULF into container; extend readiness timeout * CI: use ULF write + mount for Unity licensing; remove serial/email/pass from container * CI: entitlement activation (UNITY_SERIAL=''); verify host ULF cache; keep mount * CI: write ULF from secret and verify; drop entitlement activation step * CI: detect any licensing path; GameCI prime; status dir env; log+probe readiness; fix YAML * CI: add GameCI license prime; conditional ULF write; one-shot license validation; explicit status dir + license env * CI: fix YAML (inline python), add Anthropic key detect via GITHUB_ENV; ready to run happy path * CI: mount Unity token/ulf/cache dirs into container to share host license; create dirs before start * CI: fix YAML indentation; write ULF on host; activate in container with shared mounts; mount .config and .cache too * CI: gate Claude via outputs; mount all Unity license dirs; fix inline probe python; stabilize licensing flow * CI: normalize detect to step outputs; ensure license dirs mounted and validated; fix indentation * Bridge: honor UNITY_MCP_STATUS_DIR for heartbeat/status file (CI-friendly) * CI: guard project path for activation/start; align tool allowlist; run MCP server with python; tighten secret scoping * CI: finalize Unity licensing mounts + status dir; mode-detect (ULF/EBL); readiness logs+probe; Claude gating via outputs * CI: fix YAML probe (inline python -c) and finalize happy-path Unity licensing and MCP/Claude wiring * CI: inline python probe; unify Unity image and cache mounts; ready to test * CI: fix docker run IMAGE placement; ignore cache find perms; keep same editor image * CI: pass -manualLicenseFile to persistent Editor; keep mounts and single image * CI: mount full GameCI cache to /root in persistent Unity; set HOME=/root; add optional license check * CI: make -manualLicenseFile conditional; keep full /root mount and license check * CI: set HOME=/github/home; mount GameCI cache there; adjust manualLicenseFile path; expand license check * CI: EBL sign-in for persistent Unity (email/password/serial); revert HOME=/root and full /root mount; keep conditional manualLicenseFile and improved readiness * CI: run full NL/T suite prompt (nl-unity-suite-full.md) instead of mini * NL/T: require unified diffs + explicit verdicts in JUnit; CI: remove short sanity step, publish JUnit, upload artifacts * NL/T prompt: require CDATA wrapping for JUnit XML fields; guidance for splitting embedded ]]>; keep VERDICT in CDATA only * CI: remove in-container license check step; keep readiness and full suite * NL/T prompt: add version header, stricter JUnit schema, hashing/normalization, anchors, statuses, atomic semantics, tool logging * CI: increase Claude NL/T suite timeout to 30 minutes * CI: pre-create reports dir and result files to avoid tool approval prompts * CI: skip wait if container not running; skip Editor start if project missing; broaden MCP deps detection; expand allowed tools * fixies to harden ManageScript * CI: sanitize NL/T markdown report to avoid NUL/encoding issues * revert breaking yyaml changes * CI: prime license, robust Unity start/wait, sanitize markdown via heredoc * Resolve merge: accept upstream renames/installer (fix/installer-cleanup-v2) and keep local framing/script-editing - Restored upstream server.py, EditorWindow, uv.lock\n- Preserved ManageScript editing/validation; switched to atomic write + debounced refresh\n- Updated tools/__init__.py to keep script_edits/resources and adopt new logger name\n- All Python tests via uv: 7 passed, 6 skipped, 9 xpassed; Unity compile OK * Fix Claude Desktop config path and atomic write issues - Fix macOS path for Claude Desktop config: use ~/Library/Application Support/Claude/ instead of ~/.config/Claude/ - Improve atomic write pattern with backup/restore safety - Replace File.Replace() with File.Move() for better macOS compatibility - Add proper error handling and cleanup for file operations - Resolves issue where installer couldn't find Claude Desktop config on macOS * Editor: use macConfigPath on macOS for MCP client config writes (Claude Desktop, etc.). Fallback to linuxConfigPath only if mac path missing. * Models: add macConfigPath to McpClient for macOS config path selection (fixes CS1061 in editor window). * Editor: on macOS, prefer macConfigPath in ManualConfigEditorWindow (fallback to linux path); Linux/Windows unchanged. * Fix McpClient: align with upstream/main, prep for framing split * NL suite: shard workflow; tighten bridge readiness; add MCP preflight; use env-based shard vars * NL suite: fix shard step indentation; move shard vars to env; remove invalid inputs * MCP clients: split VSCode Copilot config paths into macConfigPath and linuxConfigPath * Unity bridge: clean stale status; bind host; robust wait probe with IPv4/IPv6 + diagnostics * CI: use MCPForUnity.Editor.MCPForUnityBridge.StartAutoConnect as executeMethod * Action wiring: inline mcpServers in settings for all shards; remove redundant .claude/mcp.json step * CI: embed mcpServers in settings for all shards; fix startup sanity step; lint clean * CI: pin claude-code-base-action to e6f32c8; use claude_args --mcp-config; switch to allowed_tools; ensure MCP config per step * CI: unpin claude-code-base-action to @beta (commit ref not found) * CI: align with claude-code-base-action @beta; pass MCP via claude_args and allowedTools * Editor: Fix apply_text_edits heuristic when edits shift positions; recompute method span on candidate text with fallback delta adjustment * CI: unify MCP wiring across workflows; write .claude/mcp.json; switch to claude_args with --mcp-config/--allowedTools; remove unsupported inputs * CI: collapse NL suite shards into a single run to avoid repeated test execution * CI: minimize allowedTools for NL suite to essential Unity MCP + Bash("git:*") + Write * CI: mkdir -p reports before run; remove unsupported --timeout-minutes from claude_args * CI: broaden allowedTools to include find_in_file and mcp__unity__* * CI: enable use_node_cache and switch NL suite model to claude-3-7-haiku-20250219 * CI: disable use_node_cache to avoid setup-node lockfile error * CI: set NL suite model to claude-3-haiku-20240307 * CI: cap Haiku output with --max-tokens 2048 for NL suite * CI: switch to claude-3-7-sonnet-latest and remove unsupported --max-tokens * CI: update allowedTools to Bash(*) and explicit Unity MCP tool list * CI: update NL suite workflow (latest tweaks) * Tests: tighten NL suite prompt for logging, hash discipline, stale retry, evidence windows, diff cap, and VERDICT line * Add disallowed tools to NL suite workflow * docs: clarify stale write retry * Add fallback JUnit report and adjust publisher * Indent fallback JUnit XML in workflow * fix: correct fallback JUnit report generation * Update mcp-quickprobe.md Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> * Update mcp-quickprobe.md Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> * Update Response.cs Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> * Update MCPForUnityBridge.cs Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> * fix: correct McpTypes reference * Add directory existence checks for symlink and XDG paths * fix: only set installation flag after successful server install * Update resource_tools.py Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> * fix: respect mac config paths * Use File.Replace for atomic config write * Remove unused imports in manage_script * bump server version * Tests: update NL suite prompt and workflows; remove deprecated smoke/desktop-parity; quickprobe tidy * Editor: atomic config write via File.Replace fallback; remove redundant backups and racey exists checks * CI: harden NL suite - idempotent docker, gate on unity_ok, safer port probe, least-priv perms * Editor: make atomic config write restoration safe (flag writeDone; copy-overwrite restore; cleanup in finally) * CI: fix fallback JUnit heredoc by using printf lines (no EOF delimiter issues) * CI: switch NL suite to mini prompt; mini prompt honors / and NL discipline * CI: replace claude_args with allowed_tools/model/mcp_config per action schema * CI: expand UNITY_PROJECT_ROOT via in MCP config heredoc * EditorWindow: add cross-platform fallback for File.Replace; macOS-insensitive PathsEqual; safer uv resolve; honor macConfigPath * CI: strengthen JUnit publishing for NL mini suite (normalize, debug list, publish both, fail_on_parse_error) * CI: set job-wide JUNIT_OUT/MD_OUT; normalization uses env; publish references env and ungroup reports * CI: publish a single normalized JUnit (reports/junit-for-actions.xml); fallback writes same; avoid checkName/reportPaths mismatch * CI: align mini prompt report filenames; redact Unity log tail in diagnostics * chore: sync workflow and mini prompt; redacted logs; JUnit normalization/publish tweaks * CI: redact sensitive tokens in Stop Unity; docs: CI usage + edit tools * prompts: update nl-unity-suite-full (mini-style setup + reporting discipline); remove obsolete prompts * CI: harden NL workflows (timeout_minutes, robust normalization); prompts: unify JUnit suite name and reporting discipline * prompts: add guarded write pattern (LF hash, stale_file retry) to full suite * prompts: enforce continue-on-failure, driver flow, and status handling in full suite * Make test list more explicit in prompt. Get rid of old test prompts for hygeine. * prompts: add stale fast-retry (server hash) + in-memory buf guidance * CI: standardize JUNIT_OUT to reports/junit-nl-suite.xml; fix artifact upload indentation; prompt copy cleanups * prompts: reporting discipline — append-only fragments, batch writes, no model round-trip * prompts: stale fast-retry preference, buffer/sha carry, snapshot revert, essential logging * workflows(nl-suite): precreate report skeletons, assemble junit, synthesize markdown; restrict allowed_tools to append-only Bash + MCP tools * thsis too * Update README-DEV.md Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update .github/workflows/claude-nl-suite-mini.yml Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update .github/workflows/claude-nl-suite.yml Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * workflows(nl-mini): fix YAML indentation/trailing spaces under with: and cleanup heredoc spacing * workflows(nl-suite): fix indentation on docker logs redaction line (YAML lint) * Add write to allowlist * nl-suite: harden reporting discipline (fragment-only writes, forbid alt paths); workflow: clean stray junit-*updated*.xml * nl-suite: enforce end-of-suite single Write (no bash redirection); workflow: restrict allowed_tools to Write+MCP only * prompts(nl-full): end-of-suite results must be valid XML with single <cases> root and only <testcase> children; no raw text outside CDATA * workflows(nl-suite): make Claude step non-fatal; tolerant normalizer extracts <testcase> via regex on bad fragments * nl-suite: fix stale classname to UnityMCP.NL-T in mini fallback; prompt: require re-read after every revert; correct PLAN/PROGRESS to 15 * nl-suite: fix fallback JUnit classname to UnityMCP.NL-T; prompt: forbid create_script and env/mkdir checks, enforce single baseline-byte revert flow and post-revert re-read; add corruption-handling guidance * prompts(nl-full): after each write re-read raw bytes to refresh pre_sha; prefer script_apply_edits for anchors; avoid header/using changes * prompts(nl-full): canonicalize outputs to /; allow small fragment appends via Write or Bash(printf/echo); forbid wrappers and full-file round-trips * prompts(nl-full): finalize markdown formatting for guarded write, execution order, specs, status * workflows(nl-suite, mini): header/lint fixes and constrained Bash append path; align allowed_tools * prompts(nl-full): format Fast Restore, Guarded Write, Execution, Specs, Status as proper markdown lists and code fences * workflows(nl-suite): keep header tidy and append-path alignment with prompt * minor fix * workflows(nl-suite): fix indentation and dispatch; align allowed_tools and revert helper * prompts(nl-full): switch to read_resource for buf/sha; re-read only when needed; convert 'Print this once' to heading; note snapshot helper creates parent dirs * workflows(nl-suite): normalize step removes bootstrap when real testcases present; recompute tests/failures * workflows(nl-suite): enrich Markdown summary by extracting per-test <system-out> blocks (truncated) * clarify prompt resilience instructions * ci(nl-suite): revert prompt and workflow to known-good e0f8a72 for green run; remove extra MD details * ci(nl-suite): minimal fixes — no-mkdir guard in prompt; drop bootstrap and recompute JUnit counts * ci(nl-suite): richer JUnit→Markdown report (per-test system-out) * Small guard to incorret asset read call. * ci(nl-suite): refine MD builder — unescape XML entities, safe code fences, PASS/FAIL badges * Update UnityMcpBridge/UnityMcpServer~/src/tools/resource_tools.py Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update UnityMcpBridge/UnityMcpServer~/src/unity_connection.py Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update UnityMcpBridge/UnityMcpServer~/src/tools/manage_script_edits.py Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update .github/scripts/mark_skipped.py Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update .github/scripts/mark_skipped.py Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update .github/scripts/mark_skipped.py Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> * server(manage_script): robust URI handling — percent-decode file://, normalize, strip host/leading slashes, return Assets-relative if present * Update .claude/prompts/nl-unity-suite-full.md Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> * tests(framing): reduce handshake poll window, nonblocking peek to avoid disconnect race; still enforce pre-handshake data drop * tests(manage_script): add _split_uri tests for unity://path, file:// URLs (decoded/Assets-relative), and plain paths * server+tests: fix handshake syntax error; robust file:// URI normalization in manage_script; add _split_uri tests; adjust stdout scan to ignore venv/site-packages * bridge(framing): accept zero-length frames (treat as empty keepalive) * tests(logging): use errors='replace' on decode fallback to avoid silent drops * resources(list): restrict to Assets/, resolve symlinks, enforce .cs; add traversal/outside-path tests * Update .claude/prompts/nl-unity-suite-full.md Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update UnityMcpBridge/UnityMcpServer~/src/unity_connection.py Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * misc: framing keepalive (zero-length), regex preview consistency, resource.list hardening, URI parsing, legacy update routing, test cleanups * docs(tools): richer MCP tool descriptions; tests accept decorator kwargs; resource URI parsing hardened * Update .claude/prompts/nl-unity-suite-full.md Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update UnityMcpBridge/UnityMcpServer~/src/tools/resource_tools.py Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update UnityMcpBridge/UnityMcpServer~/src/unity_connection.py Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * net+docs: hard-reject zero-length frames; TCP_NODELAY on connect; Assets detection case-insensitive; NL prompt statuses aligned * prompt(nl-suite): constrain Write destinations under reports/, forbid traversal * prompt+net: harden Write path rules; use monotonic deadline and plain-text advisory for non-framed peers * unity_connection: restore recv timeout via try/finally; make global connection getter thread-safe with module lock and double-checked init * NL/T prompt: pin structured edit ops for T-D/T-E; add schema-error guarded write behavior; keep existing path/URI and revert rules * unity_connection: add FRAMED_MAX; use ValueError for framed length violations; lower framed receive log to debug; serialize connect() with per-instance lock * ManageScript: use UTF8Encoding(without BOM) for atomic writes in ApplyTextEdits/EditScript to align with Create/Update and avoid BOM-related diffs/hash mismatches * NL/T prompt: make helper deletion regex multiline-safe ((?ms) so ^ anchors line starts) * ManageScript: emit structured overlap status {status:"overlap"} for overlapping edit ranges in apply_text_edits and edit paths * NL/T prompt: clarify fallback vs failure — fallback only for unsupported/missing_field; treat bad_request as failure; note unsupported after fallback as failure * NL/T prompt: pin deterministic overlap probe (apply_text_edits two ranges from same snapshot); gate too_large behind RUN_TOO_LARGE env hint * TB update * NL/T prompt: harden Output Rules — constrain Bash(printf|echo) to stdout-only; forbid redirection/here-docs/tee; only scripts/nlt-revert.sh may mutate FS * Prompt: enumerate allowed script_apply_edits ops; add manage_editor/read_console guidance; fix T‑F atomic batch to single script_apply_edits. ManageScript: regex timeout for diagnostics; symlink ancestor guard; complete allowed-modes list. * Fixes * ManageScript: add rich overlap diagnostics (conflicts + hint) for both text range and structured batch paths * ManageScript: return structured {status:"validation_failed"} diagnostics in create/update/edits and validate before commit * ManageScript: echo canonical uri in responses (create/read/update/apply_text_edits/structured edits) to reinforce resource identity * improve clarity of capabilities message * Framing: allow zero-length frames on both ends (C# bridge, Python server). Prompt: harden T-F to single text-range apply_text_edits batch (descending order, one snapshot). URI: normalize file:// outside Assets by stripping leading slash. * ManageScript: include new sha256 in success payload for apply_text_edits; harden TryResolveUnderAssets by rejecting symlinked ancestors up to Assets/. * remove claudetest dir * manage_script_edits: normalize method-anchored anchor_insert to insert_method (map text->replacement); improves CI compatibility for T‑A/T‑E without changing Editor behavior. * tighten testing protocol around mkdir * manage_script: validate create_script inputs (Assets/.cs/name/no traversal); add Assets/ guard to delete_script; validate level+Assets in validate_script; make legacy manage_script optional params; harden legacy update routing with base64 reuse and payload size preflight. * Tighten prompt for testing * Update .claude/prompts/nl-unity-suite-full.md Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update .claude/prompts/nl-unity-suite-full.md Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update UnityMcpBridge/Editor/Tools/ManageScript.cs Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * manage_script_edits: honor ignore_case on anchor_insert and regex_replace in both direct and text-conversion paths (MULTILINE|IGNORECASE). * remove extra file * workflow: use python3 for inline scripts and port detection on ubuntu-latest. * Tighten prompt + manage_script * Update UnityMcpBridge/UnityMcpServer~/src/tools/manage_script_edits.py Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update UnityMcpBridge/UnityMcpServer~/src/tools/manage_script_edits.py Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update .claude/prompts/nl-unity-suite-full.md Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update UnityMcpBridge/Editor/Tools/ManageScript.cs Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update .claude/prompts/nl-unity-suite-full.md Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * manage_script: improve file:// UNC handling; preserve POSIX absolute semantics internally; keep test-expected slash stripping for non-Assets paths. * ManageScript.cs: add TimeSpan timeouts to all Regex uses (IsMatch/Match/new Regex) and keep CultureInvariant/Multiline options; reduces risk of catastrophic backtracking stalls. * workflow: ensure reports/ exists in markdown build step to avoid FileNotFoundError when writing MD_OUT. * fix brace * manage_script_edits: expand backrefs for regex_replace in preview->text conversion and translate to \g<n> in local apply; keeps previews and actual edits consistent. * anchor_insert: default to position=after, normalize surrounding newlines in Python conversion paths; C# path ensures trailing newline and skips duplicate insertion within class. * feat(mcp): add get_sha tool; apply_text_edits normalization+overlap preflight+strict; no-op evidence in C#; update NL suite prompt; add unit tests * feat(frames): accept zero-length heartbeat frames in client; add heartbeat test * feat(edits): guard destructive regex_replace with structural preflight; add robust tests; prompt uses delete_method for temp helper * feat(frames): bound heartbeat loop with timeout/threshold; align zero-length response with C#; update test * SDK hardening: atomic multi-span text edits; stop forcing sequential for structured ops; forward options on apply_text_edits; add validate=relaxed support and scoped checks; update NL/T prompt; add tests for options forwarding, relaxed mode, and atomic batches * Router: default applyMode=atomic for multi-span apply_text_edits; add tests * CI prompt: pass options.validate=relaxed for T-B/C; options.applyMode=atomic for T-F; emphasize always writing testcase and restoring on errors * Validation & DX: add validate=syntax (scoped), standardize evidence windows; early regex compile with hints; debug_preview for apply_text_edits * Update UnityMcpBridge/Editor/Windows/MCPForUnityEditorWindow.cs Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * NL/T suite-driven edits: LongUnityScriptClaudeTest, bridge helpers, server_version; prepare framing tests * Fix duplicate macConfigPath field in McpClient to resolve CS0102 * Editor threading: run EnsureServerInstalled on main thread; marshal EditorPrefs/DeleteKey + logging via delayCall * Docs(apply_text_edits): strengthen guidance on 1-based positions, verify-before-edit, and recommend anchors/structured edits * Docs(script_apply_edits): add safety guidance (anchors, method ops, validators) and recommended practices * Framed VerifyBridgePing in editor window; docs hardening for apply_text_edits and script_apply_edits --------- Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
2025-08-31 00:55:38 +08:00
Debug.LogWarning("manage_script.read is deprecated; prefer resources/read. Serving read for backward compatibility.");
2025-03-31 03:58:01 +08:00
return ReadScript(fullPath, relativePath);
case "update":
Claude‑friendly edit tools + framed transport + live Unity NL test framework (#243) * CI: gate desktop-parity on Anthropic key; pass anthropic_api_key like NL suite * Add quickprobe prompt and CI workflow (mcp-quickprobe.md, unity-mcp-quickprobe.yml) * strictier tool use to prevent subagent spawning and force mcp tools * update workflow filesto reduce likelihood of subagent spawning * improve permissions for claude agent, fix mcpbridge timeout/token issue * increase max turns to 10 * ci: align NL suite to new permissions schema; prevent subagent drift * ci: NL suite -> mini prompt for e2e; add full NL/T prompt; server: ctx optional + project_root fallback; workflows: set UNITY_PROJECT_ROOT for CI * ci: add checks:write; revert local project hardcodes (manifest, ProjectVersion.txt) * tools: text-edit routing fixes (anchor_insert via text, CRLF calc); prompts: mini NL/T clarifications * ci: use absolute UNITY_PROJECT_ROOT; prompts target TestProjects; server: accept relative UNITY_PROJECT_ROOT and bare spec URI * ci: ignore Unity test project's packages-lock.json; remove from repo to avoid absolute paths * CI: start persistent Unity Editor for MCP (guarded by license) + allow batch-mode bridge via UNITY_MCP_ALLOW_BATCH * CI: hide license and pass via env to docker; fix invalid ref format * CI: readiness probe uses handshake on Unity MCP port (deterministic) * CI: fix YAML; use TCP handshake readiness probe (FRAMING=1) * CI: prime Unity license via game-ci; mount ULF into container; extend readiness timeout * CI: use ULF write + mount for Unity licensing; remove serial/email/pass from container * CI: entitlement activation (UNITY_SERIAL=''); verify host ULF cache; keep mount * CI: write ULF from secret and verify; drop entitlement activation step * CI: detect any licensing path; GameCI prime; status dir env; log+probe readiness; fix YAML * CI: add GameCI license prime; conditional ULF write; one-shot license validation; explicit status dir + license env * CI: fix YAML (inline python), add Anthropic key detect via GITHUB_ENV; ready to run happy path * CI: mount Unity token/ulf/cache dirs into container to share host license; create dirs before start * CI: fix YAML indentation; write ULF on host; activate in container with shared mounts; mount .config and .cache too * CI: gate Claude via outputs; mount all Unity license dirs; fix inline probe python; stabilize licensing flow * CI: normalize detect to step outputs; ensure license dirs mounted and validated; fix indentation * Bridge: honor UNITY_MCP_STATUS_DIR for heartbeat/status file (CI-friendly) * CI: guard project path for activation/start; align tool allowlist; run MCP server with python; tighten secret scoping * CI: finalize Unity licensing mounts + status dir; mode-detect (ULF/EBL); readiness logs+probe; Claude gating via outputs * CI: fix YAML probe (inline python -c) and finalize happy-path Unity licensing and MCP/Claude wiring * CI: inline python probe; unify Unity image and cache mounts; ready to test * CI: fix docker run IMAGE placement; ignore cache find perms; keep same editor image * CI: pass -manualLicenseFile to persistent Editor; keep mounts and single image * CI: mount full GameCI cache to /root in persistent Unity; set HOME=/root; add optional license check * CI: make -manualLicenseFile conditional; keep full /root mount and license check * CI: set HOME=/github/home; mount GameCI cache there; adjust manualLicenseFile path; expand license check * CI: EBL sign-in for persistent Unity (email/password/serial); revert HOME=/root and full /root mount; keep conditional manualLicenseFile and improved readiness * CI: run full NL/T suite prompt (nl-unity-suite-full.md) instead of mini * NL/T: require unified diffs + explicit verdicts in JUnit; CI: remove short sanity step, publish JUnit, upload artifacts * NL/T prompt: require CDATA wrapping for JUnit XML fields; guidance for splitting embedded ]]>; keep VERDICT in CDATA only * CI: remove in-container license check step; keep readiness and full suite * NL/T prompt: add version header, stricter JUnit schema, hashing/normalization, anchors, statuses, atomic semantics, tool logging * CI: increase Claude NL/T suite timeout to 30 minutes * CI: pre-create reports dir and result files to avoid tool approval prompts * CI: skip wait if container not running; skip Editor start if project missing; broaden MCP deps detection; expand allowed tools * fixies to harden ManageScript * CI: sanitize NL/T markdown report to avoid NUL/encoding issues * revert breaking yyaml changes * CI: prime license, robust Unity start/wait, sanitize markdown via heredoc * Resolve merge: accept upstream renames/installer (fix/installer-cleanup-v2) and keep local framing/script-editing - Restored upstream server.py, EditorWindow, uv.lock\n- Preserved ManageScript editing/validation; switched to atomic write + debounced refresh\n- Updated tools/__init__.py to keep script_edits/resources and adopt new logger name\n- All Python tests via uv: 7 passed, 6 skipped, 9 xpassed; Unity compile OK * Fix Claude Desktop config path and atomic write issues - Fix macOS path for Claude Desktop config: use ~/Library/Application Support/Claude/ instead of ~/.config/Claude/ - Improve atomic write pattern with backup/restore safety - Replace File.Replace() with File.Move() for better macOS compatibility - Add proper error handling and cleanup for file operations - Resolves issue where installer couldn't find Claude Desktop config on macOS * Editor: use macConfigPath on macOS for MCP client config writes (Claude Desktop, etc.). Fallback to linuxConfigPath only if mac path missing. * Models: add macConfigPath to McpClient for macOS config path selection (fixes CS1061 in editor window). * Editor: on macOS, prefer macConfigPath in ManualConfigEditorWindow (fallback to linux path); Linux/Windows unchanged. * Fix McpClient: align with upstream/main, prep for framing split * NL suite: shard workflow; tighten bridge readiness; add MCP preflight; use env-based shard vars * NL suite: fix shard step indentation; move shard vars to env; remove invalid inputs * MCP clients: split VSCode Copilot config paths into macConfigPath and linuxConfigPath * Unity bridge: clean stale status; bind host; robust wait probe with IPv4/IPv6 + diagnostics * CI: use MCPForUnity.Editor.MCPForUnityBridge.StartAutoConnect as executeMethod * Action wiring: inline mcpServers in settings for all shards; remove redundant .claude/mcp.json step * CI: embed mcpServers in settings for all shards; fix startup sanity step; lint clean * CI: pin claude-code-base-action to e6f32c8; use claude_args --mcp-config; switch to allowed_tools; ensure MCP config per step * CI: unpin claude-code-base-action to @beta (commit ref not found) * CI: align with claude-code-base-action @beta; pass MCP via claude_args and allowedTools * Editor: Fix apply_text_edits heuristic when edits shift positions; recompute method span on candidate text with fallback delta adjustment * CI: unify MCP wiring across workflows; write .claude/mcp.json; switch to claude_args with --mcp-config/--allowedTools; remove unsupported inputs * CI: collapse NL suite shards into a single run to avoid repeated test execution * CI: minimize allowedTools for NL suite to essential Unity MCP + Bash("git:*") + Write * CI: mkdir -p reports before run; remove unsupported --timeout-minutes from claude_args * CI: broaden allowedTools to include find_in_file and mcp__unity__* * CI: enable use_node_cache and switch NL suite model to claude-3-7-haiku-20250219 * CI: disable use_node_cache to avoid setup-node lockfile error * CI: set NL suite model to claude-3-haiku-20240307 * CI: cap Haiku output with --max-tokens 2048 for NL suite * CI: switch to claude-3-7-sonnet-latest and remove unsupported --max-tokens * CI: update allowedTools to Bash(*) and explicit Unity MCP tool list * CI: update NL suite workflow (latest tweaks) * Tests: tighten NL suite prompt for logging, hash discipline, stale retry, evidence windows, diff cap, and VERDICT line * Add disallowed tools to NL suite workflow * docs: clarify stale write retry * Add fallback JUnit report and adjust publisher * Indent fallback JUnit XML in workflow * fix: correct fallback JUnit report generation * Update mcp-quickprobe.md Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> * Update mcp-quickprobe.md Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> * Update Response.cs Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> * Update MCPForUnityBridge.cs Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> * fix: correct McpTypes reference * Add directory existence checks for symlink and XDG paths * fix: only set installation flag after successful server install * Update resource_tools.py Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> * fix: respect mac config paths * Use File.Replace for atomic config write * Remove unused imports in manage_script * bump server version * Tests: update NL suite prompt and workflows; remove deprecated smoke/desktop-parity; quickprobe tidy * Editor: atomic config write via File.Replace fallback; remove redundant backups and racey exists checks * CI: harden NL suite - idempotent docker, gate on unity_ok, safer port probe, least-priv perms * Editor: make atomic config write restoration safe (flag writeDone; copy-overwrite restore; cleanup in finally) * CI: fix fallback JUnit heredoc by using printf lines (no EOF delimiter issues) * CI: switch NL suite to mini prompt; mini prompt honors / and NL discipline * CI: replace claude_args with allowed_tools/model/mcp_config per action schema * CI: expand UNITY_PROJECT_ROOT via in MCP config heredoc * EditorWindow: add cross-platform fallback for File.Replace; macOS-insensitive PathsEqual; safer uv resolve; honor macConfigPath * CI: strengthen JUnit publishing for NL mini suite (normalize, debug list, publish both, fail_on_parse_error) * CI: set job-wide JUNIT_OUT/MD_OUT; normalization uses env; publish references env and ungroup reports * CI: publish a single normalized JUnit (reports/junit-for-actions.xml); fallback writes same; avoid checkName/reportPaths mismatch * CI: align mini prompt report filenames; redact Unity log tail in diagnostics * chore: sync workflow and mini prompt; redacted logs; JUnit normalization/publish tweaks * CI: redact sensitive tokens in Stop Unity; docs: CI usage + edit tools * prompts: update nl-unity-suite-full (mini-style setup + reporting discipline); remove obsolete prompts * CI: harden NL workflows (timeout_minutes, robust normalization); prompts: unify JUnit suite name and reporting discipline * prompts: add guarded write pattern (LF hash, stale_file retry) to full suite * prompts: enforce continue-on-failure, driver flow, and status handling in full suite * Make test list more explicit in prompt. Get rid of old test prompts for hygeine. * prompts: add stale fast-retry (server hash) + in-memory buf guidance * CI: standardize JUNIT_OUT to reports/junit-nl-suite.xml; fix artifact upload indentation; prompt copy cleanups * prompts: reporting discipline — append-only fragments, batch writes, no model round-trip * prompts: stale fast-retry preference, buffer/sha carry, snapshot revert, essential logging * workflows(nl-suite): precreate report skeletons, assemble junit, synthesize markdown; restrict allowed_tools to append-only Bash + MCP tools * thsis too * Update README-DEV.md Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update .github/workflows/claude-nl-suite-mini.yml Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update .github/workflows/claude-nl-suite.yml Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * workflows(nl-mini): fix YAML indentation/trailing spaces under with: and cleanup heredoc spacing * workflows(nl-suite): fix indentation on docker logs redaction line (YAML lint) * Add write to allowlist * nl-suite: harden reporting discipline (fragment-only writes, forbid alt paths); workflow: clean stray junit-*updated*.xml * nl-suite: enforce end-of-suite single Write (no bash redirection); workflow: restrict allowed_tools to Write+MCP only * prompts(nl-full): end-of-suite results must be valid XML with single <cases> root and only <testcase> children; no raw text outside CDATA * workflows(nl-suite): make Claude step non-fatal; tolerant normalizer extracts <testcase> via regex on bad fragments * nl-suite: fix stale classname to UnityMCP.NL-T in mini fallback; prompt: require re-read after every revert; correct PLAN/PROGRESS to 15 * nl-suite: fix fallback JUnit classname to UnityMCP.NL-T; prompt: forbid create_script and env/mkdir checks, enforce single baseline-byte revert flow and post-revert re-read; add corruption-handling guidance * prompts(nl-full): after each write re-read raw bytes to refresh pre_sha; prefer script_apply_edits for anchors; avoid header/using changes * prompts(nl-full): canonicalize outputs to /; allow small fragment appends via Write or Bash(printf/echo); forbid wrappers and full-file round-trips * prompts(nl-full): finalize markdown formatting for guarded write, execution order, specs, status * workflows(nl-suite, mini): header/lint fixes and constrained Bash append path; align allowed_tools * prompts(nl-full): format Fast Restore, Guarded Write, Execution, Specs, Status as proper markdown lists and code fences * workflows(nl-suite): keep header tidy and append-path alignment with prompt * minor fix * workflows(nl-suite): fix indentation and dispatch; align allowed_tools and revert helper * prompts(nl-full): switch to read_resource for buf/sha; re-read only when needed; convert 'Print this once' to heading; note snapshot helper creates parent dirs * workflows(nl-suite): normalize step removes bootstrap when real testcases present; recompute tests/failures * workflows(nl-suite): enrich Markdown summary by extracting per-test <system-out> blocks (truncated) * clarify prompt resilience instructions * ci(nl-suite): revert prompt and workflow to known-good e0f8a72 for green run; remove extra MD details * ci(nl-suite): minimal fixes — no-mkdir guard in prompt; drop bootstrap and recompute JUnit counts * ci(nl-suite): richer JUnit→Markdown report (per-test system-out) * Small guard to incorret asset read call. * ci(nl-suite): refine MD builder — unescape XML entities, safe code fences, PASS/FAIL badges * Update UnityMcpBridge/UnityMcpServer~/src/tools/resource_tools.py Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update UnityMcpBridge/UnityMcpServer~/src/unity_connection.py Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update UnityMcpBridge/UnityMcpServer~/src/tools/manage_script_edits.py Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update .github/scripts/mark_skipped.py Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update .github/scripts/mark_skipped.py Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update .github/scripts/mark_skipped.py Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> * server(manage_script): robust URI handling — percent-decode file://, normalize, strip host/leading slashes, return Assets-relative if present * Update .claude/prompts/nl-unity-suite-full.md Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> * tests(framing): reduce handshake poll window, nonblocking peek to avoid disconnect race; still enforce pre-handshake data drop * tests(manage_script): add _split_uri tests for unity://path, file:// URLs (decoded/Assets-relative), and plain paths * server+tests: fix handshake syntax error; robust file:// URI normalization in manage_script; add _split_uri tests; adjust stdout scan to ignore venv/site-packages * bridge(framing): accept zero-length frames (treat as empty keepalive) * tests(logging): use errors='replace' on decode fallback to avoid silent drops * resources(list): restrict to Assets/, resolve symlinks, enforce .cs; add traversal/outside-path tests * Update .claude/prompts/nl-unity-suite-full.md Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update UnityMcpBridge/UnityMcpServer~/src/unity_connection.py Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * misc: framing keepalive (zero-length), regex preview consistency, resource.list hardening, URI parsing, legacy update routing, test cleanups * docs(tools): richer MCP tool descriptions; tests accept decorator kwargs; resource URI parsing hardened * Update .claude/prompts/nl-unity-suite-full.md Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update UnityMcpBridge/UnityMcpServer~/src/tools/resource_tools.py Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update UnityMcpBridge/UnityMcpServer~/src/unity_connection.py Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * net+docs: hard-reject zero-length frames; TCP_NODELAY on connect; Assets detection case-insensitive; NL prompt statuses aligned * prompt(nl-suite): constrain Write destinations under reports/, forbid traversal * prompt+net: harden Write path rules; use monotonic deadline and plain-text advisory for non-framed peers * unity_connection: restore recv timeout via try/finally; make global connection getter thread-safe with module lock and double-checked init * NL/T prompt: pin structured edit ops for T-D/T-E; add schema-error guarded write behavior; keep existing path/URI and revert rules * unity_connection: add FRAMED_MAX; use ValueError for framed length violations; lower framed receive log to debug; serialize connect() with per-instance lock * ManageScript: use UTF8Encoding(without BOM) for atomic writes in ApplyTextEdits/EditScript to align with Create/Update and avoid BOM-related diffs/hash mismatches * NL/T prompt: make helper deletion regex multiline-safe ((?ms) so ^ anchors line starts) * ManageScript: emit structured overlap status {status:"overlap"} for overlapping edit ranges in apply_text_edits and edit paths * NL/T prompt: clarify fallback vs failure — fallback only for unsupported/missing_field; treat bad_request as failure; note unsupported after fallback as failure * NL/T prompt: pin deterministic overlap probe (apply_text_edits two ranges from same snapshot); gate too_large behind RUN_TOO_LARGE env hint * TB update * NL/T prompt: harden Output Rules — constrain Bash(printf|echo) to stdout-only; forbid redirection/here-docs/tee; only scripts/nlt-revert.sh may mutate FS * Prompt: enumerate allowed script_apply_edits ops; add manage_editor/read_console guidance; fix T‑F atomic batch to single script_apply_edits. ManageScript: regex timeout for diagnostics; symlink ancestor guard; complete allowed-modes list. * Fixes * ManageScript: add rich overlap diagnostics (conflicts + hint) for both text range and structured batch paths * ManageScript: return structured {status:"validation_failed"} diagnostics in create/update/edits and validate before commit * ManageScript: echo canonical uri in responses (create/read/update/apply_text_edits/structured edits) to reinforce resource identity * improve clarity of capabilities message * Framing: allow zero-length frames on both ends (C# bridge, Python server). Prompt: harden T-F to single text-range apply_text_edits batch (descending order, one snapshot). URI: normalize file:// outside Assets by stripping leading slash. * ManageScript: include new sha256 in success payload for apply_text_edits; harden TryResolveUnderAssets by rejecting symlinked ancestors up to Assets/. * remove claudetest dir * manage_script_edits: normalize method-anchored anchor_insert to insert_method (map text->replacement); improves CI compatibility for T‑A/T‑E without changing Editor behavior. * tighten testing protocol around mkdir * manage_script: validate create_script inputs (Assets/.cs/name/no traversal); add Assets/ guard to delete_script; validate level+Assets in validate_script; make legacy manage_script optional params; harden legacy update routing with base64 reuse and payload size preflight. * Tighten prompt for testing * Update .claude/prompts/nl-unity-suite-full.md Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update .claude/prompts/nl-unity-suite-full.md Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update UnityMcpBridge/Editor/Tools/ManageScript.cs Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * manage_script_edits: honor ignore_case on anchor_insert and regex_replace in both direct and text-conversion paths (MULTILINE|IGNORECASE). * remove extra file * workflow: use python3 for inline scripts and port detection on ubuntu-latest. * Tighten prompt + manage_script * Update UnityMcpBridge/UnityMcpServer~/src/tools/manage_script_edits.py Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update UnityMcpBridge/UnityMcpServer~/src/tools/manage_script_edits.py Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update .claude/prompts/nl-unity-suite-full.md Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update UnityMcpBridge/Editor/Tools/ManageScript.cs Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update .claude/prompts/nl-unity-suite-full.md Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * manage_script: improve file:// UNC handling; preserve POSIX absolute semantics internally; keep test-expected slash stripping for non-Assets paths. * ManageScript.cs: add TimeSpan timeouts to all Regex uses (IsMatch/Match/new Regex) and keep CultureInvariant/Multiline options; reduces risk of catastrophic backtracking stalls. * workflow: ensure reports/ exists in markdown build step to avoid FileNotFoundError when writing MD_OUT. * fix brace * manage_script_edits: expand backrefs for regex_replace in preview->text conversion and translate to \g<n> in local apply; keeps previews and actual edits consistent. * anchor_insert: default to position=after, normalize surrounding newlines in Python conversion paths; C# path ensures trailing newline and skips duplicate insertion within class. * feat(mcp): add get_sha tool; apply_text_edits normalization+overlap preflight+strict; no-op evidence in C#; update NL suite prompt; add unit tests * feat(frames): accept zero-length heartbeat frames in client; add heartbeat test * feat(edits): guard destructive regex_replace with structural preflight; add robust tests; prompt uses delete_method for temp helper * feat(frames): bound heartbeat loop with timeout/threshold; align zero-length response with C#; update test * SDK hardening: atomic multi-span text edits; stop forcing sequential for structured ops; forward options on apply_text_edits; add validate=relaxed support and scoped checks; update NL/T prompt; add tests for options forwarding, relaxed mode, and atomic batches * Router: default applyMode=atomic for multi-span apply_text_edits; add tests * CI prompt: pass options.validate=relaxed for T-B/C; options.applyMode=atomic for T-F; emphasize always writing testcase and restoring on errors * Validation & DX: add validate=syntax (scoped), standardize evidence windows; early regex compile with hints; debug_preview for apply_text_edits * Update UnityMcpBridge/Editor/Windows/MCPForUnityEditorWindow.cs Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * NL/T suite-driven edits: LongUnityScriptClaudeTest, bridge helpers, server_version; prepare framing tests * Fix duplicate macConfigPath field in McpClient to resolve CS0102 * Editor threading: run EnsureServerInstalled on main thread; marshal EditorPrefs/DeleteKey + logging via delayCall * Docs(apply_text_edits): strengthen guidance on 1-based positions, verify-before-edit, and recommend anchors/structured edits * Docs(script_apply_edits): add safety guidance (anchors, method ops, validators) and recommended practices * Framed VerifyBridgePing in editor window; docs hardening for apply_text_edits and script_apply_edits --------- Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
2025-08-31 00:55:38 +08:00
Debug.LogWarning("manage_script.update is deprecated; prefer apply_text_edits. Serving update for backward compatibility.");
2025-03-31 03:58:01 +08:00
return UpdateScript(fullPath, relativePath, name, contents);
case "delete":
return DeleteScript(fullPath, relativePath);
Claude‑friendly edit tools + framed transport + live Unity NL test framework (#243) * CI: gate desktop-parity on Anthropic key; pass anthropic_api_key like NL suite * Add quickprobe prompt and CI workflow (mcp-quickprobe.md, unity-mcp-quickprobe.yml) * strictier tool use to prevent subagent spawning and force mcp tools * update workflow filesto reduce likelihood of subagent spawning * improve permissions for claude agent, fix mcpbridge timeout/token issue * increase max turns to 10 * ci: align NL suite to new permissions schema; prevent subagent drift * ci: NL suite -> mini prompt for e2e; add full NL/T prompt; server: ctx optional + project_root fallback; workflows: set UNITY_PROJECT_ROOT for CI * ci: add checks:write; revert local project hardcodes (manifest, ProjectVersion.txt) * tools: text-edit routing fixes (anchor_insert via text, CRLF calc); prompts: mini NL/T clarifications * ci: use absolute UNITY_PROJECT_ROOT; prompts target TestProjects; server: accept relative UNITY_PROJECT_ROOT and bare spec URI * ci: ignore Unity test project's packages-lock.json; remove from repo to avoid absolute paths * CI: start persistent Unity Editor for MCP (guarded by license) + allow batch-mode bridge via UNITY_MCP_ALLOW_BATCH * CI: hide license and pass via env to docker; fix invalid ref format * CI: readiness probe uses handshake on Unity MCP port (deterministic) * CI: fix YAML; use TCP handshake readiness probe (FRAMING=1) * CI: prime Unity license via game-ci; mount ULF into container; extend readiness timeout * CI: use ULF write + mount for Unity licensing; remove serial/email/pass from container * CI: entitlement activation (UNITY_SERIAL=''); verify host ULF cache; keep mount * CI: write ULF from secret and verify; drop entitlement activation step * CI: detect any licensing path; GameCI prime; status dir env; log+probe readiness; fix YAML * CI: add GameCI license prime; conditional ULF write; one-shot license validation; explicit status dir + license env * CI: fix YAML (inline python), add Anthropic key detect via GITHUB_ENV; ready to run happy path * CI: mount Unity token/ulf/cache dirs into container to share host license; create dirs before start * CI: fix YAML indentation; write ULF on host; activate in container with shared mounts; mount .config and .cache too * CI: gate Claude via outputs; mount all Unity license dirs; fix inline probe python; stabilize licensing flow * CI: normalize detect to step outputs; ensure license dirs mounted and validated; fix indentation * Bridge: honor UNITY_MCP_STATUS_DIR for heartbeat/status file (CI-friendly) * CI: guard project path for activation/start; align tool allowlist; run MCP server with python; tighten secret scoping * CI: finalize Unity licensing mounts + status dir; mode-detect (ULF/EBL); readiness logs+probe; Claude gating via outputs * CI: fix YAML probe (inline python -c) and finalize happy-path Unity licensing and MCP/Claude wiring * CI: inline python probe; unify Unity image and cache mounts; ready to test * CI: fix docker run IMAGE placement; ignore cache find perms; keep same editor image * CI: pass -manualLicenseFile to persistent Editor; keep mounts and single image * CI: mount full GameCI cache to /root in persistent Unity; set HOME=/root; add optional license check * CI: make -manualLicenseFile conditional; keep full /root mount and license check * CI: set HOME=/github/home; mount GameCI cache there; adjust manualLicenseFile path; expand license check * CI: EBL sign-in for persistent Unity (email/password/serial); revert HOME=/root and full /root mount; keep conditional manualLicenseFile and improved readiness * CI: run full NL/T suite prompt (nl-unity-suite-full.md) instead of mini * NL/T: require unified diffs + explicit verdicts in JUnit; CI: remove short sanity step, publish JUnit, upload artifacts * NL/T prompt: require CDATA wrapping for JUnit XML fields; guidance for splitting embedded ]]>; keep VERDICT in CDATA only * CI: remove in-container license check step; keep readiness and full suite * NL/T prompt: add version header, stricter JUnit schema, hashing/normalization, anchors, statuses, atomic semantics, tool logging * CI: increase Claude NL/T suite timeout to 30 minutes * CI: pre-create reports dir and result files to avoid tool approval prompts * CI: skip wait if container not running; skip Editor start if project missing; broaden MCP deps detection; expand allowed tools * fixies to harden ManageScript * CI: sanitize NL/T markdown report to avoid NUL/encoding issues * revert breaking yyaml changes * CI: prime license, robust Unity start/wait, sanitize markdown via heredoc * Resolve merge: accept upstream renames/installer (fix/installer-cleanup-v2) and keep local framing/script-editing - Restored upstream server.py, EditorWindow, uv.lock\n- Preserved ManageScript editing/validation; switched to atomic write + debounced refresh\n- Updated tools/__init__.py to keep script_edits/resources and adopt new logger name\n- All Python tests via uv: 7 passed, 6 skipped, 9 xpassed; Unity compile OK * Fix Claude Desktop config path and atomic write issues - Fix macOS path for Claude Desktop config: use ~/Library/Application Support/Claude/ instead of ~/.config/Claude/ - Improve atomic write pattern with backup/restore safety - Replace File.Replace() with File.Move() for better macOS compatibility - Add proper error handling and cleanup for file operations - Resolves issue where installer couldn't find Claude Desktop config on macOS * Editor: use macConfigPath on macOS for MCP client config writes (Claude Desktop, etc.). Fallback to linuxConfigPath only if mac path missing. * Models: add macConfigPath to McpClient for macOS config path selection (fixes CS1061 in editor window). * Editor: on macOS, prefer macConfigPath in ManualConfigEditorWindow (fallback to linux path); Linux/Windows unchanged. * Fix McpClient: align with upstream/main, prep for framing split * NL suite: shard workflow; tighten bridge readiness; add MCP preflight; use env-based shard vars * NL suite: fix shard step indentation; move shard vars to env; remove invalid inputs * MCP clients: split VSCode Copilot config paths into macConfigPath and linuxConfigPath * Unity bridge: clean stale status; bind host; robust wait probe with IPv4/IPv6 + diagnostics * CI: use MCPForUnity.Editor.MCPForUnityBridge.StartAutoConnect as executeMethod * Action wiring: inline mcpServers in settings for all shards; remove redundant .claude/mcp.json step * CI: embed mcpServers in settings for all shards; fix startup sanity step; lint clean * CI: pin claude-code-base-action to e6f32c8; use claude_args --mcp-config; switch to allowed_tools; ensure MCP config per step * CI: unpin claude-code-base-action to @beta (commit ref not found) * CI: align with claude-code-base-action @beta; pass MCP via claude_args and allowedTools * Editor: Fix apply_text_edits heuristic when edits shift positions; recompute method span on candidate text with fallback delta adjustment * CI: unify MCP wiring across workflows; write .claude/mcp.json; switch to claude_args with --mcp-config/--allowedTools; remove unsupported inputs * CI: collapse NL suite shards into a single run to avoid repeated test execution * CI: minimize allowedTools for NL suite to essential Unity MCP + Bash("git:*") + Write * CI: mkdir -p reports before run; remove unsupported --timeout-minutes from claude_args * CI: broaden allowedTools to include find_in_file and mcp__unity__* * CI: enable use_node_cache and switch NL suite model to claude-3-7-haiku-20250219 * CI: disable use_node_cache to avoid setup-node lockfile error * CI: set NL suite model to claude-3-haiku-20240307 * CI: cap Haiku output with --max-tokens 2048 for NL suite * CI: switch to claude-3-7-sonnet-latest and remove unsupported --max-tokens * CI: update allowedTools to Bash(*) and explicit Unity MCP tool list * CI: update NL suite workflow (latest tweaks) * Tests: tighten NL suite prompt for logging, hash discipline, stale retry, evidence windows, diff cap, and VERDICT line * Add disallowed tools to NL suite workflow * docs: clarify stale write retry * Add fallback JUnit report and adjust publisher * Indent fallback JUnit XML in workflow * fix: correct fallback JUnit report generation * Update mcp-quickprobe.md Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> * Update mcp-quickprobe.md Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> * Update Response.cs Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> * Update MCPForUnityBridge.cs Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> * fix: correct McpTypes reference * Add directory existence checks for symlink and XDG paths * fix: only set installation flag after successful server install * Update resource_tools.py Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> * fix: respect mac config paths * Use File.Replace for atomic config write * Remove unused imports in manage_script * bump server version * Tests: update NL suite prompt and workflows; remove deprecated smoke/desktop-parity; quickprobe tidy * Editor: atomic config write via File.Replace fallback; remove redundant backups and racey exists checks * CI: harden NL suite - idempotent docker, gate on unity_ok, safer port probe, least-priv perms * Editor: make atomic config write restoration safe (flag writeDone; copy-overwrite restore; cleanup in finally) * CI: fix fallback JUnit heredoc by using printf lines (no EOF delimiter issues) * CI: switch NL suite to mini prompt; mini prompt honors / and NL discipline * CI: replace claude_args with allowed_tools/model/mcp_config per action schema * CI: expand UNITY_PROJECT_ROOT via in MCP config heredoc * EditorWindow: add cross-platform fallback for File.Replace; macOS-insensitive PathsEqual; safer uv resolve; honor macConfigPath * CI: strengthen JUnit publishing for NL mini suite (normalize, debug list, publish both, fail_on_parse_error) * CI: set job-wide JUNIT_OUT/MD_OUT; normalization uses env; publish references env and ungroup reports * CI: publish a single normalized JUnit (reports/junit-for-actions.xml); fallback writes same; avoid checkName/reportPaths mismatch * CI: align mini prompt report filenames; redact Unity log tail in diagnostics * chore: sync workflow and mini prompt; redacted logs; JUnit normalization/publish tweaks * CI: redact sensitive tokens in Stop Unity; docs: CI usage + edit tools * prompts: update nl-unity-suite-full (mini-style setup + reporting discipline); remove obsolete prompts * CI: harden NL workflows (timeout_minutes, robust normalization); prompts: unify JUnit suite name and reporting discipline * prompts: add guarded write pattern (LF hash, stale_file retry) to full suite * prompts: enforce continue-on-failure, driver flow, and status handling in full suite * Make test list more explicit in prompt. Get rid of old test prompts for hygeine. * prompts: add stale fast-retry (server hash) + in-memory buf guidance * CI: standardize JUNIT_OUT to reports/junit-nl-suite.xml; fix artifact upload indentation; prompt copy cleanups * prompts: reporting discipline — append-only fragments, batch writes, no model round-trip * prompts: stale fast-retry preference, buffer/sha carry, snapshot revert, essential logging * workflows(nl-suite): precreate report skeletons, assemble junit, synthesize markdown; restrict allowed_tools to append-only Bash + MCP tools * thsis too * Update README-DEV.md Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update .github/workflows/claude-nl-suite-mini.yml Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update .github/workflows/claude-nl-suite.yml Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * workflows(nl-mini): fix YAML indentation/trailing spaces under with: and cleanup heredoc spacing * workflows(nl-suite): fix indentation on docker logs redaction line (YAML lint) * Add write to allowlist * nl-suite: harden reporting discipline (fragment-only writes, forbid alt paths); workflow: clean stray junit-*updated*.xml * nl-suite: enforce end-of-suite single Write (no bash redirection); workflow: restrict allowed_tools to Write+MCP only * prompts(nl-full): end-of-suite results must be valid XML with single <cases> root and only <testcase> children; no raw text outside CDATA * workflows(nl-suite): make Claude step non-fatal; tolerant normalizer extracts <testcase> via regex on bad fragments * nl-suite: fix stale classname to UnityMCP.NL-T in mini fallback; prompt: require re-read after every revert; correct PLAN/PROGRESS to 15 * nl-suite: fix fallback JUnit classname to UnityMCP.NL-T; prompt: forbid create_script and env/mkdir checks, enforce single baseline-byte revert flow and post-revert re-read; add corruption-handling guidance * prompts(nl-full): after each write re-read raw bytes to refresh pre_sha; prefer script_apply_edits for anchors; avoid header/using changes * prompts(nl-full): canonicalize outputs to /; allow small fragment appends via Write or Bash(printf/echo); forbid wrappers and full-file round-trips * prompts(nl-full): finalize markdown formatting for guarded write, execution order, specs, status * workflows(nl-suite, mini): header/lint fixes and constrained Bash append path; align allowed_tools * prompts(nl-full): format Fast Restore, Guarded Write, Execution, Specs, Status as proper markdown lists and code fences * workflows(nl-suite): keep header tidy and append-path alignment with prompt * minor fix * workflows(nl-suite): fix indentation and dispatch; align allowed_tools and revert helper * prompts(nl-full): switch to read_resource for buf/sha; re-read only when needed; convert 'Print this once' to heading; note snapshot helper creates parent dirs * workflows(nl-suite): normalize step removes bootstrap when real testcases present; recompute tests/failures * workflows(nl-suite): enrich Markdown summary by extracting per-test <system-out> blocks (truncated) * clarify prompt resilience instructions * ci(nl-suite): revert prompt and workflow to known-good e0f8a72 for green run; remove extra MD details * ci(nl-suite): minimal fixes — no-mkdir guard in prompt; drop bootstrap and recompute JUnit counts * ci(nl-suite): richer JUnit→Markdown report (per-test system-out) * Small guard to incorret asset read call. * ci(nl-suite): refine MD builder — unescape XML entities, safe code fences, PASS/FAIL badges * Update UnityMcpBridge/UnityMcpServer~/src/tools/resource_tools.py Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update UnityMcpBridge/UnityMcpServer~/src/unity_connection.py Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update UnityMcpBridge/UnityMcpServer~/src/tools/manage_script_edits.py Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update .github/scripts/mark_skipped.py Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update .github/scripts/mark_skipped.py Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update .github/scripts/mark_skipped.py Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> * server(manage_script): robust URI handling — percent-decode file://, normalize, strip host/leading slashes, return Assets-relative if present * Update .claude/prompts/nl-unity-suite-full.md Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> * tests(framing): reduce handshake poll window, nonblocking peek to avoid disconnect race; still enforce pre-handshake data drop * tests(manage_script): add _split_uri tests for unity://path, file:// URLs (decoded/Assets-relative), and plain paths * server+tests: fix handshake syntax error; robust file:// URI normalization in manage_script; add _split_uri tests; adjust stdout scan to ignore venv/site-packages * bridge(framing): accept zero-length frames (treat as empty keepalive) * tests(logging): use errors='replace' on decode fallback to avoid silent drops * resources(list): restrict to Assets/, resolve symlinks, enforce .cs; add traversal/outside-path tests * Update .claude/prompts/nl-unity-suite-full.md Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update UnityMcpBridge/UnityMcpServer~/src/unity_connection.py Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * misc: framing keepalive (zero-length), regex preview consistency, resource.list hardening, URI parsing, legacy update routing, test cleanups * docs(tools): richer MCP tool descriptions; tests accept decorator kwargs; resource URI parsing hardened * Update .claude/prompts/nl-unity-suite-full.md Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update UnityMcpBridge/UnityMcpServer~/src/tools/resource_tools.py Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update UnityMcpBridge/UnityMcpServer~/src/unity_connection.py Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * net+docs: hard-reject zero-length frames; TCP_NODELAY on connect; Assets detection case-insensitive; NL prompt statuses aligned * prompt(nl-suite): constrain Write destinations under reports/, forbid traversal * prompt+net: harden Write path rules; use monotonic deadline and plain-text advisory for non-framed peers * unity_connection: restore recv timeout via try/finally; make global connection getter thread-safe with module lock and double-checked init * NL/T prompt: pin structured edit ops for T-D/T-E; add schema-error guarded write behavior; keep existing path/URI and revert rules * unity_connection: add FRAMED_MAX; use ValueError for framed length violations; lower framed receive log to debug; serialize connect() with per-instance lock * ManageScript: use UTF8Encoding(without BOM) for atomic writes in ApplyTextEdits/EditScript to align with Create/Update and avoid BOM-related diffs/hash mismatches * NL/T prompt: make helper deletion regex multiline-safe ((?ms) so ^ anchors line starts) * ManageScript: emit structured overlap status {status:"overlap"} for overlapping edit ranges in apply_text_edits and edit paths * NL/T prompt: clarify fallback vs failure — fallback only for unsupported/missing_field; treat bad_request as failure; note unsupported after fallback as failure * NL/T prompt: pin deterministic overlap probe (apply_text_edits two ranges from same snapshot); gate too_large behind RUN_TOO_LARGE env hint * TB update * NL/T prompt: harden Output Rules — constrain Bash(printf|echo) to stdout-only; forbid redirection/here-docs/tee; only scripts/nlt-revert.sh may mutate FS * Prompt: enumerate allowed script_apply_edits ops; add manage_editor/read_console guidance; fix T‑F atomic batch to single script_apply_edits. ManageScript: regex timeout for diagnostics; symlink ancestor guard; complete allowed-modes list. * Fixes * ManageScript: add rich overlap diagnostics (conflicts + hint) for both text range and structured batch paths * ManageScript: return structured {status:"validation_failed"} diagnostics in create/update/edits and validate before commit * ManageScript: echo canonical uri in responses (create/read/update/apply_text_edits/structured edits) to reinforce resource identity * improve clarity of capabilities message * Framing: allow zero-length frames on both ends (C# bridge, Python server). Prompt: harden T-F to single text-range apply_text_edits batch (descending order, one snapshot). URI: normalize file:// outside Assets by stripping leading slash. * ManageScript: include new sha256 in success payload for apply_text_edits; harden TryResolveUnderAssets by rejecting symlinked ancestors up to Assets/. * remove claudetest dir * manage_script_edits: normalize method-anchored anchor_insert to insert_method (map text->replacement); improves CI compatibility for T‑A/T‑E without changing Editor behavior. * tighten testing protocol around mkdir * manage_script: validate create_script inputs (Assets/.cs/name/no traversal); add Assets/ guard to delete_script; validate level+Assets in validate_script; make legacy manage_script optional params; harden legacy update routing with base64 reuse and payload size preflight. * Tighten prompt for testing * Update .claude/prompts/nl-unity-suite-full.md Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update .claude/prompts/nl-unity-suite-full.md Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update UnityMcpBridge/Editor/Tools/ManageScript.cs Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * manage_script_edits: honor ignore_case on anchor_insert and regex_replace in both direct and text-conversion paths (MULTILINE|IGNORECASE). * remove extra file * workflow: use python3 for inline scripts and port detection on ubuntu-latest. * Tighten prompt + manage_script * Update UnityMcpBridge/UnityMcpServer~/src/tools/manage_script_edits.py Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update UnityMcpBridge/UnityMcpServer~/src/tools/manage_script_edits.py Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update .claude/prompts/nl-unity-suite-full.md Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update UnityMcpBridge/Editor/Tools/ManageScript.cs Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update .claude/prompts/nl-unity-suite-full.md Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * manage_script: improve file:// UNC handling; preserve POSIX absolute semantics internally; keep test-expected slash stripping for non-Assets paths. * ManageScript.cs: add TimeSpan timeouts to all Regex uses (IsMatch/Match/new Regex) and keep CultureInvariant/Multiline options; reduces risk of catastrophic backtracking stalls. * workflow: ensure reports/ exists in markdown build step to avoid FileNotFoundError when writing MD_OUT. * fix brace * manage_script_edits: expand backrefs for regex_replace in preview->text conversion and translate to \g<n> in local apply; keeps previews and actual edits consistent. * anchor_insert: default to position=after, normalize surrounding newlines in Python conversion paths; C# path ensures trailing newline and skips duplicate insertion within class. * feat(mcp): add get_sha tool; apply_text_edits normalization+overlap preflight+strict; no-op evidence in C#; update NL suite prompt; add unit tests * feat(frames): accept zero-length heartbeat frames in client; add heartbeat test * feat(edits): guard destructive regex_replace with structural preflight; add robust tests; prompt uses delete_method for temp helper * feat(frames): bound heartbeat loop with timeout/threshold; align zero-length response with C#; update test * SDK hardening: atomic multi-span text edits; stop forcing sequential for structured ops; forward options on apply_text_edits; add validate=relaxed support and scoped checks; update NL/T prompt; add tests for options forwarding, relaxed mode, and atomic batches * Router: default applyMode=atomic for multi-span apply_text_edits; add tests * CI prompt: pass options.validate=relaxed for T-B/C; options.applyMode=atomic for T-F; emphasize always writing testcase and restoring on errors * Validation & DX: add validate=syntax (scoped), standardize evidence windows; early regex compile with hints; debug_preview for apply_text_edits * Update UnityMcpBridge/Editor/Windows/MCPForUnityEditorWindow.cs Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * NL/T suite-driven edits: LongUnityScriptClaudeTest, bridge helpers, server_version; prepare framing tests * Fix duplicate macConfigPath field in McpClient to resolve CS0102 * Editor threading: run EnsureServerInstalled on main thread; marshal EditorPrefs/DeleteKey + logging via delayCall * Docs(apply_text_edits): strengthen guidance on 1-based positions, verify-before-edit, and recommend anchors/structured edits * Docs(script_apply_edits): add safety guidance (anchors, method ops, validators) and recommended practices * Framed VerifyBridgePing in editor window; docs hardening for apply_text_edits and script_apply_edits --------- Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
2025-08-31 00:55:38 +08:00
case "apply_text_edits":
{
var textEdits = @params["edits"] as JArray;
string precondition = @params["precondition_sha256"]?.ToString();
// Respect optional options
string refreshOpt = @params["options"]?["refresh"]?.ToString()?.ToLowerInvariant();
string validateOpt = @params["options"]?["validate"]?.ToString()?.ToLowerInvariant();
return ApplyTextEdits(fullPath, relativePath, name, textEdits, precondition, refreshOpt, validateOpt);
}
case "validate":
{
string level = @params["level"]?.ToString()?.ToLowerInvariant() ?? "standard";
var chosen = level switch
{
"basic" => ValidationLevel.Basic,
"standard" => ValidationLevel.Standard,
"strict" => ValidationLevel.Strict,
"comprehensive" => ValidationLevel.Comprehensive,
_ => ValidationLevel.Standard
};
string fileText;
try { fileText = File.ReadAllText(fullPath); }
catch (Exception ex) { return Response.Error($"Failed to read script: {ex.Message}"); }
bool ok = ValidateScriptSyntax(fileText, chosen, out string[] diagsRaw);
var diags = (diagsRaw ?? Array.Empty<string>()).Select(s =>
{
var m = Regex.Match(
s,
@"^(ERROR|WARNING|INFO): (.*?)(?: \(Line (\d+)\))?$",
RegexOptions.CultureInvariant | RegexOptions.Multiline,
TimeSpan.FromMilliseconds(250)
);
string severity = m.Success ? m.Groups[1].Value.ToLowerInvariant() : "info";
string message = m.Success ? m.Groups[2].Value : s;
int lineNum = m.Success && int.TryParse(m.Groups[3].Value, out var l) ? l : 0;
return new { line = lineNum, col = 0, severity, message };
}).ToArray();
var result = new { diagnostics = diags };
return ok ? Response.Success("Validation completed.", result)
: Response.Error("Validation failed.", result);
}
case "edit":
Debug.LogWarning("manage_script.edit is deprecated; prefer apply_text_edits. Serving structured edit for backward compatibility.");
var structEdits = @params["edits"] as JArray;
var options = @params["options"] as JObject;
return EditScript(fullPath, relativePath, name, structEdits, options);
case "get_sha":
{
try
{
if (!File.Exists(fullPath))
return Response.Error($"Script not found at '{relativePath}'.");
string text = File.ReadAllText(fullPath);
string sha = ComputeSha256(text);
var fi = new FileInfo(fullPath);
long lengthBytes;
try { lengthBytes = new System.Text.UTF8Encoding(encoderShouldEmitUTF8Identifier: false).GetByteCount(text); }
catch { lengthBytes = fi.Exists ? fi.Length : 0; }
var data = new
{
uri = $"unity://path/{relativePath}",
path = relativePath,
sha256 = sha,
lengthBytes,
lastModifiedUtc = fi.Exists ? fi.LastWriteTimeUtc.ToString("o") : string.Empty
};
return Response.Success($"SHA computed for '{relativePath}'.", data);
}
catch (Exception ex)
{
return Response.Error($"Failed to compute SHA: {ex.Message}");
}
}
2025-03-31 03:58:01 +08:00
default:
return Response.Error(
Claude‑friendly edit tools + framed transport + live Unity NL test framework (#243) * CI: gate desktop-parity on Anthropic key; pass anthropic_api_key like NL suite * Add quickprobe prompt and CI workflow (mcp-quickprobe.md, unity-mcp-quickprobe.yml) * strictier tool use to prevent subagent spawning and force mcp tools * update workflow filesto reduce likelihood of subagent spawning * improve permissions for claude agent, fix mcpbridge timeout/token issue * increase max turns to 10 * ci: align NL suite to new permissions schema; prevent subagent drift * ci: NL suite -> mini prompt for e2e; add full NL/T prompt; server: ctx optional + project_root fallback; workflows: set UNITY_PROJECT_ROOT for CI * ci: add checks:write; revert local project hardcodes (manifest, ProjectVersion.txt) * tools: text-edit routing fixes (anchor_insert via text, CRLF calc); prompts: mini NL/T clarifications * ci: use absolute UNITY_PROJECT_ROOT; prompts target TestProjects; server: accept relative UNITY_PROJECT_ROOT and bare spec URI * ci: ignore Unity test project's packages-lock.json; remove from repo to avoid absolute paths * CI: start persistent Unity Editor for MCP (guarded by license) + allow batch-mode bridge via UNITY_MCP_ALLOW_BATCH * CI: hide license and pass via env to docker; fix invalid ref format * CI: readiness probe uses handshake on Unity MCP port (deterministic) * CI: fix YAML; use TCP handshake readiness probe (FRAMING=1) * CI: prime Unity license via game-ci; mount ULF into container; extend readiness timeout * CI: use ULF write + mount for Unity licensing; remove serial/email/pass from container * CI: entitlement activation (UNITY_SERIAL=''); verify host ULF cache; keep mount * CI: write ULF from secret and verify; drop entitlement activation step * CI: detect any licensing path; GameCI prime; status dir env; log+probe readiness; fix YAML * CI: add GameCI license prime; conditional ULF write; one-shot license validation; explicit status dir + license env * CI: fix YAML (inline python), add Anthropic key detect via GITHUB_ENV; ready to run happy path * CI: mount Unity token/ulf/cache dirs into container to share host license; create dirs before start * CI: fix YAML indentation; write ULF on host; activate in container with shared mounts; mount .config and .cache too * CI: gate Claude via outputs; mount all Unity license dirs; fix inline probe python; stabilize licensing flow * CI: normalize detect to step outputs; ensure license dirs mounted and validated; fix indentation * Bridge: honor UNITY_MCP_STATUS_DIR for heartbeat/status file (CI-friendly) * CI: guard project path for activation/start; align tool allowlist; run MCP server with python; tighten secret scoping * CI: finalize Unity licensing mounts + status dir; mode-detect (ULF/EBL); readiness logs+probe; Claude gating via outputs * CI: fix YAML probe (inline python -c) and finalize happy-path Unity licensing and MCP/Claude wiring * CI: inline python probe; unify Unity image and cache mounts; ready to test * CI: fix docker run IMAGE placement; ignore cache find perms; keep same editor image * CI: pass -manualLicenseFile to persistent Editor; keep mounts and single image * CI: mount full GameCI cache to /root in persistent Unity; set HOME=/root; add optional license check * CI: make -manualLicenseFile conditional; keep full /root mount and license check * CI: set HOME=/github/home; mount GameCI cache there; adjust manualLicenseFile path; expand license check * CI: EBL sign-in for persistent Unity (email/password/serial); revert HOME=/root and full /root mount; keep conditional manualLicenseFile and improved readiness * CI: run full NL/T suite prompt (nl-unity-suite-full.md) instead of mini * NL/T: require unified diffs + explicit verdicts in JUnit; CI: remove short sanity step, publish JUnit, upload artifacts * NL/T prompt: require CDATA wrapping for JUnit XML fields; guidance for splitting embedded ]]>; keep VERDICT in CDATA only * CI: remove in-container license check step; keep readiness and full suite * NL/T prompt: add version header, stricter JUnit schema, hashing/normalization, anchors, statuses, atomic semantics, tool logging * CI: increase Claude NL/T suite timeout to 30 minutes * CI: pre-create reports dir and result files to avoid tool approval prompts * CI: skip wait if container not running; skip Editor start if project missing; broaden MCP deps detection; expand allowed tools * fixies to harden ManageScript * CI: sanitize NL/T markdown report to avoid NUL/encoding issues * revert breaking yyaml changes * CI: prime license, robust Unity start/wait, sanitize markdown via heredoc * Resolve merge: accept upstream renames/installer (fix/installer-cleanup-v2) and keep local framing/script-editing - Restored upstream server.py, EditorWindow, uv.lock\n- Preserved ManageScript editing/validation; switched to atomic write + debounced refresh\n- Updated tools/__init__.py to keep script_edits/resources and adopt new logger name\n- All Python tests via uv: 7 passed, 6 skipped, 9 xpassed; Unity compile OK * Fix Claude Desktop config path and atomic write issues - Fix macOS path for Claude Desktop config: use ~/Library/Application Support/Claude/ instead of ~/.config/Claude/ - Improve atomic write pattern with backup/restore safety - Replace File.Replace() with File.Move() for better macOS compatibility - Add proper error handling and cleanup for file operations - Resolves issue where installer couldn't find Claude Desktop config on macOS * Editor: use macConfigPath on macOS for MCP client config writes (Claude Desktop, etc.). Fallback to linuxConfigPath only if mac path missing. * Models: add macConfigPath to McpClient for macOS config path selection (fixes CS1061 in editor window). * Editor: on macOS, prefer macConfigPath in ManualConfigEditorWindow (fallback to linux path); Linux/Windows unchanged. * Fix McpClient: align with upstream/main, prep for framing split * NL suite: shard workflow; tighten bridge readiness; add MCP preflight; use env-based shard vars * NL suite: fix shard step indentation; move shard vars to env; remove invalid inputs * MCP clients: split VSCode Copilot config paths into macConfigPath and linuxConfigPath * Unity bridge: clean stale status; bind host; robust wait probe with IPv4/IPv6 + diagnostics * CI: use MCPForUnity.Editor.MCPForUnityBridge.StartAutoConnect as executeMethod * Action wiring: inline mcpServers in settings for all shards; remove redundant .claude/mcp.json step * CI: embed mcpServers in settings for all shards; fix startup sanity step; lint clean * CI: pin claude-code-base-action to e6f32c8; use claude_args --mcp-config; switch to allowed_tools; ensure MCP config per step * CI: unpin claude-code-base-action to @beta (commit ref not found) * CI: align with claude-code-base-action @beta; pass MCP via claude_args and allowedTools * Editor: Fix apply_text_edits heuristic when edits shift positions; recompute method span on candidate text with fallback delta adjustment * CI: unify MCP wiring across workflows; write .claude/mcp.json; switch to claude_args with --mcp-config/--allowedTools; remove unsupported inputs * CI: collapse NL suite shards into a single run to avoid repeated test execution * CI: minimize allowedTools for NL suite to essential Unity MCP + Bash("git:*") + Write * CI: mkdir -p reports before run; remove unsupported --timeout-minutes from claude_args * CI: broaden allowedTools to include find_in_file and mcp__unity__* * CI: enable use_node_cache and switch NL suite model to claude-3-7-haiku-20250219 * CI: disable use_node_cache to avoid setup-node lockfile error * CI: set NL suite model to claude-3-haiku-20240307 * CI: cap Haiku output with --max-tokens 2048 for NL suite * CI: switch to claude-3-7-sonnet-latest and remove unsupported --max-tokens * CI: update allowedTools to Bash(*) and explicit Unity MCP tool list * CI: update NL suite workflow (latest tweaks) * Tests: tighten NL suite prompt for logging, hash discipline, stale retry, evidence windows, diff cap, and VERDICT line * Add disallowed tools to NL suite workflow * docs: clarify stale write retry * Add fallback JUnit report and adjust publisher * Indent fallback JUnit XML in workflow * fix: correct fallback JUnit report generation * Update mcp-quickprobe.md Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> * Update mcp-quickprobe.md Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> * Update Response.cs Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> * Update MCPForUnityBridge.cs Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> * fix: correct McpTypes reference * Add directory existence checks for symlink and XDG paths * fix: only set installation flag after successful server install * Update resource_tools.py Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> * fix: respect mac config paths * Use File.Replace for atomic config write * Remove unused imports in manage_script * bump server version * Tests: update NL suite prompt and workflows; remove deprecated smoke/desktop-parity; quickprobe tidy * Editor: atomic config write via File.Replace fallback; remove redundant backups and racey exists checks * CI: harden NL suite - idempotent docker, gate on unity_ok, safer port probe, least-priv perms * Editor: make atomic config write restoration safe (flag writeDone; copy-overwrite restore; cleanup in finally) * CI: fix fallback JUnit heredoc by using printf lines (no EOF delimiter issues) * CI: switch NL suite to mini prompt; mini prompt honors / and NL discipline * CI: replace claude_args with allowed_tools/model/mcp_config per action schema * CI: expand UNITY_PROJECT_ROOT via in MCP config heredoc * EditorWindow: add cross-platform fallback for File.Replace; macOS-insensitive PathsEqual; safer uv resolve; honor macConfigPath * CI: strengthen JUnit publishing for NL mini suite (normalize, debug list, publish both, fail_on_parse_error) * CI: set job-wide JUNIT_OUT/MD_OUT; normalization uses env; publish references env and ungroup reports * CI: publish a single normalized JUnit (reports/junit-for-actions.xml); fallback writes same; avoid checkName/reportPaths mismatch * CI: align mini prompt report filenames; redact Unity log tail in diagnostics * chore: sync workflow and mini prompt; redacted logs; JUnit normalization/publish tweaks * CI: redact sensitive tokens in Stop Unity; docs: CI usage + edit tools * prompts: update nl-unity-suite-full (mini-style setup + reporting discipline); remove obsolete prompts * CI: harden NL workflows (timeout_minutes, robust normalization); prompts: unify JUnit suite name and reporting discipline * prompts: add guarded write pattern (LF hash, stale_file retry) to full suite * prompts: enforce continue-on-failure, driver flow, and status handling in full suite * Make test list more explicit in prompt. Get rid of old test prompts for hygeine. * prompts: add stale fast-retry (server hash) + in-memory buf guidance * CI: standardize JUNIT_OUT to reports/junit-nl-suite.xml; fix artifact upload indentation; prompt copy cleanups * prompts: reporting discipline — append-only fragments, batch writes, no model round-trip * prompts: stale fast-retry preference, buffer/sha carry, snapshot revert, essential logging * workflows(nl-suite): precreate report skeletons, assemble junit, synthesize markdown; restrict allowed_tools to append-only Bash + MCP tools * thsis too * Update README-DEV.md Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update .github/workflows/claude-nl-suite-mini.yml Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update .github/workflows/claude-nl-suite.yml Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * workflows(nl-mini): fix YAML indentation/trailing spaces under with: and cleanup heredoc spacing * workflows(nl-suite): fix indentation on docker logs redaction line (YAML lint) * Add write to allowlist * nl-suite: harden reporting discipline (fragment-only writes, forbid alt paths); workflow: clean stray junit-*updated*.xml * nl-suite: enforce end-of-suite single Write (no bash redirection); workflow: restrict allowed_tools to Write+MCP only * prompts(nl-full): end-of-suite results must be valid XML with single <cases> root and only <testcase> children; no raw text outside CDATA * workflows(nl-suite): make Claude step non-fatal; tolerant normalizer extracts <testcase> via regex on bad fragments * nl-suite: fix stale classname to UnityMCP.NL-T in mini fallback; prompt: require re-read after every revert; correct PLAN/PROGRESS to 15 * nl-suite: fix fallback JUnit classname to UnityMCP.NL-T; prompt: forbid create_script and env/mkdir checks, enforce single baseline-byte revert flow and post-revert re-read; add corruption-handling guidance * prompts(nl-full): after each write re-read raw bytes to refresh pre_sha; prefer script_apply_edits for anchors; avoid header/using changes * prompts(nl-full): canonicalize outputs to /; allow small fragment appends via Write or Bash(printf/echo); forbid wrappers and full-file round-trips * prompts(nl-full): finalize markdown formatting for guarded write, execution order, specs, status * workflows(nl-suite, mini): header/lint fixes and constrained Bash append path; align allowed_tools * prompts(nl-full): format Fast Restore, Guarded Write, Execution, Specs, Status as proper markdown lists and code fences * workflows(nl-suite): keep header tidy and append-path alignment with prompt * minor fix * workflows(nl-suite): fix indentation and dispatch; align allowed_tools and revert helper * prompts(nl-full): switch to read_resource for buf/sha; re-read only when needed; convert 'Print this once' to heading; note snapshot helper creates parent dirs * workflows(nl-suite): normalize step removes bootstrap when real testcases present; recompute tests/failures * workflows(nl-suite): enrich Markdown summary by extracting per-test <system-out> blocks (truncated) * clarify prompt resilience instructions * ci(nl-suite): revert prompt and workflow to known-good e0f8a72 for green run; remove extra MD details * ci(nl-suite): minimal fixes — no-mkdir guard in prompt; drop bootstrap and recompute JUnit counts * ci(nl-suite): richer JUnit→Markdown report (per-test system-out) * Small guard to incorret asset read call. * ci(nl-suite): refine MD builder — unescape XML entities, safe code fences, PASS/FAIL badges * Update UnityMcpBridge/UnityMcpServer~/src/tools/resource_tools.py Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update UnityMcpBridge/UnityMcpServer~/src/unity_connection.py Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update UnityMcpBridge/UnityMcpServer~/src/tools/manage_script_edits.py Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update .github/scripts/mark_skipped.py Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update .github/scripts/mark_skipped.py Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update .github/scripts/mark_skipped.py Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> * server(manage_script): robust URI handling — percent-decode file://, normalize, strip host/leading slashes, return Assets-relative if present * Update .claude/prompts/nl-unity-suite-full.md Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> * tests(framing): reduce handshake poll window, nonblocking peek to avoid disconnect race; still enforce pre-handshake data drop * tests(manage_script): add _split_uri tests for unity://path, file:// URLs (decoded/Assets-relative), and plain paths * server+tests: fix handshake syntax error; robust file:// URI normalization in manage_script; add _split_uri tests; adjust stdout scan to ignore venv/site-packages * bridge(framing): accept zero-length frames (treat as empty keepalive) * tests(logging): use errors='replace' on decode fallback to avoid silent drops * resources(list): restrict to Assets/, resolve symlinks, enforce .cs; add traversal/outside-path tests * Update .claude/prompts/nl-unity-suite-full.md Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update UnityMcpBridge/UnityMcpServer~/src/unity_connection.py Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * misc: framing keepalive (zero-length), regex preview consistency, resource.list hardening, URI parsing, legacy update routing, test cleanups * docs(tools): richer MCP tool descriptions; tests accept decorator kwargs; resource URI parsing hardened * Update .claude/prompts/nl-unity-suite-full.md Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update UnityMcpBridge/UnityMcpServer~/src/tools/resource_tools.py Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update UnityMcpBridge/UnityMcpServer~/src/unity_connection.py Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * net+docs: hard-reject zero-length frames; TCP_NODELAY on connect; Assets detection case-insensitive; NL prompt statuses aligned * prompt(nl-suite): constrain Write destinations under reports/, forbid traversal * prompt+net: harden Write path rules; use monotonic deadline and plain-text advisory for non-framed peers * unity_connection: restore recv timeout via try/finally; make global connection getter thread-safe with module lock and double-checked init * NL/T prompt: pin structured edit ops for T-D/T-E; add schema-error guarded write behavior; keep existing path/URI and revert rules * unity_connection: add FRAMED_MAX; use ValueError for framed length violations; lower framed receive log to debug; serialize connect() with per-instance lock * ManageScript: use UTF8Encoding(without BOM) for atomic writes in ApplyTextEdits/EditScript to align with Create/Update and avoid BOM-related diffs/hash mismatches * NL/T prompt: make helper deletion regex multiline-safe ((?ms) so ^ anchors line starts) * ManageScript: emit structured overlap status {status:"overlap"} for overlapping edit ranges in apply_text_edits and edit paths * NL/T prompt: clarify fallback vs failure — fallback only for unsupported/missing_field; treat bad_request as failure; note unsupported after fallback as failure * NL/T prompt: pin deterministic overlap probe (apply_text_edits two ranges from same snapshot); gate too_large behind RUN_TOO_LARGE env hint * TB update * NL/T prompt: harden Output Rules — constrain Bash(printf|echo) to stdout-only; forbid redirection/here-docs/tee; only scripts/nlt-revert.sh may mutate FS * Prompt: enumerate allowed script_apply_edits ops; add manage_editor/read_console guidance; fix T‑F atomic batch to single script_apply_edits. ManageScript: regex timeout for diagnostics; symlink ancestor guard; complete allowed-modes list. * Fixes * ManageScript: add rich overlap diagnostics (conflicts + hint) for both text range and structured batch paths * ManageScript: return structured {status:"validation_failed"} diagnostics in create/update/edits and validate before commit * ManageScript: echo canonical uri in responses (create/read/update/apply_text_edits/structured edits) to reinforce resource identity * improve clarity of capabilities message * Framing: allow zero-length frames on both ends (C# bridge, Python server). Prompt: harden T-F to single text-range apply_text_edits batch (descending order, one snapshot). URI: normalize file:// outside Assets by stripping leading slash. * ManageScript: include new sha256 in success payload for apply_text_edits; harden TryResolveUnderAssets by rejecting symlinked ancestors up to Assets/. * remove claudetest dir * manage_script_edits: normalize method-anchored anchor_insert to insert_method (map text->replacement); improves CI compatibility for T‑A/T‑E without changing Editor behavior. * tighten testing protocol around mkdir * manage_script: validate create_script inputs (Assets/.cs/name/no traversal); add Assets/ guard to delete_script; validate level+Assets in validate_script; make legacy manage_script optional params; harden legacy update routing with base64 reuse and payload size preflight. * Tighten prompt for testing * Update .claude/prompts/nl-unity-suite-full.md Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update .claude/prompts/nl-unity-suite-full.md Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update UnityMcpBridge/Editor/Tools/ManageScript.cs Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * manage_script_edits: honor ignore_case on anchor_insert and regex_replace in both direct and text-conversion paths (MULTILINE|IGNORECASE). * remove extra file * workflow: use python3 for inline scripts and port detection on ubuntu-latest. * Tighten prompt + manage_script * Update UnityMcpBridge/UnityMcpServer~/src/tools/manage_script_edits.py Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update UnityMcpBridge/UnityMcpServer~/src/tools/manage_script_edits.py Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update .claude/prompts/nl-unity-suite-full.md Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update UnityMcpBridge/Editor/Tools/ManageScript.cs Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update .claude/prompts/nl-unity-suite-full.md Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * manage_script: improve file:// UNC handling; preserve POSIX absolute semantics internally; keep test-expected slash stripping for non-Assets paths. * ManageScript.cs: add TimeSpan timeouts to all Regex uses (IsMatch/Match/new Regex) and keep CultureInvariant/Multiline options; reduces risk of catastrophic backtracking stalls. * workflow: ensure reports/ exists in markdown build step to avoid FileNotFoundError when writing MD_OUT. * fix brace * manage_script_edits: expand backrefs for regex_replace in preview->text conversion and translate to \g<n> in local apply; keeps previews and actual edits consistent. * anchor_insert: default to position=after, normalize surrounding newlines in Python conversion paths; C# path ensures trailing newline and skips duplicate insertion within class. * feat(mcp): add get_sha tool; apply_text_edits normalization+overlap preflight+strict; no-op evidence in C#; update NL suite prompt; add unit tests * feat(frames): accept zero-length heartbeat frames in client; add heartbeat test * feat(edits): guard destructive regex_replace with structural preflight; add robust tests; prompt uses delete_method for temp helper * feat(frames): bound heartbeat loop with timeout/threshold; align zero-length response with C#; update test * SDK hardening: atomic multi-span text edits; stop forcing sequential for structured ops; forward options on apply_text_edits; add validate=relaxed support and scoped checks; update NL/T prompt; add tests for options forwarding, relaxed mode, and atomic batches * Router: default applyMode=atomic for multi-span apply_text_edits; add tests * CI prompt: pass options.validate=relaxed for T-B/C; options.applyMode=atomic for T-F; emphasize always writing testcase and restoring on errors * Validation & DX: add validate=syntax (scoped), standardize evidence windows; early regex compile with hints; debug_preview for apply_text_edits * Update UnityMcpBridge/Editor/Windows/MCPForUnityEditorWindow.cs Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * NL/T suite-driven edits: LongUnityScriptClaudeTest, bridge helpers, server_version; prepare framing tests * Fix duplicate macConfigPath field in McpClient to resolve CS0102 * Editor threading: run EnsureServerInstalled on main thread; marshal EditorPrefs/DeleteKey + logging via delayCall * Docs(apply_text_edits): strengthen guidance on 1-based positions, verify-before-edit, and recommend anchors/structured edits * Docs(script_apply_edits): add safety guidance (anchors, method ops, validators) and recommended practices * Framed VerifyBridgePing in editor window; docs hardening for apply_text_edits and script_apply_edits --------- Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
2025-08-31 00:55:38 +08:00
$"Unknown action: '{action}'. Valid actions are: create, delete, apply_text_edits, validate, read (deprecated), update (deprecated), edit (deprecated)."
);
2025-03-31 03:58:01 +08:00
}
}
/// <summary>
/// Decode base64 string to normal text
/// </summary>
private static string DecodeBase64(string encoded)
{
byte[] data = Convert.FromBase64String(encoded);
return System.Text.Encoding.UTF8.GetString(data);
}
/// <summary>
/// Encode text to base64 string
/// </summary>
private static string EncodeBase64(string text)
{
byte[] data = System.Text.Encoding.UTF8.GetBytes(text);
return Convert.ToBase64String(data);
}
private static object CreateScript(
string fullPath,
string relativePath,
string name,
string contents,
string scriptType,
string namespaceName
)
2025-03-31 03:58:01 +08:00
{
// Check if script already exists
if (File.Exists(fullPath))
{
return Response.Error(
$"Script already exists at '{relativePath}'. Use 'update' action to modify."
);
2025-03-31 03:58:01 +08:00
}
// Generate default content if none provided
if (string.IsNullOrEmpty(contents))
{
contents = GenerateDefaultScriptContent(name, scriptType, namespaceName);
}
// Validate syntax with detailed error reporting using GUI setting
ValidationLevel validationLevel = GetValidationLevelFromGUI();
bool isValid = ValidateScriptSyntax(contents, validationLevel, out string[] validationErrors);
if (!isValid)
{
Claude‑friendly edit tools + framed transport + live Unity NL test framework (#243) * CI: gate desktop-parity on Anthropic key; pass anthropic_api_key like NL suite * Add quickprobe prompt and CI workflow (mcp-quickprobe.md, unity-mcp-quickprobe.yml) * strictier tool use to prevent subagent spawning and force mcp tools * update workflow filesto reduce likelihood of subagent spawning * improve permissions for claude agent, fix mcpbridge timeout/token issue * increase max turns to 10 * ci: align NL suite to new permissions schema; prevent subagent drift * ci: NL suite -> mini prompt for e2e; add full NL/T prompt; server: ctx optional + project_root fallback; workflows: set UNITY_PROJECT_ROOT for CI * ci: add checks:write; revert local project hardcodes (manifest, ProjectVersion.txt) * tools: text-edit routing fixes (anchor_insert via text, CRLF calc); prompts: mini NL/T clarifications * ci: use absolute UNITY_PROJECT_ROOT; prompts target TestProjects; server: accept relative UNITY_PROJECT_ROOT and bare spec URI * ci: ignore Unity test project's packages-lock.json; remove from repo to avoid absolute paths * CI: start persistent Unity Editor for MCP (guarded by license) + allow batch-mode bridge via UNITY_MCP_ALLOW_BATCH * CI: hide license and pass via env to docker; fix invalid ref format * CI: readiness probe uses handshake on Unity MCP port (deterministic) * CI: fix YAML; use TCP handshake readiness probe (FRAMING=1) * CI: prime Unity license via game-ci; mount ULF into container; extend readiness timeout * CI: use ULF write + mount for Unity licensing; remove serial/email/pass from container * CI: entitlement activation (UNITY_SERIAL=''); verify host ULF cache; keep mount * CI: write ULF from secret and verify; drop entitlement activation step * CI: detect any licensing path; GameCI prime; status dir env; log+probe readiness; fix YAML * CI: add GameCI license prime; conditional ULF write; one-shot license validation; explicit status dir + license env * CI: fix YAML (inline python), add Anthropic key detect via GITHUB_ENV; ready to run happy path * CI: mount Unity token/ulf/cache dirs into container to share host license; create dirs before start * CI: fix YAML indentation; write ULF on host; activate in container with shared mounts; mount .config and .cache too * CI: gate Claude via outputs; mount all Unity license dirs; fix inline probe python; stabilize licensing flow * CI: normalize detect to step outputs; ensure license dirs mounted and validated; fix indentation * Bridge: honor UNITY_MCP_STATUS_DIR for heartbeat/status file (CI-friendly) * CI: guard project path for activation/start; align tool allowlist; run MCP server with python; tighten secret scoping * CI: finalize Unity licensing mounts + status dir; mode-detect (ULF/EBL); readiness logs+probe; Claude gating via outputs * CI: fix YAML probe (inline python -c) and finalize happy-path Unity licensing and MCP/Claude wiring * CI: inline python probe; unify Unity image and cache mounts; ready to test * CI: fix docker run IMAGE placement; ignore cache find perms; keep same editor image * CI: pass -manualLicenseFile to persistent Editor; keep mounts and single image * CI: mount full GameCI cache to /root in persistent Unity; set HOME=/root; add optional license check * CI: make -manualLicenseFile conditional; keep full /root mount and license check * CI: set HOME=/github/home; mount GameCI cache there; adjust manualLicenseFile path; expand license check * CI: EBL sign-in for persistent Unity (email/password/serial); revert HOME=/root and full /root mount; keep conditional manualLicenseFile and improved readiness * CI: run full NL/T suite prompt (nl-unity-suite-full.md) instead of mini * NL/T: require unified diffs + explicit verdicts in JUnit; CI: remove short sanity step, publish JUnit, upload artifacts * NL/T prompt: require CDATA wrapping for JUnit XML fields; guidance for splitting embedded ]]>; keep VERDICT in CDATA only * CI: remove in-container license check step; keep readiness and full suite * NL/T prompt: add version header, stricter JUnit schema, hashing/normalization, anchors, statuses, atomic semantics, tool logging * CI: increase Claude NL/T suite timeout to 30 minutes * CI: pre-create reports dir and result files to avoid tool approval prompts * CI: skip wait if container not running; skip Editor start if project missing; broaden MCP deps detection; expand allowed tools * fixies to harden ManageScript * CI: sanitize NL/T markdown report to avoid NUL/encoding issues * revert breaking yyaml changes * CI: prime license, robust Unity start/wait, sanitize markdown via heredoc * Resolve merge: accept upstream renames/installer (fix/installer-cleanup-v2) and keep local framing/script-editing - Restored upstream server.py, EditorWindow, uv.lock\n- Preserved ManageScript editing/validation; switched to atomic write + debounced refresh\n- Updated tools/__init__.py to keep script_edits/resources and adopt new logger name\n- All Python tests via uv: 7 passed, 6 skipped, 9 xpassed; Unity compile OK * Fix Claude Desktop config path and atomic write issues - Fix macOS path for Claude Desktop config: use ~/Library/Application Support/Claude/ instead of ~/.config/Claude/ - Improve atomic write pattern with backup/restore safety - Replace File.Replace() with File.Move() for better macOS compatibility - Add proper error handling and cleanup for file operations - Resolves issue where installer couldn't find Claude Desktop config on macOS * Editor: use macConfigPath on macOS for MCP client config writes (Claude Desktop, etc.). Fallback to linuxConfigPath only if mac path missing. * Models: add macConfigPath to McpClient for macOS config path selection (fixes CS1061 in editor window). * Editor: on macOS, prefer macConfigPath in ManualConfigEditorWindow (fallback to linux path); Linux/Windows unchanged. * Fix McpClient: align with upstream/main, prep for framing split * NL suite: shard workflow; tighten bridge readiness; add MCP preflight; use env-based shard vars * NL suite: fix shard step indentation; move shard vars to env; remove invalid inputs * MCP clients: split VSCode Copilot config paths into macConfigPath and linuxConfigPath * Unity bridge: clean stale status; bind host; robust wait probe with IPv4/IPv6 + diagnostics * CI: use MCPForUnity.Editor.MCPForUnityBridge.StartAutoConnect as executeMethod * Action wiring: inline mcpServers in settings for all shards; remove redundant .claude/mcp.json step * CI: embed mcpServers in settings for all shards; fix startup sanity step; lint clean * CI: pin claude-code-base-action to e6f32c8; use claude_args --mcp-config; switch to allowed_tools; ensure MCP config per step * CI: unpin claude-code-base-action to @beta (commit ref not found) * CI: align with claude-code-base-action @beta; pass MCP via claude_args and allowedTools * Editor: Fix apply_text_edits heuristic when edits shift positions; recompute method span on candidate text with fallback delta adjustment * CI: unify MCP wiring across workflows; write .claude/mcp.json; switch to claude_args with --mcp-config/--allowedTools; remove unsupported inputs * CI: collapse NL suite shards into a single run to avoid repeated test execution * CI: minimize allowedTools for NL suite to essential Unity MCP + Bash("git:*") + Write * CI: mkdir -p reports before run; remove unsupported --timeout-minutes from claude_args * CI: broaden allowedTools to include find_in_file and mcp__unity__* * CI: enable use_node_cache and switch NL suite model to claude-3-7-haiku-20250219 * CI: disable use_node_cache to avoid setup-node lockfile error * CI: set NL suite model to claude-3-haiku-20240307 * CI: cap Haiku output with --max-tokens 2048 for NL suite * CI: switch to claude-3-7-sonnet-latest and remove unsupported --max-tokens * CI: update allowedTools to Bash(*) and explicit Unity MCP tool list * CI: update NL suite workflow (latest tweaks) * Tests: tighten NL suite prompt for logging, hash discipline, stale retry, evidence windows, diff cap, and VERDICT line * Add disallowed tools to NL suite workflow * docs: clarify stale write retry * Add fallback JUnit report and adjust publisher * Indent fallback JUnit XML in workflow * fix: correct fallback JUnit report generation * Update mcp-quickprobe.md Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> * Update mcp-quickprobe.md Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> * Update Response.cs Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> * Update MCPForUnityBridge.cs Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> * fix: correct McpTypes reference * Add directory existence checks for symlink and XDG paths * fix: only set installation flag after successful server install * Update resource_tools.py Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> * fix: respect mac config paths * Use File.Replace for atomic config write * Remove unused imports in manage_script * bump server version * Tests: update NL suite prompt and workflows; remove deprecated smoke/desktop-parity; quickprobe tidy * Editor: atomic config write via File.Replace fallback; remove redundant backups and racey exists checks * CI: harden NL suite - idempotent docker, gate on unity_ok, safer port probe, least-priv perms * Editor: make atomic config write restoration safe (flag writeDone; copy-overwrite restore; cleanup in finally) * CI: fix fallback JUnit heredoc by using printf lines (no EOF delimiter issues) * CI: switch NL suite to mini prompt; mini prompt honors / and NL discipline * CI: replace claude_args with allowed_tools/model/mcp_config per action schema * CI: expand UNITY_PROJECT_ROOT via in MCP config heredoc * EditorWindow: add cross-platform fallback for File.Replace; macOS-insensitive PathsEqual; safer uv resolve; honor macConfigPath * CI: strengthen JUnit publishing for NL mini suite (normalize, debug list, publish both, fail_on_parse_error) * CI: set job-wide JUNIT_OUT/MD_OUT; normalization uses env; publish references env and ungroup reports * CI: publish a single normalized JUnit (reports/junit-for-actions.xml); fallback writes same; avoid checkName/reportPaths mismatch * CI: align mini prompt report filenames; redact Unity log tail in diagnostics * chore: sync workflow and mini prompt; redacted logs; JUnit normalization/publish tweaks * CI: redact sensitive tokens in Stop Unity; docs: CI usage + edit tools * prompts: update nl-unity-suite-full (mini-style setup + reporting discipline); remove obsolete prompts * CI: harden NL workflows (timeout_minutes, robust normalization); prompts: unify JUnit suite name and reporting discipline * prompts: add guarded write pattern (LF hash, stale_file retry) to full suite * prompts: enforce continue-on-failure, driver flow, and status handling in full suite * Make test list more explicit in prompt. Get rid of old test prompts for hygeine. * prompts: add stale fast-retry (server hash) + in-memory buf guidance * CI: standardize JUNIT_OUT to reports/junit-nl-suite.xml; fix artifact upload indentation; prompt copy cleanups * prompts: reporting discipline — append-only fragments, batch writes, no model round-trip * prompts: stale fast-retry preference, buffer/sha carry, snapshot revert, essential logging * workflows(nl-suite): precreate report skeletons, assemble junit, synthesize markdown; restrict allowed_tools to append-only Bash + MCP tools * thsis too * Update README-DEV.md Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update .github/workflows/claude-nl-suite-mini.yml Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update .github/workflows/claude-nl-suite.yml Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * workflows(nl-mini): fix YAML indentation/trailing spaces under with: and cleanup heredoc spacing * workflows(nl-suite): fix indentation on docker logs redaction line (YAML lint) * Add write to allowlist * nl-suite: harden reporting discipline (fragment-only writes, forbid alt paths); workflow: clean stray junit-*updated*.xml * nl-suite: enforce end-of-suite single Write (no bash redirection); workflow: restrict allowed_tools to Write+MCP only * prompts(nl-full): end-of-suite results must be valid XML with single <cases> root and only <testcase> children; no raw text outside CDATA * workflows(nl-suite): make Claude step non-fatal; tolerant normalizer extracts <testcase> via regex on bad fragments * nl-suite: fix stale classname to UnityMCP.NL-T in mini fallback; prompt: require re-read after every revert; correct PLAN/PROGRESS to 15 * nl-suite: fix fallback JUnit classname to UnityMCP.NL-T; prompt: forbid create_script and env/mkdir checks, enforce single baseline-byte revert flow and post-revert re-read; add corruption-handling guidance * prompts(nl-full): after each write re-read raw bytes to refresh pre_sha; prefer script_apply_edits for anchors; avoid header/using changes * prompts(nl-full): canonicalize outputs to /; allow small fragment appends via Write or Bash(printf/echo); forbid wrappers and full-file round-trips * prompts(nl-full): finalize markdown formatting for guarded write, execution order, specs, status * workflows(nl-suite, mini): header/lint fixes and constrained Bash append path; align allowed_tools * prompts(nl-full): format Fast Restore, Guarded Write, Execution, Specs, Status as proper markdown lists and code fences * workflows(nl-suite): keep header tidy and append-path alignment with prompt * minor fix * workflows(nl-suite): fix indentation and dispatch; align allowed_tools and revert helper * prompts(nl-full): switch to read_resource for buf/sha; re-read only when needed; convert 'Print this once' to heading; note snapshot helper creates parent dirs * workflows(nl-suite): normalize step removes bootstrap when real testcases present; recompute tests/failures * workflows(nl-suite): enrich Markdown summary by extracting per-test <system-out> blocks (truncated) * clarify prompt resilience instructions * ci(nl-suite): revert prompt and workflow to known-good e0f8a72 for green run; remove extra MD details * ci(nl-suite): minimal fixes — no-mkdir guard in prompt; drop bootstrap and recompute JUnit counts * ci(nl-suite): richer JUnit→Markdown report (per-test system-out) * Small guard to incorret asset read call. * ci(nl-suite): refine MD builder — unescape XML entities, safe code fences, PASS/FAIL badges * Update UnityMcpBridge/UnityMcpServer~/src/tools/resource_tools.py Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update UnityMcpBridge/UnityMcpServer~/src/unity_connection.py Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update UnityMcpBridge/UnityMcpServer~/src/tools/manage_script_edits.py Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update .github/scripts/mark_skipped.py Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update .github/scripts/mark_skipped.py Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update .github/scripts/mark_skipped.py Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> * server(manage_script): robust URI handling — percent-decode file://, normalize, strip host/leading slashes, return Assets-relative if present * Update .claude/prompts/nl-unity-suite-full.md Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> * tests(framing): reduce handshake poll window, nonblocking peek to avoid disconnect race; still enforce pre-handshake data drop * tests(manage_script): add _split_uri tests for unity://path, file:// URLs (decoded/Assets-relative), and plain paths * server+tests: fix handshake syntax error; robust file:// URI normalization in manage_script; add _split_uri tests; adjust stdout scan to ignore venv/site-packages * bridge(framing): accept zero-length frames (treat as empty keepalive) * tests(logging): use errors='replace' on decode fallback to avoid silent drops * resources(list): restrict to Assets/, resolve symlinks, enforce .cs; add traversal/outside-path tests * Update .claude/prompts/nl-unity-suite-full.md Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update UnityMcpBridge/UnityMcpServer~/src/unity_connection.py Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * misc: framing keepalive (zero-length), regex preview consistency, resource.list hardening, URI parsing, legacy update routing, test cleanups * docs(tools): richer MCP tool descriptions; tests accept decorator kwargs; resource URI parsing hardened * Update .claude/prompts/nl-unity-suite-full.md Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update UnityMcpBridge/UnityMcpServer~/src/tools/resource_tools.py Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update UnityMcpBridge/UnityMcpServer~/src/unity_connection.py Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * net+docs: hard-reject zero-length frames; TCP_NODELAY on connect; Assets detection case-insensitive; NL prompt statuses aligned * prompt(nl-suite): constrain Write destinations under reports/, forbid traversal * prompt+net: harden Write path rules; use monotonic deadline and plain-text advisory for non-framed peers * unity_connection: restore recv timeout via try/finally; make global connection getter thread-safe with module lock and double-checked init * NL/T prompt: pin structured edit ops for T-D/T-E; add schema-error guarded write behavior; keep existing path/URI and revert rules * unity_connection: add FRAMED_MAX; use ValueError for framed length violations; lower framed receive log to debug; serialize connect() with per-instance lock * ManageScript: use UTF8Encoding(without BOM) for atomic writes in ApplyTextEdits/EditScript to align with Create/Update and avoid BOM-related diffs/hash mismatches * NL/T prompt: make helper deletion regex multiline-safe ((?ms) so ^ anchors line starts) * ManageScript: emit structured overlap status {status:"overlap"} for overlapping edit ranges in apply_text_edits and edit paths * NL/T prompt: clarify fallback vs failure — fallback only for unsupported/missing_field; treat bad_request as failure; note unsupported after fallback as failure * NL/T prompt: pin deterministic overlap probe (apply_text_edits two ranges from same snapshot); gate too_large behind RUN_TOO_LARGE env hint * TB update * NL/T prompt: harden Output Rules — constrain Bash(printf|echo) to stdout-only; forbid redirection/here-docs/tee; only scripts/nlt-revert.sh may mutate FS * Prompt: enumerate allowed script_apply_edits ops; add manage_editor/read_console guidance; fix T‑F atomic batch to single script_apply_edits. ManageScript: regex timeout for diagnostics; symlink ancestor guard; complete allowed-modes list. * Fixes * ManageScript: add rich overlap diagnostics (conflicts + hint) for both text range and structured batch paths * ManageScript: return structured {status:"validation_failed"} diagnostics in create/update/edits and validate before commit * ManageScript: echo canonical uri in responses (create/read/update/apply_text_edits/structured edits) to reinforce resource identity * improve clarity of capabilities message * Framing: allow zero-length frames on both ends (C# bridge, Python server). Prompt: harden T-F to single text-range apply_text_edits batch (descending order, one snapshot). URI: normalize file:// outside Assets by stripping leading slash. * ManageScript: include new sha256 in success payload for apply_text_edits; harden TryResolveUnderAssets by rejecting symlinked ancestors up to Assets/. * remove claudetest dir * manage_script_edits: normalize method-anchored anchor_insert to insert_method (map text->replacement); improves CI compatibility for T‑A/T‑E without changing Editor behavior. * tighten testing protocol around mkdir * manage_script: validate create_script inputs (Assets/.cs/name/no traversal); add Assets/ guard to delete_script; validate level+Assets in validate_script; make legacy manage_script optional params; harden legacy update routing with base64 reuse and payload size preflight. * Tighten prompt for testing * Update .claude/prompts/nl-unity-suite-full.md Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update .claude/prompts/nl-unity-suite-full.md Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update UnityMcpBridge/Editor/Tools/ManageScript.cs Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * manage_script_edits: honor ignore_case on anchor_insert and regex_replace in both direct and text-conversion paths (MULTILINE|IGNORECASE). * remove extra file * workflow: use python3 for inline scripts and port detection on ubuntu-latest. * Tighten prompt + manage_script * Update UnityMcpBridge/UnityMcpServer~/src/tools/manage_script_edits.py Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update UnityMcpBridge/UnityMcpServer~/src/tools/manage_script_edits.py Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update .claude/prompts/nl-unity-suite-full.md Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update UnityMcpBridge/Editor/Tools/ManageScript.cs Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update .claude/prompts/nl-unity-suite-full.md Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * manage_script: improve file:// UNC handling; preserve POSIX absolute semantics internally; keep test-expected slash stripping for non-Assets paths. * ManageScript.cs: add TimeSpan timeouts to all Regex uses (IsMatch/Match/new Regex) and keep CultureInvariant/Multiline options; reduces risk of catastrophic backtracking stalls. * workflow: ensure reports/ exists in markdown build step to avoid FileNotFoundError when writing MD_OUT. * fix brace * manage_script_edits: expand backrefs for regex_replace in preview->text conversion and translate to \g<n> in local apply; keeps previews and actual edits consistent. * anchor_insert: default to position=after, normalize surrounding newlines in Python conversion paths; C# path ensures trailing newline and skips duplicate insertion within class. * feat(mcp): add get_sha tool; apply_text_edits normalization+overlap preflight+strict; no-op evidence in C#; update NL suite prompt; add unit tests * feat(frames): accept zero-length heartbeat frames in client; add heartbeat test * feat(edits): guard destructive regex_replace with structural preflight; add robust tests; prompt uses delete_method for temp helper * feat(frames): bound heartbeat loop with timeout/threshold; align zero-length response with C#; update test * SDK hardening: atomic multi-span text edits; stop forcing sequential for structured ops; forward options on apply_text_edits; add validate=relaxed support and scoped checks; update NL/T prompt; add tests for options forwarding, relaxed mode, and atomic batches * Router: default applyMode=atomic for multi-span apply_text_edits; add tests * CI prompt: pass options.validate=relaxed for T-B/C; options.applyMode=atomic for T-F; emphasize always writing testcase and restoring on errors * Validation & DX: add validate=syntax (scoped), standardize evidence windows; early regex compile with hints; debug_preview for apply_text_edits * Update UnityMcpBridge/Editor/Windows/MCPForUnityEditorWindow.cs Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * NL/T suite-driven edits: LongUnityScriptClaudeTest, bridge helpers, server_version; prepare framing tests * Fix duplicate macConfigPath field in McpClient to resolve CS0102 * Editor threading: run EnsureServerInstalled on main thread; marshal EditorPrefs/DeleteKey + logging via delayCall * Docs(apply_text_edits): strengthen guidance on 1-based positions, verify-before-edit, and recommend anchors/structured edits * Docs(script_apply_edits): add safety guidance (anchors, method ops, validators) and recommended practices * Framed VerifyBridgePing in editor window; docs hardening for apply_text_edits and script_apply_edits --------- Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
2025-08-31 00:55:38 +08:00
return Response.Error("validation_failed", new { status = "validation_failed", diagnostics = validationErrors ?? Array.Empty<string>() });
}
else if (validationErrors != null && validationErrors.Length > 0)
2025-03-31 03:58:01 +08:00
{
// Log warnings but don't block creation
Debug.LogWarning($"Script validation warnings for {name}:\n" + string.Join("\n", validationErrors));
2025-03-31 03:58:01 +08:00
}
try
{
Claude‑friendly edit tools + framed transport + live Unity NL test framework (#243) * CI: gate desktop-parity on Anthropic key; pass anthropic_api_key like NL suite * Add quickprobe prompt and CI workflow (mcp-quickprobe.md, unity-mcp-quickprobe.yml) * strictier tool use to prevent subagent spawning and force mcp tools * update workflow filesto reduce likelihood of subagent spawning * improve permissions for claude agent, fix mcpbridge timeout/token issue * increase max turns to 10 * ci: align NL suite to new permissions schema; prevent subagent drift * ci: NL suite -> mini prompt for e2e; add full NL/T prompt; server: ctx optional + project_root fallback; workflows: set UNITY_PROJECT_ROOT for CI * ci: add checks:write; revert local project hardcodes (manifest, ProjectVersion.txt) * tools: text-edit routing fixes (anchor_insert via text, CRLF calc); prompts: mini NL/T clarifications * ci: use absolute UNITY_PROJECT_ROOT; prompts target TestProjects; server: accept relative UNITY_PROJECT_ROOT and bare spec URI * ci: ignore Unity test project's packages-lock.json; remove from repo to avoid absolute paths * CI: start persistent Unity Editor for MCP (guarded by license) + allow batch-mode bridge via UNITY_MCP_ALLOW_BATCH * CI: hide license and pass via env to docker; fix invalid ref format * CI: readiness probe uses handshake on Unity MCP port (deterministic) * CI: fix YAML; use TCP handshake readiness probe (FRAMING=1) * CI: prime Unity license via game-ci; mount ULF into container; extend readiness timeout * CI: use ULF write + mount for Unity licensing; remove serial/email/pass from container * CI: entitlement activation (UNITY_SERIAL=''); verify host ULF cache; keep mount * CI: write ULF from secret and verify; drop entitlement activation step * CI: detect any licensing path; GameCI prime; status dir env; log+probe readiness; fix YAML * CI: add GameCI license prime; conditional ULF write; one-shot license validation; explicit status dir + license env * CI: fix YAML (inline python), add Anthropic key detect via GITHUB_ENV; ready to run happy path * CI: mount Unity token/ulf/cache dirs into container to share host license; create dirs before start * CI: fix YAML indentation; write ULF on host; activate in container with shared mounts; mount .config and .cache too * CI: gate Claude via outputs; mount all Unity license dirs; fix inline probe python; stabilize licensing flow * CI: normalize detect to step outputs; ensure license dirs mounted and validated; fix indentation * Bridge: honor UNITY_MCP_STATUS_DIR for heartbeat/status file (CI-friendly) * CI: guard project path for activation/start; align tool allowlist; run MCP server with python; tighten secret scoping * CI: finalize Unity licensing mounts + status dir; mode-detect (ULF/EBL); readiness logs+probe; Claude gating via outputs * CI: fix YAML probe (inline python -c) and finalize happy-path Unity licensing and MCP/Claude wiring * CI: inline python probe; unify Unity image and cache mounts; ready to test * CI: fix docker run IMAGE placement; ignore cache find perms; keep same editor image * CI: pass -manualLicenseFile to persistent Editor; keep mounts and single image * CI: mount full GameCI cache to /root in persistent Unity; set HOME=/root; add optional license check * CI: make -manualLicenseFile conditional; keep full /root mount and license check * CI: set HOME=/github/home; mount GameCI cache there; adjust manualLicenseFile path; expand license check * CI: EBL sign-in for persistent Unity (email/password/serial); revert HOME=/root and full /root mount; keep conditional manualLicenseFile and improved readiness * CI: run full NL/T suite prompt (nl-unity-suite-full.md) instead of mini * NL/T: require unified diffs + explicit verdicts in JUnit; CI: remove short sanity step, publish JUnit, upload artifacts * NL/T prompt: require CDATA wrapping for JUnit XML fields; guidance for splitting embedded ]]>; keep VERDICT in CDATA only * CI: remove in-container license check step; keep readiness and full suite * NL/T prompt: add version header, stricter JUnit schema, hashing/normalization, anchors, statuses, atomic semantics, tool logging * CI: increase Claude NL/T suite timeout to 30 minutes * CI: pre-create reports dir and result files to avoid tool approval prompts * CI: skip wait if container not running; skip Editor start if project missing; broaden MCP deps detection; expand allowed tools * fixies to harden ManageScript * CI: sanitize NL/T markdown report to avoid NUL/encoding issues * revert breaking yyaml changes * CI: prime license, robust Unity start/wait, sanitize markdown via heredoc * Resolve merge: accept upstream renames/installer (fix/installer-cleanup-v2) and keep local framing/script-editing - Restored upstream server.py, EditorWindow, uv.lock\n- Preserved ManageScript editing/validation; switched to atomic write + debounced refresh\n- Updated tools/__init__.py to keep script_edits/resources and adopt new logger name\n- All Python tests via uv: 7 passed, 6 skipped, 9 xpassed; Unity compile OK * Fix Claude Desktop config path and atomic write issues - Fix macOS path for Claude Desktop config: use ~/Library/Application Support/Claude/ instead of ~/.config/Claude/ - Improve atomic write pattern with backup/restore safety - Replace File.Replace() with File.Move() for better macOS compatibility - Add proper error handling and cleanup for file operations - Resolves issue where installer couldn't find Claude Desktop config on macOS * Editor: use macConfigPath on macOS for MCP client config writes (Claude Desktop, etc.). Fallback to linuxConfigPath only if mac path missing. * Models: add macConfigPath to McpClient for macOS config path selection (fixes CS1061 in editor window). * Editor: on macOS, prefer macConfigPath in ManualConfigEditorWindow (fallback to linux path); Linux/Windows unchanged. * Fix McpClient: align with upstream/main, prep for framing split * NL suite: shard workflow; tighten bridge readiness; add MCP preflight; use env-based shard vars * NL suite: fix shard step indentation; move shard vars to env; remove invalid inputs * MCP clients: split VSCode Copilot config paths into macConfigPath and linuxConfigPath * Unity bridge: clean stale status; bind host; robust wait probe with IPv4/IPv6 + diagnostics * CI: use MCPForUnity.Editor.MCPForUnityBridge.StartAutoConnect as executeMethod * Action wiring: inline mcpServers in settings for all shards; remove redundant .claude/mcp.json step * CI: embed mcpServers in settings for all shards; fix startup sanity step; lint clean * CI: pin claude-code-base-action to e6f32c8; use claude_args --mcp-config; switch to allowed_tools; ensure MCP config per step * CI: unpin claude-code-base-action to @beta (commit ref not found) * CI: align with claude-code-base-action @beta; pass MCP via claude_args and allowedTools * Editor: Fix apply_text_edits heuristic when edits shift positions; recompute method span on candidate text with fallback delta adjustment * CI: unify MCP wiring across workflows; write .claude/mcp.json; switch to claude_args with --mcp-config/--allowedTools; remove unsupported inputs * CI: collapse NL suite shards into a single run to avoid repeated test execution * CI: minimize allowedTools for NL suite to essential Unity MCP + Bash("git:*") + Write * CI: mkdir -p reports before run; remove unsupported --timeout-minutes from claude_args * CI: broaden allowedTools to include find_in_file and mcp__unity__* * CI: enable use_node_cache and switch NL suite model to claude-3-7-haiku-20250219 * CI: disable use_node_cache to avoid setup-node lockfile error * CI: set NL suite model to claude-3-haiku-20240307 * CI: cap Haiku output with --max-tokens 2048 for NL suite * CI: switch to claude-3-7-sonnet-latest and remove unsupported --max-tokens * CI: update allowedTools to Bash(*) and explicit Unity MCP tool list * CI: update NL suite workflow (latest tweaks) * Tests: tighten NL suite prompt for logging, hash discipline, stale retry, evidence windows, diff cap, and VERDICT line * Add disallowed tools to NL suite workflow * docs: clarify stale write retry * Add fallback JUnit report and adjust publisher * Indent fallback JUnit XML in workflow * fix: correct fallback JUnit report generation * Update mcp-quickprobe.md Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> * Update mcp-quickprobe.md Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> * Update Response.cs Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> * Update MCPForUnityBridge.cs Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> * fix: correct McpTypes reference * Add directory existence checks for symlink and XDG paths * fix: only set installation flag after successful server install * Update resource_tools.py Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> * fix: respect mac config paths * Use File.Replace for atomic config write * Remove unused imports in manage_script * bump server version * Tests: update NL suite prompt and workflows; remove deprecated smoke/desktop-parity; quickprobe tidy * Editor: atomic config write via File.Replace fallback; remove redundant backups and racey exists checks * CI: harden NL suite - idempotent docker, gate on unity_ok, safer port probe, least-priv perms * Editor: make atomic config write restoration safe (flag writeDone; copy-overwrite restore; cleanup in finally) * CI: fix fallback JUnit heredoc by using printf lines (no EOF delimiter issues) * CI: switch NL suite to mini prompt; mini prompt honors / and NL discipline * CI: replace claude_args with allowed_tools/model/mcp_config per action schema * CI: expand UNITY_PROJECT_ROOT via in MCP config heredoc * EditorWindow: add cross-platform fallback for File.Replace; macOS-insensitive PathsEqual; safer uv resolve; honor macConfigPath * CI: strengthen JUnit publishing for NL mini suite (normalize, debug list, publish both, fail_on_parse_error) * CI: set job-wide JUNIT_OUT/MD_OUT; normalization uses env; publish references env and ungroup reports * CI: publish a single normalized JUnit (reports/junit-for-actions.xml); fallback writes same; avoid checkName/reportPaths mismatch * CI: align mini prompt report filenames; redact Unity log tail in diagnostics * chore: sync workflow and mini prompt; redacted logs; JUnit normalization/publish tweaks * CI: redact sensitive tokens in Stop Unity; docs: CI usage + edit tools * prompts: update nl-unity-suite-full (mini-style setup + reporting discipline); remove obsolete prompts * CI: harden NL workflows (timeout_minutes, robust normalization); prompts: unify JUnit suite name and reporting discipline * prompts: add guarded write pattern (LF hash, stale_file retry) to full suite * prompts: enforce continue-on-failure, driver flow, and status handling in full suite * Make test list more explicit in prompt. Get rid of old test prompts for hygeine. * prompts: add stale fast-retry (server hash) + in-memory buf guidance * CI: standardize JUNIT_OUT to reports/junit-nl-suite.xml; fix artifact upload indentation; prompt copy cleanups * prompts: reporting discipline — append-only fragments, batch writes, no model round-trip * prompts: stale fast-retry preference, buffer/sha carry, snapshot revert, essential logging * workflows(nl-suite): precreate report skeletons, assemble junit, synthesize markdown; restrict allowed_tools to append-only Bash + MCP tools * thsis too * Update README-DEV.md Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update .github/workflows/claude-nl-suite-mini.yml Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update .github/workflows/claude-nl-suite.yml Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * workflows(nl-mini): fix YAML indentation/trailing spaces under with: and cleanup heredoc spacing * workflows(nl-suite): fix indentation on docker logs redaction line (YAML lint) * Add write to allowlist * nl-suite: harden reporting discipline (fragment-only writes, forbid alt paths); workflow: clean stray junit-*updated*.xml * nl-suite: enforce end-of-suite single Write (no bash redirection); workflow: restrict allowed_tools to Write+MCP only * prompts(nl-full): end-of-suite results must be valid XML with single <cases> root and only <testcase> children; no raw text outside CDATA * workflows(nl-suite): make Claude step non-fatal; tolerant normalizer extracts <testcase> via regex on bad fragments * nl-suite: fix stale classname to UnityMCP.NL-T in mini fallback; prompt: require re-read after every revert; correct PLAN/PROGRESS to 15 * nl-suite: fix fallback JUnit classname to UnityMCP.NL-T; prompt: forbid create_script and env/mkdir checks, enforce single baseline-byte revert flow and post-revert re-read; add corruption-handling guidance * prompts(nl-full): after each write re-read raw bytes to refresh pre_sha; prefer script_apply_edits for anchors; avoid header/using changes * prompts(nl-full): canonicalize outputs to /; allow small fragment appends via Write or Bash(printf/echo); forbid wrappers and full-file round-trips * prompts(nl-full): finalize markdown formatting for guarded write, execution order, specs, status * workflows(nl-suite, mini): header/lint fixes and constrained Bash append path; align allowed_tools * prompts(nl-full): format Fast Restore, Guarded Write, Execution, Specs, Status as proper markdown lists and code fences * workflows(nl-suite): keep header tidy and append-path alignment with prompt * minor fix * workflows(nl-suite): fix indentation and dispatch; align allowed_tools and revert helper * prompts(nl-full): switch to read_resource for buf/sha; re-read only when needed; convert 'Print this once' to heading; note snapshot helper creates parent dirs * workflows(nl-suite): normalize step removes bootstrap when real testcases present; recompute tests/failures * workflows(nl-suite): enrich Markdown summary by extracting per-test <system-out> blocks (truncated) * clarify prompt resilience instructions * ci(nl-suite): revert prompt and workflow to known-good e0f8a72 for green run; remove extra MD details * ci(nl-suite): minimal fixes — no-mkdir guard in prompt; drop bootstrap and recompute JUnit counts * ci(nl-suite): richer JUnit→Markdown report (per-test system-out) * Small guard to incorret asset read call. * ci(nl-suite): refine MD builder — unescape XML entities, safe code fences, PASS/FAIL badges * Update UnityMcpBridge/UnityMcpServer~/src/tools/resource_tools.py Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update UnityMcpBridge/UnityMcpServer~/src/unity_connection.py Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update UnityMcpBridge/UnityMcpServer~/src/tools/manage_script_edits.py Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update .github/scripts/mark_skipped.py Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update .github/scripts/mark_skipped.py Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update .github/scripts/mark_skipped.py Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> * server(manage_script): robust URI handling — percent-decode file://, normalize, strip host/leading slashes, return Assets-relative if present * Update .claude/prompts/nl-unity-suite-full.md Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> * tests(framing): reduce handshake poll window, nonblocking peek to avoid disconnect race; still enforce pre-handshake data drop * tests(manage_script): add _split_uri tests for unity://path, file:// URLs (decoded/Assets-relative), and plain paths * server+tests: fix handshake syntax error; robust file:// URI normalization in manage_script; add _split_uri tests; adjust stdout scan to ignore venv/site-packages * bridge(framing): accept zero-length frames (treat as empty keepalive) * tests(logging): use errors='replace' on decode fallback to avoid silent drops * resources(list): restrict to Assets/, resolve symlinks, enforce .cs; add traversal/outside-path tests * Update .claude/prompts/nl-unity-suite-full.md Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update UnityMcpBridge/UnityMcpServer~/src/unity_connection.py Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * misc: framing keepalive (zero-length), regex preview consistency, resource.list hardening, URI parsing, legacy update routing, test cleanups * docs(tools): richer MCP tool descriptions; tests accept decorator kwargs; resource URI parsing hardened * Update .claude/prompts/nl-unity-suite-full.md Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update UnityMcpBridge/UnityMcpServer~/src/tools/resource_tools.py Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update UnityMcpBridge/UnityMcpServer~/src/unity_connection.py Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * net+docs: hard-reject zero-length frames; TCP_NODELAY on connect; Assets detection case-insensitive; NL prompt statuses aligned * prompt(nl-suite): constrain Write destinations under reports/, forbid traversal * prompt+net: harden Write path rules; use monotonic deadline and plain-text advisory for non-framed peers * unity_connection: restore recv timeout via try/finally; make global connection getter thread-safe with module lock and double-checked init * NL/T prompt: pin structured edit ops for T-D/T-E; add schema-error guarded write behavior; keep existing path/URI and revert rules * unity_connection: add FRAMED_MAX; use ValueError for framed length violations; lower framed receive log to debug; serialize connect() with per-instance lock * ManageScript: use UTF8Encoding(without BOM) for atomic writes in ApplyTextEdits/EditScript to align with Create/Update and avoid BOM-related diffs/hash mismatches * NL/T prompt: make helper deletion regex multiline-safe ((?ms) so ^ anchors line starts) * ManageScript: emit structured overlap status {status:"overlap"} for overlapping edit ranges in apply_text_edits and edit paths * NL/T prompt: clarify fallback vs failure — fallback only for unsupported/missing_field; treat bad_request as failure; note unsupported after fallback as failure * NL/T prompt: pin deterministic overlap probe (apply_text_edits two ranges from same snapshot); gate too_large behind RUN_TOO_LARGE env hint * TB update * NL/T prompt: harden Output Rules — constrain Bash(printf|echo) to stdout-only; forbid redirection/here-docs/tee; only scripts/nlt-revert.sh may mutate FS * Prompt: enumerate allowed script_apply_edits ops; add manage_editor/read_console guidance; fix T‑F atomic batch to single script_apply_edits. ManageScript: regex timeout for diagnostics; symlink ancestor guard; complete allowed-modes list. * Fixes * ManageScript: add rich overlap diagnostics (conflicts + hint) for both text range and structured batch paths * ManageScript: return structured {status:"validation_failed"} diagnostics in create/update/edits and validate before commit * ManageScript: echo canonical uri in responses (create/read/update/apply_text_edits/structured edits) to reinforce resource identity * improve clarity of capabilities message * Framing: allow zero-length frames on both ends (C# bridge, Python server). Prompt: harden T-F to single text-range apply_text_edits batch (descending order, one snapshot). URI: normalize file:// outside Assets by stripping leading slash. * ManageScript: include new sha256 in success payload for apply_text_edits; harden TryResolveUnderAssets by rejecting symlinked ancestors up to Assets/. * remove claudetest dir * manage_script_edits: normalize method-anchored anchor_insert to insert_method (map text->replacement); improves CI compatibility for T‑A/T‑E without changing Editor behavior. * tighten testing protocol around mkdir * manage_script: validate create_script inputs (Assets/.cs/name/no traversal); add Assets/ guard to delete_script; validate level+Assets in validate_script; make legacy manage_script optional params; harden legacy update routing with base64 reuse and payload size preflight. * Tighten prompt for testing * Update .claude/prompts/nl-unity-suite-full.md Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update .claude/prompts/nl-unity-suite-full.md Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update UnityMcpBridge/Editor/Tools/ManageScript.cs Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * manage_script_edits: honor ignore_case on anchor_insert and regex_replace in both direct and text-conversion paths (MULTILINE|IGNORECASE). * remove extra file * workflow: use python3 for inline scripts and port detection on ubuntu-latest. * Tighten prompt + manage_script * Update UnityMcpBridge/UnityMcpServer~/src/tools/manage_script_edits.py Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update UnityMcpBridge/UnityMcpServer~/src/tools/manage_script_edits.py Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update .claude/prompts/nl-unity-suite-full.md Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update UnityMcpBridge/Editor/Tools/ManageScript.cs Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update .claude/prompts/nl-unity-suite-full.md Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * manage_script: improve file:// UNC handling; preserve POSIX absolute semantics internally; keep test-expected slash stripping for non-Assets paths. * ManageScript.cs: add TimeSpan timeouts to all Regex uses (IsMatch/Match/new Regex) and keep CultureInvariant/Multiline options; reduces risk of catastrophic backtracking stalls. * workflow: ensure reports/ exists in markdown build step to avoid FileNotFoundError when writing MD_OUT. * fix brace * manage_script_edits: expand backrefs for regex_replace in preview->text conversion and translate to \g<n> in local apply; keeps previews and actual edits consistent. * anchor_insert: default to position=after, normalize surrounding newlines in Python conversion paths; C# path ensures trailing newline and skips duplicate insertion within class. * feat(mcp): add get_sha tool; apply_text_edits normalization+overlap preflight+strict; no-op evidence in C#; update NL suite prompt; add unit tests * feat(frames): accept zero-length heartbeat frames in client; add heartbeat test * feat(edits): guard destructive regex_replace with structural preflight; add robust tests; prompt uses delete_method for temp helper * feat(frames): bound heartbeat loop with timeout/threshold; align zero-length response with C#; update test * SDK hardening: atomic multi-span text edits; stop forcing sequential for structured ops; forward options on apply_text_edits; add validate=relaxed support and scoped checks; update NL/T prompt; add tests for options forwarding, relaxed mode, and atomic batches * Router: default applyMode=atomic for multi-span apply_text_edits; add tests * CI prompt: pass options.validate=relaxed for T-B/C; options.applyMode=atomic for T-F; emphasize always writing testcase and restoring on errors * Validation & DX: add validate=syntax (scoped), standardize evidence windows; early regex compile with hints; debug_preview for apply_text_edits * Update UnityMcpBridge/Editor/Windows/MCPForUnityEditorWindow.cs Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * NL/T suite-driven edits: LongUnityScriptClaudeTest, bridge helpers, server_version; prepare framing tests * Fix duplicate macConfigPath field in McpClient to resolve CS0102 * Editor threading: run EnsureServerInstalled on main thread; marshal EditorPrefs/DeleteKey + logging via delayCall * Docs(apply_text_edits): strengthen guidance on 1-based positions, verify-before-edit, and recommend anchors/structured edits * Docs(script_apply_edits): add safety guidance (anchors, method ops, validators) and recommended practices * Framed VerifyBridgePing in editor window; docs hardening for apply_text_edits and script_apply_edits --------- Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
2025-08-31 00:55:38 +08:00
// Atomic create without BOM; schedule refresh after reply
var enc = new System.Text.UTF8Encoding(encoderShouldEmitUTF8Identifier: false);
var tmp = fullPath + ".tmp";
File.WriteAllText(tmp, contents, enc);
try
{
File.Move(tmp, fullPath);
}
catch (IOException)
{
File.Copy(tmp, fullPath, overwrite: true);
try { File.Delete(tmp); } catch { }
}
var uri = $"unity://path/{relativePath}";
var ok = Response.Success(
$"Script '{name}.cs' created successfully at '{relativePath}'.",
Claude‑friendly edit tools + framed transport + live Unity NL test framework (#243) * CI: gate desktop-parity on Anthropic key; pass anthropic_api_key like NL suite * Add quickprobe prompt and CI workflow (mcp-quickprobe.md, unity-mcp-quickprobe.yml) * strictier tool use to prevent subagent spawning and force mcp tools * update workflow filesto reduce likelihood of subagent spawning * improve permissions for claude agent, fix mcpbridge timeout/token issue * increase max turns to 10 * ci: align NL suite to new permissions schema; prevent subagent drift * ci: NL suite -> mini prompt for e2e; add full NL/T prompt; server: ctx optional + project_root fallback; workflows: set UNITY_PROJECT_ROOT for CI * ci: add checks:write; revert local project hardcodes (manifest, ProjectVersion.txt) * tools: text-edit routing fixes (anchor_insert via text, CRLF calc); prompts: mini NL/T clarifications * ci: use absolute UNITY_PROJECT_ROOT; prompts target TestProjects; server: accept relative UNITY_PROJECT_ROOT and bare spec URI * ci: ignore Unity test project's packages-lock.json; remove from repo to avoid absolute paths * CI: start persistent Unity Editor for MCP (guarded by license) + allow batch-mode bridge via UNITY_MCP_ALLOW_BATCH * CI: hide license and pass via env to docker; fix invalid ref format * CI: readiness probe uses handshake on Unity MCP port (deterministic) * CI: fix YAML; use TCP handshake readiness probe (FRAMING=1) * CI: prime Unity license via game-ci; mount ULF into container; extend readiness timeout * CI: use ULF write + mount for Unity licensing; remove serial/email/pass from container * CI: entitlement activation (UNITY_SERIAL=''); verify host ULF cache; keep mount * CI: write ULF from secret and verify; drop entitlement activation step * CI: detect any licensing path; GameCI prime; status dir env; log+probe readiness; fix YAML * CI: add GameCI license prime; conditional ULF write; one-shot license validation; explicit status dir + license env * CI: fix YAML (inline python), add Anthropic key detect via GITHUB_ENV; ready to run happy path * CI: mount Unity token/ulf/cache dirs into container to share host license; create dirs before start * CI: fix YAML indentation; write ULF on host; activate in container with shared mounts; mount .config and .cache too * CI: gate Claude via outputs; mount all Unity license dirs; fix inline probe python; stabilize licensing flow * CI: normalize detect to step outputs; ensure license dirs mounted and validated; fix indentation * Bridge: honor UNITY_MCP_STATUS_DIR for heartbeat/status file (CI-friendly) * CI: guard project path for activation/start; align tool allowlist; run MCP server with python; tighten secret scoping * CI: finalize Unity licensing mounts + status dir; mode-detect (ULF/EBL); readiness logs+probe; Claude gating via outputs * CI: fix YAML probe (inline python -c) and finalize happy-path Unity licensing and MCP/Claude wiring * CI: inline python probe; unify Unity image and cache mounts; ready to test * CI: fix docker run IMAGE placement; ignore cache find perms; keep same editor image * CI: pass -manualLicenseFile to persistent Editor; keep mounts and single image * CI: mount full GameCI cache to /root in persistent Unity; set HOME=/root; add optional license check * CI: make -manualLicenseFile conditional; keep full /root mount and license check * CI: set HOME=/github/home; mount GameCI cache there; adjust manualLicenseFile path; expand license check * CI: EBL sign-in for persistent Unity (email/password/serial); revert HOME=/root and full /root mount; keep conditional manualLicenseFile and improved readiness * CI: run full NL/T suite prompt (nl-unity-suite-full.md) instead of mini * NL/T: require unified diffs + explicit verdicts in JUnit; CI: remove short sanity step, publish JUnit, upload artifacts * NL/T prompt: require CDATA wrapping for JUnit XML fields; guidance for splitting embedded ]]>; keep VERDICT in CDATA only * CI: remove in-container license check step; keep readiness and full suite * NL/T prompt: add version header, stricter JUnit schema, hashing/normalization, anchors, statuses, atomic semantics, tool logging * CI: increase Claude NL/T suite timeout to 30 minutes * CI: pre-create reports dir and result files to avoid tool approval prompts * CI: skip wait if container not running; skip Editor start if project missing; broaden MCP deps detection; expand allowed tools * fixies to harden ManageScript * CI: sanitize NL/T markdown report to avoid NUL/encoding issues * revert breaking yyaml changes * CI: prime license, robust Unity start/wait, sanitize markdown via heredoc * Resolve merge: accept upstream renames/installer (fix/installer-cleanup-v2) and keep local framing/script-editing - Restored upstream server.py, EditorWindow, uv.lock\n- Preserved ManageScript editing/validation; switched to atomic write + debounced refresh\n- Updated tools/__init__.py to keep script_edits/resources and adopt new logger name\n- All Python tests via uv: 7 passed, 6 skipped, 9 xpassed; Unity compile OK * Fix Claude Desktop config path and atomic write issues - Fix macOS path for Claude Desktop config: use ~/Library/Application Support/Claude/ instead of ~/.config/Claude/ - Improve atomic write pattern with backup/restore safety - Replace File.Replace() with File.Move() for better macOS compatibility - Add proper error handling and cleanup for file operations - Resolves issue where installer couldn't find Claude Desktop config on macOS * Editor: use macConfigPath on macOS for MCP client config writes (Claude Desktop, etc.). Fallback to linuxConfigPath only if mac path missing. * Models: add macConfigPath to McpClient for macOS config path selection (fixes CS1061 in editor window). * Editor: on macOS, prefer macConfigPath in ManualConfigEditorWindow (fallback to linux path); Linux/Windows unchanged. * Fix McpClient: align with upstream/main, prep for framing split * NL suite: shard workflow; tighten bridge readiness; add MCP preflight; use env-based shard vars * NL suite: fix shard step indentation; move shard vars to env; remove invalid inputs * MCP clients: split VSCode Copilot config paths into macConfigPath and linuxConfigPath * Unity bridge: clean stale status; bind host; robust wait probe with IPv4/IPv6 + diagnostics * CI: use MCPForUnity.Editor.MCPForUnityBridge.StartAutoConnect as executeMethod * Action wiring: inline mcpServers in settings for all shards; remove redundant .claude/mcp.json step * CI: embed mcpServers in settings for all shards; fix startup sanity step; lint clean * CI: pin claude-code-base-action to e6f32c8; use claude_args --mcp-config; switch to allowed_tools; ensure MCP config per step * CI: unpin claude-code-base-action to @beta (commit ref not found) * CI: align with claude-code-base-action @beta; pass MCP via claude_args and allowedTools * Editor: Fix apply_text_edits heuristic when edits shift positions; recompute method span on candidate text with fallback delta adjustment * CI: unify MCP wiring across workflows; write .claude/mcp.json; switch to claude_args with --mcp-config/--allowedTools; remove unsupported inputs * CI: collapse NL suite shards into a single run to avoid repeated test execution * CI: minimize allowedTools for NL suite to essential Unity MCP + Bash("git:*") + Write * CI: mkdir -p reports before run; remove unsupported --timeout-minutes from claude_args * CI: broaden allowedTools to include find_in_file and mcp__unity__* * CI: enable use_node_cache and switch NL suite model to claude-3-7-haiku-20250219 * CI: disable use_node_cache to avoid setup-node lockfile error * CI: set NL suite model to claude-3-haiku-20240307 * CI: cap Haiku output with --max-tokens 2048 for NL suite * CI: switch to claude-3-7-sonnet-latest and remove unsupported --max-tokens * CI: update allowedTools to Bash(*) and explicit Unity MCP tool list * CI: update NL suite workflow (latest tweaks) * Tests: tighten NL suite prompt for logging, hash discipline, stale retry, evidence windows, diff cap, and VERDICT line * Add disallowed tools to NL suite workflow * docs: clarify stale write retry * Add fallback JUnit report and adjust publisher * Indent fallback JUnit XML in workflow * fix: correct fallback JUnit report generation * Update mcp-quickprobe.md Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> * Update mcp-quickprobe.md Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> * Update Response.cs Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> * Update MCPForUnityBridge.cs Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> * fix: correct McpTypes reference * Add directory existence checks for symlink and XDG paths * fix: only set installation flag after successful server install * Update resource_tools.py Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> * fix: respect mac config paths * Use File.Replace for atomic config write * Remove unused imports in manage_script * bump server version * Tests: update NL suite prompt and workflows; remove deprecated smoke/desktop-parity; quickprobe tidy * Editor: atomic config write via File.Replace fallback; remove redundant backups and racey exists checks * CI: harden NL suite - idempotent docker, gate on unity_ok, safer port probe, least-priv perms * Editor: make atomic config write restoration safe (flag writeDone; copy-overwrite restore; cleanup in finally) * CI: fix fallback JUnit heredoc by using printf lines (no EOF delimiter issues) * CI: switch NL suite to mini prompt; mini prompt honors / and NL discipline * CI: replace claude_args with allowed_tools/model/mcp_config per action schema * CI: expand UNITY_PROJECT_ROOT via in MCP config heredoc * EditorWindow: add cross-platform fallback for File.Replace; macOS-insensitive PathsEqual; safer uv resolve; honor macConfigPath * CI: strengthen JUnit publishing for NL mini suite (normalize, debug list, publish both, fail_on_parse_error) * CI: set job-wide JUNIT_OUT/MD_OUT; normalization uses env; publish references env and ungroup reports * CI: publish a single normalized JUnit (reports/junit-for-actions.xml); fallback writes same; avoid checkName/reportPaths mismatch * CI: align mini prompt report filenames; redact Unity log tail in diagnostics * chore: sync workflow and mini prompt; redacted logs; JUnit normalization/publish tweaks * CI: redact sensitive tokens in Stop Unity; docs: CI usage + edit tools * prompts: update nl-unity-suite-full (mini-style setup + reporting discipline); remove obsolete prompts * CI: harden NL workflows (timeout_minutes, robust normalization); prompts: unify JUnit suite name and reporting discipline * prompts: add guarded write pattern (LF hash, stale_file retry) to full suite * prompts: enforce continue-on-failure, driver flow, and status handling in full suite * Make test list more explicit in prompt. Get rid of old test prompts for hygeine. * prompts: add stale fast-retry (server hash) + in-memory buf guidance * CI: standardize JUNIT_OUT to reports/junit-nl-suite.xml; fix artifact upload indentation; prompt copy cleanups * prompts: reporting discipline — append-only fragments, batch writes, no model round-trip * prompts: stale fast-retry preference, buffer/sha carry, snapshot revert, essential logging * workflows(nl-suite): precreate report skeletons, assemble junit, synthesize markdown; restrict allowed_tools to append-only Bash + MCP tools * thsis too * Update README-DEV.md Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update .github/workflows/claude-nl-suite-mini.yml Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update .github/workflows/claude-nl-suite.yml Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * workflows(nl-mini): fix YAML indentation/trailing spaces under with: and cleanup heredoc spacing * workflows(nl-suite): fix indentation on docker logs redaction line (YAML lint) * Add write to allowlist * nl-suite: harden reporting discipline (fragment-only writes, forbid alt paths); workflow: clean stray junit-*updated*.xml * nl-suite: enforce end-of-suite single Write (no bash redirection); workflow: restrict allowed_tools to Write+MCP only * prompts(nl-full): end-of-suite results must be valid XML with single <cases> root and only <testcase> children; no raw text outside CDATA * workflows(nl-suite): make Claude step non-fatal; tolerant normalizer extracts <testcase> via regex on bad fragments * nl-suite: fix stale classname to UnityMCP.NL-T in mini fallback; prompt: require re-read after every revert; correct PLAN/PROGRESS to 15 * nl-suite: fix fallback JUnit classname to UnityMCP.NL-T; prompt: forbid create_script and env/mkdir checks, enforce single baseline-byte revert flow and post-revert re-read; add corruption-handling guidance * prompts(nl-full): after each write re-read raw bytes to refresh pre_sha; prefer script_apply_edits for anchors; avoid header/using changes * prompts(nl-full): canonicalize outputs to /; allow small fragment appends via Write or Bash(printf/echo); forbid wrappers and full-file round-trips * prompts(nl-full): finalize markdown formatting for guarded write, execution order, specs, status * workflows(nl-suite, mini): header/lint fixes and constrained Bash append path; align allowed_tools * prompts(nl-full): format Fast Restore, Guarded Write, Execution, Specs, Status as proper markdown lists and code fences * workflows(nl-suite): keep header tidy and append-path alignment with prompt * minor fix * workflows(nl-suite): fix indentation and dispatch; align allowed_tools and revert helper * prompts(nl-full): switch to read_resource for buf/sha; re-read only when needed; convert 'Print this once' to heading; note snapshot helper creates parent dirs * workflows(nl-suite): normalize step removes bootstrap when real testcases present; recompute tests/failures * workflows(nl-suite): enrich Markdown summary by extracting per-test <system-out> blocks (truncated) * clarify prompt resilience instructions * ci(nl-suite): revert prompt and workflow to known-good e0f8a72 for green run; remove extra MD details * ci(nl-suite): minimal fixes — no-mkdir guard in prompt; drop bootstrap and recompute JUnit counts * ci(nl-suite): richer JUnit→Markdown report (per-test system-out) * Small guard to incorret asset read call. * ci(nl-suite): refine MD builder — unescape XML entities, safe code fences, PASS/FAIL badges * Update UnityMcpBridge/UnityMcpServer~/src/tools/resource_tools.py Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update UnityMcpBridge/UnityMcpServer~/src/unity_connection.py Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update UnityMcpBridge/UnityMcpServer~/src/tools/manage_script_edits.py Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update .github/scripts/mark_skipped.py Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update .github/scripts/mark_skipped.py Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update .github/scripts/mark_skipped.py Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> * server(manage_script): robust URI handling — percent-decode file://, normalize, strip host/leading slashes, return Assets-relative if present * Update .claude/prompts/nl-unity-suite-full.md Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> * tests(framing): reduce handshake poll window, nonblocking peek to avoid disconnect race; still enforce pre-handshake data drop * tests(manage_script): add _split_uri tests for unity://path, file:// URLs (decoded/Assets-relative), and plain paths * server+tests: fix handshake syntax error; robust file:// URI normalization in manage_script; add _split_uri tests; adjust stdout scan to ignore venv/site-packages * bridge(framing): accept zero-length frames (treat as empty keepalive) * tests(logging): use errors='replace' on decode fallback to avoid silent drops * resources(list): restrict to Assets/, resolve symlinks, enforce .cs; add traversal/outside-path tests * Update .claude/prompts/nl-unity-suite-full.md Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update UnityMcpBridge/UnityMcpServer~/src/unity_connection.py Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * misc: framing keepalive (zero-length), regex preview consistency, resource.list hardening, URI parsing, legacy update routing, test cleanups * docs(tools): richer MCP tool descriptions; tests accept decorator kwargs; resource URI parsing hardened * Update .claude/prompts/nl-unity-suite-full.md Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update UnityMcpBridge/UnityMcpServer~/src/tools/resource_tools.py Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update UnityMcpBridge/UnityMcpServer~/src/unity_connection.py Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * net+docs: hard-reject zero-length frames; TCP_NODELAY on connect; Assets detection case-insensitive; NL prompt statuses aligned * prompt(nl-suite): constrain Write destinations under reports/, forbid traversal * prompt+net: harden Write path rules; use monotonic deadline and plain-text advisory for non-framed peers * unity_connection: restore recv timeout via try/finally; make global connection getter thread-safe with module lock and double-checked init * NL/T prompt: pin structured edit ops for T-D/T-E; add schema-error guarded write behavior; keep existing path/URI and revert rules * unity_connection: add FRAMED_MAX; use ValueError for framed length violations; lower framed receive log to debug; serialize connect() with per-instance lock * ManageScript: use UTF8Encoding(without BOM) for atomic writes in ApplyTextEdits/EditScript to align with Create/Update and avoid BOM-related diffs/hash mismatches * NL/T prompt: make helper deletion regex multiline-safe ((?ms) so ^ anchors line starts) * ManageScript: emit structured overlap status {status:"overlap"} for overlapping edit ranges in apply_text_edits and edit paths * NL/T prompt: clarify fallback vs failure — fallback only for unsupported/missing_field; treat bad_request as failure; note unsupported after fallback as failure * NL/T prompt: pin deterministic overlap probe (apply_text_edits two ranges from same snapshot); gate too_large behind RUN_TOO_LARGE env hint * TB update * NL/T prompt: harden Output Rules — constrain Bash(printf|echo) to stdout-only; forbid redirection/here-docs/tee; only scripts/nlt-revert.sh may mutate FS * Prompt: enumerate allowed script_apply_edits ops; add manage_editor/read_console guidance; fix T‑F atomic batch to single script_apply_edits. ManageScript: regex timeout for diagnostics; symlink ancestor guard; complete allowed-modes list. * Fixes * ManageScript: add rich overlap diagnostics (conflicts + hint) for both text range and structured batch paths * ManageScript: return structured {status:"validation_failed"} diagnostics in create/update/edits and validate before commit * ManageScript: echo canonical uri in responses (create/read/update/apply_text_edits/structured edits) to reinforce resource identity * improve clarity of capabilities message * Framing: allow zero-length frames on both ends (C# bridge, Python server). Prompt: harden T-F to single text-range apply_text_edits batch (descending order, one snapshot). URI: normalize file:// outside Assets by stripping leading slash. * ManageScript: include new sha256 in success payload for apply_text_edits; harden TryResolveUnderAssets by rejecting symlinked ancestors up to Assets/. * remove claudetest dir * manage_script_edits: normalize method-anchored anchor_insert to insert_method (map text->replacement); improves CI compatibility for T‑A/T‑E without changing Editor behavior. * tighten testing protocol around mkdir * manage_script: validate create_script inputs (Assets/.cs/name/no traversal); add Assets/ guard to delete_script; validate level+Assets in validate_script; make legacy manage_script optional params; harden legacy update routing with base64 reuse and payload size preflight. * Tighten prompt for testing * Update .claude/prompts/nl-unity-suite-full.md Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update .claude/prompts/nl-unity-suite-full.md Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update UnityMcpBridge/Editor/Tools/ManageScript.cs Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * manage_script_edits: honor ignore_case on anchor_insert and regex_replace in both direct and text-conversion paths (MULTILINE|IGNORECASE). * remove extra file * workflow: use python3 for inline scripts and port detection on ubuntu-latest. * Tighten prompt + manage_script * Update UnityMcpBridge/UnityMcpServer~/src/tools/manage_script_edits.py Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update UnityMcpBridge/UnityMcpServer~/src/tools/manage_script_edits.py Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update .claude/prompts/nl-unity-suite-full.md Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update UnityMcpBridge/Editor/Tools/ManageScript.cs Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update .claude/prompts/nl-unity-suite-full.md Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * manage_script: improve file:// UNC handling; preserve POSIX absolute semantics internally; keep test-expected slash stripping for non-Assets paths. * ManageScript.cs: add TimeSpan timeouts to all Regex uses (IsMatch/Match/new Regex) and keep CultureInvariant/Multiline options; reduces risk of catastrophic backtracking stalls. * workflow: ensure reports/ exists in markdown build step to avoid FileNotFoundError when writing MD_OUT. * fix brace * manage_script_edits: expand backrefs for regex_replace in preview->text conversion and translate to \g<n> in local apply; keeps previews and actual edits consistent. * anchor_insert: default to position=after, normalize surrounding newlines in Python conversion paths; C# path ensures trailing newline and skips duplicate insertion within class. * feat(mcp): add get_sha tool; apply_text_edits normalization+overlap preflight+strict; no-op evidence in C#; update NL suite prompt; add unit tests * feat(frames): accept zero-length heartbeat frames in client; add heartbeat test * feat(edits): guard destructive regex_replace with structural preflight; add robust tests; prompt uses delete_method for temp helper * feat(frames): bound heartbeat loop with timeout/threshold; align zero-length response with C#; update test * SDK hardening: atomic multi-span text edits; stop forcing sequential for structured ops; forward options on apply_text_edits; add validate=relaxed support and scoped checks; update NL/T prompt; add tests for options forwarding, relaxed mode, and atomic batches * Router: default applyMode=atomic for multi-span apply_text_edits; add tests * CI prompt: pass options.validate=relaxed for T-B/C; options.applyMode=atomic for T-F; emphasize always writing testcase and restoring on errors * Validation & DX: add validate=syntax (scoped), standardize evidence windows; early regex compile with hints; debug_preview for apply_text_edits * Update UnityMcpBridge/Editor/Windows/MCPForUnityEditorWindow.cs Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * NL/T suite-driven edits: LongUnityScriptClaudeTest, bridge helpers, server_version; prepare framing tests * Fix duplicate macConfigPath field in McpClient to resolve CS0102 * Editor threading: run EnsureServerInstalled on main thread; marshal EditorPrefs/DeleteKey + logging via delayCall * Docs(apply_text_edits): strengthen guidance on 1-based positions, verify-before-edit, and recommend anchors/structured edits * Docs(script_apply_edits): add safety guidance (anchors, method ops, validators) and recommended practices * Framed VerifyBridgePing in editor window; docs hardening for apply_text_edits and script_apply_edits --------- Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
2025-08-31 00:55:38 +08:00
new { uri, scheduledRefresh = true }
);
Claude‑friendly edit tools + framed transport + live Unity NL test framework (#243) * CI: gate desktop-parity on Anthropic key; pass anthropic_api_key like NL suite * Add quickprobe prompt and CI workflow (mcp-quickprobe.md, unity-mcp-quickprobe.yml) * strictier tool use to prevent subagent spawning and force mcp tools * update workflow filesto reduce likelihood of subagent spawning * improve permissions for claude agent, fix mcpbridge timeout/token issue * increase max turns to 10 * ci: align NL suite to new permissions schema; prevent subagent drift * ci: NL suite -> mini prompt for e2e; add full NL/T prompt; server: ctx optional + project_root fallback; workflows: set UNITY_PROJECT_ROOT for CI * ci: add checks:write; revert local project hardcodes (manifest, ProjectVersion.txt) * tools: text-edit routing fixes (anchor_insert via text, CRLF calc); prompts: mini NL/T clarifications * ci: use absolute UNITY_PROJECT_ROOT; prompts target TestProjects; server: accept relative UNITY_PROJECT_ROOT and bare spec URI * ci: ignore Unity test project's packages-lock.json; remove from repo to avoid absolute paths * CI: start persistent Unity Editor for MCP (guarded by license) + allow batch-mode bridge via UNITY_MCP_ALLOW_BATCH * CI: hide license and pass via env to docker; fix invalid ref format * CI: readiness probe uses handshake on Unity MCP port (deterministic) * CI: fix YAML; use TCP handshake readiness probe (FRAMING=1) * CI: prime Unity license via game-ci; mount ULF into container; extend readiness timeout * CI: use ULF write + mount for Unity licensing; remove serial/email/pass from container * CI: entitlement activation (UNITY_SERIAL=''); verify host ULF cache; keep mount * CI: write ULF from secret and verify; drop entitlement activation step * CI: detect any licensing path; GameCI prime; status dir env; log+probe readiness; fix YAML * CI: add GameCI license prime; conditional ULF write; one-shot license validation; explicit status dir + license env * CI: fix YAML (inline python), add Anthropic key detect via GITHUB_ENV; ready to run happy path * CI: mount Unity token/ulf/cache dirs into container to share host license; create dirs before start * CI: fix YAML indentation; write ULF on host; activate in container with shared mounts; mount .config and .cache too * CI: gate Claude via outputs; mount all Unity license dirs; fix inline probe python; stabilize licensing flow * CI: normalize detect to step outputs; ensure license dirs mounted and validated; fix indentation * Bridge: honor UNITY_MCP_STATUS_DIR for heartbeat/status file (CI-friendly) * CI: guard project path for activation/start; align tool allowlist; run MCP server with python; tighten secret scoping * CI: finalize Unity licensing mounts + status dir; mode-detect (ULF/EBL); readiness logs+probe; Claude gating via outputs * CI: fix YAML probe (inline python -c) and finalize happy-path Unity licensing and MCP/Claude wiring * CI: inline python probe; unify Unity image and cache mounts; ready to test * CI: fix docker run IMAGE placement; ignore cache find perms; keep same editor image * CI: pass -manualLicenseFile to persistent Editor; keep mounts and single image * CI: mount full GameCI cache to /root in persistent Unity; set HOME=/root; add optional license check * CI: make -manualLicenseFile conditional; keep full /root mount and license check * CI: set HOME=/github/home; mount GameCI cache there; adjust manualLicenseFile path; expand license check * CI: EBL sign-in for persistent Unity (email/password/serial); revert HOME=/root and full /root mount; keep conditional manualLicenseFile and improved readiness * CI: run full NL/T suite prompt (nl-unity-suite-full.md) instead of mini * NL/T: require unified diffs + explicit verdicts in JUnit; CI: remove short sanity step, publish JUnit, upload artifacts * NL/T prompt: require CDATA wrapping for JUnit XML fields; guidance for splitting embedded ]]>; keep VERDICT in CDATA only * CI: remove in-container license check step; keep readiness and full suite * NL/T prompt: add version header, stricter JUnit schema, hashing/normalization, anchors, statuses, atomic semantics, tool logging * CI: increase Claude NL/T suite timeout to 30 minutes * CI: pre-create reports dir and result files to avoid tool approval prompts * CI: skip wait if container not running; skip Editor start if project missing; broaden MCP deps detection; expand allowed tools * fixies to harden ManageScript * CI: sanitize NL/T markdown report to avoid NUL/encoding issues * revert breaking yyaml changes * CI: prime license, robust Unity start/wait, sanitize markdown via heredoc * Resolve merge: accept upstream renames/installer (fix/installer-cleanup-v2) and keep local framing/script-editing - Restored upstream server.py, EditorWindow, uv.lock\n- Preserved ManageScript editing/validation; switched to atomic write + debounced refresh\n- Updated tools/__init__.py to keep script_edits/resources and adopt new logger name\n- All Python tests via uv: 7 passed, 6 skipped, 9 xpassed; Unity compile OK * Fix Claude Desktop config path and atomic write issues - Fix macOS path for Claude Desktop config: use ~/Library/Application Support/Claude/ instead of ~/.config/Claude/ - Improve atomic write pattern with backup/restore safety - Replace File.Replace() with File.Move() for better macOS compatibility - Add proper error handling and cleanup for file operations - Resolves issue where installer couldn't find Claude Desktop config on macOS * Editor: use macConfigPath on macOS for MCP client config writes (Claude Desktop, etc.). Fallback to linuxConfigPath only if mac path missing. * Models: add macConfigPath to McpClient for macOS config path selection (fixes CS1061 in editor window). * Editor: on macOS, prefer macConfigPath in ManualConfigEditorWindow (fallback to linux path); Linux/Windows unchanged. * Fix McpClient: align with upstream/main, prep for framing split * NL suite: shard workflow; tighten bridge readiness; add MCP preflight; use env-based shard vars * NL suite: fix shard step indentation; move shard vars to env; remove invalid inputs * MCP clients: split VSCode Copilot config paths into macConfigPath and linuxConfigPath * Unity bridge: clean stale status; bind host; robust wait probe with IPv4/IPv6 + diagnostics * CI: use MCPForUnity.Editor.MCPForUnityBridge.StartAutoConnect as executeMethod * Action wiring: inline mcpServers in settings for all shards; remove redundant .claude/mcp.json step * CI: embed mcpServers in settings for all shards; fix startup sanity step; lint clean * CI: pin claude-code-base-action to e6f32c8; use claude_args --mcp-config; switch to allowed_tools; ensure MCP config per step * CI: unpin claude-code-base-action to @beta (commit ref not found) * CI: align with claude-code-base-action @beta; pass MCP via claude_args and allowedTools * Editor: Fix apply_text_edits heuristic when edits shift positions; recompute method span on candidate text with fallback delta adjustment * CI: unify MCP wiring across workflows; write .claude/mcp.json; switch to claude_args with --mcp-config/--allowedTools; remove unsupported inputs * CI: collapse NL suite shards into a single run to avoid repeated test execution * CI: minimize allowedTools for NL suite to essential Unity MCP + Bash("git:*") + Write * CI: mkdir -p reports before run; remove unsupported --timeout-minutes from claude_args * CI: broaden allowedTools to include find_in_file and mcp__unity__* * CI: enable use_node_cache and switch NL suite model to claude-3-7-haiku-20250219 * CI: disable use_node_cache to avoid setup-node lockfile error * CI: set NL suite model to claude-3-haiku-20240307 * CI: cap Haiku output with --max-tokens 2048 for NL suite * CI: switch to claude-3-7-sonnet-latest and remove unsupported --max-tokens * CI: update allowedTools to Bash(*) and explicit Unity MCP tool list * CI: update NL suite workflow (latest tweaks) * Tests: tighten NL suite prompt for logging, hash discipline, stale retry, evidence windows, diff cap, and VERDICT line * Add disallowed tools to NL suite workflow * docs: clarify stale write retry * Add fallback JUnit report and adjust publisher * Indent fallback JUnit XML in workflow * fix: correct fallback JUnit report generation * Update mcp-quickprobe.md Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> * Update mcp-quickprobe.md Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> * Update Response.cs Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> * Update MCPForUnityBridge.cs Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> * fix: correct McpTypes reference * Add directory existence checks for symlink and XDG paths * fix: only set installation flag after successful server install * Update resource_tools.py Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> * fix: respect mac config paths * Use File.Replace for atomic config write * Remove unused imports in manage_script * bump server version * Tests: update NL suite prompt and workflows; remove deprecated smoke/desktop-parity; quickprobe tidy * Editor: atomic config write via File.Replace fallback; remove redundant backups and racey exists checks * CI: harden NL suite - idempotent docker, gate on unity_ok, safer port probe, least-priv perms * Editor: make atomic config write restoration safe (flag writeDone; copy-overwrite restore; cleanup in finally) * CI: fix fallback JUnit heredoc by using printf lines (no EOF delimiter issues) * CI: switch NL suite to mini prompt; mini prompt honors / and NL discipline * CI: replace claude_args with allowed_tools/model/mcp_config per action schema * CI: expand UNITY_PROJECT_ROOT via in MCP config heredoc * EditorWindow: add cross-platform fallback for File.Replace; macOS-insensitive PathsEqual; safer uv resolve; honor macConfigPath * CI: strengthen JUnit publishing for NL mini suite (normalize, debug list, publish both, fail_on_parse_error) * CI: set job-wide JUNIT_OUT/MD_OUT; normalization uses env; publish references env and ungroup reports * CI: publish a single normalized JUnit (reports/junit-for-actions.xml); fallback writes same; avoid checkName/reportPaths mismatch * CI: align mini prompt report filenames; redact Unity log tail in diagnostics * chore: sync workflow and mini prompt; redacted logs; JUnit normalization/publish tweaks * CI: redact sensitive tokens in Stop Unity; docs: CI usage + edit tools * prompts: update nl-unity-suite-full (mini-style setup + reporting discipline); remove obsolete prompts * CI: harden NL workflows (timeout_minutes, robust normalization); prompts: unify JUnit suite name and reporting discipline * prompts: add guarded write pattern (LF hash, stale_file retry) to full suite * prompts: enforce continue-on-failure, driver flow, and status handling in full suite * Make test list more explicit in prompt. Get rid of old test prompts for hygeine. * prompts: add stale fast-retry (server hash) + in-memory buf guidance * CI: standardize JUNIT_OUT to reports/junit-nl-suite.xml; fix artifact upload indentation; prompt copy cleanups * prompts: reporting discipline — append-only fragments, batch writes, no model round-trip * prompts: stale fast-retry preference, buffer/sha carry, snapshot revert, essential logging * workflows(nl-suite): precreate report skeletons, assemble junit, synthesize markdown; restrict allowed_tools to append-only Bash + MCP tools * thsis too * Update README-DEV.md Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update .github/workflows/claude-nl-suite-mini.yml Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update .github/workflows/claude-nl-suite.yml Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * workflows(nl-mini): fix YAML indentation/trailing spaces under with: and cleanup heredoc spacing * workflows(nl-suite): fix indentation on docker logs redaction line (YAML lint) * Add write to allowlist * nl-suite: harden reporting discipline (fragment-only writes, forbid alt paths); workflow: clean stray junit-*updated*.xml * nl-suite: enforce end-of-suite single Write (no bash redirection); workflow: restrict allowed_tools to Write+MCP only * prompts(nl-full): end-of-suite results must be valid XML with single <cases> root and only <testcase> children; no raw text outside CDATA * workflows(nl-suite): make Claude step non-fatal; tolerant normalizer extracts <testcase> via regex on bad fragments * nl-suite: fix stale classname to UnityMCP.NL-T in mini fallback; prompt: require re-read after every revert; correct PLAN/PROGRESS to 15 * nl-suite: fix fallback JUnit classname to UnityMCP.NL-T; prompt: forbid create_script and env/mkdir checks, enforce single baseline-byte revert flow and post-revert re-read; add corruption-handling guidance * prompts(nl-full): after each write re-read raw bytes to refresh pre_sha; prefer script_apply_edits for anchors; avoid header/using changes * prompts(nl-full): canonicalize outputs to /; allow small fragment appends via Write or Bash(printf/echo); forbid wrappers and full-file round-trips * prompts(nl-full): finalize markdown formatting for guarded write, execution order, specs, status * workflows(nl-suite, mini): header/lint fixes and constrained Bash append path; align allowed_tools * prompts(nl-full): format Fast Restore, Guarded Write, Execution, Specs, Status as proper markdown lists and code fences * workflows(nl-suite): keep header tidy and append-path alignment with prompt * minor fix * workflows(nl-suite): fix indentation and dispatch; align allowed_tools and revert helper * prompts(nl-full): switch to read_resource for buf/sha; re-read only when needed; convert 'Print this once' to heading; note snapshot helper creates parent dirs * workflows(nl-suite): normalize step removes bootstrap when real testcases present; recompute tests/failures * workflows(nl-suite): enrich Markdown summary by extracting per-test <system-out> blocks (truncated) * clarify prompt resilience instructions * ci(nl-suite): revert prompt and workflow to known-good e0f8a72 for green run; remove extra MD details * ci(nl-suite): minimal fixes — no-mkdir guard in prompt; drop bootstrap and recompute JUnit counts * ci(nl-suite): richer JUnit→Markdown report (per-test system-out) * Small guard to incorret asset read call. * ci(nl-suite): refine MD builder — unescape XML entities, safe code fences, PASS/FAIL badges * Update UnityMcpBridge/UnityMcpServer~/src/tools/resource_tools.py Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update UnityMcpBridge/UnityMcpServer~/src/unity_connection.py Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update UnityMcpBridge/UnityMcpServer~/src/tools/manage_script_edits.py Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update .github/scripts/mark_skipped.py Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update .github/scripts/mark_skipped.py Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update .github/scripts/mark_skipped.py Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> * server(manage_script): robust URI handling — percent-decode file://, normalize, strip host/leading slashes, return Assets-relative if present * Update .claude/prompts/nl-unity-suite-full.md Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> * tests(framing): reduce handshake poll window, nonblocking peek to avoid disconnect race; still enforce pre-handshake data drop * tests(manage_script): add _split_uri tests for unity://path, file:// URLs (decoded/Assets-relative), and plain paths * server+tests: fix handshake syntax error; robust file:// URI normalization in manage_script; add _split_uri tests; adjust stdout scan to ignore venv/site-packages * bridge(framing): accept zero-length frames (treat as empty keepalive) * tests(logging): use errors='replace' on decode fallback to avoid silent drops * resources(list): restrict to Assets/, resolve symlinks, enforce .cs; add traversal/outside-path tests * Update .claude/prompts/nl-unity-suite-full.md Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update UnityMcpBridge/UnityMcpServer~/src/unity_connection.py Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * misc: framing keepalive (zero-length), regex preview consistency, resource.list hardening, URI parsing, legacy update routing, test cleanups * docs(tools): richer MCP tool descriptions; tests accept decorator kwargs; resource URI parsing hardened * Update .claude/prompts/nl-unity-suite-full.md Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update UnityMcpBridge/UnityMcpServer~/src/tools/resource_tools.py Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update UnityMcpBridge/UnityMcpServer~/src/unity_connection.py Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * net+docs: hard-reject zero-length frames; TCP_NODELAY on connect; Assets detection case-insensitive; NL prompt statuses aligned * prompt(nl-suite): constrain Write destinations under reports/, forbid traversal * prompt+net: harden Write path rules; use monotonic deadline and plain-text advisory for non-framed peers * unity_connection: restore recv timeout via try/finally; make global connection getter thread-safe with module lock and double-checked init * NL/T prompt: pin structured edit ops for T-D/T-E; add schema-error guarded write behavior; keep existing path/URI and revert rules * unity_connection: add FRAMED_MAX; use ValueError for framed length violations; lower framed receive log to debug; serialize connect() with per-instance lock * ManageScript: use UTF8Encoding(without BOM) for atomic writes in ApplyTextEdits/EditScript to align with Create/Update and avoid BOM-related diffs/hash mismatches * NL/T prompt: make helper deletion regex multiline-safe ((?ms) so ^ anchors line starts) * ManageScript: emit structured overlap status {status:"overlap"} for overlapping edit ranges in apply_text_edits and edit paths * NL/T prompt: clarify fallback vs failure — fallback only for unsupported/missing_field; treat bad_request as failure; note unsupported after fallback as failure * NL/T prompt: pin deterministic overlap probe (apply_text_edits two ranges from same snapshot); gate too_large behind RUN_TOO_LARGE env hint * TB update * NL/T prompt: harden Output Rules — constrain Bash(printf|echo) to stdout-only; forbid redirection/here-docs/tee; only scripts/nlt-revert.sh may mutate FS * Prompt: enumerate allowed script_apply_edits ops; add manage_editor/read_console guidance; fix T‑F atomic batch to single script_apply_edits. ManageScript: regex timeout for diagnostics; symlink ancestor guard; complete allowed-modes list. * Fixes * ManageScript: add rich overlap diagnostics (conflicts + hint) for both text range and structured batch paths * ManageScript: return structured {status:"validation_failed"} diagnostics in create/update/edits and validate before commit * ManageScript: echo canonical uri in responses (create/read/update/apply_text_edits/structured edits) to reinforce resource identity * improve clarity of capabilities message * Framing: allow zero-length frames on both ends (C# bridge, Python server). Prompt: harden T-F to single text-range apply_text_edits batch (descending order, one snapshot). URI: normalize file:// outside Assets by stripping leading slash. * ManageScript: include new sha256 in success payload for apply_text_edits; harden TryResolveUnderAssets by rejecting symlinked ancestors up to Assets/. * remove claudetest dir * manage_script_edits: normalize method-anchored anchor_insert to insert_method (map text->replacement); improves CI compatibility for T‑A/T‑E without changing Editor behavior. * tighten testing protocol around mkdir * manage_script: validate create_script inputs (Assets/.cs/name/no traversal); add Assets/ guard to delete_script; validate level+Assets in validate_script; make legacy manage_script optional params; harden legacy update routing with base64 reuse and payload size preflight. * Tighten prompt for testing * Update .claude/prompts/nl-unity-suite-full.md Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update .claude/prompts/nl-unity-suite-full.md Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update UnityMcpBridge/Editor/Tools/ManageScript.cs Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * manage_script_edits: honor ignore_case on anchor_insert and regex_replace in both direct and text-conversion paths (MULTILINE|IGNORECASE). * remove extra file * workflow: use python3 for inline scripts and port detection on ubuntu-latest. * Tighten prompt + manage_script * Update UnityMcpBridge/UnityMcpServer~/src/tools/manage_script_edits.py Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update UnityMcpBridge/UnityMcpServer~/src/tools/manage_script_edits.py Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update .claude/prompts/nl-unity-suite-full.md Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update UnityMcpBridge/Editor/Tools/ManageScript.cs Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update .claude/prompts/nl-unity-suite-full.md Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * manage_script: improve file:// UNC handling; preserve POSIX absolute semantics internally; keep test-expected slash stripping for non-Assets paths. * ManageScript.cs: add TimeSpan timeouts to all Regex uses (IsMatch/Match/new Regex) and keep CultureInvariant/Multiline options; reduces risk of catastrophic backtracking stalls. * workflow: ensure reports/ exists in markdown build step to avoid FileNotFoundError when writing MD_OUT. * fix brace * manage_script_edits: expand backrefs for regex_replace in preview->text conversion and translate to \g<n> in local apply; keeps previews and actual edits consistent. * anchor_insert: default to position=after, normalize surrounding newlines in Python conversion paths; C# path ensures trailing newline and skips duplicate insertion within class. * feat(mcp): add get_sha tool; apply_text_edits normalization+overlap preflight+strict; no-op evidence in C#; update NL suite prompt; add unit tests * feat(frames): accept zero-length heartbeat frames in client; add heartbeat test * feat(edits): guard destructive regex_replace with structural preflight; add robust tests; prompt uses delete_method for temp helper * feat(frames): bound heartbeat loop with timeout/threshold; align zero-length response with C#; update test * SDK hardening: atomic multi-span text edits; stop forcing sequential for structured ops; forward options on apply_text_edits; add validate=relaxed support and scoped checks; update NL/T prompt; add tests for options forwarding, relaxed mode, and atomic batches * Router: default applyMode=atomic for multi-span apply_text_edits; add tests * CI prompt: pass options.validate=relaxed for T-B/C; options.applyMode=atomic for T-F; emphasize always writing testcase and restoring on errors * Validation & DX: add validate=syntax (scoped), standardize evidence windows; early regex compile with hints; debug_preview for apply_text_edits * Update UnityMcpBridge/Editor/Windows/MCPForUnityEditorWindow.cs Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * NL/T suite-driven edits: LongUnityScriptClaudeTest, bridge helpers, server_version; prepare framing tests * Fix duplicate macConfigPath field in McpClient to resolve CS0102 * Editor threading: run EnsureServerInstalled on main thread; marshal EditorPrefs/DeleteKey + logging via delayCall * Docs(apply_text_edits): strengthen guidance on 1-based positions, verify-before-edit, and recommend anchors/structured edits * Docs(script_apply_edits): add safety guidance (anchors, method ops, validators) and recommended practices * Framed VerifyBridgePing in editor window; docs hardening for apply_text_edits and script_apply_edits --------- Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
2025-08-31 00:55:38 +08:00
// Schedule heavy work AFTER replying
ManageScriptRefreshHelpers.ScheduleScriptRefresh(relativePath);
return ok;
2025-03-31 03:58:01 +08:00
}
catch (Exception e)
{
return Response.Error($"Failed to create script '{relativePath}': {e.Message}");
}
}
private static object ReadScript(string fullPath, string relativePath)
{
if (!File.Exists(fullPath))
{
return Response.Error($"Script not found at '{relativePath}'.");
}
try
{
string contents = File.ReadAllText(fullPath);
// Return both normal and encoded contents for larger files
bool isLarge = contents.Length > 10000; // If content is large, include encoded version
Claude‑friendly edit tools + framed transport + live Unity NL test framework (#243) * CI: gate desktop-parity on Anthropic key; pass anthropic_api_key like NL suite * Add quickprobe prompt and CI workflow (mcp-quickprobe.md, unity-mcp-quickprobe.yml) * strictier tool use to prevent subagent spawning and force mcp tools * update workflow filesto reduce likelihood of subagent spawning * improve permissions for claude agent, fix mcpbridge timeout/token issue * increase max turns to 10 * ci: align NL suite to new permissions schema; prevent subagent drift * ci: NL suite -> mini prompt for e2e; add full NL/T prompt; server: ctx optional + project_root fallback; workflows: set UNITY_PROJECT_ROOT for CI * ci: add checks:write; revert local project hardcodes (manifest, ProjectVersion.txt) * tools: text-edit routing fixes (anchor_insert via text, CRLF calc); prompts: mini NL/T clarifications * ci: use absolute UNITY_PROJECT_ROOT; prompts target TestProjects; server: accept relative UNITY_PROJECT_ROOT and bare spec URI * ci: ignore Unity test project's packages-lock.json; remove from repo to avoid absolute paths * CI: start persistent Unity Editor for MCP (guarded by license) + allow batch-mode bridge via UNITY_MCP_ALLOW_BATCH * CI: hide license and pass via env to docker; fix invalid ref format * CI: readiness probe uses handshake on Unity MCP port (deterministic) * CI: fix YAML; use TCP handshake readiness probe (FRAMING=1) * CI: prime Unity license via game-ci; mount ULF into container; extend readiness timeout * CI: use ULF write + mount for Unity licensing; remove serial/email/pass from container * CI: entitlement activation (UNITY_SERIAL=''); verify host ULF cache; keep mount * CI: write ULF from secret and verify; drop entitlement activation step * CI: detect any licensing path; GameCI prime; status dir env; log+probe readiness; fix YAML * CI: add GameCI license prime; conditional ULF write; one-shot license validation; explicit status dir + license env * CI: fix YAML (inline python), add Anthropic key detect via GITHUB_ENV; ready to run happy path * CI: mount Unity token/ulf/cache dirs into container to share host license; create dirs before start * CI: fix YAML indentation; write ULF on host; activate in container with shared mounts; mount .config and .cache too * CI: gate Claude via outputs; mount all Unity license dirs; fix inline probe python; stabilize licensing flow * CI: normalize detect to step outputs; ensure license dirs mounted and validated; fix indentation * Bridge: honor UNITY_MCP_STATUS_DIR for heartbeat/status file (CI-friendly) * CI: guard project path for activation/start; align tool allowlist; run MCP server with python; tighten secret scoping * CI: finalize Unity licensing mounts + status dir; mode-detect (ULF/EBL); readiness logs+probe; Claude gating via outputs * CI: fix YAML probe (inline python -c) and finalize happy-path Unity licensing and MCP/Claude wiring * CI: inline python probe; unify Unity image and cache mounts; ready to test * CI: fix docker run IMAGE placement; ignore cache find perms; keep same editor image * CI: pass -manualLicenseFile to persistent Editor; keep mounts and single image * CI: mount full GameCI cache to /root in persistent Unity; set HOME=/root; add optional license check * CI: make -manualLicenseFile conditional; keep full /root mount and license check * CI: set HOME=/github/home; mount GameCI cache there; adjust manualLicenseFile path; expand license check * CI: EBL sign-in for persistent Unity (email/password/serial); revert HOME=/root and full /root mount; keep conditional manualLicenseFile and improved readiness * CI: run full NL/T suite prompt (nl-unity-suite-full.md) instead of mini * NL/T: require unified diffs + explicit verdicts in JUnit; CI: remove short sanity step, publish JUnit, upload artifacts * NL/T prompt: require CDATA wrapping for JUnit XML fields; guidance for splitting embedded ]]>; keep VERDICT in CDATA only * CI: remove in-container license check step; keep readiness and full suite * NL/T prompt: add version header, stricter JUnit schema, hashing/normalization, anchors, statuses, atomic semantics, tool logging * CI: increase Claude NL/T suite timeout to 30 minutes * CI: pre-create reports dir and result files to avoid tool approval prompts * CI: skip wait if container not running; skip Editor start if project missing; broaden MCP deps detection; expand allowed tools * fixies to harden ManageScript * CI: sanitize NL/T markdown report to avoid NUL/encoding issues * revert breaking yyaml changes * CI: prime license, robust Unity start/wait, sanitize markdown via heredoc * Resolve merge: accept upstream renames/installer (fix/installer-cleanup-v2) and keep local framing/script-editing - Restored upstream server.py, EditorWindow, uv.lock\n- Preserved ManageScript editing/validation; switched to atomic write + debounced refresh\n- Updated tools/__init__.py to keep script_edits/resources and adopt new logger name\n- All Python tests via uv: 7 passed, 6 skipped, 9 xpassed; Unity compile OK * Fix Claude Desktop config path and atomic write issues - Fix macOS path for Claude Desktop config: use ~/Library/Application Support/Claude/ instead of ~/.config/Claude/ - Improve atomic write pattern with backup/restore safety - Replace File.Replace() with File.Move() for better macOS compatibility - Add proper error handling and cleanup for file operations - Resolves issue where installer couldn't find Claude Desktop config on macOS * Editor: use macConfigPath on macOS for MCP client config writes (Claude Desktop, etc.). Fallback to linuxConfigPath only if mac path missing. * Models: add macConfigPath to McpClient for macOS config path selection (fixes CS1061 in editor window). * Editor: on macOS, prefer macConfigPath in ManualConfigEditorWindow (fallback to linux path); Linux/Windows unchanged. * Fix McpClient: align with upstream/main, prep for framing split * NL suite: shard workflow; tighten bridge readiness; add MCP preflight; use env-based shard vars * NL suite: fix shard step indentation; move shard vars to env; remove invalid inputs * MCP clients: split VSCode Copilot config paths into macConfigPath and linuxConfigPath * Unity bridge: clean stale status; bind host; robust wait probe with IPv4/IPv6 + diagnostics * CI: use MCPForUnity.Editor.MCPForUnityBridge.StartAutoConnect as executeMethod * Action wiring: inline mcpServers in settings for all shards; remove redundant .claude/mcp.json step * CI: embed mcpServers in settings for all shards; fix startup sanity step; lint clean * CI: pin claude-code-base-action to e6f32c8; use claude_args --mcp-config; switch to allowed_tools; ensure MCP config per step * CI: unpin claude-code-base-action to @beta (commit ref not found) * CI: align with claude-code-base-action @beta; pass MCP via claude_args and allowedTools * Editor: Fix apply_text_edits heuristic when edits shift positions; recompute method span on candidate text with fallback delta adjustment * CI: unify MCP wiring across workflows; write .claude/mcp.json; switch to claude_args with --mcp-config/--allowedTools; remove unsupported inputs * CI: collapse NL suite shards into a single run to avoid repeated test execution * CI: minimize allowedTools for NL suite to essential Unity MCP + Bash("git:*") + Write * CI: mkdir -p reports before run; remove unsupported --timeout-minutes from claude_args * CI: broaden allowedTools to include find_in_file and mcp__unity__* * CI: enable use_node_cache and switch NL suite model to claude-3-7-haiku-20250219 * CI: disable use_node_cache to avoid setup-node lockfile error * CI: set NL suite model to claude-3-haiku-20240307 * CI: cap Haiku output with --max-tokens 2048 for NL suite * CI: switch to claude-3-7-sonnet-latest and remove unsupported --max-tokens * CI: update allowedTools to Bash(*) and explicit Unity MCP tool list * CI: update NL suite workflow (latest tweaks) * Tests: tighten NL suite prompt for logging, hash discipline, stale retry, evidence windows, diff cap, and VERDICT line * Add disallowed tools to NL suite workflow * docs: clarify stale write retry * Add fallback JUnit report and adjust publisher * Indent fallback JUnit XML in workflow * fix: correct fallback JUnit report generation * Update mcp-quickprobe.md Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> * Update mcp-quickprobe.md Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> * Update Response.cs Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> * Update MCPForUnityBridge.cs Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> * fix: correct McpTypes reference * Add directory existence checks for symlink and XDG paths * fix: only set installation flag after successful server install * Update resource_tools.py Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> * fix: respect mac config paths * Use File.Replace for atomic config write * Remove unused imports in manage_script * bump server version * Tests: update NL suite prompt and workflows; remove deprecated smoke/desktop-parity; quickprobe tidy * Editor: atomic config write via File.Replace fallback; remove redundant backups and racey exists checks * CI: harden NL suite - idempotent docker, gate on unity_ok, safer port probe, least-priv perms * Editor: make atomic config write restoration safe (flag writeDone; copy-overwrite restore; cleanup in finally) * CI: fix fallback JUnit heredoc by using printf lines (no EOF delimiter issues) * CI: switch NL suite to mini prompt; mini prompt honors / and NL discipline * CI: replace claude_args with allowed_tools/model/mcp_config per action schema * CI: expand UNITY_PROJECT_ROOT via in MCP config heredoc * EditorWindow: add cross-platform fallback for File.Replace; macOS-insensitive PathsEqual; safer uv resolve; honor macConfigPath * CI: strengthen JUnit publishing for NL mini suite (normalize, debug list, publish both, fail_on_parse_error) * CI: set job-wide JUNIT_OUT/MD_OUT; normalization uses env; publish references env and ungroup reports * CI: publish a single normalized JUnit (reports/junit-for-actions.xml); fallback writes same; avoid checkName/reportPaths mismatch * CI: align mini prompt report filenames; redact Unity log tail in diagnostics * chore: sync workflow and mini prompt; redacted logs; JUnit normalization/publish tweaks * CI: redact sensitive tokens in Stop Unity; docs: CI usage + edit tools * prompts: update nl-unity-suite-full (mini-style setup + reporting discipline); remove obsolete prompts * CI: harden NL workflows (timeout_minutes, robust normalization); prompts: unify JUnit suite name and reporting discipline * prompts: add guarded write pattern (LF hash, stale_file retry) to full suite * prompts: enforce continue-on-failure, driver flow, and status handling in full suite * Make test list more explicit in prompt. Get rid of old test prompts for hygeine. * prompts: add stale fast-retry (server hash) + in-memory buf guidance * CI: standardize JUNIT_OUT to reports/junit-nl-suite.xml; fix artifact upload indentation; prompt copy cleanups * prompts: reporting discipline — append-only fragments, batch writes, no model round-trip * prompts: stale fast-retry preference, buffer/sha carry, snapshot revert, essential logging * workflows(nl-suite): precreate report skeletons, assemble junit, synthesize markdown; restrict allowed_tools to append-only Bash + MCP tools * thsis too * Update README-DEV.md Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update .github/workflows/claude-nl-suite-mini.yml Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update .github/workflows/claude-nl-suite.yml Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * workflows(nl-mini): fix YAML indentation/trailing spaces under with: and cleanup heredoc spacing * workflows(nl-suite): fix indentation on docker logs redaction line (YAML lint) * Add write to allowlist * nl-suite: harden reporting discipline (fragment-only writes, forbid alt paths); workflow: clean stray junit-*updated*.xml * nl-suite: enforce end-of-suite single Write (no bash redirection); workflow: restrict allowed_tools to Write+MCP only * prompts(nl-full): end-of-suite results must be valid XML with single <cases> root and only <testcase> children; no raw text outside CDATA * workflows(nl-suite): make Claude step non-fatal; tolerant normalizer extracts <testcase> via regex on bad fragments * nl-suite: fix stale classname to UnityMCP.NL-T in mini fallback; prompt: require re-read after every revert; correct PLAN/PROGRESS to 15 * nl-suite: fix fallback JUnit classname to UnityMCP.NL-T; prompt: forbid create_script and env/mkdir checks, enforce single baseline-byte revert flow and post-revert re-read; add corruption-handling guidance * prompts(nl-full): after each write re-read raw bytes to refresh pre_sha; prefer script_apply_edits for anchors; avoid header/using changes * prompts(nl-full): canonicalize outputs to /; allow small fragment appends via Write or Bash(printf/echo); forbid wrappers and full-file round-trips * prompts(nl-full): finalize markdown formatting for guarded write, execution order, specs, status * workflows(nl-suite, mini): header/lint fixes and constrained Bash append path; align allowed_tools * prompts(nl-full): format Fast Restore, Guarded Write, Execution, Specs, Status as proper markdown lists and code fences * workflows(nl-suite): keep header tidy and append-path alignment with prompt * minor fix * workflows(nl-suite): fix indentation and dispatch; align allowed_tools and revert helper * prompts(nl-full): switch to read_resource for buf/sha; re-read only when needed; convert 'Print this once' to heading; note snapshot helper creates parent dirs * workflows(nl-suite): normalize step removes bootstrap when real testcases present; recompute tests/failures * workflows(nl-suite): enrich Markdown summary by extracting per-test <system-out> blocks (truncated) * clarify prompt resilience instructions * ci(nl-suite): revert prompt and workflow to known-good e0f8a72 for green run; remove extra MD details * ci(nl-suite): minimal fixes — no-mkdir guard in prompt; drop bootstrap and recompute JUnit counts * ci(nl-suite): richer JUnit→Markdown report (per-test system-out) * Small guard to incorret asset read call. * ci(nl-suite): refine MD builder — unescape XML entities, safe code fences, PASS/FAIL badges * Update UnityMcpBridge/UnityMcpServer~/src/tools/resource_tools.py Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update UnityMcpBridge/UnityMcpServer~/src/unity_connection.py Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update UnityMcpBridge/UnityMcpServer~/src/tools/manage_script_edits.py Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update .github/scripts/mark_skipped.py Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update .github/scripts/mark_skipped.py Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update .github/scripts/mark_skipped.py Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> * server(manage_script): robust URI handling — percent-decode file://, normalize, strip host/leading slashes, return Assets-relative if present * Update .claude/prompts/nl-unity-suite-full.md Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> * tests(framing): reduce handshake poll window, nonblocking peek to avoid disconnect race; still enforce pre-handshake data drop * tests(manage_script): add _split_uri tests for unity://path, file:// URLs (decoded/Assets-relative), and plain paths * server+tests: fix handshake syntax error; robust file:// URI normalization in manage_script; add _split_uri tests; adjust stdout scan to ignore venv/site-packages * bridge(framing): accept zero-length frames (treat as empty keepalive) * tests(logging): use errors='replace' on decode fallback to avoid silent drops * resources(list): restrict to Assets/, resolve symlinks, enforce .cs; add traversal/outside-path tests * Update .claude/prompts/nl-unity-suite-full.md Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update UnityMcpBridge/UnityMcpServer~/src/unity_connection.py Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * misc: framing keepalive (zero-length), regex preview consistency, resource.list hardening, URI parsing, legacy update routing, test cleanups * docs(tools): richer MCP tool descriptions; tests accept decorator kwargs; resource URI parsing hardened * Update .claude/prompts/nl-unity-suite-full.md Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update UnityMcpBridge/UnityMcpServer~/src/tools/resource_tools.py Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update UnityMcpBridge/UnityMcpServer~/src/unity_connection.py Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * net+docs: hard-reject zero-length frames; TCP_NODELAY on connect; Assets detection case-insensitive; NL prompt statuses aligned * prompt(nl-suite): constrain Write destinations under reports/, forbid traversal * prompt+net: harden Write path rules; use monotonic deadline and plain-text advisory for non-framed peers * unity_connection: restore recv timeout via try/finally; make global connection getter thread-safe with module lock and double-checked init * NL/T prompt: pin structured edit ops for T-D/T-E; add schema-error guarded write behavior; keep existing path/URI and revert rules * unity_connection: add FRAMED_MAX; use ValueError for framed length violations; lower framed receive log to debug; serialize connect() with per-instance lock * ManageScript: use UTF8Encoding(without BOM) for atomic writes in ApplyTextEdits/EditScript to align with Create/Update and avoid BOM-related diffs/hash mismatches * NL/T prompt: make helper deletion regex multiline-safe ((?ms) so ^ anchors line starts) * ManageScript: emit structured overlap status {status:"overlap"} for overlapping edit ranges in apply_text_edits and edit paths * NL/T prompt: clarify fallback vs failure — fallback only for unsupported/missing_field; treat bad_request as failure; note unsupported after fallback as failure * NL/T prompt: pin deterministic overlap probe (apply_text_edits two ranges from same snapshot); gate too_large behind RUN_TOO_LARGE env hint * TB update * NL/T prompt: harden Output Rules — constrain Bash(printf|echo) to stdout-only; forbid redirection/here-docs/tee; only scripts/nlt-revert.sh may mutate FS * Prompt: enumerate allowed script_apply_edits ops; add manage_editor/read_console guidance; fix T‑F atomic batch to single script_apply_edits. ManageScript: regex timeout for diagnostics; symlink ancestor guard; complete allowed-modes list. * Fixes * ManageScript: add rich overlap diagnostics (conflicts + hint) for both text range and structured batch paths * ManageScript: return structured {status:"validation_failed"} diagnostics in create/update/edits and validate before commit * ManageScript: echo canonical uri in responses (create/read/update/apply_text_edits/structured edits) to reinforce resource identity * improve clarity of capabilities message * Framing: allow zero-length frames on both ends (C# bridge, Python server). Prompt: harden T-F to single text-range apply_text_edits batch (descending order, one snapshot). URI: normalize file:// outside Assets by stripping leading slash. * ManageScript: include new sha256 in success payload for apply_text_edits; harden TryResolveUnderAssets by rejecting symlinked ancestors up to Assets/. * remove claudetest dir * manage_script_edits: normalize method-anchored anchor_insert to insert_method (map text->replacement); improves CI compatibility for T‑A/T‑E without changing Editor behavior. * tighten testing protocol around mkdir * manage_script: validate create_script inputs (Assets/.cs/name/no traversal); add Assets/ guard to delete_script; validate level+Assets in validate_script; make legacy manage_script optional params; harden legacy update routing with base64 reuse and payload size preflight. * Tighten prompt for testing * Update .claude/prompts/nl-unity-suite-full.md Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update .claude/prompts/nl-unity-suite-full.md Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update UnityMcpBridge/Editor/Tools/ManageScript.cs Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * manage_script_edits: honor ignore_case on anchor_insert and regex_replace in both direct and text-conversion paths (MULTILINE|IGNORECASE). * remove extra file * workflow: use python3 for inline scripts and port detection on ubuntu-latest. * Tighten prompt + manage_script * Update UnityMcpBridge/UnityMcpServer~/src/tools/manage_script_edits.py Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update UnityMcpBridge/UnityMcpServer~/src/tools/manage_script_edits.py Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update .claude/prompts/nl-unity-suite-full.md Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update UnityMcpBridge/Editor/Tools/ManageScript.cs Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update .claude/prompts/nl-unity-suite-full.md Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * manage_script: improve file:// UNC handling; preserve POSIX absolute semantics internally; keep test-expected slash stripping for non-Assets paths. * ManageScript.cs: add TimeSpan timeouts to all Regex uses (IsMatch/Match/new Regex) and keep CultureInvariant/Multiline options; reduces risk of catastrophic backtracking stalls. * workflow: ensure reports/ exists in markdown build step to avoid FileNotFoundError when writing MD_OUT. * fix brace * manage_script_edits: expand backrefs for regex_replace in preview->text conversion and translate to \g<n> in local apply; keeps previews and actual edits consistent. * anchor_insert: default to position=after, normalize surrounding newlines in Python conversion paths; C# path ensures trailing newline and skips duplicate insertion within class. * feat(mcp): add get_sha tool; apply_text_edits normalization+overlap preflight+strict; no-op evidence in C#; update NL suite prompt; add unit tests * feat(frames): accept zero-length heartbeat frames in client; add heartbeat test * feat(edits): guard destructive regex_replace with structural preflight; add robust tests; prompt uses delete_method for temp helper * feat(frames): bound heartbeat loop with timeout/threshold; align zero-length response with C#; update test * SDK hardening: atomic multi-span text edits; stop forcing sequential for structured ops; forward options on apply_text_edits; add validate=relaxed support and scoped checks; update NL/T prompt; add tests for options forwarding, relaxed mode, and atomic batches * Router: default applyMode=atomic for multi-span apply_text_edits; add tests * CI prompt: pass options.validate=relaxed for T-B/C; options.applyMode=atomic for T-F; emphasize always writing testcase and restoring on errors * Validation & DX: add validate=syntax (scoped), standardize evidence windows; early regex compile with hints; debug_preview for apply_text_edits * Update UnityMcpBridge/Editor/Windows/MCPForUnityEditorWindow.cs Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * NL/T suite-driven edits: LongUnityScriptClaudeTest, bridge helpers, server_version; prepare framing tests * Fix duplicate macConfigPath field in McpClient to resolve CS0102 * Editor threading: run EnsureServerInstalled on main thread; marshal EditorPrefs/DeleteKey + logging via delayCall * Docs(apply_text_edits): strengthen guidance on 1-based positions, verify-before-edit, and recommend anchors/structured edits * Docs(script_apply_edits): add safety guidance (anchors, method ops, validators) and recommended practices * Framed VerifyBridgePing in editor window; docs hardening for apply_text_edits and script_apply_edits --------- Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
2025-08-31 00:55:38 +08:00
var uri = $"unity://path/{relativePath}";
var responseData = new
{
Claude‑friendly edit tools + framed transport + live Unity NL test framework (#243) * CI: gate desktop-parity on Anthropic key; pass anthropic_api_key like NL suite * Add quickprobe prompt and CI workflow (mcp-quickprobe.md, unity-mcp-quickprobe.yml) * strictier tool use to prevent subagent spawning and force mcp tools * update workflow filesto reduce likelihood of subagent spawning * improve permissions for claude agent, fix mcpbridge timeout/token issue * increase max turns to 10 * ci: align NL suite to new permissions schema; prevent subagent drift * ci: NL suite -> mini prompt for e2e; add full NL/T prompt; server: ctx optional + project_root fallback; workflows: set UNITY_PROJECT_ROOT for CI * ci: add checks:write; revert local project hardcodes (manifest, ProjectVersion.txt) * tools: text-edit routing fixes (anchor_insert via text, CRLF calc); prompts: mini NL/T clarifications * ci: use absolute UNITY_PROJECT_ROOT; prompts target TestProjects; server: accept relative UNITY_PROJECT_ROOT and bare spec URI * ci: ignore Unity test project's packages-lock.json; remove from repo to avoid absolute paths * CI: start persistent Unity Editor for MCP (guarded by license) + allow batch-mode bridge via UNITY_MCP_ALLOW_BATCH * CI: hide license and pass via env to docker; fix invalid ref format * CI: readiness probe uses handshake on Unity MCP port (deterministic) * CI: fix YAML; use TCP handshake readiness probe (FRAMING=1) * CI: prime Unity license via game-ci; mount ULF into container; extend readiness timeout * CI: use ULF write + mount for Unity licensing; remove serial/email/pass from container * CI: entitlement activation (UNITY_SERIAL=''); verify host ULF cache; keep mount * CI: write ULF from secret and verify; drop entitlement activation step * CI: detect any licensing path; GameCI prime; status dir env; log+probe readiness; fix YAML * CI: add GameCI license prime; conditional ULF write; one-shot license validation; explicit status dir + license env * CI: fix YAML (inline python), add Anthropic key detect via GITHUB_ENV; ready to run happy path * CI: mount Unity token/ulf/cache dirs into container to share host license; create dirs before start * CI: fix YAML indentation; write ULF on host; activate in container with shared mounts; mount .config and .cache too * CI: gate Claude via outputs; mount all Unity license dirs; fix inline probe python; stabilize licensing flow * CI: normalize detect to step outputs; ensure license dirs mounted and validated; fix indentation * Bridge: honor UNITY_MCP_STATUS_DIR for heartbeat/status file (CI-friendly) * CI: guard project path for activation/start; align tool allowlist; run MCP server with python; tighten secret scoping * CI: finalize Unity licensing mounts + status dir; mode-detect (ULF/EBL); readiness logs+probe; Claude gating via outputs * CI: fix YAML probe (inline python -c) and finalize happy-path Unity licensing and MCP/Claude wiring * CI: inline python probe; unify Unity image and cache mounts; ready to test * CI: fix docker run IMAGE placement; ignore cache find perms; keep same editor image * CI: pass -manualLicenseFile to persistent Editor; keep mounts and single image * CI: mount full GameCI cache to /root in persistent Unity; set HOME=/root; add optional license check * CI: make -manualLicenseFile conditional; keep full /root mount and license check * CI: set HOME=/github/home; mount GameCI cache there; adjust manualLicenseFile path; expand license check * CI: EBL sign-in for persistent Unity (email/password/serial); revert HOME=/root and full /root mount; keep conditional manualLicenseFile and improved readiness * CI: run full NL/T suite prompt (nl-unity-suite-full.md) instead of mini * NL/T: require unified diffs + explicit verdicts in JUnit; CI: remove short sanity step, publish JUnit, upload artifacts * NL/T prompt: require CDATA wrapping for JUnit XML fields; guidance for splitting embedded ]]>; keep VERDICT in CDATA only * CI: remove in-container license check step; keep readiness and full suite * NL/T prompt: add version header, stricter JUnit schema, hashing/normalization, anchors, statuses, atomic semantics, tool logging * CI: increase Claude NL/T suite timeout to 30 minutes * CI: pre-create reports dir and result files to avoid tool approval prompts * CI: skip wait if container not running; skip Editor start if project missing; broaden MCP deps detection; expand allowed tools * fixies to harden ManageScript * CI: sanitize NL/T markdown report to avoid NUL/encoding issues * revert breaking yyaml changes * CI: prime license, robust Unity start/wait, sanitize markdown via heredoc * Resolve merge: accept upstream renames/installer (fix/installer-cleanup-v2) and keep local framing/script-editing - Restored upstream server.py, EditorWindow, uv.lock\n- Preserved ManageScript editing/validation; switched to atomic write + debounced refresh\n- Updated tools/__init__.py to keep script_edits/resources and adopt new logger name\n- All Python tests via uv: 7 passed, 6 skipped, 9 xpassed; Unity compile OK * Fix Claude Desktop config path and atomic write issues - Fix macOS path for Claude Desktop config: use ~/Library/Application Support/Claude/ instead of ~/.config/Claude/ - Improve atomic write pattern with backup/restore safety - Replace File.Replace() with File.Move() for better macOS compatibility - Add proper error handling and cleanup for file operations - Resolves issue where installer couldn't find Claude Desktop config on macOS * Editor: use macConfigPath on macOS for MCP client config writes (Claude Desktop, etc.). Fallback to linuxConfigPath only if mac path missing. * Models: add macConfigPath to McpClient for macOS config path selection (fixes CS1061 in editor window). * Editor: on macOS, prefer macConfigPath in ManualConfigEditorWindow (fallback to linux path); Linux/Windows unchanged. * Fix McpClient: align with upstream/main, prep for framing split * NL suite: shard workflow; tighten bridge readiness; add MCP preflight; use env-based shard vars * NL suite: fix shard step indentation; move shard vars to env; remove invalid inputs * MCP clients: split VSCode Copilot config paths into macConfigPath and linuxConfigPath * Unity bridge: clean stale status; bind host; robust wait probe with IPv4/IPv6 + diagnostics * CI: use MCPForUnity.Editor.MCPForUnityBridge.StartAutoConnect as executeMethod * Action wiring: inline mcpServers in settings for all shards; remove redundant .claude/mcp.json step * CI: embed mcpServers in settings for all shards; fix startup sanity step; lint clean * CI: pin claude-code-base-action to e6f32c8; use claude_args --mcp-config; switch to allowed_tools; ensure MCP config per step * CI: unpin claude-code-base-action to @beta (commit ref not found) * CI: align with claude-code-base-action @beta; pass MCP via claude_args and allowedTools * Editor: Fix apply_text_edits heuristic when edits shift positions; recompute method span on candidate text with fallback delta adjustment * CI: unify MCP wiring across workflows; write .claude/mcp.json; switch to claude_args with --mcp-config/--allowedTools; remove unsupported inputs * CI: collapse NL suite shards into a single run to avoid repeated test execution * CI: minimize allowedTools for NL suite to essential Unity MCP + Bash("git:*") + Write * CI: mkdir -p reports before run; remove unsupported --timeout-minutes from claude_args * CI: broaden allowedTools to include find_in_file and mcp__unity__* * CI: enable use_node_cache and switch NL suite model to claude-3-7-haiku-20250219 * CI: disable use_node_cache to avoid setup-node lockfile error * CI: set NL suite model to claude-3-haiku-20240307 * CI: cap Haiku output with --max-tokens 2048 for NL suite * CI: switch to claude-3-7-sonnet-latest and remove unsupported --max-tokens * CI: update allowedTools to Bash(*) and explicit Unity MCP tool list * CI: update NL suite workflow (latest tweaks) * Tests: tighten NL suite prompt for logging, hash discipline, stale retry, evidence windows, diff cap, and VERDICT line * Add disallowed tools to NL suite workflow * docs: clarify stale write retry * Add fallback JUnit report and adjust publisher * Indent fallback JUnit XML in workflow * fix: correct fallback JUnit report generation * Update mcp-quickprobe.md Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> * Update mcp-quickprobe.md Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> * Update Response.cs Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> * Update MCPForUnityBridge.cs Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> * fix: correct McpTypes reference * Add directory existence checks for symlink and XDG paths * fix: only set installation flag after successful server install * Update resource_tools.py Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> * fix: respect mac config paths * Use File.Replace for atomic config write * Remove unused imports in manage_script * bump server version * Tests: update NL suite prompt and workflows; remove deprecated smoke/desktop-parity; quickprobe tidy * Editor: atomic config write via File.Replace fallback; remove redundant backups and racey exists checks * CI: harden NL suite - idempotent docker, gate on unity_ok, safer port probe, least-priv perms * Editor: make atomic config write restoration safe (flag writeDone; copy-overwrite restore; cleanup in finally) * CI: fix fallback JUnit heredoc by using printf lines (no EOF delimiter issues) * CI: switch NL suite to mini prompt; mini prompt honors / and NL discipline * CI: replace claude_args with allowed_tools/model/mcp_config per action schema * CI: expand UNITY_PROJECT_ROOT via in MCP config heredoc * EditorWindow: add cross-platform fallback for File.Replace; macOS-insensitive PathsEqual; safer uv resolve; honor macConfigPath * CI: strengthen JUnit publishing for NL mini suite (normalize, debug list, publish both, fail_on_parse_error) * CI: set job-wide JUNIT_OUT/MD_OUT; normalization uses env; publish references env and ungroup reports * CI: publish a single normalized JUnit (reports/junit-for-actions.xml); fallback writes same; avoid checkName/reportPaths mismatch * CI: align mini prompt report filenames; redact Unity log tail in diagnostics * chore: sync workflow and mini prompt; redacted logs; JUnit normalization/publish tweaks * CI: redact sensitive tokens in Stop Unity; docs: CI usage + edit tools * prompts: update nl-unity-suite-full (mini-style setup + reporting discipline); remove obsolete prompts * CI: harden NL workflows (timeout_minutes, robust normalization); prompts: unify JUnit suite name and reporting discipline * prompts: add guarded write pattern (LF hash, stale_file retry) to full suite * prompts: enforce continue-on-failure, driver flow, and status handling in full suite * Make test list more explicit in prompt. Get rid of old test prompts for hygeine. * prompts: add stale fast-retry (server hash) + in-memory buf guidance * CI: standardize JUNIT_OUT to reports/junit-nl-suite.xml; fix artifact upload indentation; prompt copy cleanups * prompts: reporting discipline — append-only fragments, batch writes, no model round-trip * prompts: stale fast-retry preference, buffer/sha carry, snapshot revert, essential logging * workflows(nl-suite): precreate report skeletons, assemble junit, synthesize markdown; restrict allowed_tools to append-only Bash + MCP tools * thsis too * Update README-DEV.md Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update .github/workflows/claude-nl-suite-mini.yml Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update .github/workflows/claude-nl-suite.yml Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * workflows(nl-mini): fix YAML indentation/trailing spaces under with: and cleanup heredoc spacing * workflows(nl-suite): fix indentation on docker logs redaction line (YAML lint) * Add write to allowlist * nl-suite: harden reporting discipline (fragment-only writes, forbid alt paths); workflow: clean stray junit-*updated*.xml * nl-suite: enforce end-of-suite single Write (no bash redirection); workflow: restrict allowed_tools to Write+MCP only * prompts(nl-full): end-of-suite results must be valid XML with single <cases> root and only <testcase> children; no raw text outside CDATA * workflows(nl-suite): make Claude step non-fatal; tolerant normalizer extracts <testcase> via regex on bad fragments * nl-suite: fix stale classname to UnityMCP.NL-T in mini fallback; prompt: require re-read after every revert; correct PLAN/PROGRESS to 15 * nl-suite: fix fallback JUnit classname to UnityMCP.NL-T; prompt: forbid create_script and env/mkdir checks, enforce single baseline-byte revert flow and post-revert re-read; add corruption-handling guidance * prompts(nl-full): after each write re-read raw bytes to refresh pre_sha; prefer script_apply_edits for anchors; avoid header/using changes * prompts(nl-full): canonicalize outputs to /; allow small fragment appends via Write or Bash(printf/echo); forbid wrappers and full-file round-trips * prompts(nl-full): finalize markdown formatting for guarded write, execution order, specs, status * workflows(nl-suite, mini): header/lint fixes and constrained Bash append path; align allowed_tools * prompts(nl-full): format Fast Restore, Guarded Write, Execution, Specs, Status as proper markdown lists and code fences * workflows(nl-suite): keep header tidy and append-path alignment with prompt * minor fix * workflows(nl-suite): fix indentation and dispatch; align allowed_tools and revert helper * prompts(nl-full): switch to read_resource for buf/sha; re-read only when needed; convert 'Print this once' to heading; note snapshot helper creates parent dirs * workflows(nl-suite): normalize step removes bootstrap when real testcases present; recompute tests/failures * workflows(nl-suite): enrich Markdown summary by extracting per-test <system-out> blocks (truncated) * clarify prompt resilience instructions * ci(nl-suite): revert prompt and workflow to known-good e0f8a72 for green run; remove extra MD details * ci(nl-suite): minimal fixes — no-mkdir guard in prompt; drop bootstrap and recompute JUnit counts * ci(nl-suite): richer JUnit→Markdown report (per-test system-out) * Small guard to incorret asset read call. * ci(nl-suite): refine MD builder — unescape XML entities, safe code fences, PASS/FAIL badges * Update UnityMcpBridge/UnityMcpServer~/src/tools/resource_tools.py Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update UnityMcpBridge/UnityMcpServer~/src/unity_connection.py Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update UnityMcpBridge/UnityMcpServer~/src/tools/manage_script_edits.py Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update .github/scripts/mark_skipped.py Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update .github/scripts/mark_skipped.py Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update .github/scripts/mark_skipped.py Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> * server(manage_script): robust URI handling — percent-decode file://, normalize, strip host/leading slashes, return Assets-relative if present * Update .claude/prompts/nl-unity-suite-full.md Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> * tests(framing): reduce handshake poll window, nonblocking peek to avoid disconnect race; still enforce pre-handshake data drop * tests(manage_script): add _split_uri tests for unity://path, file:// URLs (decoded/Assets-relative), and plain paths * server+tests: fix handshake syntax error; robust file:// URI normalization in manage_script; add _split_uri tests; adjust stdout scan to ignore venv/site-packages * bridge(framing): accept zero-length frames (treat as empty keepalive) * tests(logging): use errors='replace' on decode fallback to avoid silent drops * resources(list): restrict to Assets/, resolve symlinks, enforce .cs; add traversal/outside-path tests * Update .claude/prompts/nl-unity-suite-full.md Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update UnityMcpBridge/UnityMcpServer~/src/unity_connection.py Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * misc: framing keepalive (zero-length), regex preview consistency, resource.list hardening, URI parsing, legacy update routing, test cleanups * docs(tools): richer MCP tool descriptions; tests accept decorator kwargs; resource URI parsing hardened * Update .claude/prompts/nl-unity-suite-full.md Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update UnityMcpBridge/UnityMcpServer~/src/tools/resource_tools.py Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update UnityMcpBridge/UnityMcpServer~/src/unity_connection.py Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * net+docs: hard-reject zero-length frames; TCP_NODELAY on connect; Assets detection case-insensitive; NL prompt statuses aligned * prompt(nl-suite): constrain Write destinations under reports/, forbid traversal * prompt+net: harden Write path rules; use monotonic deadline and plain-text advisory for non-framed peers * unity_connection: restore recv timeout via try/finally; make global connection getter thread-safe with module lock and double-checked init * NL/T prompt: pin structured edit ops for T-D/T-E; add schema-error guarded write behavior; keep existing path/URI and revert rules * unity_connection: add FRAMED_MAX; use ValueError for framed length violations; lower framed receive log to debug; serialize connect() with per-instance lock * ManageScript: use UTF8Encoding(without BOM) for atomic writes in ApplyTextEdits/EditScript to align with Create/Update and avoid BOM-related diffs/hash mismatches * NL/T prompt: make helper deletion regex multiline-safe ((?ms) so ^ anchors line starts) * ManageScript: emit structured overlap status {status:"overlap"} for overlapping edit ranges in apply_text_edits and edit paths * NL/T prompt: clarify fallback vs failure — fallback only for unsupported/missing_field; treat bad_request as failure; note unsupported after fallback as failure * NL/T prompt: pin deterministic overlap probe (apply_text_edits two ranges from same snapshot); gate too_large behind RUN_TOO_LARGE env hint * TB update * NL/T prompt: harden Output Rules — constrain Bash(printf|echo) to stdout-only; forbid redirection/here-docs/tee; only scripts/nlt-revert.sh may mutate FS * Prompt: enumerate allowed script_apply_edits ops; add manage_editor/read_console guidance; fix T‑F atomic batch to single script_apply_edits. ManageScript: regex timeout for diagnostics; symlink ancestor guard; complete allowed-modes list. * Fixes * ManageScript: add rich overlap diagnostics (conflicts + hint) for both text range and structured batch paths * ManageScript: return structured {status:"validation_failed"} diagnostics in create/update/edits and validate before commit * ManageScript: echo canonical uri in responses (create/read/update/apply_text_edits/structured edits) to reinforce resource identity * improve clarity of capabilities message * Framing: allow zero-length frames on both ends (C# bridge, Python server). Prompt: harden T-F to single text-range apply_text_edits batch (descending order, one snapshot). URI: normalize file:// outside Assets by stripping leading slash. * ManageScript: include new sha256 in success payload for apply_text_edits; harden TryResolveUnderAssets by rejecting symlinked ancestors up to Assets/. * remove claudetest dir * manage_script_edits: normalize method-anchored anchor_insert to insert_method (map text->replacement); improves CI compatibility for T‑A/T‑E without changing Editor behavior. * tighten testing protocol around mkdir * manage_script: validate create_script inputs (Assets/.cs/name/no traversal); add Assets/ guard to delete_script; validate level+Assets in validate_script; make legacy manage_script optional params; harden legacy update routing with base64 reuse and payload size preflight. * Tighten prompt for testing * Update .claude/prompts/nl-unity-suite-full.md Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update .claude/prompts/nl-unity-suite-full.md Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update UnityMcpBridge/Editor/Tools/ManageScript.cs Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * manage_script_edits: honor ignore_case on anchor_insert and regex_replace in both direct and text-conversion paths (MULTILINE|IGNORECASE). * remove extra file * workflow: use python3 for inline scripts and port detection on ubuntu-latest. * Tighten prompt + manage_script * Update UnityMcpBridge/UnityMcpServer~/src/tools/manage_script_edits.py Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update UnityMcpBridge/UnityMcpServer~/src/tools/manage_script_edits.py Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update .claude/prompts/nl-unity-suite-full.md Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update UnityMcpBridge/Editor/Tools/ManageScript.cs Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update .claude/prompts/nl-unity-suite-full.md Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * manage_script: improve file:// UNC handling; preserve POSIX absolute semantics internally; keep test-expected slash stripping for non-Assets paths. * ManageScript.cs: add TimeSpan timeouts to all Regex uses (IsMatch/Match/new Regex) and keep CultureInvariant/Multiline options; reduces risk of catastrophic backtracking stalls. * workflow: ensure reports/ exists in markdown build step to avoid FileNotFoundError when writing MD_OUT. * fix brace * manage_script_edits: expand backrefs for regex_replace in preview->text conversion and translate to \g<n> in local apply; keeps previews and actual edits consistent. * anchor_insert: default to position=after, normalize surrounding newlines in Python conversion paths; C# path ensures trailing newline and skips duplicate insertion within class. * feat(mcp): add get_sha tool; apply_text_edits normalization+overlap preflight+strict; no-op evidence in C#; update NL suite prompt; add unit tests * feat(frames): accept zero-length heartbeat frames in client; add heartbeat test * feat(edits): guard destructive regex_replace with structural preflight; add robust tests; prompt uses delete_method for temp helper * feat(frames): bound heartbeat loop with timeout/threshold; align zero-length response with C#; update test * SDK hardening: atomic multi-span text edits; stop forcing sequential for structured ops; forward options on apply_text_edits; add validate=relaxed support and scoped checks; update NL/T prompt; add tests for options forwarding, relaxed mode, and atomic batches * Router: default applyMode=atomic for multi-span apply_text_edits; add tests * CI prompt: pass options.validate=relaxed for T-B/C; options.applyMode=atomic for T-F; emphasize always writing testcase and restoring on errors * Validation & DX: add validate=syntax (scoped), standardize evidence windows; early regex compile with hints; debug_preview for apply_text_edits * Update UnityMcpBridge/Editor/Windows/MCPForUnityEditorWindow.cs Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * NL/T suite-driven edits: LongUnityScriptClaudeTest, bridge helpers, server_version; prepare framing tests * Fix duplicate macConfigPath field in McpClient to resolve CS0102 * Editor threading: run EnsureServerInstalled on main thread; marshal EditorPrefs/DeleteKey + logging via delayCall * Docs(apply_text_edits): strengthen guidance on 1-based positions, verify-before-edit, and recommend anchors/structured edits * Docs(script_apply_edits): add safety guidance (anchors, method ops, validators) and recommended practices * Framed VerifyBridgePing in editor window; docs hardening for apply_text_edits and script_apply_edits --------- Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
2025-08-31 00:55:38 +08:00
uri,
path = relativePath,
contents = contents,
// For large files, also include base64-encoded version
encodedContents = isLarge ? EncodeBase64(contents) : null,
contentsEncoded = isLarge,
};
return Response.Success(
$"Script '{Path.GetFileName(relativePath)}' read successfully.",
responseData
);
2025-03-31 03:58:01 +08:00
}
catch (Exception e)
{
return Response.Error($"Failed to read script '{relativePath}': {e.Message}");
}
}
private static object UpdateScript(
string fullPath,
string relativePath,
string name,
string contents
)
2025-03-31 03:58:01 +08:00
{
if (!File.Exists(fullPath))
{
return Response.Error(
$"Script not found at '{relativePath}'. Use 'create' action to add a new script."
);
2025-03-31 03:58:01 +08:00
}
if (string.IsNullOrEmpty(contents))
{
return Response.Error("Content is required for the 'update' action.");
}
// Validate syntax with detailed error reporting using GUI setting
ValidationLevel validationLevel = GetValidationLevelFromGUI();
bool isValid = ValidateScriptSyntax(contents, validationLevel, out string[] validationErrors);
if (!isValid)
{
Claude‑friendly edit tools + framed transport + live Unity NL test framework (#243) * CI: gate desktop-parity on Anthropic key; pass anthropic_api_key like NL suite * Add quickprobe prompt and CI workflow (mcp-quickprobe.md, unity-mcp-quickprobe.yml) * strictier tool use to prevent subagent spawning and force mcp tools * update workflow filesto reduce likelihood of subagent spawning * improve permissions for claude agent, fix mcpbridge timeout/token issue * increase max turns to 10 * ci: align NL suite to new permissions schema; prevent subagent drift * ci: NL suite -> mini prompt for e2e; add full NL/T prompt; server: ctx optional + project_root fallback; workflows: set UNITY_PROJECT_ROOT for CI * ci: add checks:write; revert local project hardcodes (manifest, ProjectVersion.txt) * tools: text-edit routing fixes (anchor_insert via text, CRLF calc); prompts: mini NL/T clarifications * ci: use absolute UNITY_PROJECT_ROOT; prompts target TestProjects; server: accept relative UNITY_PROJECT_ROOT and bare spec URI * ci: ignore Unity test project's packages-lock.json; remove from repo to avoid absolute paths * CI: start persistent Unity Editor for MCP (guarded by license) + allow batch-mode bridge via UNITY_MCP_ALLOW_BATCH * CI: hide license and pass via env to docker; fix invalid ref format * CI: readiness probe uses handshake on Unity MCP port (deterministic) * CI: fix YAML; use TCP handshake readiness probe (FRAMING=1) * CI: prime Unity license via game-ci; mount ULF into container; extend readiness timeout * CI: use ULF write + mount for Unity licensing; remove serial/email/pass from container * CI: entitlement activation (UNITY_SERIAL=''); verify host ULF cache; keep mount * CI: write ULF from secret and verify; drop entitlement activation step * CI: detect any licensing path; GameCI prime; status dir env; log+probe readiness; fix YAML * CI: add GameCI license prime; conditional ULF write; one-shot license validation; explicit status dir + license env * CI: fix YAML (inline python), add Anthropic key detect via GITHUB_ENV; ready to run happy path * CI: mount Unity token/ulf/cache dirs into container to share host license; create dirs before start * CI: fix YAML indentation; write ULF on host; activate in container with shared mounts; mount .config and .cache too * CI: gate Claude via outputs; mount all Unity license dirs; fix inline probe python; stabilize licensing flow * CI: normalize detect to step outputs; ensure license dirs mounted and validated; fix indentation * Bridge: honor UNITY_MCP_STATUS_DIR for heartbeat/status file (CI-friendly) * CI: guard project path for activation/start; align tool allowlist; run MCP server with python; tighten secret scoping * CI: finalize Unity licensing mounts + status dir; mode-detect (ULF/EBL); readiness logs+probe; Claude gating via outputs * CI: fix YAML probe (inline python -c) and finalize happy-path Unity licensing and MCP/Claude wiring * CI: inline python probe; unify Unity image and cache mounts; ready to test * CI: fix docker run IMAGE placement; ignore cache find perms; keep same editor image * CI: pass -manualLicenseFile to persistent Editor; keep mounts and single image * CI: mount full GameCI cache to /root in persistent Unity; set HOME=/root; add optional license check * CI: make -manualLicenseFile conditional; keep full /root mount and license check * CI: set HOME=/github/home; mount GameCI cache there; adjust manualLicenseFile path; expand license check * CI: EBL sign-in for persistent Unity (email/password/serial); revert HOME=/root and full /root mount; keep conditional manualLicenseFile and improved readiness * CI: run full NL/T suite prompt (nl-unity-suite-full.md) instead of mini * NL/T: require unified diffs + explicit verdicts in JUnit; CI: remove short sanity step, publish JUnit, upload artifacts * NL/T prompt: require CDATA wrapping for JUnit XML fields; guidance for splitting embedded ]]>; keep VERDICT in CDATA only * CI: remove in-container license check step; keep readiness and full suite * NL/T prompt: add version header, stricter JUnit schema, hashing/normalization, anchors, statuses, atomic semantics, tool logging * CI: increase Claude NL/T suite timeout to 30 minutes * CI: pre-create reports dir and result files to avoid tool approval prompts * CI: skip wait if container not running; skip Editor start if project missing; broaden MCP deps detection; expand allowed tools * fixies to harden ManageScript * CI: sanitize NL/T markdown report to avoid NUL/encoding issues * revert breaking yyaml changes * CI: prime license, robust Unity start/wait, sanitize markdown via heredoc * Resolve merge: accept upstream renames/installer (fix/installer-cleanup-v2) and keep local framing/script-editing - Restored upstream server.py, EditorWindow, uv.lock\n- Preserved ManageScript editing/validation; switched to atomic write + debounced refresh\n- Updated tools/__init__.py to keep script_edits/resources and adopt new logger name\n- All Python tests via uv: 7 passed, 6 skipped, 9 xpassed; Unity compile OK * Fix Claude Desktop config path and atomic write issues - Fix macOS path for Claude Desktop config: use ~/Library/Application Support/Claude/ instead of ~/.config/Claude/ - Improve atomic write pattern with backup/restore safety - Replace File.Replace() with File.Move() for better macOS compatibility - Add proper error handling and cleanup for file operations - Resolves issue where installer couldn't find Claude Desktop config on macOS * Editor: use macConfigPath on macOS for MCP client config writes (Claude Desktop, etc.). Fallback to linuxConfigPath only if mac path missing. * Models: add macConfigPath to McpClient for macOS config path selection (fixes CS1061 in editor window). * Editor: on macOS, prefer macConfigPath in ManualConfigEditorWindow (fallback to linux path); Linux/Windows unchanged. * Fix McpClient: align with upstream/main, prep for framing split * NL suite: shard workflow; tighten bridge readiness; add MCP preflight; use env-based shard vars * NL suite: fix shard step indentation; move shard vars to env; remove invalid inputs * MCP clients: split VSCode Copilot config paths into macConfigPath and linuxConfigPath * Unity bridge: clean stale status; bind host; robust wait probe with IPv4/IPv6 + diagnostics * CI: use MCPForUnity.Editor.MCPForUnityBridge.StartAutoConnect as executeMethod * Action wiring: inline mcpServers in settings for all shards; remove redundant .claude/mcp.json step * CI: embed mcpServers in settings for all shards; fix startup sanity step; lint clean * CI: pin claude-code-base-action to e6f32c8; use claude_args --mcp-config; switch to allowed_tools; ensure MCP config per step * CI: unpin claude-code-base-action to @beta (commit ref not found) * CI: align with claude-code-base-action @beta; pass MCP via claude_args and allowedTools * Editor: Fix apply_text_edits heuristic when edits shift positions; recompute method span on candidate text with fallback delta adjustment * CI: unify MCP wiring across workflows; write .claude/mcp.json; switch to claude_args with --mcp-config/--allowedTools; remove unsupported inputs * CI: collapse NL suite shards into a single run to avoid repeated test execution * CI: minimize allowedTools for NL suite to essential Unity MCP + Bash("git:*") + Write * CI: mkdir -p reports before run; remove unsupported --timeout-minutes from claude_args * CI: broaden allowedTools to include find_in_file and mcp__unity__* * CI: enable use_node_cache and switch NL suite model to claude-3-7-haiku-20250219 * CI: disable use_node_cache to avoid setup-node lockfile error * CI: set NL suite model to claude-3-haiku-20240307 * CI: cap Haiku output with --max-tokens 2048 for NL suite * CI: switch to claude-3-7-sonnet-latest and remove unsupported --max-tokens * CI: update allowedTools to Bash(*) and explicit Unity MCP tool list * CI: update NL suite workflow (latest tweaks) * Tests: tighten NL suite prompt for logging, hash discipline, stale retry, evidence windows, diff cap, and VERDICT line * Add disallowed tools to NL suite workflow * docs: clarify stale write retry * Add fallback JUnit report and adjust publisher * Indent fallback JUnit XML in workflow * fix: correct fallback JUnit report generation * Update mcp-quickprobe.md Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> * Update mcp-quickprobe.md Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> * Update Response.cs Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> * Update MCPForUnityBridge.cs Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> * fix: correct McpTypes reference * Add directory existence checks for symlink and XDG paths * fix: only set installation flag after successful server install * Update resource_tools.py Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> * fix: respect mac config paths * Use File.Replace for atomic config write * Remove unused imports in manage_script * bump server version * Tests: update NL suite prompt and workflows; remove deprecated smoke/desktop-parity; quickprobe tidy * Editor: atomic config write via File.Replace fallback; remove redundant backups and racey exists checks * CI: harden NL suite - idempotent docker, gate on unity_ok, safer port probe, least-priv perms * Editor: make atomic config write restoration safe (flag writeDone; copy-overwrite restore; cleanup in finally) * CI: fix fallback JUnit heredoc by using printf lines (no EOF delimiter issues) * CI: switch NL suite to mini prompt; mini prompt honors / and NL discipline * CI: replace claude_args with allowed_tools/model/mcp_config per action schema * CI: expand UNITY_PROJECT_ROOT via in MCP config heredoc * EditorWindow: add cross-platform fallback for File.Replace; macOS-insensitive PathsEqual; safer uv resolve; honor macConfigPath * CI: strengthen JUnit publishing for NL mini suite (normalize, debug list, publish both, fail_on_parse_error) * CI: set job-wide JUNIT_OUT/MD_OUT; normalization uses env; publish references env and ungroup reports * CI: publish a single normalized JUnit (reports/junit-for-actions.xml); fallback writes same; avoid checkName/reportPaths mismatch * CI: align mini prompt report filenames; redact Unity log tail in diagnostics * chore: sync workflow and mini prompt; redacted logs; JUnit normalization/publish tweaks * CI: redact sensitive tokens in Stop Unity; docs: CI usage + edit tools * prompts: update nl-unity-suite-full (mini-style setup + reporting discipline); remove obsolete prompts * CI: harden NL workflows (timeout_minutes, robust normalization); prompts: unify JUnit suite name and reporting discipline * prompts: add guarded write pattern (LF hash, stale_file retry) to full suite * prompts: enforce continue-on-failure, driver flow, and status handling in full suite * Make test list more explicit in prompt. Get rid of old test prompts for hygeine. * prompts: add stale fast-retry (server hash) + in-memory buf guidance * CI: standardize JUNIT_OUT to reports/junit-nl-suite.xml; fix artifact upload indentation; prompt copy cleanups * prompts: reporting discipline — append-only fragments, batch writes, no model round-trip * prompts: stale fast-retry preference, buffer/sha carry, snapshot revert, essential logging * workflows(nl-suite): precreate report skeletons, assemble junit, synthesize markdown; restrict allowed_tools to append-only Bash + MCP tools * thsis too * Update README-DEV.md Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update .github/workflows/claude-nl-suite-mini.yml Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update .github/workflows/claude-nl-suite.yml Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * workflows(nl-mini): fix YAML indentation/trailing spaces under with: and cleanup heredoc spacing * workflows(nl-suite): fix indentation on docker logs redaction line (YAML lint) * Add write to allowlist * nl-suite: harden reporting discipline (fragment-only writes, forbid alt paths); workflow: clean stray junit-*updated*.xml * nl-suite: enforce end-of-suite single Write (no bash redirection); workflow: restrict allowed_tools to Write+MCP only * prompts(nl-full): end-of-suite results must be valid XML with single <cases> root and only <testcase> children; no raw text outside CDATA * workflows(nl-suite): make Claude step non-fatal; tolerant normalizer extracts <testcase> via regex on bad fragments * nl-suite: fix stale classname to UnityMCP.NL-T in mini fallback; prompt: require re-read after every revert; correct PLAN/PROGRESS to 15 * nl-suite: fix fallback JUnit classname to UnityMCP.NL-T; prompt: forbid create_script and env/mkdir checks, enforce single baseline-byte revert flow and post-revert re-read; add corruption-handling guidance * prompts(nl-full): after each write re-read raw bytes to refresh pre_sha; prefer script_apply_edits for anchors; avoid header/using changes * prompts(nl-full): canonicalize outputs to /; allow small fragment appends via Write or Bash(printf/echo); forbid wrappers and full-file round-trips * prompts(nl-full): finalize markdown formatting for guarded write, execution order, specs, status * workflows(nl-suite, mini): header/lint fixes and constrained Bash append path; align allowed_tools * prompts(nl-full): format Fast Restore, Guarded Write, Execution, Specs, Status as proper markdown lists and code fences * workflows(nl-suite): keep header tidy and append-path alignment with prompt * minor fix * workflows(nl-suite): fix indentation and dispatch; align allowed_tools and revert helper * prompts(nl-full): switch to read_resource for buf/sha; re-read only when needed; convert 'Print this once' to heading; note snapshot helper creates parent dirs * workflows(nl-suite): normalize step removes bootstrap when real testcases present; recompute tests/failures * workflows(nl-suite): enrich Markdown summary by extracting per-test <system-out> blocks (truncated) * clarify prompt resilience instructions * ci(nl-suite): revert prompt and workflow to known-good e0f8a72 for green run; remove extra MD details * ci(nl-suite): minimal fixes — no-mkdir guard in prompt; drop bootstrap and recompute JUnit counts * ci(nl-suite): richer JUnit→Markdown report (per-test system-out) * Small guard to incorret asset read call. * ci(nl-suite): refine MD builder — unescape XML entities, safe code fences, PASS/FAIL badges * Update UnityMcpBridge/UnityMcpServer~/src/tools/resource_tools.py Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update UnityMcpBridge/UnityMcpServer~/src/unity_connection.py Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update UnityMcpBridge/UnityMcpServer~/src/tools/manage_script_edits.py Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update .github/scripts/mark_skipped.py Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update .github/scripts/mark_skipped.py Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update .github/scripts/mark_skipped.py Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> * server(manage_script): robust URI handling — percent-decode file://, normalize, strip host/leading slashes, return Assets-relative if present * Update .claude/prompts/nl-unity-suite-full.md Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> * tests(framing): reduce handshake poll window, nonblocking peek to avoid disconnect race; still enforce pre-handshake data drop * tests(manage_script): add _split_uri tests for unity://path, file:// URLs (decoded/Assets-relative), and plain paths * server+tests: fix handshake syntax error; robust file:// URI normalization in manage_script; add _split_uri tests; adjust stdout scan to ignore venv/site-packages * bridge(framing): accept zero-length frames (treat as empty keepalive) * tests(logging): use errors='replace' on decode fallback to avoid silent drops * resources(list): restrict to Assets/, resolve symlinks, enforce .cs; add traversal/outside-path tests * Update .claude/prompts/nl-unity-suite-full.md Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update UnityMcpBridge/UnityMcpServer~/src/unity_connection.py Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * misc: framing keepalive (zero-length), regex preview consistency, resource.list hardening, URI parsing, legacy update routing, test cleanups * docs(tools): richer MCP tool descriptions; tests accept decorator kwargs; resource URI parsing hardened * Update .claude/prompts/nl-unity-suite-full.md Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update UnityMcpBridge/UnityMcpServer~/src/tools/resource_tools.py Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update UnityMcpBridge/UnityMcpServer~/src/unity_connection.py Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * net+docs: hard-reject zero-length frames; TCP_NODELAY on connect; Assets detection case-insensitive; NL prompt statuses aligned * prompt(nl-suite): constrain Write destinations under reports/, forbid traversal * prompt+net: harden Write path rules; use monotonic deadline and plain-text advisory for non-framed peers * unity_connection: restore recv timeout via try/finally; make global connection getter thread-safe with module lock and double-checked init * NL/T prompt: pin structured edit ops for T-D/T-E; add schema-error guarded write behavior; keep existing path/URI and revert rules * unity_connection: add FRAMED_MAX; use ValueError for framed length violations; lower framed receive log to debug; serialize connect() with per-instance lock * ManageScript: use UTF8Encoding(without BOM) for atomic writes in ApplyTextEdits/EditScript to align with Create/Update and avoid BOM-related diffs/hash mismatches * NL/T prompt: make helper deletion regex multiline-safe ((?ms) so ^ anchors line starts) * ManageScript: emit structured overlap status {status:"overlap"} for overlapping edit ranges in apply_text_edits and edit paths * NL/T prompt: clarify fallback vs failure — fallback only for unsupported/missing_field; treat bad_request as failure; note unsupported after fallback as failure * NL/T prompt: pin deterministic overlap probe (apply_text_edits two ranges from same snapshot); gate too_large behind RUN_TOO_LARGE env hint * TB update * NL/T prompt: harden Output Rules — constrain Bash(printf|echo) to stdout-only; forbid redirection/here-docs/tee; only scripts/nlt-revert.sh may mutate FS * Prompt: enumerate allowed script_apply_edits ops; add manage_editor/read_console guidance; fix T‑F atomic batch to single script_apply_edits. ManageScript: regex timeout for diagnostics; symlink ancestor guard; complete allowed-modes list. * Fixes * ManageScript: add rich overlap diagnostics (conflicts + hint) for both text range and structured batch paths * ManageScript: return structured {status:"validation_failed"} diagnostics in create/update/edits and validate before commit * ManageScript: echo canonical uri in responses (create/read/update/apply_text_edits/structured edits) to reinforce resource identity * improve clarity of capabilities message * Framing: allow zero-length frames on both ends (C# bridge, Python server). Prompt: harden T-F to single text-range apply_text_edits batch (descending order, one snapshot). URI: normalize file:// outside Assets by stripping leading slash. * ManageScript: include new sha256 in success payload for apply_text_edits; harden TryResolveUnderAssets by rejecting symlinked ancestors up to Assets/. * remove claudetest dir * manage_script_edits: normalize method-anchored anchor_insert to insert_method (map text->replacement); improves CI compatibility for T‑A/T‑E without changing Editor behavior. * tighten testing protocol around mkdir * manage_script: validate create_script inputs (Assets/.cs/name/no traversal); add Assets/ guard to delete_script; validate level+Assets in validate_script; make legacy manage_script optional params; harden legacy update routing with base64 reuse and payload size preflight. * Tighten prompt for testing * Update .claude/prompts/nl-unity-suite-full.md Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update .claude/prompts/nl-unity-suite-full.md Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update UnityMcpBridge/Editor/Tools/ManageScript.cs Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * manage_script_edits: honor ignore_case on anchor_insert and regex_replace in both direct and text-conversion paths (MULTILINE|IGNORECASE). * remove extra file * workflow: use python3 for inline scripts and port detection on ubuntu-latest. * Tighten prompt + manage_script * Update UnityMcpBridge/UnityMcpServer~/src/tools/manage_script_edits.py Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update UnityMcpBridge/UnityMcpServer~/src/tools/manage_script_edits.py Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update .claude/prompts/nl-unity-suite-full.md Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update UnityMcpBridge/Editor/Tools/ManageScript.cs Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update .claude/prompts/nl-unity-suite-full.md Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * manage_script: improve file:// UNC handling; preserve POSIX absolute semantics internally; keep test-expected slash stripping for non-Assets paths. * ManageScript.cs: add TimeSpan timeouts to all Regex uses (IsMatch/Match/new Regex) and keep CultureInvariant/Multiline options; reduces risk of catastrophic backtracking stalls. * workflow: ensure reports/ exists in markdown build step to avoid FileNotFoundError when writing MD_OUT. * fix brace * manage_script_edits: expand backrefs for regex_replace in preview->text conversion and translate to \g<n> in local apply; keeps previews and actual edits consistent. * anchor_insert: default to position=after, normalize surrounding newlines in Python conversion paths; C# path ensures trailing newline and skips duplicate insertion within class. * feat(mcp): add get_sha tool; apply_text_edits normalization+overlap preflight+strict; no-op evidence in C#; update NL suite prompt; add unit tests * feat(frames): accept zero-length heartbeat frames in client; add heartbeat test * feat(edits): guard destructive regex_replace with structural preflight; add robust tests; prompt uses delete_method for temp helper * feat(frames): bound heartbeat loop with timeout/threshold; align zero-length response with C#; update test * SDK hardening: atomic multi-span text edits; stop forcing sequential for structured ops; forward options on apply_text_edits; add validate=relaxed support and scoped checks; update NL/T prompt; add tests for options forwarding, relaxed mode, and atomic batches * Router: default applyMode=atomic for multi-span apply_text_edits; add tests * CI prompt: pass options.validate=relaxed for T-B/C; options.applyMode=atomic for T-F; emphasize always writing testcase and restoring on errors * Validation & DX: add validate=syntax (scoped), standardize evidence windows; early regex compile with hints; debug_preview for apply_text_edits * Update UnityMcpBridge/Editor/Windows/MCPForUnityEditorWindow.cs Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * NL/T suite-driven edits: LongUnityScriptClaudeTest, bridge helpers, server_version; prepare framing tests * Fix duplicate macConfigPath field in McpClient to resolve CS0102 * Editor threading: run EnsureServerInstalled on main thread; marshal EditorPrefs/DeleteKey + logging via delayCall * Docs(apply_text_edits): strengthen guidance on 1-based positions, verify-before-edit, and recommend anchors/structured edits * Docs(script_apply_edits): add safety guidance (anchors, method ops, validators) and recommended practices * Framed VerifyBridgePing in editor window; docs hardening for apply_text_edits and script_apply_edits --------- Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
2025-08-31 00:55:38 +08:00
return Response.Error("validation_failed", new { status = "validation_failed", diagnostics = validationErrors ?? Array.Empty<string>() });
}
else if (validationErrors != null && validationErrors.Length > 0)
2025-03-31 03:58:01 +08:00
{
// Log warnings but don't block update
Debug.LogWarning($"Script validation warnings for {name}:\n" + string.Join("\n", validationErrors));
2025-03-31 03:58:01 +08:00
}
try
{
Claude‑friendly edit tools + framed transport + live Unity NL test framework (#243) * CI: gate desktop-parity on Anthropic key; pass anthropic_api_key like NL suite * Add quickprobe prompt and CI workflow (mcp-quickprobe.md, unity-mcp-quickprobe.yml) * strictier tool use to prevent subagent spawning and force mcp tools * update workflow filesto reduce likelihood of subagent spawning * improve permissions for claude agent, fix mcpbridge timeout/token issue * increase max turns to 10 * ci: align NL suite to new permissions schema; prevent subagent drift * ci: NL suite -> mini prompt for e2e; add full NL/T prompt; server: ctx optional + project_root fallback; workflows: set UNITY_PROJECT_ROOT for CI * ci: add checks:write; revert local project hardcodes (manifest, ProjectVersion.txt) * tools: text-edit routing fixes (anchor_insert via text, CRLF calc); prompts: mini NL/T clarifications * ci: use absolute UNITY_PROJECT_ROOT; prompts target TestProjects; server: accept relative UNITY_PROJECT_ROOT and bare spec URI * ci: ignore Unity test project's packages-lock.json; remove from repo to avoid absolute paths * CI: start persistent Unity Editor for MCP (guarded by license) + allow batch-mode bridge via UNITY_MCP_ALLOW_BATCH * CI: hide license and pass via env to docker; fix invalid ref format * CI: readiness probe uses handshake on Unity MCP port (deterministic) * CI: fix YAML; use TCP handshake readiness probe (FRAMING=1) * CI: prime Unity license via game-ci; mount ULF into container; extend readiness timeout * CI: use ULF write + mount for Unity licensing; remove serial/email/pass from container * CI: entitlement activation (UNITY_SERIAL=''); verify host ULF cache; keep mount * CI: write ULF from secret and verify; drop entitlement activation step * CI: detect any licensing path; GameCI prime; status dir env; log+probe readiness; fix YAML * CI: add GameCI license prime; conditional ULF write; one-shot license validation; explicit status dir + license env * CI: fix YAML (inline python), add Anthropic key detect via GITHUB_ENV; ready to run happy path * CI: mount Unity token/ulf/cache dirs into container to share host license; create dirs before start * CI: fix YAML indentation; write ULF on host; activate in container with shared mounts; mount .config and .cache too * CI: gate Claude via outputs; mount all Unity license dirs; fix inline probe python; stabilize licensing flow * CI: normalize detect to step outputs; ensure license dirs mounted and validated; fix indentation * Bridge: honor UNITY_MCP_STATUS_DIR for heartbeat/status file (CI-friendly) * CI: guard project path for activation/start; align tool allowlist; run MCP server with python; tighten secret scoping * CI: finalize Unity licensing mounts + status dir; mode-detect (ULF/EBL); readiness logs+probe; Claude gating via outputs * CI: fix YAML probe (inline python -c) and finalize happy-path Unity licensing and MCP/Claude wiring * CI: inline python probe; unify Unity image and cache mounts; ready to test * CI: fix docker run IMAGE placement; ignore cache find perms; keep same editor image * CI: pass -manualLicenseFile to persistent Editor; keep mounts and single image * CI: mount full GameCI cache to /root in persistent Unity; set HOME=/root; add optional license check * CI: make -manualLicenseFile conditional; keep full /root mount and license check * CI: set HOME=/github/home; mount GameCI cache there; adjust manualLicenseFile path; expand license check * CI: EBL sign-in for persistent Unity (email/password/serial); revert HOME=/root and full /root mount; keep conditional manualLicenseFile and improved readiness * CI: run full NL/T suite prompt (nl-unity-suite-full.md) instead of mini * NL/T: require unified diffs + explicit verdicts in JUnit; CI: remove short sanity step, publish JUnit, upload artifacts * NL/T prompt: require CDATA wrapping for JUnit XML fields; guidance for splitting embedded ]]>; keep VERDICT in CDATA only * CI: remove in-container license check step; keep readiness and full suite * NL/T prompt: add version header, stricter JUnit schema, hashing/normalization, anchors, statuses, atomic semantics, tool logging * CI: increase Claude NL/T suite timeout to 30 minutes * CI: pre-create reports dir and result files to avoid tool approval prompts * CI: skip wait if container not running; skip Editor start if project missing; broaden MCP deps detection; expand allowed tools * fixies to harden ManageScript * CI: sanitize NL/T markdown report to avoid NUL/encoding issues * revert breaking yyaml changes * CI: prime license, robust Unity start/wait, sanitize markdown via heredoc * Resolve merge: accept upstream renames/installer (fix/installer-cleanup-v2) and keep local framing/script-editing - Restored upstream server.py, EditorWindow, uv.lock\n- Preserved ManageScript editing/validation; switched to atomic write + debounced refresh\n- Updated tools/__init__.py to keep script_edits/resources and adopt new logger name\n- All Python tests via uv: 7 passed, 6 skipped, 9 xpassed; Unity compile OK * Fix Claude Desktop config path and atomic write issues - Fix macOS path for Claude Desktop config: use ~/Library/Application Support/Claude/ instead of ~/.config/Claude/ - Improve atomic write pattern with backup/restore safety - Replace File.Replace() with File.Move() for better macOS compatibility - Add proper error handling and cleanup for file operations - Resolves issue where installer couldn't find Claude Desktop config on macOS * Editor: use macConfigPath on macOS for MCP client config writes (Claude Desktop, etc.). Fallback to linuxConfigPath only if mac path missing. * Models: add macConfigPath to McpClient for macOS config path selection (fixes CS1061 in editor window). * Editor: on macOS, prefer macConfigPath in ManualConfigEditorWindow (fallback to linux path); Linux/Windows unchanged. * Fix McpClient: align with upstream/main, prep for framing split * NL suite: shard workflow; tighten bridge readiness; add MCP preflight; use env-based shard vars * NL suite: fix shard step indentation; move shard vars to env; remove invalid inputs * MCP clients: split VSCode Copilot config paths into macConfigPath and linuxConfigPath * Unity bridge: clean stale status; bind host; robust wait probe with IPv4/IPv6 + diagnostics * CI: use MCPForUnity.Editor.MCPForUnityBridge.StartAutoConnect as executeMethod * Action wiring: inline mcpServers in settings for all shards; remove redundant .claude/mcp.json step * CI: embed mcpServers in settings for all shards; fix startup sanity step; lint clean * CI: pin claude-code-base-action to e6f32c8; use claude_args --mcp-config; switch to allowed_tools; ensure MCP config per step * CI: unpin claude-code-base-action to @beta (commit ref not found) * CI: align with claude-code-base-action @beta; pass MCP via claude_args and allowedTools * Editor: Fix apply_text_edits heuristic when edits shift positions; recompute method span on candidate text with fallback delta adjustment * CI: unify MCP wiring across workflows; write .claude/mcp.json; switch to claude_args with --mcp-config/--allowedTools; remove unsupported inputs * CI: collapse NL suite shards into a single run to avoid repeated test execution * CI: minimize allowedTools for NL suite to essential Unity MCP + Bash("git:*") + Write * CI: mkdir -p reports before run; remove unsupported --timeout-minutes from claude_args * CI: broaden allowedTools to include find_in_file and mcp__unity__* * CI: enable use_node_cache and switch NL suite model to claude-3-7-haiku-20250219 * CI: disable use_node_cache to avoid setup-node lockfile error * CI: set NL suite model to claude-3-haiku-20240307 * CI: cap Haiku output with --max-tokens 2048 for NL suite * CI: switch to claude-3-7-sonnet-latest and remove unsupported --max-tokens * CI: update allowedTools to Bash(*) and explicit Unity MCP tool list * CI: update NL suite workflow (latest tweaks) * Tests: tighten NL suite prompt for logging, hash discipline, stale retry, evidence windows, diff cap, and VERDICT line * Add disallowed tools to NL suite workflow * docs: clarify stale write retry * Add fallback JUnit report and adjust publisher * Indent fallback JUnit XML in workflow * fix: correct fallback JUnit report generation * Update mcp-quickprobe.md Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> * Update mcp-quickprobe.md Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> * Update Response.cs Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> * Update MCPForUnityBridge.cs Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> * fix: correct McpTypes reference * Add directory existence checks for symlink and XDG paths * fix: only set installation flag after successful server install * Update resource_tools.py Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> * fix: respect mac config paths * Use File.Replace for atomic config write * Remove unused imports in manage_script * bump server version * Tests: update NL suite prompt and workflows; remove deprecated smoke/desktop-parity; quickprobe tidy * Editor: atomic config write via File.Replace fallback; remove redundant backups and racey exists checks * CI: harden NL suite - idempotent docker, gate on unity_ok, safer port probe, least-priv perms * Editor: make atomic config write restoration safe (flag writeDone; copy-overwrite restore; cleanup in finally) * CI: fix fallback JUnit heredoc by using printf lines (no EOF delimiter issues) * CI: switch NL suite to mini prompt; mini prompt honors / and NL discipline * CI: replace claude_args with allowed_tools/model/mcp_config per action schema * CI: expand UNITY_PROJECT_ROOT via in MCP config heredoc * EditorWindow: add cross-platform fallback for File.Replace; macOS-insensitive PathsEqual; safer uv resolve; honor macConfigPath * CI: strengthen JUnit publishing for NL mini suite (normalize, debug list, publish both, fail_on_parse_error) * CI: set job-wide JUNIT_OUT/MD_OUT; normalization uses env; publish references env and ungroup reports * CI: publish a single normalized JUnit (reports/junit-for-actions.xml); fallback writes same; avoid checkName/reportPaths mismatch * CI: align mini prompt report filenames; redact Unity log tail in diagnostics * chore: sync workflow and mini prompt; redacted logs; JUnit normalization/publish tweaks * CI: redact sensitive tokens in Stop Unity; docs: CI usage + edit tools * prompts: update nl-unity-suite-full (mini-style setup + reporting discipline); remove obsolete prompts * CI: harden NL workflows (timeout_minutes, robust normalization); prompts: unify JUnit suite name and reporting discipline * prompts: add guarded write pattern (LF hash, stale_file retry) to full suite * prompts: enforce continue-on-failure, driver flow, and status handling in full suite * Make test list more explicit in prompt. Get rid of old test prompts for hygeine. * prompts: add stale fast-retry (server hash) + in-memory buf guidance * CI: standardize JUNIT_OUT to reports/junit-nl-suite.xml; fix artifact upload indentation; prompt copy cleanups * prompts: reporting discipline — append-only fragments, batch writes, no model round-trip * prompts: stale fast-retry preference, buffer/sha carry, snapshot revert, essential logging * workflows(nl-suite): precreate report skeletons, assemble junit, synthesize markdown; restrict allowed_tools to append-only Bash + MCP tools * thsis too * Update README-DEV.md Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update .github/workflows/claude-nl-suite-mini.yml Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update .github/workflows/claude-nl-suite.yml Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * workflows(nl-mini): fix YAML indentation/trailing spaces under with: and cleanup heredoc spacing * workflows(nl-suite): fix indentation on docker logs redaction line (YAML lint) * Add write to allowlist * nl-suite: harden reporting discipline (fragment-only writes, forbid alt paths); workflow: clean stray junit-*updated*.xml * nl-suite: enforce end-of-suite single Write (no bash redirection); workflow: restrict allowed_tools to Write+MCP only * prompts(nl-full): end-of-suite results must be valid XML with single <cases> root and only <testcase> children; no raw text outside CDATA * workflows(nl-suite): make Claude step non-fatal; tolerant normalizer extracts <testcase> via regex on bad fragments * nl-suite: fix stale classname to UnityMCP.NL-T in mini fallback; prompt: require re-read after every revert; correct PLAN/PROGRESS to 15 * nl-suite: fix fallback JUnit classname to UnityMCP.NL-T; prompt: forbid create_script and env/mkdir checks, enforce single baseline-byte revert flow and post-revert re-read; add corruption-handling guidance * prompts(nl-full): after each write re-read raw bytes to refresh pre_sha; prefer script_apply_edits for anchors; avoid header/using changes * prompts(nl-full): canonicalize outputs to /; allow small fragment appends via Write or Bash(printf/echo); forbid wrappers and full-file round-trips * prompts(nl-full): finalize markdown formatting for guarded write, execution order, specs, status * workflows(nl-suite, mini): header/lint fixes and constrained Bash append path; align allowed_tools * prompts(nl-full): format Fast Restore, Guarded Write, Execution, Specs, Status as proper markdown lists and code fences * workflows(nl-suite): keep header tidy and append-path alignment with prompt * minor fix * workflows(nl-suite): fix indentation and dispatch; align allowed_tools and revert helper * prompts(nl-full): switch to read_resource for buf/sha; re-read only when needed; convert 'Print this once' to heading; note snapshot helper creates parent dirs * workflows(nl-suite): normalize step removes bootstrap when real testcases present; recompute tests/failures * workflows(nl-suite): enrich Markdown summary by extracting per-test <system-out> blocks (truncated) * clarify prompt resilience instructions * ci(nl-suite): revert prompt and workflow to known-good e0f8a72 for green run; remove extra MD details * ci(nl-suite): minimal fixes — no-mkdir guard in prompt; drop bootstrap and recompute JUnit counts * ci(nl-suite): richer JUnit→Markdown report (per-test system-out) * Small guard to incorret asset read call. * ci(nl-suite): refine MD builder — unescape XML entities, safe code fences, PASS/FAIL badges * Update UnityMcpBridge/UnityMcpServer~/src/tools/resource_tools.py Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update UnityMcpBridge/UnityMcpServer~/src/unity_connection.py Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update UnityMcpBridge/UnityMcpServer~/src/tools/manage_script_edits.py Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update .github/scripts/mark_skipped.py Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update .github/scripts/mark_skipped.py Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update .github/scripts/mark_skipped.py Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> * server(manage_script): robust URI handling — percent-decode file://, normalize, strip host/leading slashes, return Assets-relative if present * Update .claude/prompts/nl-unity-suite-full.md Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> * tests(framing): reduce handshake poll window, nonblocking peek to avoid disconnect race; still enforce pre-handshake data drop * tests(manage_script): add _split_uri tests for unity://path, file:// URLs (decoded/Assets-relative), and plain paths * server+tests: fix handshake syntax error; robust file:// URI normalization in manage_script; add _split_uri tests; adjust stdout scan to ignore venv/site-packages * bridge(framing): accept zero-length frames (treat as empty keepalive) * tests(logging): use errors='replace' on decode fallback to avoid silent drops * resources(list): restrict to Assets/, resolve symlinks, enforce .cs; add traversal/outside-path tests * Update .claude/prompts/nl-unity-suite-full.md Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update UnityMcpBridge/UnityMcpServer~/src/unity_connection.py Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * misc: framing keepalive (zero-length), regex preview consistency, resource.list hardening, URI parsing, legacy update routing, test cleanups * docs(tools): richer MCP tool descriptions; tests accept decorator kwargs; resource URI parsing hardened * Update .claude/prompts/nl-unity-suite-full.md Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update UnityMcpBridge/UnityMcpServer~/src/tools/resource_tools.py Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update UnityMcpBridge/UnityMcpServer~/src/unity_connection.py Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * net+docs: hard-reject zero-length frames; TCP_NODELAY on connect; Assets detection case-insensitive; NL prompt statuses aligned * prompt(nl-suite): constrain Write destinations under reports/, forbid traversal * prompt+net: harden Write path rules; use monotonic deadline and plain-text advisory for non-framed peers * unity_connection: restore recv timeout via try/finally; make global connection getter thread-safe with module lock and double-checked init * NL/T prompt: pin structured edit ops for T-D/T-E; add schema-error guarded write behavior; keep existing path/URI and revert rules * unity_connection: add FRAMED_MAX; use ValueError for framed length violations; lower framed receive log to debug; serialize connect() with per-instance lock * ManageScript: use UTF8Encoding(without BOM) for atomic writes in ApplyTextEdits/EditScript to align with Create/Update and avoid BOM-related diffs/hash mismatches * NL/T prompt: make helper deletion regex multiline-safe ((?ms) so ^ anchors line starts) * ManageScript: emit structured overlap status {status:"overlap"} for overlapping edit ranges in apply_text_edits and edit paths * NL/T prompt: clarify fallback vs failure — fallback only for unsupported/missing_field; treat bad_request as failure; note unsupported after fallback as failure * NL/T prompt: pin deterministic overlap probe (apply_text_edits two ranges from same snapshot); gate too_large behind RUN_TOO_LARGE env hint * TB update * NL/T prompt: harden Output Rules — constrain Bash(printf|echo) to stdout-only; forbid redirection/here-docs/tee; only scripts/nlt-revert.sh may mutate FS * Prompt: enumerate allowed script_apply_edits ops; add manage_editor/read_console guidance; fix T‑F atomic batch to single script_apply_edits. ManageScript: regex timeout for diagnostics; symlink ancestor guard; complete allowed-modes list. * Fixes * ManageScript: add rich overlap diagnostics (conflicts + hint) for both text range and structured batch paths * ManageScript: return structured {status:"validation_failed"} diagnostics in create/update/edits and validate before commit * ManageScript: echo canonical uri in responses (create/read/update/apply_text_edits/structured edits) to reinforce resource identity * improve clarity of capabilities message * Framing: allow zero-length frames on both ends (C# bridge, Python server). Prompt: harden T-F to single text-range apply_text_edits batch (descending order, one snapshot). URI: normalize file:// outside Assets by stripping leading slash. * ManageScript: include new sha256 in success payload for apply_text_edits; harden TryResolveUnderAssets by rejecting symlinked ancestors up to Assets/. * remove claudetest dir * manage_script_edits: normalize method-anchored anchor_insert to insert_method (map text->replacement); improves CI compatibility for T‑A/T‑E without changing Editor behavior. * tighten testing protocol around mkdir * manage_script: validate create_script inputs (Assets/.cs/name/no traversal); add Assets/ guard to delete_script; validate level+Assets in validate_script; make legacy manage_script optional params; harden legacy update routing with base64 reuse and payload size preflight. * Tighten prompt for testing * Update .claude/prompts/nl-unity-suite-full.md Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update .claude/prompts/nl-unity-suite-full.md Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update UnityMcpBridge/Editor/Tools/ManageScript.cs Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * manage_script_edits: honor ignore_case on anchor_insert and regex_replace in both direct and text-conversion paths (MULTILINE|IGNORECASE). * remove extra file * workflow: use python3 for inline scripts and port detection on ubuntu-latest. * Tighten prompt + manage_script * Update UnityMcpBridge/UnityMcpServer~/src/tools/manage_script_edits.py Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update UnityMcpBridge/UnityMcpServer~/src/tools/manage_script_edits.py Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update .claude/prompts/nl-unity-suite-full.md Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update UnityMcpBridge/Editor/Tools/ManageScript.cs Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update .claude/prompts/nl-unity-suite-full.md Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * manage_script: improve file:// UNC handling; preserve POSIX absolute semantics internally; keep test-expected slash stripping for non-Assets paths. * ManageScript.cs: add TimeSpan timeouts to all Regex uses (IsMatch/Match/new Regex) and keep CultureInvariant/Multiline options; reduces risk of catastrophic backtracking stalls. * workflow: ensure reports/ exists in markdown build step to avoid FileNotFoundError when writing MD_OUT. * fix brace * manage_script_edits: expand backrefs for regex_replace in preview->text conversion and translate to \g<n> in local apply; keeps previews and actual edits consistent. * anchor_insert: default to position=after, normalize surrounding newlines in Python conversion paths; C# path ensures trailing newline and skips duplicate insertion within class. * feat(mcp): add get_sha tool; apply_text_edits normalization+overlap preflight+strict; no-op evidence in C#; update NL suite prompt; add unit tests * feat(frames): accept zero-length heartbeat frames in client; add heartbeat test * feat(edits): guard destructive regex_replace with structural preflight; add robust tests; prompt uses delete_method for temp helper * feat(frames): bound heartbeat loop with timeout/threshold; align zero-length response with C#; update test * SDK hardening: atomic multi-span text edits; stop forcing sequential for structured ops; forward options on apply_text_edits; add validate=relaxed support and scoped checks; update NL/T prompt; add tests for options forwarding, relaxed mode, and atomic batches * Router: default applyMode=atomic for multi-span apply_text_edits; add tests * CI prompt: pass options.validate=relaxed for T-B/C; options.applyMode=atomic for T-F; emphasize always writing testcase and restoring on errors * Validation & DX: add validate=syntax (scoped), standardize evidence windows; early regex compile with hints; debug_preview for apply_text_edits * Update UnityMcpBridge/Editor/Windows/MCPForUnityEditorWindow.cs Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * NL/T suite-driven edits: LongUnityScriptClaudeTest, bridge helpers, server_version; prepare framing tests * Fix duplicate macConfigPath field in McpClient to resolve CS0102 * Editor threading: run EnsureServerInstalled on main thread; marshal EditorPrefs/DeleteKey + logging via delayCall * Docs(apply_text_edits): strengthen guidance on 1-based positions, verify-before-edit, and recommend anchors/structured edits * Docs(script_apply_edits): add safety guidance (anchors, method ops, validators) and recommended practices * Framed VerifyBridgePing in editor window; docs hardening for apply_text_edits and script_apply_edits --------- Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
2025-08-31 00:55:38 +08:00
// Safe write with atomic replace when available, without BOM
var encoding = new System.Text.UTF8Encoding(encoderShouldEmitUTF8Identifier: false);
string tempPath = fullPath + ".tmp";
File.WriteAllText(tempPath, contents, encoding);
string backupPath = fullPath + ".bak";
try
{
File.Replace(tempPath, fullPath, backupPath);
try { if (File.Exists(backupPath)) File.Delete(backupPath); } catch { }
}
catch (PlatformNotSupportedException)
{
File.Copy(tempPath, fullPath, true);
try { File.Delete(tempPath); } catch { }
try { if (File.Exists(backupPath)) File.Delete(backupPath); } catch { }
}
catch (IOException)
{
File.Copy(tempPath, fullPath, true);
try { File.Delete(tempPath); } catch { }
try { if (File.Exists(backupPath)) File.Delete(backupPath); } catch { }
}
// Prepare success response BEFORE any operation that can trigger a domain reload
var uri = $"unity://path/{relativePath}";
var ok = Response.Success(
$"Script '{name}.cs' updated successfully at '{relativePath}'.",
Claude‑friendly edit tools + framed transport + live Unity NL test framework (#243) * CI: gate desktop-parity on Anthropic key; pass anthropic_api_key like NL suite * Add quickprobe prompt and CI workflow (mcp-quickprobe.md, unity-mcp-quickprobe.yml) * strictier tool use to prevent subagent spawning and force mcp tools * update workflow filesto reduce likelihood of subagent spawning * improve permissions for claude agent, fix mcpbridge timeout/token issue * increase max turns to 10 * ci: align NL suite to new permissions schema; prevent subagent drift * ci: NL suite -> mini prompt for e2e; add full NL/T prompt; server: ctx optional + project_root fallback; workflows: set UNITY_PROJECT_ROOT for CI * ci: add checks:write; revert local project hardcodes (manifest, ProjectVersion.txt) * tools: text-edit routing fixes (anchor_insert via text, CRLF calc); prompts: mini NL/T clarifications * ci: use absolute UNITY_PROJECT_ROOT; prompts target TestProjects; server: accept relative UNITY_PROJECT_ROOT and bare spec URI * ci: ignore Unity test project's packages-lock.json; remove from repo to avoid absolute paths * CI: start persistent Unity Editor for MCP (guarded by license) + allow batch-mode bridge via UNITY_MCP_ALLOW_BATCH * CI: hide license and pass via env to docker; fix invalid ref format * CI: readiness probe uses handshake on Unity MCP port (deterministic) * CI: fix YAML; use TCP handshake readiness probe (FRAMING=1) * CI: prime Unity license via game-ci; mount ULF into container; extend readiness timeout * CI: use ULF write + mount for Unity licensing; remove serial/email/pass from container * CI: entitlement activation (UNITY_SERIAL=''); verify host ULF cache; keep mount * CI: write ULF from secret and verify; drop entitlement activation step * CI: detect any licensing path; GameCI prime; status dir env; log+probe readiness; fix YAML * CI: add GameCI license prime; conditional ULF write; one-shot license validation; explicit status dir + license env * CI: fix YAML (inline python), add Anthropic key detect via GITHUB_ENV; ready to run happy path * CI: mount Unity token/ulf/cache dirs into container to share host license; create dirs before start * CI: fix YAML indentation; write ULF on host; activate in container with shared mounts; mount .config and .cache too * CI: gate Claude via outputs; mount all Unity license dirs; fix inline probe python; stabilize licensing flow * CI: normalize detect to step outputs; ensure license dirs mounted and validated; fix indentation * Bridge: honor UNITY_MCP_STATUS_DIR for heartbeat/status file (CI-friendly) * CI: guard project path for activation/start; align tool allowlist; run MCP server with python; tighten secret scoping * CI: finalize Unity licensing mounts + status dir; mode-detect (ULF/EBL); readiness logs+probe; Claude gating via outputs * CI: fix YAML probe (inline python -c) and finalize happy-path Unity licensing and MCP/Claude wiring * CI: inline python probe; unify Unity image and cache mounts; ready to test * CI: fix docker run IMAGE placement; ignore cache find perms; keep same editor image * CI: pass -manualLicenseFile to persistent Editor; keep mounts and single image * CI: mount full GameCI cache to /root in persistent Unity; set HOME=/root; add optional license check * CI: make -manualLicenseFile conditional; keep full /root mount and license check * CI: set HOME=/github/home; mount GameCI cache there; adjust manualLicenseFile path; expand license check * CI: EBL sign-in for persistent Unity (email/password/serial); revert HOME=/root and full /root mount; keep conditional manualLicenseFile and improved readiness * CI: run full NL/T suite prompt (nl-unity-suite-full.md) instead of mini * NL/T: require unified diffs + explicit verdicts in JUnit; CI: remove short sanity step, publish JUnit, upload artifacts * NL/T prompt: require CDATA wrapping for JUnit XML fields; guidance for splitting embedded ]]>; keep VERDICT in CDATA only * CI: remove in-container license check step; keep readiness and full suite * NL/T prompt: add version header, stricter JUnit schema, hashing/normalization, anchors, statuses, atomic semantics, tool logging * CI: increase Claude NL/T suite timeout to 30 minutes * CI: pre-create reports dir and result files to avoid tool approval prompts * CI: skip wait if container not running; skip Editor start if project missing; broaden MCP deps detection; expand allowed tools * fixies to harden ManageScript * CI: sanitize NL/T markdown report to avoid NUL/encoding issues * revert breaking yyaml changes * CI: prime license, robust Unity start/wait, sanitize markdown via heredoc * Resolve merge: accept upstream renames/installer (fix/installer-cleanup-v2) and keep local framing/script-editing - Restored upstream server.py, EditorWindow, uv.lock\n- Preserved ManageScript editing/validation; switched to atomic write + debounced refresh\n- Updated tools/__init__.py to keep script_edits/resources and adopt new logger name\n- All Python tests via uv: 7 passed, 6 skipped, 9 xpassed; Unity compile OK * Fix Claude Desktop config path and atomic write issues - Fix macOS path for Claude Desktop config: use ~/Library/Application Support/Claude/ instead of ~/.config/Claude/ - Improve atomic write pattern with backup/restore safety - Replace File.Replace() with File.Move() for better macOS compatibility - Add proper error handling and cleanup for file operations - Resolves issue where installer couldn't find Claude Desktop config on macOS * Editor: use macConfigPath on macOS for MCP client config writes (Claude Desktop, etc.). Fallback to linuxConfigPath only if mac path missing. * Models: add macConfigPath to McpClient for macOS config path selection (fixes CS1061 in editor window). * Editor: on macOS, prefer macConfigPath in ManualConfigEditorWindow (fallback to linux path); Linux/Windows unchanged. * Fix McpClient: align with upstream/main, prep for framing split * NL suite: shard workflow; tighten bridge readiness; add MCP preflight; use env-based shard vars * NL suite: fix shard step indentation; move shard vars to env; remove invalid inputs * MCP clients: split VSCode Copilot config paths into macConfigPath and linuxConfigPath * Unity bridge: clean stale status; bind host; robust wait probe with IPv4/IPv6 + diagnostics * CI: use MCPForUnity.Editor.MCPForUnityBridge.StartAutoConnect as executeMethod * Action wiring: inline mcpServers in settings for all shards; remove redundant .claude/mcp.json step * CI: embed mcpServers in settings for all shards; fix startup sanity step; lint clean * CI: pin claude-code-base-action to e6f32c8; use claude_args --mcp-config; switch to allowed_tools; ensure MCP config per step * CI: unpin claude-code-base-action to @beta (commit ref not found) * CI: align with claude-code-base-action @beta; pass MCP via claude_args and allowedTools * Editor: Fix apply_text_edits heuristic when edits shift positions; recompute method span on candidate text with fallback delta adjustment * CI: unify MCP wiring across workflows; write .claude/mcp.json; switch to claude_args with --mcp-config/--allowedTools; remove unsupported inputs * CI: collapse NL suite shards into a single run to avoid repeated test execution * CI: minimize allowedTools for NL suite to essential Unity MCP + Bash("git:*") + Write * CI: mkdir -p reports before run; remove unsupported --timeout-minutes from claude_args * CI: broaden allowedTools to include find_in_file and mcp__unity__* * CI: enable use_node_cache and switch NL suite model to claude-3-7-haiku-20250219 * CI: disable use_node_cache to avoid setup-node lockfile error * CI: set NL suite model to claude-3-haiku-20240307 * CI: cap Haiku output with --max-tokens 2048 for NL suite * CI: switch to claude-3-7-sonnet-latest and remove unsupported --max-tokens * CI: update allowedTools to Bash(*) and explicit Unity MCP tool list * CI: update NL suite workflow (latest tweaks) * Tests: tighten NL suite prompt for logging, hash discipline, stale retry, evidence windows, diff cap, and VERDICT line * Add disallowed tools to NL suite workflow * docs: clarify stale write retry * Add fallback JUnit report and adjust publisher * Indent fallback JUnit XML in workflow * fix: correct fallback JUnit report generation * Update mcp-quickprobe.md Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> * Update mcp-quickprobe.md Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> * Update Response.cs Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> * Update MCPForUnityBridge.cs Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> * fix: correct McpTypes reference * Add directory existence checks for symlink and XDG paths * fix: only set installation flag after successful server install * Update resource_tools.py Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> * fix: respect mac config paths * Use File.Replace for atomic config write * Remove unused imports in manage_script * bump server version * Tests: update NL suite prompt and workflows; remove deprecated smoke/desktop-parity; quickprobe tidy * Editor: atomic config write via File.Replace fallback; remove redundant backups and racey exists checks * CI: harden NL suite - idempotent docker, gate on unity_ok, safer port probe, least-priv perms * Editor: make atomic config write restoration safe (flag writeDone; copy-overwrite restore; cleanup in finally) * CI: fix fallback JUnit heredoc by using printf lines (no EOF delimiter issues) * CI: switch NL suite to mini prompt; mini prompt honors / and NL discipline * CI: replace claude_args with allowed_tools/model/mcp_config per action schema * CI: expand UNITY_PROJECT_ROOT via in MCP config heredoc * EditorWindow: add cross-platform fallback for File.Replace; macOS-insensitive PathsEqual; safer uv resolve; honor macConfigPath * CI: strengthen JUnit publishing for NL mini suite (normalize, debug list, publish both, fail_on_parse_error) * CI: set job-wide JUNIT_OUT/MD_OUT; normalization uses env; publish references env and ungroup reports * CI: publish a single normalized JUnit (reports/junit-for-actions.xml); fallback writes same; avoid checkName/reportPaths mismatch * CI: align mini prompt report filenames; redact Unity log tail in diagnostics * chore: sync workflow and mini prompt; redacted logs; JUnit normalization/publish tweaks * CI: redact sensitive tokens in Stop Unity; docs: CI usage + edit tools * prompts: update nl-unity-suite-full (mini-style setup + reporting discipline); remove obsolete prompts * CI: harden NL workflows (timeout_minutes, robust normalization); prompts: unify JUnit suite name and reporting discipline * prompts: add guarded write pattern (LF hash, stale_file retry) to full suite * prompts: enforce continue-on-failure, driver flow, and status handling in full suite * Make test list more explicit in prompt. Get rid of old test prompts for hygeine. * prompts: add stale fast-retry (server hash) + in-memory buf guidance * CI: standardize JUNIT_OUT to reports/junit-nl-suite.xml; fix artifact upload indentation; prompt copy cleanups * prompts: reporting discipline — append-only fragments, batch writes, no model round-trip * prompts: stale fast-retry preference, buffer/sha carry, snapshot revert, essential logging * workflows(nl-suite): precreate report skeletons, assemble junit, synthesize markdown; restrict allowed_tools to append-only Bash + MCP tools * thsis too * Update README-DEV.md Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update .github/workflows/claude-nl-suite-mini.yml Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update .github/workflows/claude-nl-suite.yml Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * workflows(nl-mini): fix YAML indentation/trailing spaces under with: and cleanup heredoc spacing * workflows(nl-suite): fix indentation on docker logs redaction line (YAML lint) * Add write to allowlist * nl-suite: harden reporting discipline (fragment-only writes, forbid alt paths); workflow: clean stray junit-*updated*.xml * nl-suite: enforce end-of-suite single Write (no bash redirection); workflow: restrict allowed_tools to Write+MCP only * prompts(nl-full): end-of-suite results must be valid XML with single <cases> root and only <testcase> children; no raw text outside CDATA * workflows(nl-suite): make Claude step non-fatal; tolerant normalizer extracts <testcase> via regex on bad fragments * nl-suite: fix stale classname to UnityMCP.NL-T in mini fallback; prompt: require re-read after every revert; correct PLAN/PROGRESS to 15 * nl-suite: fix fallback JUnit classname to UnityMCP.NL-T; prompt: forbid create_script and env/mkdir checks, enforce single baseline-byte revert flow and post-revert re-read; add corruption-handling guidance * prompts(nl-full): after each write re-read raw bytes to refresh pre_sha; prefer script_apply_edits for anchors; avoid header/using changes * prompts(nl-full): canonicalize outputs to /; allow small fragment appends via Write or Bash(printf/echo); forbid wrappers and full-file round-trips * prompts(nl-full): finalize markdown formatting for guarded write, execution order, specs, status * workflows(nl-suite, mini): header/lint fixes and constrained Bash append path; align allowed_tools * prompts(nl-full): format Fast Restore, Guarded Write, Execution, Specs, Status as proper markdown lists and code fences * workflows(nl-suite): keep header tidy and append-path alignment with prompt * minor fix * workflows(nl-suite): fix indentation and dispatch; align allowed_tools and revert helper * prompts(nl-full): switch to read_resource for buf/sha; re-read only when needed; convert 'Print this once' to heading; note snapshot helper creates parent dirs * workflows(nl-suite): normalize step removes bootstrap when real testcases present; recompute tests/failures * workflows(nl-suite): enrich Markdown summary by extracting per-test <system-out> blocks (truncated) * clarify prompt resilience instructions * ci(nl-suite): revert prompt and workflow to known-good e0f8a72 for green run; remove extra MD details * ci(nl-suite): minimal fixes — no-mkdir guard in prompt; drop bootstrap and recompute JUnit counts * ci(nl-suite): richer JUnit→Markdown report (per-test system-out) * Small guard to incorret asset read call. * ci(nl-suite): refine MD builder — unescape XML entities, safe code fences, PASS/FAIL badges * Update UnityMcpBridge/UnityMcpServer~/src/tools/resource_tools.py Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update UnityMcpBridge/UnityMcpServer~/src/unity_connection.py Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update UnityMcpBridge/UnityMcpServer~/src/tools/manage_script_edits.py Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update .github/scripts/mark_skipped.py Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update .github/scripts/mark_skipped.py Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update .github/scripts/mark_skipped.py Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> * server(manage_script): robust URI handling — percent-decode file://, normalize, strip host/leading slashes, return Assets-relative if present * Update .claude/prompts/nl-unity-suite-full.md Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> * tests(framing): reduce handshake poll window, nonblocking peek to avoid disconnect race; still enforce pre-handshake data drop * tests(manage_script): add _split_uri tests for unity://path, file:// URLs (decoded/Assets-relative), and plain paths * server+tests: fix handshake syntax error; robust file:// URI normalization in manage_script; add _split_uri tests; adjust stdout scan to ignore venv/site-packages * bridge(framing): accept zero-length frames (treat as empty keepalive) * tests(logging): use errors='replace' on decode fallback to avoid silent drops * resources(list): restrict to Assets/, resolve symlinks, enforce .cs; add traversal/outside-path tests * Update .claude/prompts/nl-unity-suite-full.md Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update UnityMcpBridge/UnityMcpServer~/src/unity_connection.py Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * misc: framing keepalive (zero-length), regex preview consistency, resource.list hardening, URI parsing, legacy update routing, test cleanups * docs(tools): richer MCP tool descriptions; tests accept decorator kwargs; resource URI parsing hardened * Update .claude/prompts/nl-unity-suite-full.md Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update UnityMcpBridge/UnityMcpServer~/src/tools/resource_tools.py Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update UnityMcpBridge/UnityMcpServer~/src/unity_connection.py Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * net+docs: hard-reject zero-length frames; TCP_NODELAY on connect; Assets detection case-insensitive; NL prompt statuses aligned * prompt(nl-suite): constrain Write destinations under reports/, forbid traversal * prompt+net: harden Write path rules; use monotonic deadline and plain-text advisory for non-framed peers * unity_connection: restore recv timeout via try/finally; make global connection getter thread-safe with module lock and double-checked init * NL/T prompt: pin structured edit ops for T-D/T-E; add schema-error guarded write behavior; keep existing path/URI and revert rules * unity_connection: add FRAMED_MAX; use ValueError for framed length violations; lower framed receive log to debug; serialize connect() with per-instance lock * ManageScript: use UTF8Encoding(without BOM) for atomic writes in ApplyTextEdits/EditScript to align with Create/Update and avoid BOM-related diffs/hash mismatches * NL/T prompt: make helper deletion regex multiline-safe ((?ms) so ^ anchors line starts) * ManageScript: emit structured overlap status {status:"overlap"} for overlapping edit ranges in apply_text_edits and edit paths * NL/T prompt: clarify fallback vs failure — fallback only for unsupported/missing_field; treat bad_request as failure; note unsupported after fallback as failure * NL/T prompt: pin deterministic overlap probe (apply_text_edits two ranges from same snapshot); gate too_large behind RUN_TOO_LARGE env hint * TB update * NL/T prompt: harden Output Rules — constrain Bash(printf|echo) to stdout-only; forbid redirection/here-docs/tee; only scripts/nlt-revert.sh may mutate FS * Prompt: enumerate allowed script_apply_edits ops; add manage_editor/read_console guidance; fix T‑F atomic batch to single script_apply_edits. ManageScript: regex timeout for diagnostics; symlink ancestor guard; complete allowed-modes list. * Fixes * ManageScript: add rich overlap diagnostics (conflicts + hint) for both text range and structured batch paths * ManageScript: return structured {status:"validation_failed"} diagnostics in create/update/edits and validate before commit * ManageScript: echo canonical uri in responses (create/read/update/apply_text_edits/structured edits) to reinforce resource identity * improve clarity of capabilities message * Framing: allow zero-length frames on both ends (C# bridge, Python server). Prompt: harden T-F to single text-range apply_text_edits batch (descending order, one snapshot). URI: normalize file:// outside Assets by stripping leading slash. * ManageScript: include new sha256 in success payload for apply_text_edits; harden TryResolveUnderAssets by rejecting symlinked ancestors up to Assets/. * remove claudetest dir * manage_script_edits: normalize method-anchored anchor_insert to insert_method (map text->replacement); improves CI compatibility for T‑A/T‑E without changing Editor behavior. * tighten testing protocol around mkdir * manage_script: validate create_script inputs (Assets/.cs/name/no traversal); add Assets/ guard to delete_script; validate level+Assets in validate_script; make legacy manage_script optional params; harden legacy update routing with base64 reuse and payload size preflight. * Tighten prompt for testing * Update .claude/prompts/nl-unity-suite-full.md Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update .claude/prompts/nl-unity-suite-full.md Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update UnityMcpBridge/Editor/Tools/ManageScript.cs Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * manage_script_edits: honor ignore_case on anchor_insert and regex_replace in both direct and text-conversion paths (MULTILINE|IGNORECASE). * remove extra file * workflow: use python3 for inline scripts and port detection on ubuntu-latest. * Tighten prompt + manage_script * Update UnityMcpBridge/UnityMcpServer~/src/tools/manage_script_edits.py Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update UnityMcpBridge/UnityMcpServer~/src/tools/manage_script_edits.py Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update .claude/prompts/nl-unity-suite-full.md Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update UnityMcpBridge/Editor/Tools/ManageScript.cs Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update .claude/prompts/nl-unity-suite-full.md Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * manage_script: improve file:// UNC handling; preserve POSIX absolute semantics internally; keep test-expected slash stripping for non-Assets paths. * ManageScript.cs: add TimeSpan timeouts to all Regex uses (IsMatch/Match/new Regex) and keep CultureInvariant/Multiline options; reduces risk of catastrophic backtracking stalls. * workflow: ensure reports/ exists in markdown build step to avoid FileNotFoundError when writing MD_OUT. * fix brace * manage_script_edits: expand backrefs for regex_replace in preview->text conversion and translate to \g<n> in local apply; keeps previews and actual edits consistent. * anchor_insert: default to position=after, normalize surrounding newlines in Python conversion paths; C# path ensures trailing newline and skips duplicate insertion within class. * feat(mcp): add get_sha tool; apply_text_edits normalization+overlap preflight+strict; no-op evidence in C#; update NL suite prompt; add unit tests * feat(frames): accept zero-length heartbeat frames in client; add heartbeat test * feat(edits): guard destructive regex_replace with structural preflight; add robust tests; prompt uses delete_method for temp helper * feat(frames): bound heartbeat loop with timeout/threshold; align zero-length response with C#; update test * SDK hardening: atomic multi-span text edits; stop forcing sequential for structured ops; forward options on apply_text_edits; add validate=relaxed support and scoped checks; update NL/T prompt; add tests for options forwarding, relaxed mode, and atomic batches * Router: default applyMode=atomic for multi-span apply_text_edits; add tests * CI prompt: pass options.validate=relaxed for T-B/C; options.applyMode=atomic for T-F; emphasize always writing testcase and restoring on errors * Validation & DX: add validate=syntax (scoped), standardize evidence windows; early regex compile with hints; debug_preview for apply_text_edits * Update UnityMcpBridge/Editor/Windows/MCPForUnityEditorWindow.cs Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * NL/T suite-driven edits: LongUnityScriptClaudeTest, bridge helpers, server_version; prepare framing tests * Fix duplicate macConfigPath field in McpClient to resolve CS0102 * Editor threading: run EnsureServerInstalled on main thread; marshal EditorPrefs/DeleteKey + logging via delayCall * Docs(apply_text_edits): strengthen guidance on 1-based positions, verify-before-edit, and recommend anchors/structured edits * Docs(script_apply_edits): add safety guidance (anchors, method ops, validators) and recommended practices * Framed VerifyBridgePing in editor window; docs hardening for apply_text_edits and script_apply_edits --------- Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
2025-08-31 00:55:38 +08:00
new { uri, path = relativePath, scheduledRefresh = true }
);
Claude‑friendly edit tools + framed transport + live Unity NL test framework (#243) * CI: gate desktop-parity on Anthropic key; pass anthropic_api_key like NL suite * Add quickprobe prompt and CI workflow (mcp-quickprobe.md, unity-mcp-quickprobe.yml) * strictier tool use to prevent subagent spawning and force mcp tools * update workflow filesto reduce likelihood of subagent spawning * improve permissions for claude agent, fix mcpbridge timeout/token issue * increase max turns to 10 * ci: align NL suite to new permissions schema; prevent subagent drift * ci: NL suite -> mini prompt for e2e; add full NL/T prompt; server: ctx optional + project_root fallback; workflows: set UNITY_PROJECT_ROOT for CI * ci: add checks:write; revert local project hardcodes (manifest, ProjectVersion.txt) * tools: text-edit routing fixes (anchor_insert via text, CRLF calc); prompts: mini NL/T clarifications * ci: use absolute UNITY_PROJECT_ROOT; prompts target TestProjects; server: accept relative UNITY_PROJECT_ROOT and bare spec URI * ci: ignore Unity test project's packages-lock.json; remove from repo to avoid absolute paths * CI: start persistent Unity Editor for MCP (guarded by license) + allow batch-mode bridge via UNITY_MCP_ALLOW_BATCH * CI: hide license and pass via env to docker; fix invalid ref format * CI: readiness probe uses handshake on Unity MCP port (deterministic) * CI: fix YAML; use TCP handshake readiness probe (FRAMING=1) * CI: prime Unity license via game-ci; mount ULF into container; extend readiness timeout * CI: use ULF write + mount for Unity licensing; remove serial/email/pass from container * CI: entitlement activation (UNITY_SERIAL=''); verify host ULF cache; keep mount * CI: write ULF from secret and verify; drop entitlement activation step * CI: detect any licensing path; GameCI prime; status dir env; log+probe readiness; fix YAML * CI: add GameCI license prime; conditional ULF write; one-shot license validation; explicit status dir + license env * CI: fix YAML (inline python), add Anthropic key detect via GITHUB_ENV; ready to run happy path * CI: mount Unity token/ulf/cache dirs into container to share host license; create dirs before start * CI: fix YAML indentation; write ULF on host; activate in container with shared mounts; mount .config and .cache too * CI: gate Claude via outputs; mount all Unity license dirs; fix inline probe python; stabilize licensing flow * CI: normalize detect to step outputs; ensure license dirs mounted and validated; fix indentation * Bridge: honor UNITY_MCP_STATUS_DIR for heartbeat/status file (CI-friendly) * CI: guard project path for activation/start; align tool allowlist; run MCP server with python; tighten secret scoping * CI: finalize Unity licensing mounts + status dir; mode-detect (ULF/EBL); readiness logs+probe; Claude gating via outputs * CI: fix YAML probe (inline python -c) and finalize happy-path Unity licensing and MCP/Claude wiring * CI: inline python probe; unify Unity image and cache mounts; ready to test * CI: fix docker run IMAGE placement; ignore cache find perms; keep same editor image * CI: pass -manualLicenseFile to persistent Editor; keep mounts and single image * CI: mount full GameCI cache to /root in persistent Unity; set HOME=/root; add optional license check * CI: make -manualLicenseFile conditional; keep full /root mount and license check * CI: set HOME=/github/home; mount GameCI cache there; adjust manualLicenseFile path; expand license check * CI: EBL sign-in for persistent Unity (email/password/serial); revert HOME=/root and full /root mount; keep conditional manualLicenseFile and improved readiness * CI: run full NL/T suite prompt (nl-unity-suite-full.md) instead of mini * NL/T: require unified diffs + explicit verdicts in JUnit; CI: remove short sanity step, publish JUnit, upload artifacts * NL/T prompt: require CDATA wrapping for JUnit XML fields; guidance for splitting embedded ]]>; keep VERDICT in CDATA only * CI: remove in-container license check step; keep readiness and full suite * NL/T prompt: add version header, stricter JUnit schema, hashing/normalization, anchors, statuses, atomic semantics, tool logging * CI: increase Claude NL/T suite timeout to 30 minutes * CI: pre-create reports dir and result files to avoid tool approval prompts * CI: skip wait if container not running; skip Editor start if project missing; broaden MCP deps detection; expand allowed tools * fixies to harden ManageScript * CI: sanitize NL/T markdown report to avoid NUL/encoding issues * revert breaking yyaml changes * CI: prime license, robust Unity start/wait, sanitize markdown via heredoc * Resolve merge: accept upstream renames/installer (fix/installer-cleanup-v2) and keep local framing/script-editing - Restored upstream server.py, EditorWindow, uv.lock\n- Preserved ManageScript editing/validation; switched to atomic write + debounced refresh\n- Updated tools/__init__.py to keep script_edits/resources and adopt new logger name\n- All Python tests via uv: 7 passed, 6 skipped, 9 xpassed; Unity compile OK * Fix Claude Desktop config path and atomic write issues - Fix macOS path for Claude Desktop config: use ~/Library/Application Support/Claude/ instead of ~/.config/Claude/ - Improve atomic write pattern with backup/restore safety - Replace File.Replace() with File.Move() for better macOS compatibility - Add proper error handling and cleanup for file operations - Resolves issue where installer couldn't find Claude Desktop config on macOS * Editor: use macConfigPath on macOS for MCP client config writes (Claude Desktop, etc.). Fallback to linuxConfigPath only if mac path missing. * Models: add macConfigPath to McpClient for macOS config path selection (fixes CS1061 in editor window). * Editor: on macOS, prefer macConfigPath in ManualConfigEditorWindow (fallback to linux path); Linux/Windows unchanged. * Fix McpClient: align with upstream/main, prep for framing split * NL suite: shard workflow; tighten bridge readiness; add MCP preflight; use env-based shard vars * NL suite: fix shard step indentation; move shard vars to env; remove invalid inputs * MCP clients: split VSCode Copilot config paths into macConfigPath and linuxConfigPath * Unity bridge: clean stale status; bind host; robust wait probe with IPv4/IPv6 + diagnostics * CI: use MCPForUnity.Editor.MCPForUnityBridge.StartAutoConnect as executeMethod * Action wiring: inline mcpServers in settings for all shards; remove redundant .claude/mcp.json step * CI: embed mcpServers in settings for all shards; fix startup sanity step; lint clean * CI: pin claude-code-base-action to e6f32c8; use claude_args --mcp-config; switch to allowed_tools; ensure MCP config per step * CI: unpin claude-code-base-action to @beta (commit ref not found) * CI: align with claude-code-base-action @beta; pass MCP via claude_args and allowedTools * Editor: Fix apply_text_edits heuristic when edits shift positions; recompute method span on candidate text with fallback delta adjustment * CI: unify MCP wiring across workflows; write .claude/mcp.json; switch to claude_args with --mcp-config/--allowedTools; remove unsupported inputs * CI: collapse NL suite shards into a single run to avoid repeated test execution * CI: minimize allowedTools for NL suite to essential Unity MCP + Bash("git:*") + Write * CI: mkdir -p reports before run; remove unsupported --timeout-minutes from claude_args * CI: broaden allowedTools to include find_in_file and mcp__unity__* * CI: enable use_node_cache and switch NL suite model to claude-3-7-haiku-20250219 * CI: disable use_node_cache to avoid setup-node lockfile error * CI: set NL suite model to claude-3-haiku-20240307 * CI: cap Haiku output with --max-tokens 2048 for NL suite * CI: switch to claude-3-7-sonnet-latest and remove unsupported --max-tokens * CI: update allowedTools to Bash(*) and explicit Unity MCP tool list * CI: update NL suite workflow (latest tweaks) * Tests: tighten NL suite prompt for logging, hash discipline, stale retry, evidence windows, diff cap, and VERDICT line * Add disallowed tools to NL suite workflow * docs: clarify stale write retry * Add fallback JUnit report and adjust publisher * Indent fallback JUnit XML in workflow * fix: correct fallback JUnit report generation * Update mcp-quickprobe.md Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> * Update mcp-quickprobe.md Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> * Update Response.cs Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> * Update MCPForUnityBridge.cs Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> * fix: correct McpTypes reference * Add directory existence checks for symlink and XDG paths * fix: only set installation flag after successful server install * Update resource_tools.py Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> * fix: respect mac config paths * Use File.Replace for atomic config write * Remove unused imports in manage_script * bump server version * Tests: update NL suite prompt and workflows; remove deprecated smoke/desktop-parity; quickprobe tidy * Editor: atomic config write via File.Replace fallback; remove redundant backups and racey exists checks * CI: harden NL suite - idempotent docker, gate on unity_ok, safer port probe, least-priv perms * Editor: make atomic config write restoration safe (flag writeDone; copy-overwrite restore; cleanup in finally) * CI: fix fallback JUnit heredoc by using printf lines (no EOF delimiter issues) * CI: switch NL suite to mini prompt; mini prompt honors / and NL discipline * CI: replace claude_args with allowed_tools/model/mcp_config per action schema * CI: expand UNITY_PROJECT_ROOT via in MCP config heredoc * EditorWindow: add cross-platform fallback for File.Replace; macOS-insensitive PathsEqual; safer uv resolve; honor macConfigPath * CI: strengthen JUnit publishing for NL mini suite (normalize, debug list, publish both, fail_on_parse_error) * CI: set job-wide JUNIT_OUT/MD_OUT; normalization uses env; publish references env and ungroup reports * CI: publish a single normalized JUnit (reports/junit-for-actions.xml); fallback writes same; avoid checkName/reportPaths mismatch * CI: align mini prompt report filenames; redact Unity log tail in diagnostics * chore: sync workflow and mini prompt; redacted logs; JUnit normalization/publish tweaks * CI: redact sensitive tokens in Stop Unity; docs: CI usage + edit tools * prompts: update nl-unity-suite-full (mini-style setup + reporting discipline); remove obsolete prompts * CI: harden NL workflows (timeout_minutes, robust normalization); prompts: unify JUnit suite name and reporting discipline * prompts: add guarded write pattern (LF hash, stale_file retry) to full suite * prompts: enforce continue-on-failure, driver flow, and status handling in full suite * Make test list more explicit in prompt. Get rid of old test prompts for hygeine. * prompts: add stale fast-retry (server hash) + in-memory buf guidance * CI: standardize JUNIT_OUT to reports/junit-nl-suite.xml; fix artifact upload indentation; prompt copy cleanups * prompts: reporting discipline — append-only fragments, batch writes, no model round-trip * prompts: stale fast-retry preference, buffer/sha carry, snapshot revert, essential logging * workflows(nl-suite): precreate report skeletons, assemble junit, synthesize markdown; restrict allowed_tools to append-only Bash + MCP tools * thsis too * Update README-DEV.md Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update .github/workflows/claude-nl-suite-mini.yml Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update .github/workflows/claude-nl-suite.yml Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * workflows(nl-mini): fix YAML indentation/trailing spaces under with: and cleanup heredoc spacing * workflows(nl-suite): fix indentation on docker logs redaction line (YAML lint) * Add write to allowlist * nl-suite: harden reporting discipline (fragment-only writes, forbid alt paths); workflow: clean stray junit-*updated*.xml * nl-suite: enforce end-of-suite single Write (no bash redirection); workflow: restrict allowed_tools to Write+MCP only * prompts(nl-full): end-of-suite results must be valid XML with single <cases> root and only <testcase> children; no raw text outside CDATA * workflows(nl-suite): make Claude step non-fatal; tolerant normalizer extracts <testcase> via regex on bad fragments * nl-suite: fix stale classname to UnityMCP.NL-T in mini fallback; prompt: require re-read after every revert; correct PLAN/PROGRESS to 15 * nl-suite: fix fallback JUnit classname to UnityMCP.NL-T; prompt: forbid create_script and env/mkdir checks, enforce single baseline-byte revert flow and post-revert re-read; add corruption-handling guidance * prompts(nl-full): after each write re-read raw bytes to refresh pre_sha; prefer script_apply_edits for anchors; avoid header/using changes * prompts(nl-full): canonicalize outputs to /; allow small fragment appends via Write or Bash(printf/echo); forbid wrappers and full-file round-trips * prompts(nl-full): finalize markdown formatting for guarded write, execution order, specs, status * workflows(nl-suite, mini): header/lint fixes and constrained Bash append path; align allowed_tools * prompts(nl-full): format Fast Restore, Guarded Write, Execution, Specs, Status as proper markdown lists and code fences * workflows(nl-suite): keep header tidy and append-path alignment with prompt * minor fix * workflows(nl-suite): fix indentation and dispatch; align allowed_tools and revert helper * prompts(nl-full): switch to read_resource for buf/sha; re-read only when needed; convert 'Print this once' to heading; note snapshot helper creates parent dirs * workflows(nl-suite): normalize step removes bootstrap when real testcases present; recompute tests/failures * workflows(nl-suite): enrich Markdown summary by extracting per-test <system-out> blocks (truncated) * clarify prompt resilience instructions * ci(nl-suite): revert prompt and workflow to known-good e0f8a72 for green run; remove extra MD details * ci(nl-suite): minimal fixes — no-mkdir guard in prompt; drop bootstrap and recompute JUnit counts * ci(nl-suite): richer JUnit→Markdown report (per-test system-out) * Small guard to incorret asset read call. * ci(nl-suite): refine MD builder — unescape XML entities, safe code fences, PASS/FAIL badges * Update UnityMcpBridge/UnityMcpServer~/src/tools/resource_tools.py Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update UnityMcpBridge/UnityMcpServer~/src/unity_connection.py Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update UnityMcpBridge/UnityMcpServer~/src/tools/manage_script_edits.py Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update .github/scripts/mark_skipped.py Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update .github/scripts/mark_skipped.py Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update .github/scripts/mark_skipped.py Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> * server(manage_script): robust URI handling — percent-decode file://, normalize, strip host/leading slashes, return Assets-relative if present * Update .claude/prompts/nl-unity-suite-full.md Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> * tests(framing): reduce handshake poll window, nonblocking peek to avoid disconnect race; still enforce pre-handshake data drop * tests(manage_script): add _split_uri tests for unity://path, file:// URLs (decoded/Assets-relative), and plain paths * server+tests: fix handshake syntax error; robust file:// URI normalization in manage_script; add _split_uri tests; adjust stdout scan to ignore venv/site-packages * bridge(framing): accept zero-length frames (treat as empty keepalive) * tests(logging): use errors='replace' on decode fallback to avoid silent drops * resources(list): restrict to Assets/, resolve symlinks, enforce .cs; add traversal/outside-path tests * Update .claude/prompts/nl-unity-suite-full.md Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update UnityMcpBridge/UnityMcpServer~/src/unity_connection.py Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * misc: framing keepalive (zero-length), regex preview consistency, resource.list hardening, URI parsing, legacy update routing, test cleanups * docs(tools): richer MCP tool descriptions; tests accept decorator kwargs; resource URI parsing hardened * Update .claude/prompts/nl-unity-suite-full.md Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update UnityMcpBridge/UnityMcpServer~/src/tools/resource_tools.py Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update UnityMcpBridge/UnityMcpServer~/src/unity_connection.py Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * net+docs: hard-reject zero-length frames; TCP_NODELAY on connect; Assets detection case-insensitive; NL prompt statuses aligned * prompt(nl-suite): constrain Write destinations under reports/, forbid traversal * prompt+net: harden Write path rules; use monotonic deadline and plain-text advisory for non-framed peers * unity_connection: restore recv timeout via try/finally; make global connection getter thread-safe with module lock and double-checked init * NL/T prompt: pin structured edit ops for T-D/T-E; add schema-error guarded write behavior; keep existing path/URI and revert rules * unity_connection: add FRAMED_MAX; use ValueError for framed length violations; lower framed receive log to debug; serialize connect() with per-instance lock * ManageScript: use UTF8Encoding(without BOM) for atomic writes in ApplyTextEdits/EditScript to align with Create/Update and avoid BOM-related diffs/hash mismatches * NL/T prompt: make helper deletion regex multiline-safe ((?ms) so ^ anchors line starts) * ManageScript: emit structured overlap status {status:"overlap"} for overlapping edit ranges in apply_text_edits and edit paths * NL/T prompt: clarify fallback vs failure — fallback only for unsupported/missing_field; treat bad_request as failure; note unsupported after fallback as failure * NL/T prompt: pin deterministic overlap probe (apply_text_edits two ranges from same snapshot); gate too_large behind RUN_TOO_LARGE env hint * TB update * NL/T prompt: harden Output Rules — constrain Bash(printf|echo) to stdout-only; forbid redirection/here-docs/tee; only scripts/nlt-revert.sh may mutate FS * Prompt: enumerate allowed script_apply_edits ops; add manage_editor/read_console guidance; fix T‑F atomic batch to single script_apply_edits. ManageScript: regex timeout for diagnostics; symlink ancestor guard; complete allowed-modes list. * Fixes * ManageScript: add rich overlap diagnostics (conflicts + hint) for both text range and structured batch paths * ManageScript: return structured {status:"validation_failed"} diagnostics in create/update/edits and validate before commit * ManageScript: echo canonical uri in responses (create/read/update/apply_text_edits/structured edits) to reinforce resource identity * improve clarity of capabilities message * Framing: allow zero-length frames on both ends (C# bridge, Python server). Prompt: harden T-F to single text-range apply_text_edits batch (descending order, one snapshot). URI: normalize file:// outside Assets by stripping leading slash. * ManageScript: include new sha256 in success payload for apply_text_edits; harden TryResolveUnderAssets by rejecting symlinked ancestors up to Assets/. * remove claudetest dir * manage_script_edits: normalize method-anchored anchor_insert to insert_method (map text->replacement); improves CI compatibility for T‑A/T‑E without changing Editor behavior. * tighten testing protocol around mkdir * manage_script: validate create_script inputs (Assets/.cs/name/no traversal); add Assets/ guard to delete_script; validate level+Assets in validate_script; make legacy manage_script optional params; harden legacy update routing with base64 reuse and payload size preflight. * Tighten prompt for testing * Update .claude/prompts/nl-unity-suite-full.md Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update .claude/prompts/nl-unity-suite-full.md Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update UnityMcpBridge/Editor/Tools/ManageScript.cs Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * manage_script_edits: honor ignore_case on anchor_insert and regex_replace in both direct and text-conversion paths (MULTILINE|IGNORECASE). * remove extra file * workflow: use python3 for inline scripts and port detection on ubuntu-latest. * Tighten prompt + manage_script * Update UnityMcpBridge/UnityMcpServer~/src/tools/manage_script_edits.py Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update UnityMcpBridge/UnityMcpServer~/src/tools/manage_script_edits.py Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update .claude/prompts/nl-unity-suite-full.md Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update UnityMcpBridge/Editor/Tools/ManageScript.cs Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update .claude/prompts/nl-unity-suite-full.md Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * manage_script: improve file:// UNC handling; preserve POSIX absolute semantics internally; keep test-expected slash stripping for non-Assets paths. * ManageScript.cs: add TimeSpan timeouts to all Regex uses (IsMatch/Match/new Regex) and keep CultureInvariant/Multiline options; reduces risk of catastrophic backtracking stalls. * workflow: ensure reports/ exists in markdown build step to avoid FileNotFoundError when writing MD_OUT. * fix brace * manage_script_edits: expand backrefs for regex_replace in preview->text conversion and translate to \g<n> in local apply; keeps previews and actual edits consistent. * anchor_insert: default to position=after, normalize surrounding newlines in Python conversion paths; C# path ensures trailing newline and skips duplicate insertion within class. * feat(mcp): add get_sha tool; apply_text_edits normalization+overlap preflight+strict; no-op evidence in C#; update NL suite prompt; add unit tests * feat(frames): accept zero-length heartbeat frames in client; add heartbeat test * feat(edits): guard destructive regex_replace with structural preflight; add robust tests; prompt uses delete_method for temp helper * feat(frames): bound heartbeat loop with timeout/threshold; align zero-length response with C#; update test * SDK hardening: atomic multi-span text edits; stop forcing sequential for structured ops; forward options on apply_text_edits; add validate=relaxed support and scoped checks; update NL/T prompt; add tests for options forwarding, relaxed mode, and atomic batches * Router: default applyMode=atomic for multi-span apply_text_edits; add tests * CI prompt: pass options.validate=relaxed for T-B/C; options.applyMode=atomic for T-F; emphasize always writing testcase and restoring on errors * Validation & DX: add validate=syntax (scoped), standardize evidence windows; early regex compile with hints; debug_preview for apply_text_edits * Update UnityMcpBridge/Editor/Windows/MCPForUnityEditorWindow.cs Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * NL/T suite-driven edits: LongUnityScriptClaudeTest, bridge helpers, server_version; prepare framing tests * Fix duplicate macConfigPath field in McpClient to resolve CS0102 * Editor threading: run EnsureServerInstalled on main thread; marshal EditorPrefs/DeleteKey + logging via delayCall * Docs(apply_text_edits): strengthen guidance on 1-based positions, verify-before-edit, and recommend anchors/structured edits * Docs(script_apply_edits): add safety guidance (anchors, method ops, validators) and recommended practices * Framed VerifyBridgePing in editor window; docs hardening for apply_text_edits and script_apply_edits --------- Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
2025-08-31 00:55:38 +08:00
// Schedule a debounced import/compile on next editor tick to avoid stalling the reply
ManageScriptRefreshHelpers.ScheduleScriptRefresh(relativePath);
return ok;
2025-03-31 03:58:01 +08:00
}
catch (Exception e)
{
return Response.Error($"Failed to update script '{relativePath}': {e.Message}");
}
}
Claude‑friendly edit tools + framed transport + live Unity NL test framework (#243) * CI: gate desktop-parity on Anthropic key; pass anthropic_api_key like NL suite * Add quickprobe prompt and CI workflow (mcp-quickprobe.md, unity-mcp-quickprobe.yml) * strictier tool use to prevent subagent spawning and force mcp tools * update workflow filesto reduce likelihood of subagent spawning * improve permissions for claude agent, fix mcpbridge timeout/token issue * increase max turns to 10 * ci: align NL suite to new permissions schema; prevent subagent drift * ci: NL suite -> mini prompt for e2e; add full NL/T prompt; server: ctx optional + project_root fallback; workflows: set UNITY_PROJECT_ROOT for CI * ci: add checks:write; revert local project hardcodes (manifest, ProjectVersion.txt) * tools: text-edit routing fixes (anchor_insert via text, CRLF calc); prompts: mini NL/T clarifications * ci: use absolute UNITY_PROJECT_ROOT; prompts target TestProjects; server: accept relative UNITY_PROJECT_ROOT and bare spec URI * ci: ignore Unity test project's packages-lock.json; remove from repo to avoid absolute paths * CI: start persistent Unity Editor for MCP (guarded by license) + allow batch-mode bridge via UNITY_MCP_ALLOW_BATCH * CI: hide license and pass via env to docker; fix invalid ref format * CI: readiness probe uses handshake on Unity MCP port (deterministic) * CI: fix YAML; use TCP handshake readiness probe (FRAMING=1) * CI: prime Unity license via game-ci; mount ULF into container; extend readiness timeout * CI: use ULF write + mount for Unity licensing; remove serial/email/pass from container * CI: entitlement activation (UNITY_SERIAL=''); verify host ULF cache; keep mount * CI: write ULF from secret and verify; drop entitlement activation step * CI: detect any licensing path; GameCI prime; status dir env; log+probe readiness; fix YAML * CI: add GameCI license prime; conditional ULF write; one-shot license validation; explicit status dir + license env * CI: fix YAML (inline python), add Anthropic key detect via GITHUB_ENV; ready to run happy path * CI: mount Unity token/ulf/cache dirs into container to share host license; create dirs before start * CI: fix YAML indentation; write ULF on host; activate in container with shared mounts; mount .config and .cache too * CI: gate Claude via outputs; mount all Unity license dirs; fix inline probe python; stabilize licensing flow * CI: normalize detect to step outputs; ensure license dirs mounted and validated; fix indentation * Bridge: honor UNITY_MCP_STATUS_DIR for heartbeat/status file (CI-friendly) * CI: guard project path for activation/start; align tool allowlist; run MCP server with python; tighten secret scoping * CI: finalize Unity licensing mounts + status dir; mode-detect (ULF/EBL); readiness logs+probe; Claude gating via outputs * CI: fix YAML probe (inline python -c) and finalize happy-path Unity licensing and MCP/Claude wiring * CI: inline python probe; unify Unity image and cache mounts; ready to test * CI: fix docker run IMAGE placement; ignore cache find perms; keep same editor image * CI: pass -manualLicenseFile to persistent Editor; keep mounts and single image * CI: mount full GameCI cache to /root in persistent Unity; set HOME=/root; add optional license check * CI: make -manualLicenseFile conditional; keep full /root mount and license check * CI: set HOME=/github/home; mount GameCI cache there; adjust manualLicenseFile path; expand license check * CI: EBL sign-in for persistent Unity (email/password/serial); revert HOME=/root and full /root mount; keep conditional manualLicenseFile and improved readiness * CI: run full NL/T suite prompt (nl-unity-suite-full.md) instead of mini * NL/T: require unified diffs + explicit verdicts in JUnit; CI: remove short sanity step, publish JUnit, upload artifacts * NL/T prompt: require CDATA wrapping for JUnit XML fields; guidance for splitting embedded ]]>; keep VERDICT in CDATA only * CI: remove in-container license check step; keep readiness and full suite * NL/T prompt: add version header, stricter JUnit schema, hashing/normalization, anchors, statuses, atomic semantics, tool logging * CI: increase Claude NL/T suite timeout to 30 minutes * CI: pre-create reports dir and result files to avoid tool approval prompts * CI: skip wait if container not running; skip Editor start if project missing; broaden MCP deps detection; expand allowed tools * fixies to harden ManageScript * CI: sanitize NL/T markdown report to avoid NUL/encoding issues * revert breaking yyaml changes * CI: prime license, robust Unity start/wait, sanitize markdown via heredoc * Resolve merge: accept upstream renames/installer (fix/installer-cleanup-v2) and keep local framing/script-editing - Restored upstream server.py, EditorWindow, uv.lock\n- Preserved ManageScript editing/validation; switched to atomic write + debounced refresh\n- Updated tools/__init__.py to keep script_edits/resources and adopt new logger name\n- All Python tests via uv: 7 passed, 6 skipped, 9 xpassed; Unity compile OK * Fix Claude Desktop config path and atomic write issues - Fix macOS path for Claude Desktop config: use ~/Library/Application Support/Claude/ instead of ~/.config/Claude/ - Improve atomic write pattern with backup/restore safety - Replace File.Replace() with File.Move() for better macOS compatibility - Add proper error handling and cleanup for file operations - Resolves issue where installer couldn't find Claude Desktop config on macOS * Editor: use macConfigPath on macOS for MCP client config writes (Claude Desktop, etc.). Fallback to linuxConfigPath only if mac path missing. * Models: add macConfigPath to McpClient for macOS config path selection (fixes CS1061 in editor window). * Editor: on macOS, prefer macConfigPath in ManualConfigEditorWindow (fallback to linux path); Linux/Windows unchanged. * Fix McpClient: align with upstream/main, prep for framing split * NL suite: shard workflow; tighten bridge readiness; add MCP preflight; use env-based shard vars * NL suite: fix shard step indentation; move shard vars to env; remove invalid inputs * MCP clients: split VSCode Copilot config paths into macConfigPath and linuxConfigPath * Unity bridge: clean stale status; bind host; robust wait probe with IPv4/IPv6 + diagnostics * CI: use MCPForUnity.Editor.MCPForUnityBridge.StartAutoConnect as executeMethod * Action wiring: inline mcpServers in settings for all shards; remove redundant .claude/mcp.json step * CI: embed mcpServers in settings for all shards; fix startup sanity step; lint clean * CI: pin claude-code-base-action to e6f32c8; use claude_args --mcp-config; switch to allowed_tools; ensure MCP config per step * CI: unpin claude-code-base-action to @beta (commit ref not found) * CI: align with claude-code-base-action @beta; pass MCP via claude_args and allowedTools * Editor: Fix apply_text_edits heuristic when edits shift positions; recompute method span on candidate text with fallback delta adjustment * CI: unify MCP wiring across workflows; write .claude/mcp.json; switch to claude_args with --mcp-config/--allowedTools; remove unsupported inputs * CI: collapse NL suite shards into a single run to avoid repeated test execution * CI: minimize allowedTools for NL suite to essential Unity MCP + Bash("git:*") + Write * CI: mkdir -p reports before run; remove unsupported --timeout-minutes from claude_args * CI: broaden allowedTools to include find_in_file and mcp__unity__* * CI: enable use_node_cache and switch NL suite model to claude-3-7-haiku-20250219 * CI: disable use_node_cache to avoid setup-node lockfile error * CI: set NL suite model to claude-3-haiku-20240307 * CI: cap Haiku output with --max-tokens 2048 for NL suite * CI: switch to claude-3-7-sonnet-latest and remove unsupported --max-tokens * CI: update allowedTools to Bash(*) and explicit Unity MCP tool list * CI: update NL suite workflow (latest tweaks) * Tests: tighten NL suite prompt for logging, hash discipline, stale retry, evidence windows, diff cap, and VERDICT line * Add disallowed tools to NL suite workflow * docs: clarify stale write retry * Add fallback JUnit report and adjust publisher * Indent fallback JUnit XML in workflow * fix: correct fallback JUnit report generation * Update mcp-quickprobe.md Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> * Update mcp-quickprobe.md Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> * Update Response.cs Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> * Update MCPForUnityBridge.cs Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> * fix: correct McpTypes reference * Add directory existence checks for symlink and XDG paths * fix: only set installation flag after successful server install * Update resource_tools.py Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> * fix: respect mac config paths * Use File.Replace for atomic config write * Remove unused imports in manage_script * bump server version * Tests: update NL suite prompt and workflows; remove deprecated smoke/desktop-parity; quickprobe tidy * Editor: atomic config write via File.Replace fallback; remove redundant backups and racey exists checks * CI: harden NL suite - idempotent docker, gate on unity_ok, safer port probe, least-priv perms * Editor: make atomic config write restoration safe (flag writeDone; copy-overwrite restore; cleanup in finally) * CI: fix fallback JUnit heredoc by using printf lines (no EOF delimiter issues) * CI: switch NL suite to mini prompt; mini prompt honors / and NL discipline * CI: replace claude_args with allowed_tools/model/mcp_config per action schema * CI: expand UNITY_PROJECT_ROOT via in MCP config heredoc * EditorWindow: add cross-platform fallback for File.Replace; macOS-insensitive PathsEqual; safer uv resolve; honor macConfigPath * CI: strengthen JUnit publishing for NL mini suite (normalize, debug list, publish both, fail_on_parse_error) * CI: set job-wide JUNIT_OUT/MD_OUT; normalization uses env; publish references env and ungroup reports * CI: publish a single normalized JUnit (reports/junit-for-actions.xml); fallback writes same; avoid checkName/reportPaths mismatch * CI: align mini prompt report filenames; redact Unity log tail in diagnostics * chore: sync workflow and mini prompt; redacted logs; JUnit normalization/publish tweaks * CI: redact sensitive tokens in Stop Unity; docs: CI usage + edit tools * prompts: update nl-unity-suite-full (mini-style setup + reporting discipline); remove obsolete prompts * CI: harden NL workflows (timeout_minutes, robust normalization); prompts: unify JUnit suite name and reporting discipline * prompts: add guarded write pattern (LF hash, stale_file retry) to full suite * prompts: enforce continue-on-failure, driver flow, and status handling in full suite * Make test list more explicit in prompt. Get rid of old test prompts for hygeine. * prompts: add stale fast-retry (server hash) + in-memory buf guidance * CI: standardize JUNIT_OUT to reports/junit-nl-suite.xml; fix artifact upload indentation; prompt copy cleanups * prompts: reporting discipline — append-only fragments, batch writes, no model round-trip * prompts: stale fast-retry preference, buffer/sha carry, snapshot revert, essential logging * workflows(nl-suite): precreate report skeletons, assemble junit, synthesize markdown; restrict allowed_tools to append-only Bash + MCP tools * thsis too * Update README-DEV.md Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update .github/workflows/claude-nl-suite-mini.yml Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update .github/workflows/claude-nl-suite.yml Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * workflows(nl-mini): fix YAML indentation/trailing spaces under with: and cleanup heredoc spacing * workflows(nl-suite): fix indentation on docker logs redaction line (YAML lint) * Add write to allowlist * nl-suite: harden reporting discipline (fragment-only writes, forbid alt paths); workflow: clean stray junit-*updated*.xml * nl-suite: enforce end-of-suite single Write (no bash redirection); workflow: restrict allowed_tools to Write+MCP only * prompts(nl-full): end-of-suite results must be valid XML with single <cases> root and only <testcase> children; no raw text outside CDATA * workflows(nl-suite): make Claude step non-fatal; tolerant normalizer extracts <testcase> via regex on bad fragments * nl-suite: fix stale classname to UnityMCP.NL-T in mini fallback; prompt: require re-read after every revert; correct PLAN/PROGRESS to 15 * nl-suite: fix fallback JUnit classname to UnityMCP.NL-T; prompt: forbid create_script and env/mkdir checks, enforce single baseline-byte revert flow and post-revert re-read; add corruption-handling guidance * prompts(nl-full): after each write re-read raw bytes to refresh pre_sha; prefer script_apply_edits for anchors; avoid header/using changes * prompts(nl-full): canonicalize outputs to /; allow small fragment appends via Write or Bash(printf/echo); forbid wrappers and full-file round-trips * prompts(nl-full): finalize markdown formatting for guarded write, execution order, specs, status * workflows(nl-suite, mini): header/lint fixes and constrained Bash append path; align allowed_tools * prompts(nl-full): format Fast Restore, Guarded Write, Execution, Specs, Status as proper markdown lists and code fences * workflows(nl-suite): keep header tidy and append-path alignment with prompt * minor fix * workflows(nl-suite): fix indentation and dispatch; align allowed_tools and revert helper * prompts(nl-full): switch to read_resource for buf/sha; re-read only when needed; convert 'Print this once' to heading; note snapshot helper creates parent dirs * workflows(nl-suite): normalize step removes bootstrap when real testcases present; recompute tests/failures * workflows(nl-suite): enrich Markdown summary by extracting per-test <system-out> blocks (truncated) * clarify prompt resilience instructions * ci(nl-suite): revert prompt and workflow to known-good e0f8a72 for green run; remove extra MD details * ci(nl-suite): minimal fixes — no-mkdir guard in prompt; drop bootstrap and recompute JUnit counts * ci(nl-suite): richer JUnit→Markdown report (per-test system-out) * Small guard to incorret asset read call. * ci(nl-suite): refine MD builder — unescape XML entities, safe code fences, PASS/FAIL badges * Update UnityMcpBridge/UnityMcpServer~/src/tools/resource_tools.py Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update UnityMcpBridge/UnityMcpServer~/src/unity_connection.py Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update UnityMcpBridge/UnityMcpServer~/src/tools/manage_script_edits.py Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update .github/scripts/mark_skipped.py Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update .github/scripts/mark_skipped.py Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update .github/scripts/mark_skipped.py Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> * server(manage_script): robust URI handling — percent-decode file://, normalize, strip host/leading slashes, return Assets-relative if present * Update .claude/prompts/nl-unity-suite-full.md Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> * tests(framing): reduce handshake poll window, nonblocking peek to avoid disconnect race; still enforce pre-handshake data drop * tests(manage_script): add _split_uri tests for unity://path, file:// URLs (decoded/Assets-relative), and plain paths * server+tests: fix handshake syntax error; robust file:// URI normalization in manage_script; add _split_uri tests; adjust stdout scan to ignore venv/site-packages * bridge(framing): accept zero-length frames (treat as empty keepalive) * tests(logging): use errors='replace' on decode fallback to avoid silent drops * resources(list): restrict to Assets/, resolve symlinks, enforce .cs; add traversal/outside-path tests * Update .claude/prompts/nl-unity-suite-full.md Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update UnityMcpBridge/UnityMcpServer~/src/unity_connection.py Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * misc: framing keepalive (zero-length), regex preview consistency, resource.list hardening, URI parsing, legacy update routing, test cleanups * docs(tools): richer MCP tool descriptions; tests accept decorator kwargs; resource URI parsing hardened * Update .claude/prompts/nl-unity-suite-full.md Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update UnityMcpBridge/UnityMcpServer~/src/tools/resource_tools.py Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update UnityMcpBridge/UnityMcpServer~/src/unity_connection.py Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * net+docs: hard-reject zero-length frames; TCP_NODELAY on connect; Assets detection case-insensitive; NL prompt statuses aligned * prompt(nl-suite): constrain Write destinations under reports/, forbid traversal * prompt+net: harden Write path rules; use monotonic deadline and plain-text advisory for non-framed peers * unity_connection: restore recv timeout via try/finally; make global connection getter thread-safe with module lock and double-checked init * NL/T prompt: pin structured edit ops for T-D/T-E; add schema-error guarded write behavior; keep existing path/URI and revert rules * unity_connection: add FRAMED_MAX; use ValueError for framed length violations; lower framed receive log to debug; serialize connect() with per-instance lock * ManageScript: use UTF8Encoding(without BOM) for atomic writes in ApplyTextEdits/EditScript to align with Create/Update and avoid BOM-related diffs/hash mismatches * NL/T prompt: make helper deletion regex multiline-safe ((?ms) so ^ anchors line starts) * ManageScript: emit structured overlap status {status:"overlap"} for overlapping edit ranges in apply_text_edits and edit paths * NL/T prompt: clarify fallback vs failure — fallback only for unsupported/missing_field; treat bad_request as failure; note unsupported after fallback as failure * NL/T prompt: pin deterministic overlap probe (apply_text_edits two ranges from same snapshot); gate too_large behind RUN_TOO_LARGE env hint * TB update * NL/T prompt: harden Output Rules — constrain Bash(printf|echo) to stdout-only; forbid redirection/here-docs/tee; only scripts/nlt-revert.sh may mutate FS * Prompt: enumerate allowed script_apply_edits ops; add manage_editor/read_console guidance; fix T‑F atomic batch to single script_apply_edits. ManageScript: regex timeout for diagnostics; symlink ancestor guard; complete allowed-modes list. * Fixes * ManageScript: add rich overlap diagnostics (conflicts + hint) for both text range and structured batch paths * ManageScript: return structured {status:"validation_failed"} diagnostics in create/update/edits and validate before commit * ManageScript: echo canonical uri in responses (create/read/update/apply_text_edits/structured edits) to reinforce resource identity * improve clarity of capabilities message * Framing: allow zero-length frames on both ends (C# bridge, Python server). Prompt: harden T-F to single text-range apply_text_edits batch (descending order, one snapshot). URI: normalize file:// outside Assets by stripping leading slash. * ManageScript: include new sha256 in success payload for apply_text_edits; harden TryResolveUnderAssets by rejecting symlinked ancestors up to Assets/. * remove claudetest dir * manage_script_edits: normalize method-anchored anchor_insert to insert_method (map text->replacement); improves CI compatibility for T‑A/T‑E without changing Editor behavior. * tighten testing protocol around mkdir * manage_script: validate create_script inputs (Assets/.cs/name/no traversal); add Assets/ guard to delete_script; validate level+Assets in validate_script; make legacy manage_script optional params; harden legacy update routing with base64 reuse and payload size preflight. * Tighten prompt for testing * Update .claude/prompts/nl-unity-suite-full.md Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update .claude/prompts/nl-unity-suite-full.md Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update UnityMcpBridge/Editor/Tools/ManageScript.cs Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * manage_script_edits: honor ignore_case on anchor_insert and regex_replace in both direct and text-conversion paths (MULTILINE|IGNORECASE). * remove extra file * workflow: use python3 for inline scripts and port detection on ubuntu-latest. * Tighten prompt + manage_script * Update UnityMcpBridge/UnityMcpServer~/src/tools/manage_script_edits.py Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update UnityMcpBridge/UnityMcpServer~/src/tools/manage_script_edits.py Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update .claude/prompts/nl-unity-suite-full.md Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update UnityMcpBridge/Editor/Tools/ManageScript.cs Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update .claude/prompts/nl-unity-suite-full.md Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * manage_script: improve file:// UNC handling; preserve POSIX absolute semantics internally; keep test-expected slash stripping for non-Assets paths. * ManageScript.cs: add TimeSpan timeouts to all Regex uses (IsMatch/Match/new Regex) and keep CultureInvariant/Multiline options; reduces risk of catastrophic backtracking stalls. * workflow: ensure reports/ exists in markdown build step to avoid FileNotFoundError when writing MD_OUT. * fix brace * manage_script_edits: expand backrefs for regex_replace in preview->text conversion and translate to \g<n> in local apply; keeps previews and actual edits consistent. * anchor_insert: default to position=after, normalize surrounding newlines in Python conversion paths; C# path ensures trailing newline and skips duplicate insertion within class. * feat(mcp): add get_sha tool; apply_text_edits normalization+overlap preflight+strict; no-op evidence in C#; update NL suite prompt; add unit tests * feat(frames): accept zero-length heartbeat frames in client; add heartbeat test * feat(edits): guard destructive regex_replace with structural preflight; add robust tests; prompt uses delete_method for temp helper * feat(frames): bound heartbeat loop with timeout/threshold; align zero-length response with C#; update test * SDK hardening: atomic multi-span text edits; stop forcing sequential for structured ops; forward options on apply_text_edits; add validate=relaxed support and scoped checks; update NL/T prompt; add tests for options forwarding, relaxed mode, and atomic batches * Router: default applyMode=atomic for multi-span apply_text_edits; add tests * CI prompt: pass options.validate=relaxed for T-B/C; options.applyMode=atomic for T-F; emphasize always writing testcase and restoring on errors * Validation & DX: add validate=syntax (scoped), standardize evidence windows; early regex compile with hints; debug_preview for apply_text_edits * Update UnityMcpBridge/Editor/Windows/MCPForUnityEditorWindow.cs Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * NL/T suite-driven edits: LongUnityScriptClaudeTest, bridge helpers, server_version; prepare framing tests * Fix duplicate macConfigPath field in McpClient to resolve CS0102 * Editor threading: run EnsureServerInstalled on main thread; marshal EditorPrefs/DeleteKey + logging via delayCall * Docs(apply_text_edits): strengthen guidance on 1-based positions, verify-before-edit, and recommend anchors/structured edits * Docs(script_apply_edits): add safety guidance (anchors, method ops, validators) and recommended practices * Framed VerifyBridgePing in editor window; docs hardening for apply_text_edits and script_apply_edits --------- Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
2025-08-31 00:55:38 +08:00
/// <summary>
/// Apply simple text edits specified by line/column ranges. Applies transactionally and validates result.
/// </summary>
private const int MaxEditPayloadBytes = 64 * 1024;
private static object ApplyTextEdits(
string fullPath,
string relativePath,
string name,
JArray edits,
string preconditionSha256,
string refreshModeFromCaller = null,
string validateMode = null)
{
if (!File.Exists(fullPath))
return Response.Error($"Script not found at '{relativePath}'.");
// Refuse edits if the target or any ancestor is a symlink
try
{
var di = new DirectoryInfo(Path.GetDirectoryName(fullPath) ?? "");
while (di != null && !string.Equals(di.FullName.Replace('\\','/'), Application.dataPath.Replace('\\','/'), StringComparison.OrdinalIgnoreCase))
{
if (di.Exists && (di.Attributes & FileAttributes.ReparsePoint) != 0)
return Response.Error("Refusing to edit a symlinked script path.");
di = di.Parent;
}
}
catch
{
// If checking attributes fails, proceed without the symlink guard
}
if (edits == null || edits.Count == 0)
return Response.Error("No edits provided.");
string original;
try { original = File.ReadAllText(fullPath); }
catch (Exception ex) { return Response.Error($"Failed to read script: {ex.Message}"); }
// Require precondition to avoid drift on large files
string currentSha = ComputeSha256(original);
if (string.IsNullOrEmpty(preconditionSha256))
return Response.Error("precondition_required", new { status = "precondition_required", current_sha256 = currentSha });
if (!preconditionSha256.Equals(currentSha, StringComparison.OrdinalIgnoreCase))
return Response.Error("stale_file", new { status = "stale_file", expected_sha256 = preconditionSha256, current_sha256 = currentSha });
// Convert edits to absolute index ranges
var spans = new List<(int start, int end, string text)>();
long totalBytes = 0;
foreach (var e in edits)
{
try
{
int sl = Math.Max(1, e.Value<int>("startLine"));
int sc = Math.Max(1, e.Value<int>("startCol"));
int el = Math.Max(1, e.Value<int>("endLine"));
int ec = Math.Max(1, e.Value<int>("endCol"));
string newText = e.Value<string>("newText") ?? string.Empty;
if (!TryIndexFromLineCol(original, sl, sc, out int sidx))
return Response.Error($"apply_text_edits: start out of range (line {sl}, col {sc})");
if (!TryIndexFromLineCol(original, el, ec, out int eidx))
return Response.Error($"apply_text_edits: end out of range (line {el}, col {ec})");
if (eidx < sidx) (sidx, eidx) = (eidx, sidx);
spans.Add((sidx, eidx, newText));
checked
{
totalBytes += System.Text.Encoding.UTF8.GetByteCount(newText);
}
}
catch (Exception ex)
{
return Response.Error($"Invalid edit payload: {ex.Message}");
}
}
// Header guard: refuse edits that touch before the first 'using ' directive (after optional BOM) to prevent file corruption
int headerBoundary = (original.Length > 0 && original[0] == '\uFEFF') ? 1 : 0; // skip BOM once if present
// Find first top-level using (supports alias, static, and dotted namespaces)
var mUsing = System.Text.RegularExpressions.Regex.Match(
original,
@"(?m)^\s*using\s+(?:static\s+)?(?:[A-Za-z_]\w*\s*=\s*)?[A-Za-z_]\w*(?:\.[A-Za-z_]\w*)*\s*;",
System.Text.RegularExpressions.RegexOptions.CultureInvariant,
TimeSpan.FromSeconds(2)
);
if (mUsing.Success)
{
headerBoundary = Math.Min(Math.Max(headerBoundary, mUsing.Index), original.Length);
}
foreach (var sp in spans)
{
if (sp.start < headerBoundary)
{
return Response.Error("using_guard", new { status = "using_guard", hint = "Refusing to edit before the first 'using'. Use anchor_insert near a method or a structured edit." });
}
}
// Attempt auto-upgrade: if a single edit targets a method header/body, re-route as structured replace_method
if (spans.Count == 1)
{
var sp = spans[0];
// Heuristic: around the start of the edit, try to match a method header in original
int searchStart = Math.Max(0, sp.start - 200);
int searchEnd = Math.Min(original.Length, sp.start + 200);
string slice = original.Substring(searchStart, searchEnd - searchStart);
var rx = new System.Text.RegularExpressions.Regex(@"(?m)^[\t ]*(?:\[[^\]]+\][\t ]*)*[\t ]*(?:public|private|protected|internal|static|virtual|override|sealed|async|extern|unsafe|new|partial)[\s\S]*?\b([A-Za-z_][A-Za-z0-9_]*)\s*\(");
var mh = rx.Match(slice);
if (mh.Success)
{
string methodName = mh.Groups[1].Value;
// Find class span containing the edit
if (TryComputeClassSpan(original, name, null, out var clsStart, out var clsLen, out _))
{
if (TryComputeMethodSpan(original, clsStart, clsLen, methodName, null, null, null, out var mStart, out var mLen, out _))
{
// If the edit overlaps the method span significantly, treat as replace_method
if (sp.start <= mStart + 2 && sp.end >= mStart + 1)
{
var structEdits = new JArray();
// Apply the edit to get a candidate string, then recompute method span on the edited text
string candidate = original.Remove(sp.start, sp.end - sp.start).Insert(sp.start, sp.text ?? string.Empty);
string replacementText;
if (TryComputeClassSpan(candidate, name, null, out var cls2Start, out var cls2Len, out _)
&& TryComputeMethodSpan(candidate, cls2Start, cls2Len, methodName, null, null, null, out var m2Start, out var m2Len, out _))
{
replacementText = candidate.Substring(m2Start, m2Len);
}
else
{
// Fallback: adjust method start by the net delta if the edit was before the method
int delta = (sp.text?.Length ?? 0) - (sp.end - sp.start);
int adjustedStart = mStart + (sp.start <= mStart ? delta : 0);
adjustedStart = Math.Max(0, Math.Min(adjustedStart, candidate.Length));
// If the edit was within the original method span, adjust the length by the delta within-method
int withinMethodDelta = 0;
if (sp.start >= mStart && sp.start <= mStart + mLen)
{
withinMethodDelta = delta;
}
int adjustedLen = mLen + withinMethodDelta;
adjustedLen = Math.Max(0, Math.Min(candidate.Length - adjustedStart, adjustedLen));
replacementText = candidate.Substring(adjustedStart, adjustedLen);
}
var op = new JObject
{
["mode"] = "replace_method",
["className"] = name,
["methodName"] = methodName,
["replacement"] = replacementText
};
structEdits.Add(op);
// Reuse structured path
return EditScript(fullPath, relativePath, name, structEdits, new JObject{ ["refresh"] = "immediate", ["validate"] = "standard" });
}
}
}
}
}
if (totalBytes > MaxEditPayloadBytes)
{
return Response.Error("too_large", new { status = "too_large", limitBytes = MaxEditPayloadBytes, hint = "split into smaller edits" });
}
// Ensure non-overlap and apply from back to front
spans = spans.OrderByDescending(t => t.start).ToList();
for (int i = 1; i < spans.Count; i++)
{
if (spans[i].end > spans[i - 1].start)
{
var conflict = new[] { new { startA = spans[i].start, endA = spans[i].end, startB = spans[i - 1].start, endB = spans[i - 1].end } };
return Response.Error("overlap", new { status = "overlap", conflicts = conflict, hint = "Sort ranges descending by start and compute from the same snapshot." });
}
}
string working = original;
bool relaxed = string.Equals(validateMode, "relaxed", StringComparison.OrdinalIgnoreCase);
bool syntaxOnly = string.Equals(validateMode, "syntax", StringComparison.OrdinalIgnoreCase);
foreach (var sp in spans)
{
string next = working.Remove(sp.start, sp.end - sp.start).Insert(sp.start, sp.text ?? string.Empty);
if (relaxed)
{
// Scoped balance check: validate just around the changed region to avoid false positives
if (!CheckScopedBalance(next, Math.Max(0, sp.start - 500), Math.Min(next.Length, sp.start + (sp.text?.Length ?? 0) + 500)))
{
return Response.Error("unbalanced_braces", new { status = "unbalanced_braces", line = 0, expected = "{}()[] (scoped)", hint = "Use standard validation or shrink the edit range." });
}
}
working = next;
}
// No-op guard: if resulting text is identical, avoid writes and return explicit no-op
if (string.Equals(working, original, StringComparison.Ordinal))
{
string noChangeSha = ComputeSha256(original);
return Response.Success(
$"No-op: contents unchanged for '{relativePath}'.",
new
{
uri = $"unity://path/{relativePath}",
path = relativePath,
editsApplied = 0,
no_op = true,
sha256 = noChangeSha,
evidence = new { reason = "identical_content" }
}
);
}
if (!relaxed && !CheckBalancedDelimiters(working, out int line, out char expected))
{
int startLine = Math.Max(1, line - 5);
int endLine = line + 5;
string hint = $"unbalanced_braces at line {line}. Call resources/read for lines {startLine}-{endLine} and resend a smaller apply_text_edits that restores balance.";
return Response.Error(hint, new { status = "unbalanced_braces", line, expected = expected.ToString(), evidenceWindow = new { startLine, endLine } });
}
#if USE_ROSLYN
if (!syntaxOnly)
{
var tree = CSharpSyntaxTree.ParseText(working);
var diagnostics = tree.GetDiagnostics().Where(d => d.Severity == DiagnosticSeverity.Error).Take(3)
.Select(d => new {
line = d.Location.GetLineSpan().StartLinePosition.Line + 1,
col = d.Location.GetLineSpan().StartLinePosition.Character + 1,
code = d.Id,
message = d.GetMessage()
}).ToArray();
if (diagnostics.Length > 0)
{
int firstLine = diagnostics[0].line;
int startLineRos = Math.Max(1, firstLine - 5);
int endLineRos = firstLine + 5;
return Response.Error("syntax_error", new { status = "syntax_error", diagnostics, evidenceWindow = new { startLine = startLineRos, endLine = endLineRos } });
}
// Optional formatting
try
{
var root = tree.GetRoot();
var workspace = new AdhocWorkspace();
root = Microsoft.CodeAnalysis.Formatting.Formatter.Format(root, workspace);
working = root.ToFullString();
}
catch { }
}
#endif
string newSha = ComputeSha256(working);
// Atomic write and schedule refresh
try
{
var enc = new System.Text.UTF8Encoding(encoderShouldEmitUTF8Identifier: false);
var tmp = fullPath + ".tmp";
File.WriteAllText(tmp, working, enc);
string backup = fullPath + ".bak";
try
{
File.Replace(tmp, fullPath, backup);
try { if (File.Exists(backup)) File.Delete(backup); } catch { /* ignore */ }
}
catch (PlatformNotSupportedException)
{
File.Copy(tmp, fullPath, true);
try { File.Delete(tmp); } catch { }
try { if (File.Exists(backup)) File.Delete(backup); } catch { }
}
catch (IOException)
{
File.Copy(tmp, fullPath, true);
try { File.Delete(tmp); } catch { }
try { if (File.Exists(backup)) File.Delete(backup); } catch { }
}
// Respect refresh mode: immediate vs debounced
bool immediate = string.Equals(refreshModeFromCaller, "immediate", StringComparison.OrdinalIgnoreCase) ||
string.Equals(refreshModeFromCaller, "sync", StringComparison.OrdinalIgnoreCase);
if (immediate)
{
EditorApplication.delayCall += () =>
{
AssetDatabase.ImportAsset(
relativePath,
ImportAssetOptions.ForceSynchronousImport | ImportAssetOptions.ForceUpdate
);
#if UNITY_EDITOR
UnityEditor.Compilation.CompilationPipeline.RequestScriptCompilation();
#endif
};
}
else
{
ManageScriptRefreshHelpers.ScheduleScriptRefresh(relativePath);
}
return Response.Success(
$"Applied {spans.Count} text edit(s) to '{relativePath}'.",
new
{
uri = $"unity://path/{relativePath}",
path = relativePath,
editsApplied = spans.Count,
sha256 = newSha
}
);
}
catch (Exception ex)
{
return Response.Error($"Failed to write edits: {ex.Message}");
}
}
private static bool TryIndexFromLineCol(string text, int line1, int col1, out int index)
{
// 1-based line/col to absolute index (0-based), col positions are counted in code points
int line = 1, col = 1;
for (int i = 0; i <= text.Length; i++)
{
if (line == line1 && col == col1)
{
index = i;
return true;
}
if (i == text.Length) break;
char c = text[i];
if (c == '\r')
{
// Treat CRLF as a single newline; skip the LF if present
if (i + 1 < text.Length && text[i + 1] == '\n')
i++;
line++;
col = 1;
}
else if (c == '\n')
{
line++;
col = 1;
}
else
{
col++;
}
}
index = -1;
return false;
}
private static string ComputeSha256(string contents)
{
using (var sha = SHA256.Create())
{
var bytes = System.Text.Encoding.UTF8.GetBytes(contents);
var hash = sha.ComputeHash(bytes);
return BitConverter.ToString(hash).Replace("-", string.Empty).ToLowerInvariant();
}
}
private static bool CheckBalancedDelimiters(string text, out int line, out char expected)
{
var braceStack = new Stack<int>();
var parenStack = new Stack<int>();
var bracketStack = new Stack<int>();
bool inString = false, inChar = false, inSingle = false, inMulti = false, escape = false;
line = 1; expected = '\0';
for (int i = 0; i < text.Length; i++)
{
char c = text[i];
char next = i + 1 < text.Length ? text[i + 1] : '\0';
if (c == '\n') { line++; if (inSingle) inSingle = false; }
if (escape) { escape = false; continue; }
if (inString)
{
if (c == '\\') { escape = true; }
else if (c == '"') inString = false;
continue;
}
if (inChar)
{
if (c == '\\') { escape = true; }
else if (c == '\'') inChar = false;
continue;
}
if (inSingle) continue;
if (inMulti)
{
if (c == '*' && next == '/') { inMulti = false; i++; }
continue;
}
if (c == '"') { inString = true; continue; }
if (c == '\'') { inChar = true; continue; }
if (c == '/' && next == '/') { inSingle = true; i++; continue; }
if (c == '/' && next == '*') { inMulti = true; i++; continue; }
switch (c)
{
case '{': braceStack.Push(line); break;
case '}':
if (braceStack.Count == 0) { expected = '{'; return false; }
braceStack.Pop();
break;
case '(': parenStack.Push(line); break;
case ')':
if (parenStack.Count == 0) { expected = '('; return false; }
parenStack.Pop();
break;
case '[': bracketStack.Push(line); break;
case ']':
if (bracketStack.Count == 0) { expected = '['; return false; }
bracketStack.Pop();
break;
}
}
if (braceStack.Count > 0) { line = braceStack.Peek(); expected = '}'; return false; }
if (parenStack.Count > 0) { line = parenStack.Peek(); expected = ')'; return false; }
if (bracketStack.Count > 0) { line = bracketStack.Peek(); expected = ']'; return false; }
return true;
}
// Lightweight scoped balance: checks delimiters within a substring, ignoring outer context
private static bool CheckScopedBalance(string text, int start, int end)
{
start = Math.Max(0, Math.Min(text.Length, start));
end = Math.Max(start, Math.Min(text.Length, end));
int brace = 0, paren = 0, bracket = 0;
bool inStr = false, inChr = false, esc = false;
for (int i = start; i < end; i++)
{
char c = text[i];
char n = (i + 1 < end) ? text[i + 1] : '\0';
if (inStr)
{
if (!esc && c == '"') inStr = false; esc = (!esc && c == '\\'); continue;
}
if (inChr)
{
if (!esc && c == '\'') inChr = false; esc = (!esc && c == '\\'); continue;
}
if (c == '"') { inStr = true; esc = false; continue; }
if (c == '\'') { inChr = true; esc = false; continue; }
if (c == '/' && n == '/') { while (i < end && text[i] != '\n') i++; continue; }
if (c == '/' && n == '*') { i += 2; while (i + 1 < end && !(text[i] == '*' && text[i + 1] == '/')) i++; i++; continue; }
if (c == '{') brace++; else if (c == '}') brace--;
else if (c == '(') paren++; else if (c == ')') paren--;
else if (c == '[') bracket++; else if (c == ']') bracket--;
if (brace < 0 || paren < 0 || bracket < 0) return false;
}
return brace >= -1 && paren >= -1 && bracket >= -1; // tolerate context from outside region
}
2025-03-31 03:58:01 +08:00
private static object DeleteScript(string fullPath, string relativePath)
{
if (!File.Exists(fullPath))
{
return Response.Error($"Script not found at '{relativePath}'. Cannot delete.");
}
try
{
// Use AssetDatabase.MoveAssetToTrash for safer deletion (allows undo)
bool deleted = AssetDatabase.MoveAssetToTrash(relativePath);
if (deleted)
{
AssetDatabase.Refresh();
return Response.Success(
Claude‑friendly edit tools + framed transport + live Unity NL test framework (#243) * CI: gate desktop-parity on Anthropic key; pass anthropic_api_key like NL suite * Add quickprobe prompt and CI workflow (mcp-quickprobe.md, unity-mcp-quickprobe.yml) * strictier tool use to prevent subagent spawning and force mcp tools * update workflow filesto reduce likelihood of subagent spawning * improve permissions for claude agent, fix mcpbridge timeout/token issue * increase max turns to 10 * ci: align NL suite to new permissions schema; prevent subagent drift * ci: NL suite -> mini prompt for e2e; add full NL/T prompt; server: ctx optional + project_root fallback; workflows: set UNITY_PROJECT_ROOT for CI * ci: add checks:write; revert local project hardcodes (manifest, ProjectVersion.txt) * tools: text-edit routing fixes (anchor_insert via text, CRLF calc); prompts: mini NL/T clarifications * ci: use absolute UNITY_PROJECT_ROOT; prompts target TestProjects; server: accept relative UNITY_PROJECT_ROOT and bare spec URI * ci: ignore Unity test project's packages-lock.json; remove from repo to avoid absolute paths * CI: start persistent Unity Editor for MCP (guarded by license) + allow batch-mode bridge via UNITY_MCP_ALLOW_BATCH * CI: hide license and pass via env to docker; fix invalid ref format * CI: readiness probe uses handshake on Unity MCP port (deterministic) * CI: fix YAML; use TCP handshake readiness probe (FRAMING=1) * CI: prime Unity license via game-ci; mount ULF into container; extend readiness timeout * CI: use ULF write + mount for Unity licensing; remove serial/email/pass from container * CI: entitlement activation (UNITY_SERIAL=''); verify host ULF cache; keep mount * CI: write ULF from secret and verify; drop entitlement activation step * CI: detect any licensing path; GameCI prime; status dir env; log+probe readiness; fix YAML * CI: add GameCI license prime; conditional ULF write; one-shot license validation; explicit status dir + license env * CI: fix YAML (inline python), add Anthropic key detect via GITHUB_ENV; ready to run happy path * CI: mount Unity token/ulf/cache dirs into container to share host license; create dirs before start * CI: fix YAML indentation; write ULF on host; activate in container with shared mounts; mount .config and .cache too * CI: gate Claude via outputs; mount all Unity license dirs; fix inline probe python; stabilize licensing flow * CI: normalize detect to step outputs; ensure license dirs mounted and validated; fix indentation * Bridge: honor UNITY_MCP_STATUS_DIR for heartbeat/status file (CI-friendly) * CI: guard project path for activation/start; align tool allowlist; run MCP server with python; tighten secret scoping * CI: finalize Unity licensing mounts + status dir; mode-detect (ULF/EBL); readiness logs+probe; Claude gating via outputs * CI: fix YAML probe (inline python -c) and finalize happy-path Unity licensing and MCP/Claude wiring * CI: inline python probe; unify Unity image and cache mounts; ready to test * CI: fix docker run IMAGE placement; ignore cache find perms; keep same editor image * CI: pass -manualLicenseFile to persistent Editor; keep mounts and single image * CI: mount full GameCI cache to /root in persistent Unity; set HOME=/root; add optional license check * CI: make -manualLicenseFile conditional; keep full /root mount and license check * CI: set HOME=/github/home; mount GameCI cache there; adjust manualLicenseFile path; expand license check * CI: EBL sign-in for persistent Unity (email/password/serial); revert HOME=/root and full /root mount; keep conditional manualLicenseFile and improved readiness * CI: run full NL/T suite prompt (nl-unity-suite-full.md) instead of mini * NL/T: require unified diffs + explicit verdicts in JUnit; CI: remove short sanity step, publish JUnit, upload artifacts * NL/T prompt: require CDATA wrapping for JUnit XML fields; guidance for splitting embedded ]]>; keep VERDICT in CDATA only * CI: remove in-container license check step; keep readiness and full suite * NL/T prompt: add version header, stricter JUnit schema, hashing/normalization, anchors, statuses, atomic semantics, tool logging * CI: increase Claude NL/T suite timeout to 30 minutes * CI: pre-create reports dir and result files to avoid tool approval prompts * CI: skip wait if container not running; skip Editor start if project missing; broaden MCP deps detection; expand allowed tools * fixies to harden ManageScript * CI: sanitize NL/T markdown report to avoid NUL/encoding issues * revert breaking yyaml changes * CI: prime license, robust Unity start/wait, sanitize markdown via heredoc * Resolve merge: accept upstream renames/installer (fix/installer-cleanup-v2) and keep local framing/script-editing - Restored upstream server.py, EditorWindow, uv.lock\n- Preserved ManageScript editing/validation; switched to atomic write + debounced refresh\n- Updated tools/__init__.py to keep script_edits/resources and adopt new logger name\n- All Python tests via uv: 7 passed, 6 skipped, 9 xpassed; Unity compile OK * Fix Claude Desktop config path and atomic write issues - Fix macOS path for Claude Desktop config: use ~/Library/Application Support/Claude/ instead of ~/.config/Claude/ - Improve atomic write pattern with backup/restore safety - Replace File.Replace() with File.Move() for better macOS compatibility - Add proper error handling and cleanup for file operations - Resolves issue where installer couldn't find Claude Desktop config on macOS * Editor: use macConfigPath on macOS for MCP client config writes (Claude Desktop, etc.). Fallback to linuxConfigPath only if mac path missing. * Models: add macConfigPath to McpClient for macOS config path selection (fixes CS1061 in editor window). * Editor: on macOS, prefer macConfigPath in ManualConfigEditorWindow (fallback to linux path); Linux/Windows unchanged. * Fix McpClient: align with upstream/main, prep for framing split * NL suite: shard workflow; tighten bridge readiness; add MCP preflight; use env-based shard vars * NL suite: fix shard step indentation; move shard vars to env; remove invalid inputs * MCP clients: split VSCode Copilot config paths into macConfigPath and linuxConfigPath * Unity bridge: clean stale status; bind host; robust wait probe with IPv4/IPv6 + diagnostics * CI: use MCPForUnity.Editor.MCPForUnityBridge.StartAutoConnect as executeMethod * Action wiring: inline mcpServers in settings for all shards; remove redundant .claude/mcp.json step * CI: embed mcpServers in settings for all shards; fix startup sanity step; lint clean * CI: pin claude-code-base-action to e6f32c8; use claude_args --mcp-config; switch to allowed_tools; ensure MCP config per step * CI: unpin claude-code-base-action to @beta (commit ref not found) * CI: align with claude-code-base-action @beta; pass MCP via claude_args and allowedTools * Editor: Fix apply_text_edits heuristic when edits shift positions; recompute method span on candidate text with fallback delta adjustment * CI: unify MCP wiring across workflows; write .claude/mcp.json; switch to claude_args with --mcp-config/--allowedTools; remove unsupported inputs * CI: collapse NL suite shards into a single run to avoid repeated test execution * CI: minimize allowedTools for NL suite to essential Unity MCP + Bash("git:*") + Write * CI: mkdir -p reports before run; remove unsupported --timeout-minutes from claude_args * CI: broaden allowedTools to include find_in_file and mcp__unity__* * CI: enable use_node_cache and switch NL suite model to claude-3-7-haiku-20250219 * CI: disable use_node_cache to avoid setup-node lockfile error * CI: set NL suite model to claude-3-haiku-20240307 * CI: cap Haiku output with --max-tokens 2048 for NL suite * CI: switch to claude-3-7-sonnet-latest and remove unsupported --max-tokens * CI: update allowedTools to Bash(*) and explicit Unity MCP tool list * CI: update NL suite workflow (latest tweaks) * Tests: tighten NL suite prompt for logging, hash discipline, stale retry, evidence windows, diff cap, and VERDICT line * Add disallowed tools to NL suite workflow * docs: clarify stale write retry * Add fallback JUnit report and adjust publisher * Indent fallback JUnit XML in workflow * fix: correct fallback JUnit report generation * Update mcp-quickprobe.md Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> * Update mcp-quickprobe.md Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> * Update Response.cs Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> * Update MCPForUnityBridge.cs Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> * fix: correct McpTypes reference * Add directory existence checks for symlink and XDG paths * fix: only set installation flag after successful server install * Update resource_tools.py Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> * fix: respect mac config paths * Use File.Replace for atomic config write * Remove unused imports in manage_script * bump server version * Tests: update NL suite prompt and workflows; remove deprecated smoke/desktop-parity; quickprobe tidy * Editor: atomic config write via File.Replace fallback; remove redundant backups and racey exists checks * CI: harden NL suite - idempotent docker, gate on unity_ok, safer port probe, least-priv perms * Editor: make atomic config write restoration safe (flag writeDone; copy-overwrite restore; cleanup in finally) * CI: fix fallback JUnit heredoc by using printf lines (no EOF delimiter issues) * CI: switch NL suite to mini prompt; mini prompt honors / and NL discipline * CI: replace claude_args with allowed_tools/model/mcp_config per action schema * CI: expand UNITY_PROJECT_ROOT via in MCP config heredoc * EditorWindow: add cross-platform fallback for File.Replace; macOS-insensitive PathsEqual; safer uv resolve; honor macConfigPath * CI: strengthen JUnit publishing for NL mini suite (normalize, debug list, publish both, fail_on_parse_error) * CI: set job-wide JUNIT_OUT/MD_OUT; normalization uses env; publish references env and ungroup reports * CI: publish a single normalized JUnit (reports/junit-for-actions.xml); fallback writes same; avoid checkName/reportPaths mismatch * CI: align mini prompt report filenames; redact Unity log tail in diagnostics * chore: sync workflow and mini prompt; redacted logs; JUnit normalization/publish tweaks * CI: redact sensitive tokens in Stop Unity; docs: CI usage + edit tools * prompts: update nl-unity-suite-full (mini-style setup + reporting discipline); remove obsolete prompts * CI: harden NL workflows (timeout_minutes, robust normalization); prompts: unify JUnit suite name and reporting discipline * prompts: add guarded write pattern (LF hash, stale_file retry) to full suite * prompts: enforce continue-on-failure, driver flow, and status handling in full suite * Make test list more explicit in prompt. Get rid of old test prompts for hygeine. * prompts: add stale fast-retry (server hash) + in-memory buf guidance * CI: standardize JUNIT_OUT to reports/junit-nl-suite.xml; fix artifact upload indentation; prompt copy cleanups * prompts: reporting discipline — append-only fragments, batch writes, no model round-trip * prompts: stale fast-retry preference, buffer/sha carry, snapshot revert, essential logging * workflows(nl-suite): precreate report skeletons, assemble junit, synthesize markdown; restrict allowed_tools to append-only Bash + MCP tools * thsis too * Update README-DEV.md Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update .github/workflows/claude-nl-suite-mini.yml Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update .github/workflows/claude-nl-suite.yml Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * workflows(nl-mini): fix YAML indentation/trailing spaces under with: and cleanup heredoc spacing * workflows(nl-suite): fix indentation on docker logs redaction line (YAML lint) * Add write to allowlist * nl-suite: harden reporting discipline (fragment-only writes, forbid alt paths); workflow: clean stray junit-*updated*.xml * nl-suite: enforce end-of-suite single Write (no bash redirection); workflow: restrict allowed_tools to Write+MCP only * prompts(nl-full): end-of-suite results must be valid XML with single <cases> root and only <testcase> children; no raw text outside CDATA * workflows(nl-suite): make Claude step non-fatal; tolerant normalizer extracts <testcase> via regex on bad fragments * nl-suite: fix stale classname to UnityMCP.NL-T in mini fallback; prompt: require re-read after every revert; correct PLAN/PROGRESS to 15 * nl-suite: fix fallback JUnit classname to UnityMCP.NL-T; prompt: forbid create_script and env/mkdir checks, enforce single baseline-byte revert flow and post-revert re-read; add corruption-handling guidance * prompts(nl-full): after each write re-read raw bytes to refresh pre_sha; prefer script_apply_edits for anchors; avoid header/using changes * prompts(nl-full): canonicalize outputs to /; allow small fragment appends via Write or Bash(printf/echo); forbid wrappers and full-file round-trips * prompts(nl-full): finalize markdown formatting for guarded write, execution order, specs, status * workflows(nl-suite, mini): header/lint fixes and constrained Bash append path; align allowed_tools * prompts(nl-full): format Fast Restore, Guarded Write, Execution, Specs, Status as proper markdown lists and code fences * workflows(nl-suite): keep header tidy and append-path alignment with prompt * minor fix * workflows(nl-suite): fix indentation and dispatch; align allowed_tools and revert helper * prompts(nl-full): switch to read_resource for buf/sha; re-read only when needed; convert 'Print this once' to heading; note snapshot helper creates parent dirs * workflows(nl-suite): normalize step removes bootstrap when real testcases present; recompute tests/failures * workflows(nl-suite): enrich Markdown summary by extracting per-test <system-out> blocks (truncated) * clarify prompt resilience instructions * ci(nl-suite): revert prompt and workflow to known-good e0f8a72 for green run; remove extra MD details * ci(nl-suite): minimal fixes — no-mkdir guard in prompt; drop bootstrap and recompute JUnit counts * ci(nl-suite): richer JUnit→Markdown report (per-test system-out) * Small guard to incorret asset read call. * ci(nl-suite): refine MD builder — unescape XML entities, safe code fences, PASS/FAIL badges * Update UnityMcpBridge/UnityMcpServer~/src/tools/resource_tools.py Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update UnityMcpBridge/UnityMcpServer~/src/unity_connection.py Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update UnityMcpBridge/UnityMcpServer~/src/tools/manage_script_edits.py Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update .github/scripts/mark_skipped.py Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update .github/scripts/mark_skipped.py Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update .github/scripts/mark_skipped.py Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> * server(manage_script): robust URI handling — percent-decode file://, normalize, strip host/leading slashes, return Assets-relative if present * Update .claude/prompts/nl-unity-suite-full.md Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> * tests(framing): reduce handshake poll window, nonblocking peek to avoid disconnect race; still enforce pre-handshake data drop * tests(manage_script): add _split_uri tests for unity://path, file:// URLs (decoded/Assets-relative), and plain paths * server+tests: fix handshake syntax error; robust file:// URI normalization in manage_script; add _split_uri tests; adjust stdout scan to ignore venv/site-packages * bridge(framing): accept zero-length frames (treat as empty keepalive) * tests(logging): use errors='replace' on decode fallback to avoid silent drops * resources(list): restrict to Assets/, resolve symlinks, enforce .cs; add traversal/outside-path tests * Update .claude/prompts/nl-unity-suite-full.md Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update UnityMcpBridge/UnityMcpServer~/src/unity_connection.py Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * misc: framing keepalive (zero-length), regex preview consistency, resource.list hardening, URI parsing, legacy update routing, test cleanups * docs(tools): richer MCP tool descriptions; tests accept decorator kwargs; resource URI parsing hardened * Update .claude/prompts/nl-unity-suite-full.md Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update UnityMcpBridge/UnityMcpServer~/src/tools/resource_tools.py Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update UnityMcpBridge/UnityMcpServer~/src/unity_connection.py Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * net+docs: hard-reject zero-length frames; TCP_NODELAY on connect; Assets detection case-insensitive; NL prompt statuses aligned * prompt(nl-suite): constrain Write destinations under reports/, forbid traversal * prompt+net: harden Write path rules; use monotonic deadline and plain-text advisory for non-framed peers * unity_connection: restore recv timeout via try/finally; make global connection getter thread-safe with module lock and double-checked init * NL/T prompt: pin structured edit ops for T-D/T-E; add schema-error guarded write behavior; keep existing path/URI and revert rules * unity_connection: add FRAMED_MAX; use ValueError for framed length violations; lower framed receive log to debug; serialize connect() with per-instance lock * ManageScript: use UTF8Encoding(without BOM) for atomic writes in ApplyTextEdits/EditScript to align with Create/Update and avoid BOM-related diffs/hash mismatches * NL/T prompt: make helper deletion regex multiline-safe ((?ms) so ^ anchors line starts) * ManageScript: emit structured overlap status {status:"overlap"} for overlapping edit ranges in apply_text_edits and edit paths * NL/T prompt: clarify fallback vs failure — fallback only for unsupported/missing_field; treat bad_request as failure; note unsupported after fallback as failure * NL/T prompt: pin deterministic overlap probe (apply_text_edits two ranges from same snapshot); gate too_large behind RUN_TOO_LARGE env hint * TB update * NL/T prompt: harden Output Rules — constrain Bash(printf|echo) to stdout-only; forbid redirection/here-docs/tee; only scripts/nlt-revert.sh may mutate FS * Prompt: enumerate allowed script_apply_edits ops; add manage_editor/read_console guidance; fix T‑F atomic batch to single script_apply_edits. ManageScript: regex timeout for diagnostics; symlink ancestor guard; complete allowed-modes list. * Fixes * ManageScript: add rich overlap diagnostics (conflicts + hint) for both text range and structured batch paths * ManageScript: return structured {status:"validation_failed"} diagnostics in create/update/edits and validate before commit * ManageScript: echo canonical uri in responses (create/read/update/apply_text_edits/structured edits) to reinforce resource identity * improve clarity of capabilities message * Framing: allow zero-length frames on both ends (C# bridge, Python server). Prompt: harden T-F to single text-range apply_text_edits batch (descending order, one snapshot). URI: normalize file:// outside Assets by stripping leading slash. * ManageScript: include new sha256 in success payload for apply_text_edits; harden TryResolveUnderAssets by rejecting symlinked ancestors up to Assets/. * remove claudetest dir * manage_script_edits: normalize method-anchored anchor_insert to insert_method (map text->replacement); improves CI compatibility for T‑A/T‑E without changing Editor behavior. * tighten testing protocol around mkdir * manage_script: validate create_script inputs (Assets/.cs/name/no traversal); add Assets/ guard to delete_script; validate level+Assets in validate_script; make legacy manage_script optional params; harden legacy update routing with base64 reuse and payload size preflight. * Tighten prompt for testing * Update .claude/prompts/nl-unity-suite-full.md Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update .claude/prompts/nl-unity-suite-full.md Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update UnityMcpBridge/Editor/Tools/ManageScript.cs Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * manage_script_edits: honor ignore_case on anchor_insert and regex_replace in both direct and text-conversion paths (MULTILINE|IGNORECASE). * remove extra file * workflow: use python3 for inline scripts and port detection on ubuntu-latest. * Tighten prompt + manage_script * Update UnityMcpBridge/UnityMcpServer~/src/tools/manage_script_edits.py Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update UnityMcpBridge/UnityMcpServer~/src/tools/manage_script_edits.py Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update .claude/prompts/nl-unity-suite-full.md Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update UnityMcpBridge/Editor/Tools/ManageScript.cs Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update .claude/prompts/nl-unity-suite-full.md Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * manage_script: improve file:// UNC handling; preserve POSIX absolute semantics internally; keep test-expected slash stripping for non-Assets paths. * ManageScript.cs: add TimeSpan timeouts to all Regex uses (IsMatch/Match/new Regex) and keep CultureInvariant/Multiline options; reduces risk of catastrophic backtracking stalls. * workflow: ensure reports/ exists in markdown build step to avoid FileNotFoundError when writing MD_OUT. * fix brace * manage_script_edits: expand backrefs for regex_replace in preview->text conversion and translate to \g<n> in local apply; keeps previews and actual edits consistent. * anchor_insert: default to position=after, normalize surrounding newlines in Python conversion paths; C# path ensures trailing newline and skips duplicate insertion within class. * feat(mcp): add get_sha tool; apply_text_edits normalization+overlap preflight+strict; no-op evidence in C#; update NL suite prompt; add unit tests * feat(frames): accept zero-length heartbeat frames in client; add heartbeat test * feat(edits): guard destructive regex_replace with structural preflight; add robust tests; prompt uses delete_method for temp helper * feat(frames): bound heartbeat loop with timeout/threshold; align zero-length response with C#; update test * SDK hardening: atomic multi-span text edits; stop forcing sequential for structured ops; forward options on apply_text_edits; add validate=relaxed support and scoped checks; update NL/T prompt; add tests for options forwarding, relaxed mode, and atomic batches * Router: default applyMode=atomic for multi-span apply_text_edits; add tests * CI prompt: pass options.validate=relaxed for T-B/C; options.applyMode=atomic for T-F; emphasize always writing testcase and restoring on errors * Validation & DX: add validate=syntax (scoped), standardize evidence windows; early regex compile with hints; debug_preview for apply_text_edits * Update UnityMcpBridge/Editor/Windows/MCPForUnityEditorWindow.cs Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * NL/T suite-driven edits: LongUnityScriptClaudeTest, bridge helpers, server_version; prepare framing tests * Fix duplicate macConfigPath field in McpClient to resolve CS0102 * Editor threading: run EnsureServerInstalled on main thread; marshal EditorPrefs/DeleteKey + logging via delayCall * Docs(apply_text_edits): strengthen guidance on 1-based positions, verify-before-edit, and recommend anchors/structured edits * Docs(script_apply_edits): add safety guidance (anchors, method ops, validators) and recommended practices * Framed VerifyBridgePing in editor window; docs hardening for apply_text_edits and script_apply_edits --------- Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
2025-08-31 00:55:38 +08:00
$"Script '{Path.GetFileName(relativePath)}' moved to trash successfully.",
new { deleted = true }
);
2025-03-31 03:58:01 +08:00
}
else
{
// Fallback or error if MoveAssetToTrash fails
return Response.Error(
$"Failed to move script '{relativePath}' to trash. It might be locked or in use."
);
2025-03-31 03:58:01 +08:00
}
}
catch (Exception e)
{
return Response.Error($"Error deleting script '{relativePath}': {e.Message}");
}
}
Claude‑friendly edit tools + framed transport + live Unity NL test framework (#243) * CI: gate desktop-parity on Anthropic key; pass anthropic_api_key like NL suite * Add quickprobe prompt and CI workflow (mcp-quickprobe.md, unity-mcp-quickprobe.yml) * strictier tool use to prevent subagent spawning and force mcp tools * update workflow filesto reduce likelihood of subagent spawning * improve permissions for claude agent, fix mcpbridge timeout/token issue * increase max turns to 10 * ci: align NL suite to new permissions schema; prevent subagent drift * ci: NL suite -> mini prompt for e2e; add full NL/T prompt; server: ctx optional + project_root fallback; workflows: set UNITY_PROJECT_ROOT for CI * ci: add checks:write; revert local project hardcodes (manifest, ProjectVersion.txt) * tools: text-edit routing fixes (anchor_insert via text, CRLF calc); prompts: mini NL/T clarifications * ci: use absolute UNITY_PROJECT_ROOT; prompts target TestProjects; server: accept relative UNITY_PROJECT_ROOT and bare spec URI * ci: ignore Unity test project's packages-lock.json; remove from repo to avoid absolute paths * CI: start persistent Unity Editor for MCP (guarded by license) + allow batch-mode bridge via UNITY_MCP_ALLOW_BATCH * CI: hide license and pass via env to docker; fix invalid ref format * CI: readiness probe uses handshake on Unity MCP port (deterministic) * CI: fix YAML; use TCP handshake readiness probe (FRAMING=1) * CI: prime Unity license via game-ci; mount ULF into container; extend readiness timeout * CI: use ULF write + mount for Unity licensing; remove serial/email/pass from container * CI: entitlement activation (UNITY_SERIAL=''); verify host ULF cache; keep mount * CI: write ULF from secret and verify; drop entitlement activation step * CI: detect any licensing path; GameCI prime; status dir env; log+probe readiness; fix YAML * CI: add GameCI license prime; conditional ULF write; one-shot license validation; explicit status dir + license env * CI: fix YAML (inline python), add Anthropic key detect via GITHUB_ENV; ready to run happy path * CI: mount Unity token/ulf/cache dirs into container to share host license; create dirs before start * CI: fix YAML indentation; write ULF on host; activate in container with shared mounts; mount .config and .cache too * CI: gate Claude via outputs; mount all Unity license dirs; fix inline probe python; stabilize licensing flow * CI: normalize detect to step outputs; ensure license dirs mounted and validated; fix indentation * Bridge: honor UNITY_MCP_STATUS_DIR for heartbeat/status file (CI-friendly) * CI: guard project path for activation/start; align tool allowlist; run MCP server with python; tighten secret scoping * CI: finalize Unity licensing mounts + status dir; mode-detect (ULF/EBL); readiness logs+probe; Claude gating via outputs * CI: fix YAML probe (inline python -c) and finalize happy-path Unity licensing and MCP/Claude wiring * CI: inline python probe; unify Unity image and cache mounts; ready to test * CI: fix docker run IMAGE placement; ignore cache find perms; keep same editor image * CI: pass -manualLicenseFile to persistent Editor; keep mounts and single image * CI: mount full GameCI cache to /root in persistent Unity; set HOME=/root; add optional license check * CI: make -manualLicenseFile conditional; keep full /root mount and license check * CI: set HOME=/github/home; mount GameCI cache there; adjust manualLicenseFile path; expand license check * CI: EBL sign-in for persistent Unity (email/password/serial); revert HOME=/root and full /root mount; keep conditional manualLicenseFile and improved readiness * CI: run full NL/T suite prompt (nl-unity-suite-full.md) instead of mini * NL/T: require unified diffs + explicit verdicts in JUnit; CI: remove short sanity step, publish JUnit, upload artifacts * NL/T prompt: require CDATA wrapping for JUnit XML fields; guidance for splitting embedded ]]>; keep VERDICT in CDATA only * CI: remove in-container license check step; keep readiness and full suite * NL/T prompt: add version header, stricter JUnit schema, hashing/normalization, anchors, statuses, atomic semantics, tool logging * CI: increase Claude NL/T suite timeout to 30 minutes * CI: pre-create reports dir and result files to avoid tool approval prompts * CI: skip wait if container not running; skip Editor start if project missing; broaden MCP deps detection; expand allowed tools * fixies to harden ManageScript * CI: sanitize NL/T markdown report to avoid NUL/encoding issues * revert breaking yyaml changes * CI: prime license, robust Unity start/wait, sanitize markdown via heredoc * Resolve merge: accept upstream renames/installer (fix/installer-cleanup-v2) and keep local framing/script-editing - Restored upstream server.py, EditorWindow, uv.lock\n- Preserved ManageScript editing/validation; switched to atomic write + debounced refresh\n- Updated tools/__init__.py to keep script_edits/resources and adopt new logger name\n- All Python tests via uv: 7 passed, 6 skipped, 9 xpassed; Unity compile OK * Fix Claude Desktop config path and atomic write issues - Fix macOS path for Claude Desktop config: use ~/Library/Application Support/Claude/ instead of ~/.config/Claude/ - Improve atomic write pattern with backup/restore safety - Replace File.Replace() with File.Move() for better macOS compatibility - Add proper error handling and cleanup for file operations - Resolves issue where installer couldn't find Claude Desktop config on macOS * Editor: use macConfigPath on macOS for MCP client config writes (Claude Desktop, etc.). Fallback to linuxConfigPath only if mac path missing. * Models: add macConfigPath to McpClient for macOS config path selection (fixes CS1061 in editor window). * Editor: on macOS, prefer macConfigPath in ManualConfigEditorWindow (fallback to linux path); Linux/Windows unchanged. * Fix McpClient: align with upstream/main, prep for framing split * NL suite: shard workflow; tighten bridge readiness; add MCP preflight; use env-based shard vars * NL suite: fix shard step indentation; move shard vars to env; remove invalid inputs * MCP clients: split VSCode Copilot config paths into macConfigPath and linuxConfigPath * Unity bridge: clean stale status; bind host; robust wait probe with IPv4/IPv6 + diagnostics * CI: use MCPForUnity.Editor.MCPForUnityBridge.StartAutoConnect as executeMethod * Action wiring: inline mcpServers in settings for all shards; remove redundant .claude/mcp.json step * CI: embed mcpServers in settings for all shards; fix startup sanity step; lint clean * CI: pin claude-code-base-action to e6f32c8; use claude_args --mcp-config; switch to allowed_tools; ensure MCP config per step * CI: unpin claude-code-base-action to @beta (commit ref not found) * CI: align with claude-code-base-action @beta; pass MCP via claude_args and allowedTools * Editor: Fix apply_text_edits heuristic when edits shift positions; recompute method span on candidate text with fallback delta adjustment * CI: unify MCP wiring across workflows; write .claude/mcp.json; switch to claude_args with --mcp-config/--allowedTools; remove unsupported inputs * CI: collapse NL suite shards into a single run to avoid repeated test execution * CI: minimize allowedTools for NL suite to essential Unity MCP + Bash("git:*") + Write * CI: mkdir -p reports before run; remove unsupported --timeout-minutes from claude_args * CI: broaden allowedTools to include find_in_file and mcp__unity__* * CI: enable use_node_cache and switch NL suite model to claude-3-7-haiku-20250219 * CI: disable use_node_cache to avoid setup-node lockfile error * CI: set NL suite model to claude-3-haiku-20240307 * CI: cap Haiku output with --max-tokens 2048 for NL suite * CI: switch to claude-3-7-sonnet-latest and remove unsupported --max-tokens * CI: update allowedTools to Bash(*) and explicit Unity MCP tool list * CI: update NL suite workflow (latest tweaks) * Tests: tighten NL suite prompt for logging, hash discipline, stale retry, evidence windows, diff cap, and VERDICT line * Add disallowed tools to NL suite workflow * docs: clarify stale write retry * Add fallback JUnit report and adjust publisher * Indent fallback JUnit XML in workflow * fix: correct fallback JUnit report generation * Update mcp-quickprobe.md Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> * Update mcp-quickprobe.md Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> * Update Response.cs Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> * Update MCPForUnityBridge.cs Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> * fix: correct McpTypes reference * Add directory existence checks for symlink and XDG paths * fix: only set installation flag after successful server install * Update resource_tools.py Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> * fix: respect mac config paths * Use File.Replace for atomic config write * Remove unused imports in manage_script * bump server version * Tests: update NL suite prompt and workflows; remove deprecated smoke/desktop-parity; quickprobe tidy * Editor: atomic config write via File.Replace fallback; remove redundant backups and racey exists checks * CI: harden NL suite - idempotent docker, gate on unity_ok, safer port probe, least-priv perms * Editor: make atomic config write restoration safe (flag writeDone; copy-overwrite restore; cleanup in finally) * CI: fix fallback JUnit heredoc by using printf lines (no EOF delimiter issues) * CI: switch NL suite to mini prompt; mini prompt honors / and NL discipline * CI: replace claude_args with allowed_tools/model/mcp_config per action schema * CI: expand UNITY_PROJECT_ROOT via in MCP config heredoc * EditorWindow: add cross-platform fallback for File.Replace; macOS-insensitive PathsEqual; safer uv resolve; honor macConfigPath * CI: strengthen JUnit publishing for NL mini suite (normalize, debug list, publish both, fail_on_parse_error) * CI: set job-wide JUNIT_OUT/MD_OUT; normalization uses env; publish references env and ungroup reports * CI: publish a single normalized JUnit (reports/junit-for-actions.xml); fallback writes same; avoid checkName/reportPaths mismatch * CI: align mini prompt report filenames; redact Unity log tail in diagnostics * chore: sync workflow and mini prompt; redacted logs; JUnit normalization/publish tweaks * CI: redact sensitive tokens in Stop Unity; docs: CI usage + edit tools * prompts: update nl-unity-suite-full (mini-style setup + reporting discipline); remove obsolete prompts * CI: harden NL workflows (timeout_minutes, robust normalization); prompts: unify JUnit suite name and reporting discipline * prompts: add guarded write pattern (LF hash, stale_file retry) to full suite * prompts: enforce continue-on-failure, driver flow, and status handling in full suite * Make test list more explicit in prompt. Get rid of old test prompts for hygeine. * prompts: add stale fast-retry (server hash) + in-memory buf guidance * CI: standardize JUNIT_OUT to reports/junit-nl-suite.xml; fix artifact upload indentation; prompt copy cleanups * prompts: reporting discipline — append-only fragments, batch writes, no model round-trip * prompts: stale fast-retry preference, buffer/sha carry, snapshot revert, essential logging * workflows(nl-suite): precreate report skeletons, assemble junit, synthesize markdown; restrict allowed_tools to append-only Bash + MCP tools * thsis too * Update README-DEV.md Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update .github/workflows/claude-nl-suite-mini.yml Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update .github/workflows/claude-nl-suite.yml Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * workflows(nl-mini): fix YAML indentation/trailing spaces under with: and cleanup heredoc spacing * workflows(nl-suite): fix indentation on docker logs redaction line (YAML lint) * Add write to allowlist * nl-suite: harden reporting discipline (fragment-only writes, forbid alt paths); workflow: clean stray junit-*updated*.xml * nl-suite: enforce end-of-suite single Write (no bash redirection); workflow: restrict allowed_tools to Write+MCP only * prompts(nl-full): end-of-suite results must be valid XML with single <cases> root and only <testcase> children; no raw text outside CDATA * workflows(nl-suite): make Claude step non-fatal; tolerant normalizer extracts <testcase> via regex on bad fragments * nl-suite: fix stale classname to UnityMCP.NL-T in mini fallback; prompt: require re-read after every revert; correct PLAN/PROGRESS to 15 * nl-suite: fix fallback JUnit classname to UnityMCP.NL-T; prompt: forbid create_script and env/mkdir checks, enforce single baseline-byte revert flow and post-revert re-read; add corruption-handling guidance * prompts(nl-full): after each write re-read raw bytes to refresh pre_sha; prefer script_apply_edits for anchors; avoid header/using changes * prompts(nl-full): canonicalize outputs to /; allow small fragment appends via Write or Bash(printf/echo); forbid wrappers and full-file round-trips * prompts(nl-full): finalize markdown formatting for guarded write, execution order, specs, status * workflows(nl-suite, mini): header/lint fixes and constrained Bash append path; align allowed_tools * prompts(nl-full): format Fast Restore, Guarded Write, Execution, Specs, Status as proper markdown lists and code fences * workflows(nl-suite): keep header tidy and append-path alignment with prompt * minor fix * workflows(nl-suite): fix indentation and dispatch; align allowed_tools and revert helper * prompts(nl-full): switch to read_resource for buf/sha; re-read only when needed; convert 'Print this once' to heading; note snapshot helper creates parent dirs * workflows(nl-suite): normalize step removes bootstrap when real testcases present; recompute tests/failures * workflows(nl-suite): enrich Markdown summary by extracting per-test <system-out> blocks (truncated) * clarify prompt resilience instructions * ci(nl-suite): revert prompt and workflow to known-good e0f8a72 for green run; remove extra MD details * ci(nl-suite): minimal fixes — no-mkdir guard in prompt; drop bootstrap and recompute JUnit counts * ci(nl-suite): richer JUnit→Markdown report (per-test system-out) * Small guard to incorret asset read call. * ci(nl-suite): refine MD builder — unescape XML entities, safe code fences, PASS/FAIL badges * Update UnityMcpBridge/UnityMcpServer~/src/tools/resource_tools.py Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update UnityMcpBridge/UnityMcpServer~/src/unity_connection.py Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update UnityMcpBridge/UnityMcpServer~/src/tools/manage_script_edits.py Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update .github/scripts/mark_skipped.py Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update .github/scripts/mark_skipped.py Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update .github/scripts/mark_skipped.py Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> * server(manage_script): robust URI handling — percent-decode file://, normalize, strip host/leading slashes, return Assets-relative if present * Update .claude/prompts/nl-unity-suite-full.md Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> * tests(framing): reduce handshake poll window, nonblocking peek to avoid disconnect race; still enforce pre-handshake data drop * tests(manage_script): add _split_uri tests for unity://path, file:// URLs (decoded/Assets-relative), and plain paths * server+tests: fix handshake syntax error; robust file:// URI normalization in manage_script; add _split_uri tests; adjust stdout scan to ignore venv/site-packages * bridge(framing): accept zero-length frames (treat as empty keepalive) * tests(logging): use errors='replace' on decode fallback to avoid silent drops * resources(list): restrict to Assets/, resolve symlinks, enforce .cs; add traversal/outside-path tests * Update .claude/prompts/nl-unity-suite-full.md Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update UnityMcpBridge/UnityMcpServer~/src/unity_connection.py Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * misc: framing keepalive (zero-length), regex preview consistency, resource.list hardening, URI parsing, legacy update routing, test cleanups * docs(tools): richer MCP tool descriptions; tests accept decorator kwargs; resource URI parsing hardened * Update .claude/prompts/nl-unity-suite-full.md Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update UnityMcpBridge/UnityMcpServer~/src/tools/resource_tools.py Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update UnityMcpBridge/UnityMcpServer~/src/unity_connection.py Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * net+docs: hard-reject zero-length frames; TCP_NODELAY on connect; Assets detection case-insensitive; NL prompt statuses aligned * prompt(nl-suite): constrain Write destinations under reports/, forbid traversal * prompt+net: harden Write path rules; use monotonic deadline and plain-text advisory for non-framed peers * unity_connection: restore recv timeout via try/finally; make global connection getter thread-safe with module lock and double-checked init * NL/T prompt: pin structured edit ops for T-D/T-E; add schema-error guarded write behavior; keep existing path/URI and revert rules * unity_connection: add FRAMED_MAX; use ValueError for framed length violations; lower framed receive log to debug; serialize connect() with per-instance lock * ManageScript: use UTF8Encoding(without BOM) for atomic writes in ApplyTextEdits/EditScript to align with Create/Update and avoid BOM-related diffs/hash mismatches * NL/T prompt: make helper deletion regex multiline-safe ((?ms) so ^ anchors line starts) * ManageScript: emit structured overlap status {status:"overlap"} for overlapping edit ranges in apply_text_edits and edit paths * NL/T prompt: clarify fallback vs failure — fallback only for unsupported/missing_field; treat bad_request as failure; note unsupported after fallback as failure * NL/T prompt: pin deterministic overlap probe (apply_text_edits two ranges from same snapshot); gate too_large behind RUN_TOO_LARGE env hint * TB update * NL/T prompt: harden Output Rules — constrain Bash(printf|echo) to stdout-only; forbid redirection/here-docs/tee; only scripts/nlt-revert.sh may mutate FS * Prompt: enumerate allowed script_apply_edits ops; add manage_editor/read_console guidance; fix T‑F atomic batch to single script_apply_edits. ManageScript: regex timeout for diagnostics; symlink ancestor guard; complete allowed-modes list. * Fixes * ManageScript: add rich overlap diagnostics (conflicts + hint) for both text range and structured batch paths * ManageScript: return structured {status:"validation_failed"} diagnostics in create/update/edits and validate before commit * ManageScript: echo canonical uri in responses (create/read/update/apply_text_edits/structured edits) to reinforce resource identity * improve clarity of capabilities message * Framing: allow zero-length frames on both ends (C# bridge, Python server). Prompt: harden T-F to single text-range apply_text_edits batch (descending order, one snapshot). URI: normalize file:// outside Assets by stripping leading slash. * ManageScript: include new sha256 in success payload for apply_text_edits; harden TryResolveUnderAssets by rejecting symlinked ancestors up to Assets/. * remove claudetest dir * manage_script_edits: normalize method-anchored anchor_insert to insert_method (map text->replacement); improves CI compatibility for T‑A/T‑E without changing Editor behavior. * tighten testing protocol around mkdir * manage_script: validate create_script inputs (Assets/.cs/name/no traversal); add Assets/ guard to delete_script; validate level+Assets in validate_script; make legacy manage_script optional params; harden legacy update routing with base64 reuse and payload size preflight. * Tighten prompt for testing * Update .claude/prompts/nl-unity-suite-full.md Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update .claude/prompts/nl-unity-suite-full.md Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update UnityMcpBridge/Editor/Tools/ManageScript.cs Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * manage_script_edits: honor ignore_case on anchor_insert and regex_replace in both direct and text-conversion paths (MULTILINE|IGNORECASE). * remove extra file * workflow: use python3 for inline scripts and port detection on ubuntu-latest. * Tighten prompt + manage_script * Update UnityMcpBridge/UnityMcpServer~/src/tools/manage_script_edits.py Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update UnityMcpBridge/UnityMcpServer~/src/tools/manage_script_edits.py Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update .claude/prompts/nl-unity-suite-full.md Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update UnityMcpBridge/Editor/Tools/ManageScript.cs Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update .claude/prompts/nl-unity-suite-full.md Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * manage_script: improve file:// UNC handling; preserve POSIX absolute semantics internally; keep test-expected slash stripping for non-Assets paths. * ManageScript.cs: add TimeSpan timeouts to all Regex uses (IsMatch/Match/new Regex) and keep CultureInvariant/Multiline options; reduces risk of catastrophic backtracking stalls. * workflow: ensure reports/ exists in markdown build step to avoid FileNotFoundError when writing MD_OUT. * fix brace * manage_script_edits: expand backrefs for regex_replace in preview->text conversion and translate to \g<n> in local apply; keeps previews and actual edits consistent. * anchor_insert: default to position=after, normalize surrounding newlines in Python conversion paths; C# path ensures trailing newline and skips duplicate insertion within class. * feat(mcp): add get_sha tool; apply_text_edits normalization+overlap preflight+strict; no-op evidence in C#; update NL suite prompt; add unit tests * feat(frames): accept zero-length heartbeat frames in client; add heartbeat test * feat(edits): guard destructive regex_replace with structural preflight; add robust tests; prompt uses delete_method for temp helper * feat(frames): bound heartbeat loop with timeout/threshold; align zero-length response with C#; update test * SDK hardening: atomic multi-span text edits; stop forcing sequential for structured ops; forward options on apply_text_edits; add validate=relaxed support and scoped checks; update NL/T prompt; add tests for options forwarding, relaxed mode, and atomic batches * Router: default applyMode=atomic for multi-span apply_text_edits; add tests * CI prompt: pass options.validate=relaxed for T-B/C; options.applyMode=atomic for T-F; emphasize always writing testcase and restoring on errors * Validation & DX: add validate=syntax (scoped), standardize evidence windows; early regex compile with hints; debug_preview for apply_text_edits * Update UnityMcpBridge/Editor/Windows/MCPForUnityEditorWindow.cs Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * NL/T suite-driven edits: LongUnityScriptClaudeTest, bridge helpers, server_version; prepare framing tests * Fix duplicate macConfigPath field in McpClient to resolve CS0102 * Editor threading: run EnsureServerInstalled on main thread; marshal EditorPrefs/DeleteKey + logging via delayCall * Docs(apply_text_edits): strengthen guidance on 1-based positions, verify-before-edit, and recommend anchors/structured edits * Docs(script_apply_edits): add safety guidance (anchors, method ops, validators) and recommended practices * Framed VerifyBridgePing in editor window; docs hardening for apply_text_edits and script_apply_edits --------- Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
2025-08-31 00:55:38 +08:00
/// <summary>
/// Structured edits (AST-backed where available) on existing scripts.
/// Supports class-level replace/delete with Roslyn span computation if USE_ROSLYN is defined,
/// otherwise falls back to a conservative balanced-brace scan.
/// </summary>
private static object EditScript(
string fullPath,
string relativePath,
string name,
JArray edits,
JObject options)
{
if (!File.Exists(fullPath))
return Response.Error($"Script not found at '{relativePath}'.");
// Refuse edits if the target is a symlink
try
{
var attrs = File.GetAttributes(fullPath);
if ((attrs & FileAttributes.ReparsePoint) != 0)
return Response.Error("Refusing to edit a symlinked script path.");
}
catch
{
// ignore failures checking attributes and proceed
}
if (edits == null || edits.Count == 0)
return Response.Error("No edits provided.");
string original;
try { original = File.ReadAllText(fullPath); }
catch (Exception ex) { return Response.Error($"Failed to read script: {ex.Message}"); }
string working = original;
try
{
var replacements = new List<(int start, int length, string text)>();
int appliedCount = 0;
// Apply mode: atomic (default) computes all spans against original and applies together.
// Sequential applies each edit immediately to the current working text (useful for dependent edits).
string applyMode = options?["applyMode"]?.ToString()?.ToLowerInvariant();
bool applySequentially = applyMode == "sequential";
foreach (var e in edits)
{
var op = (JObject)e;
var mode = (op.Value<string>("mode") ?? op.Value<string>("op") ?? string.Empty).ToLowerInvariant();
switch (mode)
{
case "replace_class":
{
string className = op.Value<string>("className");
string ns = op.Value<string>("namespace");
string replacement = ExtractReplacement(op);
if (string.IsNullOrWhiteSpace(className))
return Response.Error("replace_class requires 'className'.");
if (replacement == null)
return Response.Error("replace_class requires 'replacement' (inline or base64).");
if (!TryComputeClassSpan(working, className, ns, out var spanStart, out var spanLength, out var why))
return Response.Error($"replace_class failed: {why}");
if (!ValidateClassSnippet(replacement, className, out var vErr))
return Response.Error($"Replacement snippet invalid: {vErr}");
if (applySequentially)
{
working = working.Remove(spanStart, spanLength).Insert(spanStart, NormalizeNewlines(replacement));
appliedCount++;
}
else
{
replacements.Add((spanStart, spanLength, NormalizeNewlines(replacement)));
}
break;
}
case "delete_class":
{
string className = op.Value<string>("className");
string ns = op.Value<string>("namespace");
if (string.IsNullOrWhiteSpace(className))
return Response.Error("delete_class requires 'className'.");
if (!TryComputeClassSpan(working, className, ns, out var s, out var l, out var why))
return Response.Error($"delete_class failed: {why}");
if (applySequentially)
{
working = working.Remove(s, l);
appliedCount++;
}
else
{
replacements.Add((s, l, string.Empty));
}
break;
}
case "replace_method":
{
string className = op.Value<string>("className");
string ns = op.Value<string>("namespace");
string methodName = op.Value<string>("methodName");
string replacement = ExtractReplacement(op);
string returnType = op.Value<string>("returnType");
string parametersSignature = op.Value<string>("parametersSignature");
string attributesContains = op.Value<string>("attributesContains");
if (string.IsNullOrWhiteSpace(className)) return Response.Error("replace_method requires 'className'.");
if (string.IsNullOrWhiteSpace(methodName)) return Response.Error("replace_method requires 'methodName'.");
if (replacement == null) return Response.Error("replace_method requires 'replacement' (inline or base64).");
if (!TryComputeClassSpan(working, className, ns, out var clsStart, out var clsLen, out var whyClass))
return Response.Error($"replace_method failed to locate class: {whyClass}");
if (!TryComputeMethodSpan(working, clsStart, clsLen, methodName, returnType, parametersSignature, attributesContains, out var mStart, out var mLen, out var whyMethod))
{
bool hasDependentInsert = edits.Any(j => j is JObject jo &&
string.Equals(jo.Value<string>("className"), className, StringComparison.Ordinal) &&
string.Equals(jo.Value<string>("methodName"), methodName, StringComparison.Ordinal) &&
((jo.Value<string>("mode") ?? jo.Value<string>("op") ?? string.Empty).ToLowerInvariant() == "insert_method"));
string hint = hasDependentInsert && !applySequentially ? " Hint: This batch inserts this method. Use options.applyMode='sequential' or split into separate calls." : string.Empty;
return Response.Error($"replace_method failed: {whyMethod}.{hint}");
}
if (applySequentially)
{
working = working.Remove(mStart, mLen).Insert(mStart, NormalizeNewlines(replacement));
appliedCount++;
}
else
{
replacements.Add((mStart, mLen, NormalizeNewlines(replacement)));
}
break;
}
case "delete_method":
{
string className = op.Value<string>("className");
string ns = op.Value<string>("namespace");
string methodName = op.Value<string>("methodName");
string returnType = op.Value<string>("returnType");
string parametersSignature = op.Value<string>("parametersSignature");
string attributesContains = op.Value<string>("attributesContains");
if (string.IsNullOrWhiteSpace(className)) return Response.Error("delete_method requires 'className'.");
if (string.IsNullOrWhiteSpace(methodName)) return Response.Error("delete_method requires 'methodName'.");
if (!TryComputeClassSpan(working, className, ns, out var clsStart, out var clsLen, out var whyClass))
return Response.Error($"delete_method failed to locate class: {whyClass}");
if (!TryComputeMethodSpan(working, clsStart, clsLen, methodName, returnType, parametersSignature, attributesContains, out var mStart, out var mLen, out var whyMethod))
{
bool hasDependentInsert = edits.Any(j => j is JObject jo &&
string.Equals(jo.Value<string>("className"), className, StringComparison.Ordinal) &&
string.Equals(jo.Value<string>("methodName"), methodName, StringComparison.Ordinal) &&
((jo.Value<string>("mode") ?? jo.Value<string>("op") ?? string.Empty).ToLowerInvariant() == "insert_method"));
string hint = hasDependentInsert && !applySequentially ? " Hint: This batch inserts this method. Use options.applyMode='sequential' or split into separate calls." : string.Empty;
return Response.Error($"delete_method failed: {whyMethod}.{hint}");
}
if (applySequentially)
{
working = working.Remove(mStart, mLen);
appliedCount++;
}
else
{
replacements.Add((mStart, mLen, string.Empty));
}
break;
}
case "insert_method":
{
string className = op.Value<string>("className");
string ns = op.Value<string>("namespace");
string position = (op.Value<string>("position") ?? "end").ToLowerInvariant();
string afterMethodName = op.Value<string>("afterMethodName");
string afterReturnType = op.Value<string>("afterReturnType");
string afterParameters = op.Value<string>("afterParametersSignature");
string afterAttributesContains = op.Value<string>("afterAttributesContains");
string snippet = ExtractReplacement(op);
// Harden: refuse empty replacement for inserts
if (snippet == null || snippet.Trim().Length == 0)
return Response.Error("insert_method requires a non-empty 'replacement' text.");
if (string.IsNullOrWhiteSpace(className)) return Response.Error("insert_method requires 'className'.");
if (snippet == null) return Response.Error("insert_method requires 'replacement' (inline or base64) containing a full method declaration.");
if (!TryComputeClassSpan(working, className, ns, out var clsStart, out var clsLen, out var whyClass))
return Response.Error($"insert_method failed to locate class: {whyClass}");
if (position == "after")
{
if (string.IsNullOrEmpty(afterMethodName)) return Response.Error("insert_method with position='after' requires 'afterMethodName'.");
if (!TryComputeMethodSpan(working, clsStart, clsLen, afterMethodName, afterReturnType, afterParameters, afterAttributesContains, out var aStart, out var aLen, out var whyAfter))
return Response.Error($"insert_method(after) failed to locate anchor method: {whyAfter}");
int insAt = aStart + aLen;
string text = NormalizeNewlines("\n\n" + snippet.TrimEnd() + "\n");
if (applySequentially)
{
working = working.Insert(insAt, text);
appliedCount++;
}
else
{
replacements.Add((insAt, 0, text));
}
}
else if (!TryFindClassInsertionPoint(working, clsStart, clsLen, position, out var insAt, out var whyIns))
return Response.Error($"insert_method failed: {whyIns}");
else
{
string text = NormalizeNewlines("\n\n" + snippet.TrimEnd() + "\n");
if (applySequentially)
{
working = working.Insert(insAt, text);
appliedCount++;
}
else
{
replacements.Add((insAt, 0, text));
}
}
break;
}
case "anchor_insert":
{
string anchor = op.Value<string>("anchor");
string position = (op.Value<string>("position") ?? "before").ToLowerInvariant();
string text = op.Value<string>("text") ?? ExtractReplacement(op);
if (string.IsNullOrWhiteSpace(anchor)) return Response.Error("anchor_insert requires 'anchor' (regex).");
if (string.IsNullOrEmpty(text)) return Response.Error("anchor_insert requires non-empty 'text'.");
try
{
var rx = new Regex(anchor, RegexOptions.Multiline, TimeSpan.FromSeconds(2));
var m = rx.Match(working);
if (!m.Success) return Response.Error($"anchor_insert: anchor not found: {anchor}");
int insAt = position == "after" ? m.Index + m.Length : m.Index;
string norm = NormalizeNewlines(text);
if (!norm.EndsWith("\n"))
{
norm += "\n";
}
// Duplicate guard: if identical snippet already exists within this class, skip insert
if (TryComputeClassSpan(working, name, null, out var clsStartDG, out var clsLenDG, out _))
{
string classSlice = working.Substring(clsStartDG, Math.Min(clsLenDG, working.Length - clsStartDG));
if (classSlice.IndexOf(norm, StringComparison.Ordinal) >= 0)
{
// Do not insert duplicate; treat as no-op
break;
}
}
if (applySequentially)
{
working = working.Insert(insAt, norm);
appliedCount++;
}
else
{
replacements.Add((insAt, 0, norm));
}
}
catch (Exception ex)
{
return Response.Error($"anchor_insert failed: {ex.Message}");
}
break;
}
case "anchor_delete":
{
string anchor = op.Value<string>("anchor");
if (string.IsNullOrWhiteSpace(anchor)) return Response.Error("anchor_delete requires 'anchor' (regex).");
try
{
var rx = new Regex(anchor, RegexOptions.Multiline, TimeSpan.FromSeconds(2));
var m = rx.Match(working);
if (!m.Success) return Response.Error($"anchor_delete: anchor not found: {anchor}");
int delAt = m.Index;
int delLen = m.Length;
if (applySequentially)
{
working = working.Remove(delAt, delLen);
appliedCount++;
}
else
{
replacements.Add((delAt, delLen, string.Empty));
}
}
catch (Exception ex)
{
return Response.Error($"anchor_delete failed: {ex.Message}");
}
break;
}
case "anchor_replace":
{
string anchor = op.Value<string>("anchor");
string replacement = op.Value<string>("text") ?? op.Value<string>("replacement") ?? ExtractReplacement(op) ?? string.Empty;
if (string.IsNullOrWhiteSpace(anchor)) return Response.Error("anchor_replace requires 'anchor' (regex).");
try
{
var rx = new Regex(anchor, RegexOptions.Multiline, TimeSpan.FromSeconds(2));
var m = rx.Match(working);
if (!m.Success) return Response.Error($"anchor_replace: anchor not found: {anchor}");
int at = m.Index;
int len = m.Length;
string norm = NormalizeNewlines(replacement);
if (applySequentially)
{
working = working.Remove(at, len).Insert(at, norm);
appliedCount++;
}
else
{
replacements.Add((at, len, norm));
}
}
catch (Exception ex)
{
return Response.Error($"anchor_replace failed: {ex.Message}");
}
break;
}
default:
return Response.Error($"Unknown edit mode: '{mode}'. Allowed: replace_class, delete_class, replace_method, delete_method, insert_method, anchor_insert, anchor_delete, anchor_replace.");
}
}
if (!applySequentially)
{
if (HasOverlaps(replacements))
{
var ordered = replacements.OrderByDescending(r => r.start).ToList();
for (int i = 1; i < ordered.Count; i++)
{
if (ordered[i].start + ordered[i].length > ordered[i - 1].start)
{
var conflict = new[] { new { startA = ordered[i].start, endA = ordered[i].start + ordered[i].length, startB = ordered[i - 1].start, endB = ordered[i - 1].start + ordered[i - 1].length } };
return Response.Error("overlap", new { status = "overlap", conflicts = conflict, hint = "Apply in descending order against the same precondition snapshot." });
}
}
return Response.Error("overlap", new { status = "overlap" });
}
foreach (var r in replacements.OrderByDescending(r => r.start))
working = working.Remove(r.start, r.length).Insert(r.start, r.text);
appliedCount = replacements.Count;
}
// No-op guard for structured edits: if text unchanged, return explicit no-op
if (string.Equals(working, original, StringComparison.Ordinal))
{
var sameSha = ComputeSha256(original);
return Response.Success(
$"No-op: contents unchanged for '{relativePath}'.",
new
{
path = relativePath,
uri = $"unity://path/{relativePath}",
editsApplied = 0,
no_op = true,
sha256 = sameSha,
evidence = new { reason = "identical_content" }
}
);
}
// Validate result using override from options if provided; otherwise GUI strictness
var level = GetValidationLevelFromGUI();
try
{
var validateOpt = options?["validate"]?.ToString()?.ToLowerInvariant();
if (!string.IsNullOrEmpty(validateOpt))
{
level = validateOpt switch
{
"basic" => ValidationLevel.Basic,
"standard" => ValidationLevel.Standard,
"comprehensive" => ValidationLevel.Comprehensive,
"strict" => ValidationLevel.Strict,
_ => level
};
}
}
catch { /* ignore option parsing issues */ }
if (!ValidateScriptSyntax(working, level, out var errors))
return Response.Error("validation_failed", new { status = "validation_failed", diagnostics = errors ?? Array.Empty<string>() });
else if (errors != null && errors.Length > 0)
Debug.LogWarning($"Script validation warnings for {name}:\n" + string.Join("\n", errors));
// Atomic write with backup; schedule refresh
// Decide refresh behavior
string refreshMode = options?["refresh"]?.ToString()?.ToLowerInvariant();
bool immediate = refreshMode == "immediate" || refreshMode == "sync";
// Persist changes atomically (no BOM), then compute/return new file SHA
var enc = new System.Text.UTF8Encoding(encoderShouldEmitUTF8Identifier: false);
var tmp = fullPath + ".tmp";
File.WriteAllText(tmp, working, enc);
var backup = fullPath + ".bak";
try
{
File.Replace(tmp, fullPath, backup);
try { if (File.Exists(backup)) File.Delete(backup); } catch { }
}
catch (PlatformNotSupportedException)
{
File.Copy(tmp, fullPath, true);
try { File.Delete(tmp); } catch { }
try { if (File.Exists(backup)) File.Delete(backup); } catch { }
}
catch (IOException)
{
File.Copy(tmp, fullPath, true);
try { File.Delete(tmp); } catch { }
try { if (File.Exists(backup)) File.Delete(backup); } catch { }
}
var newSha = ComputeSha256(working);
var ok = Response.Success(
$"Applied {appliedCount} structured edit(s) to '{relativePath}'.",
new
{
path = relativePath,
uri = $"unity://path/{relativePath}",
editsApplied = appliedCount,
scheduledRefresh = !immediate,
sha256 = newSha
}
);
if (immediate)
{
// Force on main thread
EditorApplication.delayCall += () =>
{
AssetDatabase.ImportAsset(
relativePath,
ImportAssetOptions.ForceSynchronousImport | ImportAssetOptions.ForceUpdate
);
#if UNITY_EDITOR
UnityEditor.Compilation.CompilationPipeline.RequestScriptCompilation();
#endif
};
}
else
{
ManageScriptRefreshHelpers.ScheduleScriptRefresh(relativePath);
}
return ok;
}
catch (Exception ex)
{
return Response.Error($"Edit failed: {ex.Message}");
}
}
private static bool HasOverlaps(IEnumerable<(int start, int length, string text)> list)
{
var arr = list.OrderBy(x => x.start).ToArray();
for (int i = 1; i < arr.Length; i++)
{
if (arr[i - 1].start + arr[i - 1].length > arr[i].start)
return true;
}
return false;
}
private static string ExtractReplacement(JObject op)
{
var inline = op.Value<string>("replacement");
if (!string.IsNullOrEmpty(inline)) return inline;
var b64 = op.Value<string>("replacementBase64");
if (!string.IsNullOrEmpty(b64))
{
try { return System.Text.Encoding.UTF8.GetString(Convert.FromBase64String(b64)); }
catch { return null; }
}
return null;
}
private static string NormalizeNewlines(string t)
{
if (string.IsNullOrEmpty(t)) return t;
return t.Replace("\r\n", "\n").Replace("\r", "\n");
}
private static bool ValidateClassSnippet(string snippet, string expectedName, out string err)
{
#if USE_ROSLYN
try
{
var tree = CSharpSyntaxTree.ParseText(snippet);
var root = tree.GetRoot();
var classes = root.DescendantNodes().OfType<Microsoft.CodeAnalysis.CSharp.Syntax.ClassDeclarationSyntax>().ToList();
if (classes.Count != 1) { err = "snippet must contain exactly one class declaration"; return false; }
// Optional: enforce expected name
// if (classes[0].Identifier.ValueText != expectedName) { err = $"snippet declares '{classes[0].Identifier.ValueText}', expected '{expectedName}'"; return false; }
err = null; return true;
}
catch (Exception ex) { err = ex.Message; return false; }
#else
if (string.IsNullOrWhiteSpace(snippet) || !snippet.Contains("class ")) { err = "no 'class' keyword found in snippet"; return false; }
err = null; return true;
#endif
}
private static bool TryComputeClassSpan(string source, string className, string ns, out int start, out int length, out string why)
{
#if USE_ROSLYN
try
{
var tree = CSharpSyntaxTree.ParseText(source);
var root = tree.GetRoot();
var classes = root.DescendantNodes()
.OfType<Microsoft.CodeAnalysis.CSharp.Syntax.ClassDeclarationSyntax>()
.Where(c => c.Identifier.ValueText == className);
if (!string.IsNullOrEmpty(ns))
{
classes = classes.Where(c =>
(c.FirstAncestorOrSelf<Microsoft.CodeAnalysis.CSharp.Syntax.NamespaceDeclarationSyntax>()?.Name?.ToString() ?? "") == ns
|| (c.FirstAncestorOrSelf<Microsoft.CodeAnalysis.CSharp.Syntax.FileScopedNamespaceDeclarationSyntax>()?.Name?.ToString() ?? "") == ns);
}
var list = classes.ToList();
if (list.Count == 0) { start = length = 0; why = $"class '{className}' not found" + (ns != null ? $" in namespace '{ns}'" : ""); return false; }
if (list.Count > 1) { start = length = 0; why = $"class '{className}' matched {list.Count} declarations (partial/nested?). Disambiguate."; return false; }
var cls = list[0];
var span = cls.FullSpan; // includes attributes & leading trivia
start = span.Start; length = span.Length; why = null; return true;
}
catch
{
// fall back below
}
#endif
return TryComputeClassSpanBalanced(source, className, ns, out start, out length, out why);
}
private static bool TryComputeClassSpanBalanced(string source, string className, string ns, out int start, out int length, out string why)
{
start = length = 0; why = null;
var idx = IndexOfClassToken(source, className);
if (idx < 0) { why = $"class '{className}' not found (balanced scan)"; return false; }
if (!string.IsNullOrEmpty(ns) && !AppearsWithinNamespaceHeader(source, idx, ns))
{ why = $"class '{className}' not under namespace '{ns}' (balanced scan)"; return false; }
// Include modifiers/attributes on the same line: back up to the start of line
int lineStart = idx;
while (lineStart > 0 && source[lineStart - 1] != '\n' && source[lineStart - 1] != '\r') lineStart--;
int i = idx;
while (i < source.Length && source[i] != '{') i++;
if (i >= source.Length) { why = "no opening brace after class header"; return false; }
int depth = 0; bool inStr = false, inChar = false, inSL = false, inML = false, esc = false;
int startSpan = lineStart;
for (; i < source.Length; i++)
{
char c = source[i];
char n = i + 1 < source.Length ? source[i + 1] : '\0';
if (inSL) { if (c == '\n') inSL = false; continue; }
if (inML) { if (c == '*' && n == '/') { inML = false; i++; } continue; }
if (inStr) { if (!esc && c == '"') inStr = false; esc = (!esc && c == '\\'); continue; }
if (inChar) { if (!esc && c == '\'') inChar = false; esc = (!esc && c == '\\'); continue; }
if (c == '/' && n == '/') { inSL = true; i++; continue; }
if (c == '/' && n == '*') { inML = true; i++; continue; }
if (c == '"') { inStr = true; continue; }
if (c == '\'') { inChar = true; continue; }
if (c == '{') { depth++; }
else if (c == '}')
{
depth--;
if (depth == 0) { start = startSpan; length = (i - startSpan) + 1; return true; }
if (depth < 0) { why = "brace underflow"; return false; }
}
}
why = "unterminated class block"; return false;
}
private static bool TryComputeMethodSpan(
string source,
int classStart,
int classLength,
string methodName,
string returnType,
string parametersSignature,
string attributesContains,
out int start,
out int length,
out string why)
{
start = length = 0; why = null;
int searchStart = classStart;
int searchEnd = Math.Min(source.Length, classStart + classLength);
// 1) Find the method header using a stricter regex (allows optional attributes above)
string rtPattern = string.IsNullOrEmpty(returnType) ? @"[^\s]+" : Regex.Escape(returnType).Replace("\\ ", "\\s+");
string namePattern = Regex.Escape(methodName);
// If a parametersSignature is provided, it may include surrounding parentheses. Strip them so
// we can safely embed the signature inside our own parenthesis group without duplicating.
string paramsPattern;
if (string.IsNullOrEmpty(parametersSignature))
{
paramsPattern = @"[\s\S]*?"; // permissive when not specified
}
else
{
string ps = parametersSignature.Trim();
if (ps.StartsWith("(") && ps.EndsWith(")") && ps.Length >= 2)
{
ps = ps.Substring(1, ps.Length - 2);
}
// Escape literal text of the signature
paramsPattern = Regex.Escape(ps);
}
string pattern =
@"(?m)^[\t ]*(?:\[[^\]]+\][\t ]*)*[\t ]*" +
@"(?:(?:public|private|protected|internal|static|virtual|override|sealed|async|extern|unsafe|new|partial|readonly|volatile|event|abstract|ref|in|out)\s+)*" +
rtPattern + @"[\t ]+" + namePattern + @"\s*(?:<[^>]+>)?\s*\(" + paramsPattern + @"\)";
string slice = source.Substring(searchStart, searchEnd - searchStart);
var headerMatch = Regex.Match(slice, pattern, RegexOptions.Multiline, TimeSpan.FromSeconds(2));
if (!headerMatch.Success)
{
why = $"method '{methodName}' header not found in class"; return false;
}
int headerIndex = searchStart + headerMatch.Index;
// Optional attributes filter: look upward from headerIndex for contiguous attribute lines
if (!string.IsNullOrEmpty(attributesContains))
{
int attrScanStart = headerIndex;
while (attrScanStart > searchStart)
{
int prevNl = source.LastIndexOf('\n', attrScanStart - 1);
if (prevNl < 0 || prevNl < searchStart) break;
string prevLine = source.Substring(prevNl + 1, attrScanStart - (prevNl + 1));
if (prevLine.TrimStart().StartsWith("[")) { attrScanStart = prevNl; continue; }
break;
}
string attrBlock = source.Substring(attrScanStart, headerIndex - attrScanStart);
if (attrBlock.IndexOf(attributesContains, StringComparison.Ordinal) < 0)
{
why = $"method '{methodName}' found but attributes filter did not match"; return false;
}
}
// backtrack to the very start of header/attributes to include in span
int lineStart = headerIndex;
while (lineStart > searchStart && source[lineStart - 1] != '\n' && source[lineStart - 1] != '\r') lineStart--;
// If previous lines are attributes, include them
int attrStart = lineStart;
int probe = lineStart - 1;
while (probe > searchStart)
{
int prevNl = source.LastIndexOf('\n', probe);
if (prevNl < 0 || prevNl < searchStart) break;
string prev = source.Substring(prevNl + 1, attrStart - (prevNl + 1));
if (prev.TrimStart().StartsWith("[")) { attrStart = prevNl + 1; probe = prevNl - 1; }
else break;
}
// 2) Walk from the end of signature to detect body style ('{' or '=> ...;') and compute end
// Find the '(' that belongs to the method signature, not attributes
int nameTokenIdx = IndexOfTokenWithin(source, methodName, headerIndex, searchEnd);
if (nameTokenIdx < 0) { why = $"method '{methodName}' token not found after header"; return false; }
int sigOpenParen = IndexOfTokenWithin(source, "(", nameTokenIdx, searchEnd);
if (sigOpenParen < 0) { why = "method parameter list '(' not found"; return false; }
int i = sigOpenParen;
int parenDepth = 0; bool inStr = false, inChar = false, inSL = false, inML = false, esc = false;
for (; i < searchEnd; i++)
{
char c = source[i];
char n = i + 1 < searchEnd ? source[i + 1] : '\0';
if (inSL) { if (c == '\n') inSL = false; continue; }
if (inML) { if (c == '*' && n == '/') { inML = false; i++; } continue; }
if (inStr) { if (!esc && c == '"') inStr = false; esc = (!esc && c == '\\'); continue; }
if (inChar) { if (!esc && c == '\'') inChar = false; esc = (!esc && c == '\\'); continue; }
if (c == '/' && n == '/') { inSL = true; i++; continue; }
if (c == '/' && n == '*') { inML = true; i++; continue; }
if (c == '"') { inStr = true; continue; }
if (c == '\'') { inChar = true; continue; }
if (c == '(') parenDepth++;
if (c == ')') { parenDepth--; if (parenDepth == 0) { i++; break; } }
}
// After params: detect expression-bodied or block-bodied
// Skip whitespace/comments
for (; i < searchEnd; i++)
{
char c = source[i];
char n = i + 1 < searchEnd ? source[i + 1] : '\0';
if (char.IsWhiteSpace(c)) continue;
if (c == '/' && n == '/') { while (i < searchEnd && source[i] != '\n') i++; continue; }
if (c == '/' && n == '*') { i += 2; while (i + 1 < searchEnd && !(source[i] == '*' && source[i + 1] == '/')) i++; i++; continue; }
break;
}
// Tolerate generic constraints between params and body: multiple 'where T : ...'
for (;;)
{
// Skip whitespace/comments before checking for 'where'
for (; i < searchEnd; i++)
{
char c = source[i];
char n = i + 1 < searchEnd ? source[i + 1] : '\0';
if (char.IsWhiteSpace(c)) continue;
if (c == '/' && n == '/') { while (i < searchEnd && source[i] != '\n') i++; continue; }
if (c == '/' && n == '*') { i += 2; while (i + 1 < searchEnd && !(source[i] == '*' && source[i + 1] == '/')) i++; i++; continue; }
break;
}
// Check word-boundary 'where'
bool hasWhere = false;
if (i + 5 <= searchEnd)
{
hasWhere = source[i] == 'w' && source[i + 1] == 'h' && source[i + 2] == 'e' && source[i + 3] == 'r' && source[i + 4] == 'e';
if (hasWhere)
{
// Left boundary
if (i - 1 >= 0)
{
char lb = source[i - 1];
if (char.IsLetterOrDigit(lb) || lb == '_') hasWhere = false;
}
// Right boundary
if (hasWhere && i + 5 < searchEnd)
{
char rb = source[i + 5];
if (char.IsLetterOrDigit(rb) || rb == '_') hasWhere = false;
}
}
}
if (!hasWhere) break;
// Advance past the entire where-constraint clause until we hit '{' or '=>' or ';'
i += 5; // past 'where'
while (i < searchEnd)
{
char c = source[i];
char n = i + 1 < searchEnd ? source[i + 1] : '\0';
if (c == '{' || c == ';' || (c == '=' && n == '>')) break;
// Skip comments inline
if (c == '/' && n == '/') { while (i < searchEnd && source[i] != '\n') i++; continue; }
if (c == '/' && n == '*') { i += 2; while (i + 1 < searchEnd && !(source[i] == '*' && source[i + 1] == '/')) i++; i++; continue; }
i++;
}
}
// Re-check for expression-bodied after constraints
if (i < searchEnd - 1 && source[i] == '=' && source[i + 1] == '>')
{
// expression-bodied method: seek to terminating semicolon
int j = i;
bool done = false;
while (j < searchEnd)
{
char c = source[j];
if (c == ';') { done = true; break; }
j++;
}
if (!done) { why = "unterminated expression-bodied method"; return false; }
start = attrStart; length = (j - attrStart) + 1; return true;
}
if (i >= searchEnd || source[i] != '{') { why = "no opening brace after method signature"; return false; }
int depth = 0; inStr = false; inChar = false; inSL = false; inML = false; esc = false;
int startSpan = attrStart;
for (; i < searchEnd; i++)
{
char c = source[i];
char n = i + 1 < searchEnd ? source[i + 1] : '\0';
if (inSL) { if (c == '\n') inSL = false; continue; }
if (inML) { if (c == '*' && n == '/') { inML = false; i++; } continue; }
if (inStr) { if (!esc && c == '"') inStr = false; esc = (!esc && c == '\\'); continue; }
if (inChar) { if (!esc && c == '\'') inChar = false; esc = (!esc && c == '\\'); continue; }
if (c == '/' && n == '/') { inSL = true; i++; continue; }
if (c == '/' && n == '*') { inML = true; i++; continue; }
if (c == '"') { inStr = true; continue; }
if (c == '\'') { inChar = true; continue; }
if (c == '{') depth++;
else if (c == '}')
{
depth--;
if (depth == 0) { start = startSpan; length = (i - startSpan) + 1; return true; }
if (depth < 0) { why = "brace underflow in method"; return false; }
}
}
why = "unterminated method block"; return false;
}
private static int IndexOfTokenWithin(string s, string token, int start, int end)
{
int idx = s.IndexOf(token, start, StringComparison.Ordinal);
return (idx >= 0 && idx < end) ? idx : -1;
}
private static bool TryFindClassInsertionPoint(string source, int classStart, int classLength, string position, out int insertAt, out string why)
{
insertAt = 0; why = null;
int searchStart = classStart;
int searchEnd = Math.Min(source.Length, classStart + classLength);
if (position == "start")
{
// find first '{' after class header, insert just after with a newline
int i = IndexOfTokenWithin(source, "{", searchStart, searchEnd);
if (i < 0) { why = "could not find class opening brace"; return false; }
insertAt = i + 1; return true;
}
else // end
{
// walk to matching closing brace of class and insert just before it
int i = IndexOfTokenWithin(source, "{", searchStart, searchEnd);
if (i < 0) { why = "could not find class opening brace"; return false; }
int depth = 0; bool inStr = false, inChar = false, inSL = false, inML = false, esc = false;
for (; i < searchEnd; i++)
{
char c = source[i];
char n = i + 1 < searchEnd ? source[i + 1] : '\0';
if (inSL) { if (c == '\n') inSL = false; continue; }
if (inML) { if (c == '*' && n == '/') { inML = false; i++; } continue; }
if (inStr) { if (!esc && c == '"') inStr = false; esc = (!esc && c == '\\'); continue; }
if (inChar) { if (!esc && c == '\'') inChar = false; esc = (!esc && c == '\\'); continue; }
if (c == '/' && n == '/') { inSL = true; i++; continue; }
if (c == '/' && n == '*') { inML = true; i++; continue; }
if (c == '"') { inStr = true; continue; }
if (c == '\'') { inChar = true; continue; }
if (c == '{') depth++;
else if (c == '}')
{
depth--;
if (depth == 0) { insertAt = i; return true; }
if (depth < 0) { why = "brace underflow while scanning class"; return false; }
}
}
why = "could not find class closing brace"; return false;
}
}
private static int IndexOfClassToken(string s, string className)
{
// simple token search; could be tightened with Regex for word boundaries
var pattern = "class " + className;
return s.IndexOf(pattern, StringComparison.Ordinal);
}
private static bool AppearsWithinNamespaceHeader(string s, int pos, string ns)
{
int from = Math.Max(0, pos - 2000);
var slice = s.Substring(from, pos - from);
return slice.Contains("namespace " + ns);
}
2025-03-31 03:58:01 +08:00
/// <summary>
/// Generates basic C# script content based on name and type.
/// </summary>
private static string GenerateDefaultScriptContent(
string name,
string scriptType,
string namespaceName
)
2025-03-31 03:58:01 +08:00
{
string usingStatements = "using UnityEngine;\nusing System.Collections;\n";
string classDeclaration;
string body =
"\n // Use this for initialization\n void Start() {\n\n }\n\n // Update is called once per frame\n void Update() {\n\n }\n";
2025-03-31 03:58:01 +08:00
string baseClass = "";
if (!string.IsNullOrEmpty(scriptType))
{
if (scriptType.Equals("MonoBehaviour", StringComparison.OrdinalIgnoreCase))
baseClass = " : MonoBehaviour";
else if (scriptType.Equals("ScriptableObject", StringComparison.OrdinalIgnoreCase))
{
baseClass = " : ScriptableObject";
body = ""; // ScriptableObjects don't usually need Start/Update
}
else if (
scriptType.Equals("Editor", StringComparison.OrdinalIgnoreCase)
|| scriptType.Equals("EditorWindow", StringComparison.OrdinalIgnoreCase)
)
2025-03-31 03:58:01 +08:00
{
usingStatements += "using UnityEditor;\n";
if (scriptType.Equals("Editor", StringComparison.OrdinalIgnoreCase))
baseClass = " : Editor";
else
baseClass = " : EditorWindow";
body = ""; // Editor scripts have different structures
}
// Add more types as needed
}
classDeclaration = $"public class {name}{baseClass}";
string fullContent = $"{usingStatements}\n";
bool useNamespace = !string.IsNullOrEmpty(namespaceName);
if (useNamespace)
{
fullContent += $"namespace {namespaceName}\n{{\n";
// Indent class and body if using namespace
classDeclaration = " " + classDeclaration;
body = string.Join("\n", body.Split('\n').Select(line => " " + line));
}
fullContent += $"{classDeclaration}\n{{\n{body}\n}}";
if (useNamespace)
{
fullContent += "\n}"; // Close namespace
}
return fullContent.Trim() + "\n"; // Ensure a trailing newline
}
/// <summary>
/// Gets the validation level from the GUI settings
/// </summary>
private static ValidationLevel GetValidationLevelFromGUI()
{
Rename namespace and public facing plugin output from "Unity MCP" to "MCP for Unity" (#225) * refactor: rename namespace from UnityMcpBridge to MCPForUnity across all files See thread in #6, we can't use Unity MCP because it violates their trademark. That name makes us look affiliated. We can use MCP for Unity * Change package display name, menu item and menu titles These are front facing so has to change for Unity asset store review * Misc name changes in logs and comments for better consistency * chore: update editor window title from 'MCP Editor' to 'MCP for Unity' * refactor: update branding from UNITY-MCP to MCP-FOR-UNITY across all log messages and warnings * chore: rename Unity MCP to MCP For Unity across all files and bump version to 2.1.2 * docs: update restore script title to clarify Unity MCP naming * Fix usage instructions * chore: update log messages to use MCP For Unity branding instead of UnityMCP * Add a README inside plugin, required for distributing via the asset store * docs: update Unity port description and fix typo in troubleshooting section * Address Rabbit feedback * Update Editor prefs to use new name Prevents overlap with other Unity MCPs, happy to revert if it's too much * refactor: rename server logger and identifier from unity-mcp-server to mcp-for-unity-server * Standardize casing of renamed project to "MCP for Unity", as it is on the asset store * Remove unused folder * refactor: rename Unity MCP to MCP for Unity across codebase * Update dangling references * docs: update product name from UnityMCP to MCP for Unity in README * Update log and comments for new name
2025-08-21 03:59:49 +08:00
string savedLevel = EditorPrefs.GetString("MCPForUnity_ScriptValidationLevel", "standard");
return savedLevel.ToLower() switch
{
"basic" => ValidationLevel.Basic,
"standard" => ValidationLevel.Standard,
"comprehensive" => ValidationLevel.Comprehensive,
"strict" => ValidationLevel.Strict,
_ => ValidationLevel.Standard // Default fallback
};
}
/// <summary>
/// Validates C# script syntax using multiple validation layers.
2025-03-31 03:58:01 +08:00
/// </summary>
private static bool ValidateScriptSyntax(string contents)
{
return ValidateScriptSyntax(contents, ValidationLevel.Standard, out _);
}
/// <summary>
/// Advanced syntax validation with detailed diagnostics and configurable strictness.
/// </summary>
private static bool ValidateScriptSyntax(string contents, ValidationLevel level, out string[] errors)
{
var errorList = new System.Collections.Generic.List<string>();
errors = null;
if (string.IsNullOrEmpty(contents))
{
return true; // Empty content is valid
}
// Basic structural validation
if (!ValidateBasicStructure(contents, errorList))
{
errors = errorList.ToArray();
return false;
}
#if USE_ROSLYN
Claude‑friendly edit tools + framed transport + live Unity NL test framework (#243) * CI: gate desktop-parity on Anthropic key; pass anthropic_api_key like NL suite * Add quickprobe prompt and CI workflow (mcp-quickprobe.md, unity-mcp-quickprobe.yml) * strictier tool use to prevent subagent spawning and force mcp tools * update workflow filesto reduce likelihood of subagent spawning * improve permissions for claude agent, fix mcpbridge timeout/token issue * increase max turns to 10 * ci: align NL suite to new permissions schema; prevent subagent drift * ci: NL suite -> mini prompt for e2e; add full NL/T prompt; server: ctx optional + project_root fallback; workflows: set UNITY_PROJECT_ROOT for CI * ci: add checks:write; revert local project hardcodes (manifest, ProjectVersion.txt) * tools: text-edit routing fixes (anchor_insert via text, CRLF calc); prompts: mini NL/T clarifications * ci: use absolute UNITY_PROJECT_ROOT; prompts target TestProjects; server: accept relative UNITY_PROJECT_ROOT and bare spec URI * ci: ignore Unity test project's packages-lock.json; remove from repo to avoid absolute paths * CI: start persistent Unity Editor for MCP (guarded by license) + allow batch-mode bridge via UNITY_MCP_ALLOW_BATCH * CI: hide license and pass via env to docker; fix invalid ref format * CI: readiness probe uses handshake on Unity MCP port (deterministic) * CI: fix YAML; use TCP handshake readiness probe (FRAMING=1) * CI: prime Unity license via game-ci; mount ULF into container; extend readiness timeout * CI: use ULF write + mount for Unity licensing; remove serial/email/pass from container * CI: entitlement activation (UNITY_SERIAL=''); verify host ULF cache; keep mount * CI: write ULF from secret and verify; drop entitlement activation step * CI: detect any licensing path; GameCI prime; status dir env; log+probe readiness; fix YAML * CI: add GameCI license prime; conditional ULF write; one-shot license validation; explicit status dir + license env * CI: fix YAML (inline python), add Anthropic key detect via GITHUB_ENV; ready to run happy path * CI: mount Unity token/ulf/cache dirs into container to share host license; create dirs before start * CI: fix YAML indentation; write ULF on host; activate in container with shared mounts; mount .config and .cache too * CI: gate Claude via outputs; mount all Unity license dirs; fix inline probe python; stabilize licensing flow * CI: normalize detect to step outputs; ensure license dirs mounted and validated; fix indentation * Bridge: honor UNITY_MCP_STATUS_DIR for heartbeat/status file (CI-friendly) * CI: guard project path for activation/start; align tool allowlist; run MCP server with python; tighten secret scoping * CI: finalize Unity licensing mounts + status dir; mode-detect (ULF/EBL); readiness logs+probe; Claude gating via outputs * CI: fix YAML probe (inline python -c) and finalize happy-path Unity licensing and MCP/Claude wiring * CI: inline python probe; unify Unity image and cache mounts; ready to test * CI: fix docker run IMAGE placement; ignore cache find perms; keep same editor image * CI: pass -manualLicenseFile to persistent Editor; keep mounts and single image * CI: mount full GameCI cache to /root in persistent Unity; set HOME=/root; add optional license check * CI: make -manualLicenseFile conditional; keep full /root mount and license check * CI: set HOME=/github/home; mount GameCI cache there; adjust manualLicenseFile path; expand license check * CI: EBL sign-in for persistent Unity (email/password/serial); revert HOME=/root and full /root mount; keep conditional manualLicenseFile and improved readiness * CI: run full NL/T suite prompt (nl-unity-suite-full.md) instead of mini * NL/T: require unified diffs + explicit verdicts in JUnit; CI: remove short sanity step, publish JUnit, upload artifacts * NL/T prompt: require CDATA wrapping for JUnit XML fields; guidance for splitting embedded ]]>; keep VERDICT in CDATA only * CI: remove in-container license check step; keep readiness and full suite * NL/T prompt: add version header, stricter JUnit schema, hashing/normalization, anchors, statuses, atomic semantics, tool logging * CI: increase Claude NL/T suite timeout to 30 minutes * CI: pre-create reports dir and result files to avoid tool approval prompts * CI: skip wait if container not running; skip Editor start if project missing; broaden MCP deps detection; expand allowed tools * fixies to harden ManageScript * CI: sanitize NL/T markdown report to avoid NUL/encoding issues * revert breaking yyaml changes * CI: prime license, robust Unity start/wait, sanitize markdown via heredoc * Resolve merge: accept upstream renames/installer (fix/installer-cleanup-v2) and keep local framing/script-editing - Restored upstream server.py, EditorWindow, uv.lock\n- Preserved ManageScript editing/validation; switched to atomic write + debounced refresh\n- Updated tools/__init__.py to keep script_edits/resources and adopt new logger name\n- All Python tests via uv: 7 passed, 6 skipped, 9 xpassed; Unity compile OK * Fix Claude Desktop config path and atomic write issues - Fix macOS path for Claude Desktop config: use ~/Library/Application Support/Claude/ instead of ~/.config/Claude/ - Improve atomic write pattern with backup/restore safety - Replace File.Replace() with File.Move() for better macOS compatibility - Add proper error handling and cleanup for file operations - Resolves issue where installer couldn't find Claude Desktop config on macOS * Editor: use macConfigPath on macOS for MCP client config writes (Claude Desktop, etc.). Fallback to linuxConfigPath only if mac path missing. * Models: add macConfigPath to McpClient for macOS config path selection (fixes CS1061 in editor window). * Editor: on macOS, prefer macConfigPath in ManualConfigEditorWindow (fallback to linux path); Linux/Windows unchanged. * Fix McpClient: align with upstream/main, prep for framing split * NL suite: shard workflow; tighten bridge readiness; add MCP preflight; use env-based shard vars * NL suite: fix shard step indentation; move shard vars to env; remove invalid inputs * MCP clients: split VSCode Copilot config paths into macConfigPath and linuxConfigPath * Unity bridge: clean stale status; bind host; robust wait probe with IPv4/IPv6 + diagnostics * CI: use MCPForUnity.Editor.MCPForUnityBridge.StartAutoConnect as executeMethod * Action wiring: inline mcpServers in settings for all shards; remove redundant .claude/mcp.json step * CI: embed mcpServers in settings for all shards; fix startup sanity step; lint clean * CI: pin claude-code-base-action to e6f32c8; use claude_args --mcp-config; switch to allowed_tools; ensure MCP config per step * CI: unpin claude-code-base-action to @beta (commit ref not found) * CI: align with claude-code-base-action @beta; pass MCP via claude_args and allowedTools * Editor: Fix apply_text_edits heuristic when edits shift positions; recompute method span on candidate text with fallback delta adjustment * CI: unify MCP wiring across workflows; write .claude/mcp.json; switch to claude_args with --mcp-config/--allowedTools; remove unsupported inputs * CI: collapse NL suite shards into a single run to avoid repeated test execution * CI: minimize allowedTools for NL suite to essential Unity MCP + Bash("git:*") + Write * CI: mkdir -p reports before run; remove unsupported --timeout-minutes from claude_args * CI: broaden allowedTools to include find_in_file and mcp__unity__* * CI: enable use_node_cache and switch NL suite model to claude-3-7-haiku-20250219 * CI: disable use_node_cache to avoid setup-node lockfile error * CI: set NL suite model to claude-3-haiku-20240307 * CI: cap Haiku output with --max-tokens 2048 for NL suite * CI: switch to claude-3-7-sonnet-latest and remove unsupported --max-tokens * CI: update allowedTools to Bash(*) and explicit Unity MCP tool list * CI: update NL suite workflow (latest tweaks) * Tests: tighten NL suite prompt for logging, hash discipline, stale retry, evidence windows, diff cap, and VERDICT line * Add disallowed tools to NL suite workflow * docs: clarify stale write retry * Add fallback JUnit report and adjust publisher * Indent fallback JUnit XML in workflow * fix: correct fallback JUnit report generation * Update mcp-quickprobe.md Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> * Update mcp-quickprobe.md Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> * Update Response.cs Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> * Update MCPForUnityBridge.cs Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> * fix: correct McpTypes reference * Add directory existence checks for symlink and XDG paths * fix: only set installation flag after successful server install * Update resource_tools.py Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> * fix: respect mac config paths * Use File.Replace for atomic config write * Remove unused imports in manage_script * bump server version * Tests: update NL suite prompt and workflows; remove deprecated smoke/desktop-parity; quickprobe tidy * Editor: atomic config write via File.Replace fallback; remove redundant backups and racey exists checks * CI: harden NL suite - idempotent docker, gate on unity_ok, safer port probe, least-priv perms * Editor: make atomic config write restoration safe (flag writeDone; copy-overwrite restore; cleanup in finally) * CI: fix fallback JUnit heredoc by using printf lines (no EOF delimiter issues) * CI: switch NL suite to mini prompt; mini prompt honors / and NL discipline * CI: replace claude_args with allowed_tools/model/mcp_config per action schema * CI: expand UNITY_PROJECT_ROOT via in MCP config heredoc * EditorWindow: add cross-platform fallback for File.Replace; macOS-insensitive PathsEqual; safer uv resolve; honor macConfigPath * CI: strengthen JUnit publishing for NL mini suite (normalize, debug list, publish both, fail_on_parse_error) * CI: set job-wide JUNIT_OUT/MD_OUT; normalization uses env; publish references env and ungroup reports * CI: publish a single normalized JUnit (reports/junit-for-actions.xml); fallback writes same; avoid checkName/reportPaths mismatch * CI: align mini prompt report filenames; redact Unity log tail in diagnostics * chore: sync workflow and mini prompt; redacted logs; JUnit normalization/publish tweaks * CI: redact sensitive tokens in Stop Unity; docs: CI usage + edit tools * prompts: update nl-unity-suite-full (mini-style setup + reporting discipline); remove obsolete prompts * CI: harden NL workflows (timeout_minutes, robust normalization); prompts: unify JUnit suite name and reporting discipline * prompts: add guarded write pattern (LF hash, stale_file retry) to full suite * prompts: enforce continue-on-failure, driver flow, and status handling in full suite * Make test list more explicit in prompt. Get rid of old test prompts for hygeine. * prompts: add stale fast-retry (server hash) + in-memory buf guidance * CI: standardize JUNIT_OUT to reports/junit-nl-suite.xml; fix artifact upload indentation; prompt copy cleanups * prompts: reporting discipline — append-only fragments, batch writes, no model round-trip * prompts: stale fast-retry preference, buffer/sha carry, snapshot revert, essential logging * workflows(nl-suite): precreate report skeletons, assemble junit, synthesize markdown; restrict allowed_tools to append-only Bash + MCP tools * thsis too * Update README-DEV.md Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update .github/workflows/claude-nl-suite-mini.yml Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update .github/workflows/claude-nl-suite.yml Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * workflows(nl-mini): fix YAML indentation/trailing spaces under with: and cleanup heredoc spacing * workflows(nl-suite): fix indentation on docker logs redaction line (YAML lint) * Add write to allowlist * nl-suite: harden reporting discipline (fragment-only writes, forbid alt paths); workflow: clean stray junit-*updated*.xml * nl-suite: enforce end-of-suite single Write (no bash redirection); workflow: restrict allowed_tools to Write+MCP only * prompts(nl-full): end-of-suite results must be valid XML with single <cases> root and only <testcase> children; no raw text outside CDATA * workflows(nl-suite): make Claude step non-fatal; tolerant normalizer extracts <testcase> via regex on bad fragments * nl-suite: fix stale classname to UnityMCP.NL-T in mini fallback; prompt: require re-read after every revert; correct PLAN/PROGRESS to 15 * nl-suite: fix fallback JUnit classname to UnityMCP.NL-T; prompt: forbid create_script and env/mkdir checks, enforce single baseline-byte revert flow and post-revert re-read; add corruption-handling guidance * prompts(nl-full): after each write re-read raw bytes to refresh pre_sha; prefer script_apply_edits for anchors; avoid header/using changes * prompts(nl-full): canonicalize outputs to /; allow small fragment appends via Write or Bash(printf/echo); forbid wrappers and full-file round-trips * prompts(nl-full): finalize markdown formatting for guarded write, execution order, specs, status * workflows(nl-suite, mini): header/lint fixes and constrained Bash append path; align allowed_tools * prompts(nl-full): format Fast Restore, Guarded Write, Execution, Specs, Status as proper markdown lists and code fences * workflows(nl-suite): keep header tidy and append-path alignment with prompt * minor fix * workflows(nl-suite): fix indentation and dispatch; align allowed_tools and revert helper * prompts(nl-full): switch to read_resource for buf/sha; re-read only when needed; convert 'Print this once' to heading; note snapshot helper creates parent dirs * workflows(nl-suite): normalize step removes bootstrap when real testcases present; recompute tests/failures * workflows(nl-suite): enrich Markdown summary by extracting per-test <system-out> blocks (truncated) * clarify prompt resilience instructions * ci(nl-suite): revert prompt and workflow to known-good e0f8a72 for green run; remove extra MD details * ci(nl-suite): minimal fixes — no-mkdir guard in prompt; drop bootstrap and recompute JUnit counts * ci(nl-suite): richer JUnit→Markdown report (per-test system-out) * Small guard to incorret asset read call. * ci(nl-suite): refine MD builder — unescape XML entities, safe code fences, PASS/FAIL badges * Update UnityMcpBridge/UnityMcpServer~/src/tools/resource_tools.py Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update UnityMcpBridge/UnityMcpServer~/src/unity_connection.py Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update UnityMcpBridge/UnityMcpServer~/src/tools/manage_script_edits.py Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update .github/scripts/mark_skipped.py Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update .github/scripts/mark_skipped.py Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update .github/scripts/mark_skipped.py Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> * server(manage_script): robust URI handling — percent-decode file://, normalize, strip host/leading slashes, return Assets-relative if present * Update .claude/prompts/nl-unity-suite-full.md Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> * tests(framing): reduce handshake poll window, nonblocking peek to avoid disconnect race; still enforce pre-handshake data drop * tests(manage_script): add _split_uri tests for unity://path, file:// URLs (decoded/Assets-relative), and plain paths * server+tests: fix handshake syntax error; robust file:// URI normalization in manage_script; add _split_uri tests; adjust stdout scan to ignore venv/site-packages * bridge(framing): accept zero-length frames (treat as empty keepalive) * tests(logging): use errors='replace' on decode fallback to avoid silent drops * resources(list): restrict to Assets/, resolve symlinks, enforce .cs; add traversal/outside-path tests * Update .claude/prompts/nl-unity-suite-full.md Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update UnityMcpBridge/UnityMcpServer~/src/unity_connection.py Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * misc: framing keepalive (zero-length), regex preview consistency, resource.list hardening, URI parsing, legacy update routing, test cleanups * docs(tools): richer MCP tool descriptions; tests accept decorator kwargs; resource URI parsing hardened * Update .claude/prompts/nl-unity-suite-full.md Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update UnityMcpBridge/UnityMcpServer~/src/tools/resource_tools.py Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update UnityMcpBridge/UnityMcpServer~/src/unity_connection.py Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * net+docs: hard-reject zero-length frames; TCP_NODELAY on connect; Assets detection case-insensitive; NL prompt statuses aligned * prompt(nl-suite): constrain Write destinations under reports/, forbid traversal * prompt+net: harden Write path rules; use monotonic deadline and plain-text advisory for non-framed peers * unity_connection: restore recv timeout via try/finally; make global connection getter thread-safe with module lock and double-checked init * NL/T prompt: pin structured edit ops for T-D/T-E; add schema-error guarded write behavior; keep existing path/URI and revert rules * unity_connection: add FRAMED_MAX; use ValueError for framed length violations; lower framed receive log to debug; serialize connect() with per-instance lock * ManageScript: use UTF8Encoding(without BOM) for atomic writes in ApplyTextEdits/EditScript to align with Create/Update and avoid BOM-related diffs/hash mismatches * NL/T prompt: make helper deletion regex multiline-safe ((?ms) so ^ anchors line starts) * ManageScript: emit structured overlap status {status:"overlap"} for overlapping edit ranges in apply_text_edits and edit paths * NL/T prompt: clarify fallback vs failure — fallback only for unsupported/missing_field; treat bad_request as failure; note unsupported after fallback as failure * NL/T prompt: pin deterministic overlap probe (apply_text_edits two ranges from same snapshot); gate too_large behind RUN_TOO_LARGE env hint * TB update * NL/T prompt: harden Output Rules — constrain Bash(printf|echo) to stdout-only; forbid redirection/here-docs/tee; only scripts/nlt-revert.sh may mutate FS * Prompt: enumerate allowed script_apply_edits ops; add manage_editor/read_console guidance; fix T‑F atomic batch to single script_apply_edits. ManageScript: regex timeout for diagnostics; symlink ancestor guard; complete allowed-modes list. * Fixes * ManageScript: add rich overlap diagnostics (conflicts + hint) for both text range and structured batch paths * ManageScript: return structured {status:"validation_failed"} diagnostics in create/update/edits and validate before commit * ManageScript: echo canonical uri in responses (create/read/update/apply_text_edits/structured edits) to reinforce resource identity * improve clarity of capabilities message * Framing: allow zero-length frames on both ends (C# bridge, Python server). Prompt: harden T-F to single text-range apply_text_edits batch (descending order, one snapshot). URI: normalize file:// outside Assets by stripping leading slash. * ManageScript: include new sha256 in success payload for apply_text_edits; harden TryResolveUnderAssets by rejecting symlinked ancestors up to Assets/. * remove claudetest dir * manage_script_edits: normalize method-anchored anchor_insert to insert_method (map text->replacement); improves CI compatibility for T‑A/T‑E without changing Editor behavior. * tighten testing protocol around mkdir * manage_script: validate create_script inputs (Assets/.cs/name/no traversal); add Assets/ guard to delete_script; validate level+Assets in validate_script; make legacy manage_script optional params; harden legacy update routing with base64 reuse and payload size preflight. * Tighten prompt for testing * Update .claude/prompts/nl-unity-suite-full.md Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update .claude/prompts/nl-unity-suite-full.md Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update UnityMcpBridge/Editor/Tools/ManageScript.cs Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * manage_script_edits: honor ignore_case on anchor_insert and regex_replace in both direct and text-conversion paths (MULTILINE|IGNORECASE). * remove extra file * workflow: use python3 for inline scripts and port detection on ubuntu-latest. * Tighten prompt + manage_script * Update UnityMcpBridge/UnityMcpServer~/src/tools/manage_script_edits.py Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update UnityMcpBridge/UnityMcpServer~/src/tools/manage_script_edits.py Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update .claude/prompts/nl-unity-suite-full.md Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update UnityMcpBridge/Editor/Tools/ManageScript.cs Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update .claude/prompts/nl-unity-suite-full.md Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * manage_script: improve file:// UNC handling; preserve POSIX absolute semantics internally; keep test-expected slash stripping for non-Assets paths. * ManageScript.cs: add TimeSpan timeouts to all Regex uses (IsMatch/Match/new Regex) and keep CultureInvariant/Multiline options; reduces risk of catastrophic backtracking stalls. * workflow: ensure reports/ exists in markdown build step to avoid FileNotFoundError when writing MD_OUT. * fix brace * manage_script_edits: expand backrefs for regex_replace in preview->text conversion and translate to \g<n> in local apply; keeps previews and actual edits consistent. * anchor_insert: default to position=after, normalize surrounding newlines in Python conversion paths; C# path ensures trailing newline and skips duplicate insertion within class. * feat(mcp): add get_sha tool; apply_text_edits normalization+overlap preflight+strict; no-op evidence in C#; update NL suite prompt; add unit tests * feat(frames): accept zero-length heartbeat frames in client; add heartbeat test * feat(edits): guard destructive regex_replace with structural preflight; add robust tests; prompt uses delete_method for temp helper * feat(frames): bound heartbeat loop with timeout/threshold; align zero-length response with C#; update test * SDK hardening: atomic multi-span text edits; stop forcing sequential for structured ops; forward options on apply_text_edits; add validate=relaxed support and scoped checks; update NL/T prompt; add tests for options forwarding, relaxed mode, and atomic batches * Router: default applyMode=atomic for multi-span apply_text_edits; add tests * CI prompt: pass options.validate=relaxed for T-B/C; options.applyMode=atomic for T-F; emphasize always writing testcase and restoring on errors * Validation & DX: add validate=syntax (scoped), standardize evidence windows; early regex compile with hints; debug_preview for apply_text_edits * Update UnityMcpBridge/Editor/Windows/MCPForUnityEditorWindow.cs Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * NL/T suite-driven edits: LongUnityScriptClaudeTest, bridge helpers, server_version; prepare framing tests * Fix duplicate macConfigPath field in McpClient to resolve CS0102 * Editor threading: run EnsureServerInstalled on main thread; marshal EditorPrefs/DeleteKey + logging via delayCall * Docs(apply_text_edits): strengthen guidance on 1-based positions, verify-before-edit, and recommend anchors/structured edits * Docs(script_apply_edits): add safety guidance (anchors, method ops, validators) and recommended practices * Framed VerifyBridgePing in editor window; docs hardening for apply_text_edits and script_apply_edits --------- Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
2025-08-31 00:55:38 +08:00
// Advanced Roslyn-based validation: only run for Standard+; fail on Roslyn errors
if (level >= ValidationLevel.Standard)
{
Claude‑friendly edit tools + framed transport + live Unity NL test framework (#243) * CI: gate desktop-parity on Anthropic key; pass anthropic_api_key like NL suite * Add quickprobe prompt and CI workflow (mcp-quickprobe.md, unity-mcp-quickprobe.yml) * strictier tool use to prevent subagent spawning and force mcp tools * update workflow filesto reduce likelihood of subagent spawning * improve permissions for claude agent, fix mcpbridge timeout/token issue * increase max turns to 10 * ci: align NL suite to new permissions schema; prevent subagent drift * ci: NL suite -> mini prompt for e2e; add full NL/T prompt; server: ctx optional + project_root fallback; workflows: set UNITY_PROJECT_ROOT for CI * ci: add checks:write; revert local project hardcodes (manifest, ProjectVersion.txt) * tools: text-edit routing fixes (anchor_insert via text, CRLF calc); prompts: mini NL/T clarifications * ci: use absolute UNITY_PROJECT_ROOT; prompts target TestProjects; server: accept relative UNITY_PROJECT_ROOT and bare spec URI * ci: ignore Unity test project's packages-lock.json; remove from repo to avoid absolute paths * CI: start persistent Unity Editor for MCP (guarded by license) + allow batch-mode bridge via UNITY_MCP_ALLOW_BATCH * CI: hide license and pass via env to docker; fix invalid ref format * CI: readiness probe uses handshake on Unity MCP port (deterministic) * CI: fix YAML; use TCP handshake readiness probe (FRAMING=1) * CI: prime Unity license via game-ci; mount ULF into container; extend readiness timeout * CI: use ULF write + mount for Unity licensing; remove serial/email/pass from container * CI: entitlement activation (UNITY_SERIAL=''); verify host ULF cache; keep mount * CI: write ULF from secret and verify; drop entitlement activation step * CI: detect any licensing path; GameCI prime; status dir env; log+probe readiness; fix YAML * CI: add GameCI license prime; conditional ULF write; one-shot license validation; explicit status dir + license env * CI: fix YAML (inline python), add Anthropic key detect via GITHUB_ENV; ready to run happy path * CI: mount Unity token/ulf/cache dirs into container to share host license; create dirs before start * CI: fix YAML indentation; write ULF on host; activate in container with shared mounts; mount .config and .cache too * CI: gate Claude via outputs; mount all Unity license dirs; fix inline probe python; stabilize licensing flow * CI: normalize detect to step outputs; ensure license dirs mounted and validated; fix indentation * Bridge: honor UNITY_MCP_STATUS_DIR for heartbeat/status file (CI-friendly) * CI: guard project path for activation/start; align tool allowlist; run MCP server with python; tighten secret scoping * CI: finalize Unity licensing mounts + status dir; mode-detect (ULF/EBL); readiness logs+probe; Claude gating via outputs * CI: fix YAML probe (inline python -c) and finalize happy-path Unity licensing and MCP/Claude wiring * CI: inline python probe; unify Unity image and cache mounts; ready to test * CI: fix docker run IMAGE placement; ignore cache find perms; keep same editor image * CI: pass -manualLicenseFile to persistent Editor; keep mounts and single image * CI: mount full GameCI cache to /root in persistent Unity; set HOME=/root; add optional license check * CI: make -manualLicenseFile conditional; keep full /root mount and license check * CI: set HOME=/github/home; mount GameCI cache there; adjust manualLicenseFile path; expand license check * CI: EBL sign-in for persistent Unity (email/password/serial); revert HOME=/root and full /root mount; keep conditional manualLicenseFile and improved readiness * CI: run full NL/T suite prompt (nl-unity-suite-full.md) instead of mini * NL/T: require unified diffs + explicit verdicts in JUnit; CI: remove short sanity step, publish JUnit, upload artifacts * NL/T prompt: require CDATA wrapping for JUnit XML fields; guidance for splitting embedded ]]>; keep VERDICT in CDATA only * CI: remove in-container license check step; keep readiness and full suite * NL/T prompt: add version header, stricter JUnit schema, hashing/normalization, anchors, statuses, atomic semantics, tool logging * CI: increase Claude NL/T suite timeout to 30 minutes * CI: pre-create reports dir and result files to avoid tool approval prompts * CI: skip wait if container not running; skip Editor start if project missing; broaden MCP deps detection; expand allowed tools * fixies to harden ManageScript * CI: sanitize NL/T markdown report to avoid NUL/encoding issues * revert breaking yyaml changes * CI: prime license, robust Unity start/wait, sanitize markdown via heredoc * Resolve merge: accept upstream renames/installer (fix/installer-cleanup-v2) and keep local framing/script-editing - Restored upstream server.py, EditorWindow, uv.lock\n- Preserved ManageScript editing/validation; switched to atomic write + debounced refresh\n- Updated tools/__init__.py to keep script_edits/resources and adopt new logger name\n- All Python tests via uv: 7 passed, 6 skipped, 9 xpassed; Unity compile OK * Fix Claude Desktop config path and atomic write issues - Fix macOS path for Claude Desktop config: use ~/Library/Application Support/Claude/ instead of ~/.config/Claude/ - Improve atomic write pattern with backup/restore safety - Replace File.Replace() with File.Move() for better macOS compatibility - Add proper error handling and cleanup for file operations - Resolves issue where installer couldn't find Claude Desktop config on macOS * Editor: use macConfigPath on macOS for MCP client config writes (Claude Desktop, etc.). Fallback to linuxConfigPath only if mac path missing. * Models: add macConfigPath to McpClient for macOS config path selection (fixes CS1061 in editor window). * Editor: on macOS, prefer macConfigPath in ManualConfigEditorWindow (fallback to linux path); Linux/Windows unchanged. * Fix McpClient: align with upstream/main, prep for framing split * NL suite: shard workflow; tighten bridge readiness; add MCP preflight; use env-based shard vars * NL suite: fix shard step indentation; move shard vars to env; remove invalid inputs * MCP clients: split VSCode Copilot config paths into macConfigPath and linuxConfigPath * Unity bridge: clean stale status; bind host; robust wait probe with IPv4/IPv6 + diagnostics * CI: use MCPForUnity.Editor.MCPForUnityBridge.StartAutoConnect as executeMethod * Action wiring: inline mcpServers in settings for all shards; remove redundant .claude/mcp.json step * CI: embed mcpServers in settings for all shards; fix startup sanity step; lint clean * CI: pin claude-code-base-action to e6f32c8; use claude_args --mcp-config; switch to allowed_tools; ensure MCP config per step * CI: unpin claude-code-base-action to @beta (commit ref not found) * CI: align with claude-code-base-action @beta; pass MCP via claude_args and allowedTools * Editor: Fix apply_text_edits heuristic when edits shift positions; recompute method span on candidate text with fallback delta adjustment * CI: unify MCP wiring across workflows; write .claude/mcp.json; switch to claude_args with --mcp-config/--allowedTools; remove unsupported inputs * CI: collapse NL suite shards into a single run to avoid repeated test execution * CI: minimize allowedTools for NL suite to essential Unity MCP + Bash("git:*") + Write * CI: mkdir -p reports before run; remove unsupported --timeout-minutes from claude_args * CI: broaden allowedTools to include find_in_file and mcp__unity__* * CI: enable use_node_cache and switch NL suite model to claude-3-7-haiku-20250219 * CI: disable use_node_cache to avoid setup-node lockfile error * CI: set NL suite model to claude-3-haiku-20240307 * CI: cap Haiku output with --max-tokens 2048 for NL suite * CI: switch to claude-3-7-sonnet-latest and remove unsupported --max-tokens * CI: update allowedTools to Bash(*) and explicit Unity MCP tool list * CI: update NL suite workflow (latest tweaks) * Tests: tighten NL suite prompt for logging, hash discipline, stale retry, evidence windows, diff cap, and VERDICT line * Add disallowed tools to NL suite workflow * docs: clarify stale write retry * Add fallback JUnit report and adjust publisher * Indent fallback JUnit XML in workflow * fix: correct fallback JUnit report generation * Update mcp-quickprobe.md Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> * Update mcp-quickprobe.md Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> * Update Response.cs Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> * Update MCPForUnityBridge.cs Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> * fix: correct McpTypes reference * Add directory existence checks for symlink and XDG paths * fix: only set installation flag after successful server install * Update resource_tools.py Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> * fix: respect mac config paths * Use File.Replace for atomic config write * Remove unused imports in manage_script * bump server version * Tests: update NL suite prompt and workflows; remove deprecated smoke/desktop-parity; quickprobe tidy * Editor: atomic config write via File.Replace fallback; remove redundant backups and racey exists checks * CI: harden NL suite - idempotent docker, gate on unity_ok, safer port probe, least-priv perms * Editor: make atomic config write restoration safe (flag writeDone; copy-overwrite restore; cleanup in finally) * CI: fix fallback JUnit heredoc by using printf lines (no EOF delimiter issues) * CI: switch NL suite to mini prompt; mini prompt honors / and NL discipline * CI: replace claude_args with allowed_tools/model/mcp_config per action schema * CI: expand UNITY_PROJECT_ROOT via in MCP config heredoc * EditorWindow: add cross-platform fallback for File.Replace; macOS-insensitive PathsEqual; safer uv resolve; honor macConfigPath * CI: strengthen JUnit publishing for NL mini suite (normalize, debug list, publish both, fail_on_parse_error) * CI: set job-wide JUNIT_OUT/MD_OUT; normalization uses env; publish references env and ungroup reports * CI: publish a single normalized JUnit (reports/junit-for-actions.xml); fallback writes same; avoid checkName/reportPaths mismatch * CI: align mini prompt report filenames; redact Unity log tail in diagnostics * chore: sync workflow and mini prompt; redacted logs; JUnit normalization/publish tweaks * CI: redact sensitive tokens in Stop Unity; docs: CI usage + edit tools * prompts: update nl-unity-suite-full (mini-style setup + reporting discipline); remove obsolete prompts * CI: harden NL workflows (timeout_minutes, robust normalization); prompts: unify JUnit suite name and reporting discipline * prompts: add guarded write pattern (LF hash, stale_file retry) to full suite * prompts: enforce continue-on-failure, driver flow, and status handling in full suite * Make test list more explicit in prompt. Get rid of old test prompts for hygeine. * prompts: add stale fast-retry (server hash) + in-memory buf guidance * CI: standardize JUNIT_OUT to reports/junit-nl-suite.xml; fix artifact upload indentation; prompt copy cleanups * prompts: reporting discipline — append-only fragments, batch writes, no model round-trip * prompts: stale fast-retry preference, buffer/sha carry, snapshot revert, essential logging * workflows(nl-suite): precreate report skeletons, assemble junit, synthesize markdown; restrict allowed_tools to append-only Bash + MCP tools * thsis too * Update README-DEV.md Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update .github/workflows/claude-nl-suite-mini.yml Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update .github/workflows/claude-nl-suite.yml Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * workflows(nl-mini): fix YAML indentation/trailing spaces under with: and cleanup heredoc spacing * workflows(nl-suite): fix indentation on docker logs redaction line (YAML lint) * Add write to allowlist * nl-suite: harden reporting discipline (fragment-only writes, forbid alt paths); workflow: clean stray junit-*updated*.xml * nl-suite: enforce end-of-suite single Write (no bash redirection); workflow: restrict allowed_tools to Write+MCP only * prompts(nl-full): end-of-suite results must be valid XML with single <cases> root and only <testcase> children; no raw text outside CDATA * workflows(nl-suite): make Claude step non-fatal; tolerant normalizer extracts <testcase> via regex on bad fragments * nl-suite: fix stale classname to UnityMCP.NL-T in mini fallback; prompt: require re-read after every revert; correct PLAN/PROGRESS to 15 * nl-suite: fix fallback JUnit classname to UnityMCP.NL-T; prompt: forbid create_script and env/mkdir checks, enforce single baseline-byte revert flow and post-revert re-read; add corruption-handling guidance * prompts(nl-full): after each write re-read raw bytes to refresh pre_sha; prefer script_apply_edits for anchors; avoid header/using changes * prompts(nl-full): canonicalize outputs to /; allow small fragment appends via Write or Bash(printf/echo); forbid wrappers and full-file round-trips * prompts(nl-full): finalize markdown formatting for guarded write, execution order, specs, status * workflows(nl-suite, mini): header/lint fixes and constrained Bash append path; align allowed_tools * prompts(nl-full): format Fast Restore, Guarded Write, Execution, Specs, Status as proper markdown lists and code fences * workflows(nl-suite): keep header tidy and append-path alignment with prompt * minor fix * workflows(nl-suite): fix indentation and dispatch; align allowed_tools and revert helper * prompts(nl-full): switch to read_resource for buf/sha; re-read only when needed; convert 'Print this once' to heading; note snapshot helper creates parent dirs * workflows(nl-suite): normalize step removes bootstrap when real testcases present; recompute tests/failures * workflows(nl-suite): enrich Markdown summary by extracting per-test <system-out> blocks (truncated) * clarify prompt resilience instructions * ci(nl-suite): revert prompt and workflow to known-good e0f8a72 for green run; remove extra MD details * ci(nl-suite): minimal fixes — no-mkdir guard in prompt; drop bootstrap and recompute JUnit counts * ci(nl-suite): richer JUnit→Markdown report (per-test system-out) * Small guard to incorret asset read call. * ci(nl-suite): refine MD builder — unescape XML entities, safe code fences, PASS/FAIL badges * Update UnityMcpBridge/UnityMcpServer~/src/tools/resource_tools.py Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update UnityMcpBridge/UnityMcpServer~/src/unity_connection.py Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update UnityMcpBridge/UnityMcpServer~/src/tools/manage_script_edits.py Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update .github/scripts/mark_skipped.py Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update .github/scripts/mark_skipped.py Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update .github/scripts/mark_skipped.py Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> * server(manage_script): robust URI handling — percent-decode file://, normalize, strip host/leading slashes, return Assets-relative if present * Update .claude/prompts/nl-unity-suite-full.md Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> * tests(framing): reduce handshake poll window, nonblocking peek to avoid disconnect race; still enforce pre-handshake data drop * tests(manage_script): add _split_uri tests for unity://path, file:// URLs (decoded/Assets-relative), and plain paths * server+tests: fix handshake syntax error; robust file:// URI normalization in manage_script; add _split_uri tests; adjust stdout scan to ignore venv/site-packages * bridge(framing): accept zero-length frames (treat as empty keepalive) * tests(logging): use errors='replace' on decode fallback to avoid silent drops * resources(list): restrict to Assets/, resolve symlinks, enforce .cs; add traversal/outside-path tests * Update .claude/prompts/nl-unity-suite-full.md Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update UnityMcpBridge/UnityMcpServer~/src/unity_connection.py Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * misc: framing keepalive (zero-length), regex preview consistency, resource.list hardening, URI parsing, legacy update routing, test cleanups * docs(tools): richer MCP tool descriptions; tests accept decorator kwargs; resource URI parsing hardened * Update .claude/prompts/nl-unity-suite-full.md Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update UnityMcpBridge/UnityMcpServer~/src/tools/resource_tools.py Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update UnityMcpBridge/UnityMcpServer~/src/unity_connection.py Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * net+docs: hard-reject zero-length frames; TCP_NODELAY on connect; Assets detection case-insensitive; NL prompt statuses aligned * prompt(nl-suite): constrain Write destinations under reports/, forbid traversal * prompt+net: harden Write path rules; use monotonic deadline and plain-text advisory for non-framed peers * unity_connection: restore recv timeout via try/finally; make global connection getter thread-safe with module lock and double-checked init * NL/T prompt: pin structured edit ops for T-D/T-E; add schema-error guarded write behavior; keep existing path/URI and revert rules * unity_connection: add FRAMED_MAX; use ValueError for framed length violations; lower framed receive log to debug; serialize connect() with per-instance lock * ManageScript: use UTF8Encoding(without BOM) for atomic writes in ApplyTextEdits/EditScript to align with Create/Update and avoid BOM-related diffs/hash mismatches * NL/T prompt: make helper deletion regex multiline-safe ((?ms) so ^ anchors line starts) * ManageScript: emit structured overlap status {status:"overlap"} for overlapping edit ranges in apply_text_edits and edit paths * NL/T prompt: clarify fallback vs failure — fallback only for unsupported/missing_field; treat bad_request as failure; note unsupported after fallback as failure * NL/T prompt: pin deterministic overlap probe (apply_text_edits two ranges from same snapshot); gate too_large behind RUN_TOO_LARGE env hint * TB update * NL/T prompt: harden Output Rules — constrain Bash(printf|echo) to stdout-only; forbid redirection/here-docs/tee; only scripts/nlt-revert.sh may mutate FS * Prompt: enumerate allowed script_apply_edits ops; add manage_editor/read_console guidance; fix T‑F atomic batch to single script_apply_edits. ManageScript: regex timeout for diagnostics; symlink ancestor guard; complete allowed-modes list. * Fixes * ManageScript: add rich overlap diagnostics (conflicts + hint) for both text range and structured batch paths * ManageScript: return structured {status:"validation_failed"} diagnostics in create/update/edits and validate before commit * ManageScript: echo canonical uri in responses (create/read/update/apply_text_edits/structured edits) to reinforce resource identity * improve clarity of capabilities message * Framing: allow zero-length frames on both ends (C# bridge, Python server). Prompt: harden T-F to single text-range apply_text_edits batch (descending order, one snapshot). URI: normalize file:// outside Assets by stripping leading slash. * ManageScript: include new sha256 in success payload for apply_text_edits; harden TryResolveUnderAssets by rejecting symlinked ancestors up to Assets/. * remove claudetest dir * manage_script_edits: normalize method-anchored anchor_insert to insert_method (map text->replacement); improves CI compatibility for T‑A/T‑E without changing Editor behavior. * tighten testing protocol around mkdir * manage_script: validate create_script inputs (Assets/.cs/name/no traversal); add Assets/ guard to delete_script; validate level+Assets in validate_script; make legacy manage_script optional params; harden legacy update routing with base64 reuse and payload size preflight. * Tighten prompt for testing * Update .claude/prompts/nl-unity-suite-full.md Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update .claude/prompts/nl-unity-suite-full.md Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update UnityMcpBridge/Editor/Tools/ManageScript.cs Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * manage_script_edits: honor ignore_case on anchor_insert and regex_replace in both direct and text-conversion paths (MULTILINE|IGNORECASE). * remove extra file * workflow: use python3 for inline scripts and port detection on ubuntu-latest. * Tighten prompt + manage_script * Update UnityMcpBridge/UnityMcpServer~/src/tools/manage_script_edits.py Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update UnityMcpBridge/UnityMcpServer~/src/tools/manage_script_edits.py Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update .claude/prompts/nl-unity-suite-full.md Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update UnityMcpBridge/Editor/Tools/ManageScript.cs Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update .claude/prompts/nl-unity-suite-full.md Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * manage_script: improve file:// UNC handling; preserve POSIX absolute semantics internally; keep test-expected slash stripping for non-Assets paths. * ManageScript.cs: add TimeSpan timeouts to all Regex uses (IsMatch/Match/new Regex) and keep CultureInvariant/Multiline options; reduces risk of catastrophic backtracking stalls. * workflow: ensure reports/ exists in markdown build step to avoid FileNotFoundError when writing MD_OUT. * fix brace * manage_script_edits: expand backrefs for regex_replace in preview->text conversion and translate to \g<n> in local apply; keeps previews and actual edits consistent. * anchor_insert: default to position=after, normalize surrounding newlines in Python conversion paths; C# path ensures trailing newline and skips duplicate insertion within class. * feat(mcp): add get_sha tool; apply_text_edits normalization+overlap preflight+strict; no-op evidence in C#; update NL suite prompt; add unit tests * feat(frames): accept zero-length heartbeat frames in client; add heartbeat test * feat(edits): guard destructive regex_replace with structural preflight; add robust tests; prompt uses delete_method for temp helper * feat(frames): bound heartbeat loop with timeout/threshold; align zero-length response with C#; update test * SDK hardening: atomic multi-span text edits; stop forcing sequential for structured ops; forward options on apply_text_edits; add validate=relaxed support and scoped checks; update NL/T prompt; add tests for options forwarding, relaxed mode, and atomic batches * Router: default applyMode=atomic for multi-span apply_text_edits; add tests * CI prompt: pass options.validate=relaxed for T-B/C; options.applyMode=atomic for T-F; emphasize always writing testcase and restoring on errors * Validation & DX: add validate=syntax (scoped), standardize evidence windows; early regex compile with hints; debug_preview for apply_text_edits * Update UnityMcpBridge/Editor/Windows/MCPForUnityEditorWindow.cs Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * NL/T suite-driven edits: LongUnityScriptClaudeTest, bridge helpers, server_version; prepare framing tests * Fix duplicate macConfigPath field in McpClient to resolve CS0102 * Editor threading: run EnsureServerInstalled on main thread; marshal EditorPrefs/DeleteKey + logging via delayCall * Docs(apply_text_edits): strengthen guidance on 1-based positions, verify-before-edit, and recommend anchors/structured edits * Docs(script_apply_edits): add safety guidance (anchors, method ops, validators) and recommended practices * Framed VerifyBridgePing in editor window; docs hardening for apply_text_edits and script_apply_edits --------- Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
2025-08-31 00:55:38 +08:00
if (!ValidateScriptSyntaxRoslyn(contents, level, errorList))
{
errors = errorList.ToArray();
return false;
}
}
#endif
// Unity-specific validation
if (level >= ValidationLevel.Standard)
{
ValidateScriptSyntaxUnity(contents, errorList);
}
// Semantic analysis for common issues
if (level >= ValidationLevel.Comprehensive)
{
ValidateSemanticRules(contents, errorList);
}
2025-03-31 03:58:01 +08:00
#if USE_ROSLYN
// Full semantic compilation validation for Strict level
if (level == ValidationLevel.Strict)
{
if (!ValidateScriptSemantics(contents, errorList))
{
errors = errorList.ToArray();
return false; // Strict level fails on any semantic errors
}
}
#endif
errors = errorList.ToArray();
return errorList.Count == 0 || (level != ValidationLevel.Strict && !errorList.Any(e => e.StartsWith("ERROR:")));
}
/// <summary>
/// Validation strictness levels
/// </summary>
private enum ValidationLevel
{
Basic, // Only syntax errors
Standard, // Syntax + Unity best practices
Comprehensive, // All checks + semantic analysis
Strict // Treat all issues as errors
}
/// <summary>
/// Validates basic code structure (braces, quotes, comments)
/// </summary>
private static bool ValidateBasicStructure(string contents, System.Collections.Generic.List<string> errors)
{
bool isValid = true;
2025-03-31 03:58:01 +08:00
int braceBalance = 0;
int parenBalance = 0;
int bracketBalance = 0;
bool inStringLiteral = false;
bool inCharLiteral = false;
bool inSingleLineComment = false;
bool inMultiLineComment = false;
bool escaped = false;
for (int i = 0; i < contents.Length; i++)
{
char c = contents[i];
char next = i + 1 < contents.Length ? contents[i + 1] : '\0';
// Handle escape sequences
if (escaped)
{
escaped = false;
continue;
}
if (c == '\\' && (inStringLiteral || inCharLiteral))
{
escaped = true;
continue;
}
// Handle comments
if (!inStringLiteral && !inCharLiteral)
{
if (c == '/' && next == '/' && !inMultiLineComment)
{
inSingleLineComment = true;
continue;
}
if (c == '/' && next == '*' && !inSingleLineComment)
{
inMultiLineComment = true;
i++; // Skip next character
continue;
}
if (c == '*' && next == '/' && inMultiLineComment)
{
inMultiLineComment = false;
i++; // Skip next character
continue;
}
}
if (c == '\n')
{
inSingleLineComment = false;
continue;
}
if (inSingleLineComment || inMultiLineComment)
continue;
// Handle string and character literals
if (c == '"' && !inCharLiteral)
{
inStringLiteral = !inStringLiteral;
continue;
}
if (c == '\'' && !inStringLiteral)
{
inCharLiteral = !inCharLiteral;
continue;
}
if (inStringLiteral || inCharLiteral)
continue;
// Count brackets and braces
switch (c)
{
case '{': braceBalance++; break;
case '}': braceBalance--; break;
case '(': parenBalance++; break;
case ')': parenBalance--; break;
case '[': bracketBalance++; break;
case ']': bracketBalance--; break;
}
// Check for negative balances (closing without opening)
if (braceBalance < 0)
{
errors.Add("ERROR: Unmatched closing brace '}'");
isValid = false;
}
if (parenBalance < 0)
{
errors.Add("ERROR: Unmatched closing parenthesis ')'");
isValid = false;
}
if (bracketBalance < 0)
{
errors.Add("ERROR: Unmatched closing bracket ']'");
isValid = false;
}
}
// Check final balances
if (braceBalance != 0)
{
errors.Add($"ERROR: Unbalanced braces (difference: {braceBalance})");
isValid = false;
}
if (parenBalance != 0)
{
errors.Add($"ERROR: Unbalanced parentheses (difference: {parenBalance})");
isValid = false;
}
if (bracketBalance != 0)
{
errors.Add($"ERROR: Unbalanced brackets (difference: {bracketBalance})");
isValid = false;
}
if (inStringLiteral)
2025-03-31 03:58:01 +08:00
{
errors.Add("ERROR: Unterminated string literal");
isValid = false;
}
if (inCharLiteral)
{
errors.Add("ERROR: Unterminated character literal");
isValid = false;
}
if (inMultiLineComment)
{
errors.Add("WARNING: Unterminated multi-line comment");
2025-03-31 03:58:01 +08:00
}
return isValid;
2025-03-31 03:58:01 +08:00
}
#if USE_ROSLYN
/// <summary>
/// Cached compilation references for performance
/// </summary>
private static System.Collections.Generic.List<MetadataReference> _cachedReferences = null;
private static DateTime _cacheTime = DateTime.MinValue;
private static readonly TimeSpan CacheExpiry = TimeSpan.FromMinutes(5);
/// <summary>
/// Validates syntax using Roslyn compiler services
/// </summary>
private static bool ValidateScriptSyntaxRoslyn(string contents, ValidationLevel level, System.Collections.Generic.List<string> errors)
{
try
{
var syntaxTree = CSharpSyntaxTree.ParseText(contents);
var diagnostics = syntaxTree.GetDiagnostics();
bool hasErrors = false;
foreach (var diagnostic in diagnostics)
{
string severity = diagnostic.Severity.ToString().ToUpper();
string message = $"{severity}: {diagnostic.GetMessage()}";
if (diagnostic.Severity == DiagnosticSeverity.Error)
{
hasErrors = true;
}
// Include warnings in comprehensive mode
if (level >= ValidationLevel.Standard || diagnostic.Severity == DiagnosticSeverity.Error) //Also use Standard for now
{
var location = diagnostic.Location.GetLineSpan();
if (location.IsValid)
{
message += $" (Line {location.StartLinePosition.Line + 1})";
}
errors.Add(message);
}
}
return !hasErrors;
}
catch (Exception ex)
{
errors.Add($"ERROR: Roslyn validation failed: {ex.Message}");
return false;
}
}
/// <summary>
/// Validates script semantics using full compilation context to catch namespace, type, and method resolution errors
/// </summary>
private static bool ValidateScriptSemantics(string contents, System.Collections.Generic.List<string> errors)
{
try
{
// Get compilation references with caching
var references = GetCompilationReferences();
if (references == null || references.Count == 0)
{
errors.Add("WARNING: Could not load compilation references for semantic validation");
return true; // Don't fail if we can't get references
}
// Create syntax tree
var syntaxTree = CSharpSyntaxTree.ParseText(contents);
// Create compilation with full context
var compilation = CSharpCompilation.Create(
"TempValidation",
new[] { syntaxTree },
references,
new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary)
);
// Get semantic diagnostics - this catches all the issues you mentioned!
var diagnostics = compilation.GetDiagnostics();
bool hasErrors = false;
foreach (var diagnostic in diagnostics)
{
if (diagnostic.Severity == DiagnosticSeverity.Error)
{
hasErrors = true;
var location = diagnostic.Location.GetLineSpan();
string locationInfo = location.IsValid ?
$" (Line {location.StartLinePosition.Line + 1}, Column {location.StartLinePosition.Character + 1})" : "";
// Include diagnostic ID for better error identification
string diagnosticId = !string.IsNullOrEmpty(diagnostic.Id) ? $" [{diagnostic.Id}]" : "";
errors.Add($"ERROR: {diagnostic.GetMessage()}{diagnosticId}{locationInfo}");
}
else if (diagnostic.Severity == DiagnosticSeverity.Warning)
{
var location = diagnostic.Location.GetLineSpan();
string locationInfo = location.IsValid ?
$" (Line {location.StartLinePosition.Line + 1}, Column {location.StartLinePosition.Character + 1})" : "";
string diagnosticId = !string.IsNullOrEmpty(diagnostic.Id) ? $" [{diagnostic.Id}]" : "";
errors.Add($"WARNING: {diagnostic.GetMessage()}{diagnosticId}{locationInfo}");
}
}
return !hasErrors;
}
catch (Exception ex)
{
errors.Add($"ERROR: Semantic validation failed: {ex.Message}");
return false;
}
}
/// <summary>
/// Gets compilation references with caching for performance
/// </summary>
private static System.Collections.Generic.List<MetadataReference> GetCompilationReferences()
{
// Check cache validity
if (_cachedReferences != null && DateTime.Now - _cacheTime < CacheExpiry)
{
return _cachedReferences;
}
try
{
var references = new System.Collections.Generic.List<MetadataReference>();
// Core .NET assemblies
references.Add(MetadataReference.CreateFromFile(typeof(object).Assembly.Location)); // mscorlib/System.Private.CoreLib
references.Add(MetadataReference.CreateFromFile(typeof(System.Linq.Enumerable).Assembly.Location)); // System.Linq
references.Add(MetadataReference.CreateFromFile(typeof(System.Collections.Generic.List<>).Assembly.Location)); // System.Collections
// Unity assemblies
try
{
references.Add(MetadataReference.CreateFromFile(typeof(UnityEngine.Debug).Assembly.Location)); // UnityEngine
}
catch (Exception ex)
{
Debug.LogWarning($"Could not load UnityEngine assembly: {ex.Message}");
}
#if UNITY_EDITOR
try
{
references.Add(MetadataReference.CreateFromFile(typeof(UnityEditor.Editor).Assembly.Location)); // UnityEditor
}
catch (Exception ex)
{
Debug.LogWarning($"Could not load UnityEditor assembly: {ex.Message}");
}
// Get Unity project assemblies
try
{
var assemblies = CompilationPipeline.GetAssemblies();
foreach (var assembly in assemblies)
{
if (File.Exists(assembly.outputPath))
{
references.Add(MetadataReference.CreateFromFile(assembly.outputPath));
}
}
}
catch (Exception ex)
{
Debug.LogWarning($"Could not load Unity project assemblies: {ex.Message}");
}
#endif
// Cache the results
_cachedReferences = references;
_cacheTime = DateTime.Now;
return references;
}
catch (Exception ex)
{
Debug.LogError($"Failed to get compilation references: {ex.Message}");
return new System.Collections.Generic.List<MetadataReference>();
}
}
#else
private static bool ValidateScriptSyntaxRoslyn(string contents, ValidationLevel level, System.Collections.Generic.List<string> errors)
{
// Fallback when Roslyn is not available
return true;
}
#endif
/// <summary>
/// Validates Unity-specific coding rules and best practices
/// //TODO: Naive Unity Checks and not really yield any results, need to be improved
/// </summary>
private static void ValidateScriptSyntaxUnity(string contents, System.Collections.Generic.List<string> errors)
{
// Check for common Unity anti-patterns
if (contents.Contains("FindObjectOfType") && contents.Contains("Update()"))
{
errors.Add("WARNING: FindObjectOfType in Update() can cause performance issues");
}
if (contents.Contains("GameObject.Find") && contents.Contains("Update()"))
{
errors.Add("WARNING: GameObject.Find in Update() can cause performance issues");
}
// Check for proper MonoBehaviour usage
if (contents.Contains(": MonoBehaviour") && !contents.Contains("using UnityEngine"))
{
errors.Add("WARNING: MonoBehaviour requires 'using UnityEngine;'");
}
// Check for SerializeField usage
if (contents.Contains("[SerializeField]") && !contents.Contains("using UnityEngine"))
{
errors.Add("WARNING: SerializeField requires 'using UnityEngine;'");
}
// Check for proper coroutine usage
if (contents.Contains("StartCoroutine") && !contents.Contains("IEnumerator"))
{
errors.Add("WARNING: StartCoroutine typically requires IEnumerator methods");
}
// Check for Update without FixedUpdate for physics
if (contents.Contains("Rigidbody") && contents.Contains("Update()") && !contents.Contains("FixedUpdate()"))
{
errors.Add("WARNING: Consider using FixedUpdate() for Rigidbody operations");
}
// Check for missing null checks on Unity objects
if (contents.Contains("GetComponent<") && !contents.Contains("!= null"))
{
errors.Add("WARNING: Consider null checking GetComponent results");
}
// Check for proper event function signatures
if (contents.Contains("void Start(") && !contents.Contains("void Start()"))
{
errors.Add("WARNING: Start() should not have parameters");
}
if (contents.Contains("void Update(") && !contents.Contains("void Update()"))
{
errors.Add("WARNING: Update() should not have parameters");
}
// Check for inefficient string operations
if (contents.Contains("Update()") && contents.Contains("\"") && contents.Contains("+"))
{
errors.Add("WARNING: String concatenation in Update() can cause garbage collection issues");
}
}
/// <summary>
/// Validates semantic rules and common coding issues
/// </summary>
private static void ValidateSemanticRules(string contents, System.Collections.Generic.List<string> errors)
{
// Check for potential memory leaks
if (contents.Contains("new ") && contents.Contains("Update()"))
{
errors.Add("WARNING: Creating objects in Update() may cause memory issues");
}
// Check for magic numbers
Claude‑friendly edit tools + framed transport + live Unity NL test framework (#243) * CI: gate desktop-parity on Anthropic key; pass anthropic_api_key like NL suite * Add quickprobe prompt and CI workflow (mcp-quickprobe.md, unity-mcp-quickprobe.yml) * strictier tool use to prevent subagent spawning and force mcp tools * update workflow filesto reduce likelihood of subagent spawning * improve permissions for claude agent, fix mcpbridge timeout/token issue * increase max turns to 10 * ci: align NL suite to new permissions schema; prevent subagent drift * ci: NL suite -> mini prompt for e2e; add full NL/T prompt; server: ctx optional + project_root fallback; workflows: set UNITY_PROJECT_ROOT for CI * ci: add checks:write; revert local project hardcodes (manifest, ProjectVersion.txt) * tools: text-edit routing fixes (anchor_insert via text, CRLF calc); prompts: mini NL/T clarifications * ci: use absolute UNITY_PROJECT_ROOT; prompts target TestProjects; server: accept relative UNITY_PROJECT_ROOT and bare spec URI * ci: ignore Unity test project's packages-lock.json; remove from repo to avoid absolute paths * CI: start persistent Unity Editor for MCP (guarded by license) + allow batch-mode bridge via UNITY_MCP_ALLOW_BATCH * CI: hide license and pass via env to docker; fix invalid ref format * CI: readiness probe uses handshake on Unity MCP port (deterministic) * CI: fix YAML; use TCP handshake readiness probe (FRAMING=1) * CI: prime Unity license via game-ci; mount ULF into container; extend readiness timeout * CI: use ULF write + mount for Unity licensing; remove serial/email/pass from container * CI: entitlement activation (UNITY_SERIAL=''); verify host ULF cache; keep mount * CI: write ULF from secret and verify; drop entitlement activation step * CI: detect any licensing path; GameCI prime; status dir env; log+probe readiness; fix YAML * CI: add GameCI license prime; conditional ULF write; one-shot license validation; explicit status dir + license env * CI: fix YAML (inline python), add Anthropic key detect via GITHUB_ENV; ready to run happy path * CI: mount Unity token/ulf/cache dirs into container to share host license; create dirs before start * CI: fix YAML indentation; write ULF on host; activate in container with shared mounts; mount .config and .cache too * CI: gate Claude via outputs; mount all Unity license dirs; fix inline probe python; stabilize licensing flow * CI: normalize detect to step outputs; ensure license dirs mounted and validated; fix indentation * Bridge: honor UNITY_MCP_STATUS_DIR for heartbeat/status file (CI-friendly) * CI: guard project path for activation/start; align tool allowlist; run MCP server with python; tighten secret scoping * CI: finalize Unity licensing mounts + status dir; mode-detect (ULF/EBL); readiness logs+probe; Claude gating via outputs * CI: fix YAML probe (inline python -c) and finalize happy-path Unity licensing and MCP/Claude wiring * CI: inline python probe; unify Unity image and cache mounts; ready to test * CI: fix docker run IMAGE placement; ignore cache find perms; keep same editor image * CI: pass -manualLicenseFile to persistent Editor; keep mounts and single image * CI: mount full GameCI cache to /root in persistent Unity; set HOME=/root; add optional license check * CI: make -manualLicenseFile conditional; keep full /root mount and license check * CI: set HOME=/github/home; mount GameCI cache there; adjust manualLicenseFile path; expand license check * CI: EBL sign-in for persistent Unity (email/password/serial); revert HOME=/root and full /root mount; keep conditional manualLicenseFile and improved readiness * CI: run full NL/T suite prompt (nl-unity-suite-full.md) instead of mini * NL/T: require unified diffs + explicit verdicts in JUnit; CI: remove short sanity step, publish JUnit, upload artifacts * NL/T prompt: require CDATA wrapping for JUnit XML fields; guidance for splitting embedded ]]>; keep VERDICT in CDATA only * CI: remove in-container license check step; keep readiness and full suite * NL/T prompt: add version header, stricter JUnit schema, hashing/normalization, anchors, statuses, atomic semantics, tool logging * CI: increase Claude NL/T suite timeout to 30 minutes * CI: pre-create reports dir and result files to avoid tool approval prompts * CI: skip wait if container not running; skip Editor start if project missing; broaden MCP deps detection; expand allowed tools * fixies to harden ManageScript * CI: sanitize NL/T markdown report to avoid NUL/encoding issues * revert breaking yyaml changes * CI: prime license, robust Unity start/wait, sanitize markdown via heredoc * Resolve merge: accept upstream renames/installer (fix/installer-cleanup-v2) and keep local framing/script-editing - Restored upstream server.py, EditorWindow, uv.lock\n- Preserved ManageScript editing/validation; switched to atomic write + debounced refresh\n- Updated tools/__init__.py to keep script_edits/resources and adopt new logger name\n- All Python tests via uv: 7 passed, 6 skipped, 9 xpassed; Unity compile OK * Fix Claude Desktop config path and atomic write issues - Fix macOS path for Claude Desktop config: use ~/Library/Application Support/Claude/ instead of ~/.config/Claude/ - Improve atomic write pattern with backup/restore safety - Replace File.Replace() with File.Move() for better macOS compatibility - Add proper error handling and cleanup for file operations - Resolves issue where installer couldn't find Claude Desktop config on macOS * Editor: use macConfigPath on macOS for MCP client config writes (Claude Desktop, etc.). Fallback to linuxConfigPath only if mac path missing. * Models: add macConfigPath to McpClient for macOS config path selection (fixes CS1061 in editor window). * Editor: on macOS, prefer macConfigPath in ManualConfigEditorWindow (fallback to linux path); Linux/Windows unchanged. * Fix McpClient: align with upstream/main, prep for framing split * NL suite: shard workflow; tighten bridge readiness; add MCP preflight; use env-based shard vars * NL suite: fix shard step indentation; move shard vars to env; remove invalid inputs * MCP clients: split VSCode Copilot config paths into macConfigPath and linuxConfigPath * Unity bridge: clean stale status; bind host; robust wait probe with IPv4/IPv6 + diagnostics * CI: use MCPForUnity.Editor.MCPForUnityBridge.StartAutoConnect as executeMethod * Action wiring: inline mcpServers in settings for all shards; remove redundant .claude/mcp.json step * CI: embed mcpServers in settings for all shards; fix startup sanity step; lint clean * CI: pin claude-code-base-action to e6f32c8; use claude_args --mcp-config; switch to allowed_tools; ensure MCP config per step * CI: unpin claude-code-base-action to @beta (commit ref not found) * CI: align with claude-code-base-action @beta; pass MCP via claude_args and allowedTools * Editor: Fix apply_text_edits heuristic when edits shift positions; recompute method span on candidate text with fallback delta adjustment * CI: unify MCP wiring across workflows; write .claude/mcp.json; switch to claude_args with --mcp-config/--allowedTools; remove unsupported inputs * CI: collapse NL suite shards into a single run to avoid repeated test execution * CI: minimize allowedTools for NL suite to essential Unity MCP + Bash("git:*") + Write * CI: mkdir -p reports before run; remove unsupported --timeout-minutes from claude_args * CI: broaden allowedTools to include find_in_file and mcp__unity__* * CI: enable use_node_cache and switch NL suite model to claude-3-7-haiku-20250219 * CI: disable use_node_cache to avoid setup-node lockfile error * CI: set NL suite model to claude-3-haiku-20240307 * CI: cap Haiku output with --max-tokens 2048 for NL suite * CI: switch to claude-3-7-sonnet-latest and remove unsupported --max-tokens * CI: update allowedTools to Bash(*) and explicit Unity MCP tool list * CI: update NL suite workflow (latest tweaks) * Tests: tighten NL suite prompt for logging, hash discipline, stale retry, evidence windows, diff cap, and VERDICT line * Add disallowed tools to NL suite workflow * docs: clarify stale write retry * Add fallback JUnit report and adjust publisher * Indent fallback JUnit XML in workflow * fix: correct fallback JUnit report generation * Update mcp-quickprobe.md Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> * Update mcp-quickprobe.md Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> * Update Response.cs Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> * Update MCPForUnityBridge.cs Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> * fix: correct McpTypes reference * Add directory existence checks for symlink and XDG paths * fix: only set installation flag after successful server install * Update resource_tools.py Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> * fix: respect mac config paths * Use File.Replace for atomic config write * Remove unused imports in manage_script * bump server version * Tests: update NL suite prompt and workflows; remove deprecated smoke/desktop-parity; quickprobe tidy * Editor: atomic config write via File.Replace fallback; remove redundant backups and racey exists checks * CI: harden NL suite - idempotent docker, gate on unity_ok, safer port probe, least-priv perms * Editor: make atomic config write restoration safe (flag writeDone; copy-overwrite restore; cleanup in finally) * CI: fix fallback JUnit heredoc by using printf lines (no EOF delimiter issues) * CI: switch NL suite to mini prompt; mini prompt honors / and NL discipline * CI: replace claude_args with allowed_tools/model/mcp_config per action schema * CI: expand UNITY_PROJECT_ROOT via in MCP config heredoc * EditorWindow: add cross-platform fallback for File.Replace; macOS-insensitive PathsEqual; safer uv resolve; honor macConfigPath * CI: strengthen JUnit publishing for NL mini suite (normalize, debug list, publish both, fail_on_parse_error) * CI: set job-wide JUNIT_OUT/MD_OUT; normalization uses env; publish references env and ungroup reports * CI: publish a single normalized JUnit (reports/junit-for-actions.xml); fallback writes same; avoid checkName/reportPaths mismatch * CI: align mini prompt report filenames; redact Unity log tail in diagnostics * chore: sync workflow and mini prompt; redacted logs; JUnit normalization/publish tweaks * CI: redact sensitive tokens in Stop Unity; docs: CI usage + edit tools * prompts: update nl-unity-suite-full (mini-style setup + reporting discipline); remove obsolete prompts * CI: harden NL workflows (timeout_minutes, robust normalization); prompts: unify JUnit suite name and reporting discipline * prompts: add guarded write pattern (LF hash, stale_file retry) to full suite * prompts: enforce continue-on-failure, driver flow, and status handling in full suite * Make test list more explicit in prompt. Get rid of old test prompts for hygeine. * prompts: add stale fast-retry (server hash) + in-memory buf guidance * CI: standardize JUNIT_OUT to reports/junit-nl-suite.xml; fix artifact upload indentation; prompt copy cleanups * prompts: reporting discipline — append-only fragments, batch writes, no model round-trip * prompts: stale fast-retry preference, buffer/sha carry, snapshot revert, essential logging * workflows(nl-suite): precreate report skeletons, assemble junit, synthesize markdown; restrict allowed_tools to append-only Bash + MCP tools * thsis too * Update README-DEV.md Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update .github/workflows/claude-nl-suite-mini.yml Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update .github/workflows/claude-nl-suite.yml Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * workflows(nl-mini): fix YAML indentation/trailing spaces under with: and cleanup heredoc spacing * workflows(nl-suite): fix indentation on docker logs redaction line (YAML lint) * Add write to allowlist * nl-suite: harden reporting discipline (fragment-only writes, forbid alt paths); workflow: clean stray junit-*updated*.xml * nl-suite: enforce end-of-suite single Write (no bash redirection); workflow: restrict allowed_tools to Write+MCP only * prompts(nl-full): end-of-suite results must be valid XML with single <cases> root and only <testcase> children; no raw text outside CDATA * workflows(nl-suite): make Claude step non-fatal; tolerant normalizer extracts <testcase> via regex on bad fragments * nl-suite: fix stale classname to UnityMCP.NL-T in mini fallback; prompt: require re-read after every revert; correct PLAN/PROGRESS to 15 * nl-suite: fix fallback JUnit classname to UnityMCP.NL-T; prompt: forbid create_script and env/mkdir checks, enforce single baseline-byte revert flow and post-revert re-read; add corruption-handling guidance * prompts(nl-full): after each write re-read raw bytes to refresh pre_sha; prefer script_apply_edits for anchors; avoid header/using changes * prompts(nl-full): canonicalize outputs to /; allow small fragment appends via Write or Bash(printf/echo); forbid wrappers and full-file round-trips * prompts(nl-full): finalize markdown formatting for guarded write, execution order, specs, status * workflows(nl-suite, mini): header/lint fixes and constrained Bash append path; align allowed_tools * prompts(nl-full): format Fast Restore, Guarded Write, Execution, Specs, Status as proper markdown lists and code fences * workflows(nl-suite): keep header tidy and append-path alignment with prompt * minor fix * workflows(nl-suite): fix indentation and dispatch; align allowed_tools and revert helper * prompts(nl-full): switch to read_resource for buf/sha; re-read only when needed; convert 'Print this once' to heading; note snapshot helper creates parent dirs * workflows(nl-suite): normalize step removes bootstrap when real testcases present; recompute tests/failures * workflows(nl-suite): enrich Markdown summary by extracting per-test <system-out> blocks (truncated) * clarify prompt resilience instructions * ci(nl-suite): revert prompt and workflow to known-good e0f8a72 for green run; remove extra MD details * ci(nl-suite): minimal fixes — no-mkdir guard in prompt; drop bootstrap and recompute JUnit counts * ci(nl-suite): richer JUnit→Markdown report (per-test system-out) * Small guard to incorret asset read call. * ci(nl-suite): refine MD builder — unescape XML entities, safe code fences, PASS/FAIL badges * Update UnityMcpBridge/UnityMcpServer~/src/tools/resource_tools.py Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update UnityMcpBridge/UnityMcpServer~/src/unity_connection.py Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update UnityMcpBridge/UnityMcpServer~/src/tools/manage_script_edits.py Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update .github/scripts/mark_skipped.py Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update .github/scripts/mark_skipped.py Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update .github/scripts/mark_skipped.py Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> * server(manage_script): robust URI handling — percent-decode file://, normalize, strip host/leading slashes, return Assets-relative if present * Update .claude/prompts/nl-unity-suite-full.md Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> * tests(framing): reduce handshake poll window, nonblocking peek to avoid disconnect race; still enforce pre-handshake data drop * tests(manage_script): add _split_uri tests for unity://path, file:// URLs (decoded/Assets-relative), and plain paths * server+tests: fix handshake syntax error; robust file:// URI normalization in manage_script; add _split_uri tests; adjust stdout scan to ignore venv/site-packages * bridge(framing): accept zero-length frames (treat as empty keepalive) * tests(logging): use errors='replace' on decode fallback to avoid silent drops * resources(list): restrict to Assets/, resolve symlinks, enforce .cs; add traversal/outside-path tests * Update .claude/prompts/nl-unity-suite-full.md Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update UnityMcpBridge/UnityMcpServer~/src/unity_connection.py Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * misc: framing keepalive (zero-length), regex preview consistency, resource.list hardening, URI parsing, legacy update routing, test cleanups * docs(tools): richer MCP tool descriptions; tests accept decorator kwargs; resource URI parsing hardened * Update .claude/prompts/nl-unity-suite-full.md Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update UnityMcpBridge/UnityMcpServer~/src/tools/resource_tools.py Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update UnityMcpBridge/UnityMcpServer~/src/unity_connection.py Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * net+docs: hard-reject zero-length frames; TCP_NODELAY on connect; Assets detection case-insensitive; NL prompt statuses aligned * prompt(nl-suite): constrain Write destinations under reports/, forbid traversal * prompt+net: harden Write path rules; use monotonic deadline and plain-text advisory for non-framed peers * unity_connection: restore recv timeout via try/finally; make global connection getter thread-safe with module lock and double-checked init * NL/T prompt: pin structured edit ops for T-D/T-E; add schema-error guarded write behavior; keep existing path/URI and revert rules * unity_connection: add FRAMED_MAX; use ValueError for framed length violations; lower framed receive log to debug; serialize connect() with per-instance lock * ManageScript: use UTF8Encoding(without BOM) for atomic writes in ApplyTextEdits/EditScript to align with Create/Update and avoid BOM-related diffs/hash mismatches * NL/T prompt: make helper deletion regex multiline-safe ((?ms) so ^ anchors line starts) * ManageScript: emit structured overlap status {status:"overlap"} for overlapping edit ranges in apply_text_edits and edit paths * NL/T prompt: clarify fallback vs failure — fallback only for unsupported/missing_field; treat bad_request as failure; note unsupported after fallback as failure * NL/T prompt: pin deterministic overlap probe (apply_text_edits two ranges from same snapshot); gate too_large behind RUN_TOO_LARGE env hint * TB update * NL/T prompt: harden Output Rules — constrain Bash(printf|echo) to stdout-only; forbid redirection/here-docs/tee; only scripts/nlt-revert.sh may mutate FS * Prompt: enumerate allowed script_apply_edits ops; add manage_editor/read_console guidance; fix T‑F atomic batch to single script_apply_edits. ManageScript: regex timeout for diagnostics; symlink ancestor guard; complete allowed-modes list. * Fixes * ManageScript: add rich overlap diagnostics (conflicts + hint) for both text range and structured batch paths * ManageScript: return structured {status:"validation_failed"} diagnostics in create/update/edits and validate before commit * ManageScript: echo canonical uri in responses (create/read/update/apply_text_edits/structured edits) to reinforce resource identity * improve clarity of capabilities message * Framing: allow zero-length frames on both ends (C# bridge, Python server). Prompt: harden T-F to single text-range apply_text_edits batch (descending order, one snapshot). URI: normalize file:// outside Assets by stripping leading slash. * ManageScript: include new sha256 in success payload for apply_text_edits; harden TryResolveUnderAssets by rejecting symlinked ancestors up to Assets/. * remove claudetest dir * manage_script_edits: normalize method-anchored anchor_insert to insert_method (map text->replacement); improves CI compatibility for T‑A/T‑E without changing Editor behavior. * tighten testing protocol around mkdir * manage_script: validate create_script inputs (Assets/.cs/name/no traversal); add Assets/ guard to delete_script; validate level+Assets in validate_script; make legacy manage_script optional params; harden legacy update routing with base64 reuse and payload size preflight. * Tighten prompt for testing * Update .claude/prompts/nl-unity-suite-full.md Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update .claude/prompts/nl-unity-suite-full.md Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update UnityMcpBridge/Editor/Tools/ManageScript.cs Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * manage_script_edits: honor ignore_case on anchor_insert and regex_replace in both direct and text-conversion paths (MULTILINE|IGNORECASE). * remove extra file * workflow: use python3 for inline scripts and port detection on ubuntu-latest. * Tighten prompt + manage_script * Update UnityMcpBridge/UnityMcpServer~/src/tools/manage_script_edits.py Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update UnityMcpBridge/UnityMcpServer~/src/tools/manage_script_edits.py Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update .claude/prompts/nl-unity-suite-full.md Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update UnityMcpBridge/Editor/Tools/ManageScript.cs Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update .claude/prompts/nl-unity-suite-full.md Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * manage_script: improve file:// UNC handling; preserve POSIX absolute semantics internally; keep test-expected slash stripping for non-Assets paths. * ManageScript.cs: add TimeSpan timeouts to all Regex uses (IsMatch/Match/new Regex) and keep CultureInvariant/Multiline options; reduces risk of catastrophic backtracking stalls. * workflow: ensure reports/ exists in markdown build step to avoid FileNotFoundError when writing MD_OUT. * fix brace * manage_script_edits: expand backrefs for regex_replace in preview->text conversion and translate to \g<n> in local apply; keeps previews and actual edits consistent. * anchor_insert: default to position=after, normalize surrounding newlines in Python conversion paths; C# path ensures trailing newline and skips duplicate insertion within class. * feat(mcp): add get_sha tool; apply_text_edits normalization+overlap preflight+strict; no-op evidence in C#; update NL suite prompt; add unit tests * feat(frames): accept zero-length heartbeat frames in client; add heartbeat test * feat(edits): guard destructive regex_replace with structural preflight; add robust tests; prompt uses delete_method for temp helper * feat(frames): bound heartbeat loop with timeout/threshold; align zero-length response with C#; update test * SDK hardening: atomic multi-span text edits; stop forcing sequential for structured ops; forward options on apply_text_edits; add validate=relaxed support and scoped checks; update NL/T prompt; add tests for options forwarding, relaxed mode, and atomic batches * Router: default applyMode=atomic for multi-span apply_text_edits; add tests * CI prompt: pass options.validate=relaxed for T-B/C; options.applyMode=atomic for T-F; emphasize always writing testcase and restoring on errors * Validation & DX: add validate=syntax (scoped), standardize evidence windows; early regex compile with hints; debug_preview for apply_text_edits * Update UnityMcpBridge/Editor/Windows/MCPForUnityEditorWindow.cs Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * NL/T suite-driven edits: LongUnityScriptClaudeTest, bridge helpers, server_version; prepare framing tests * Fix duplicate macConfigPath field in McpClient to resolve CS0102 * Editor threading: run EnsureServerInstalled on main thread; marshal EditorPrefs/DeleteKey + logging via delayCall * Docs(apply_text_edits): strengthen guidance on 1-based positions, verify-before-edit, and recommend anchors/structured edits * Docs(script_apply_edits): add safety guidance (anchors, method ops, validators) and recommended practices * Framed VerifyBridgePing in editor window; docs hardening for apply_text_edits and script_apply_edits --------- Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
2025-08-31 00:55:38 +08:00
var magicNumberPattern = new Regex(@"\b\d+\.?\d*f?\b(?!\s*[;})\]])", RegexOptions.CultureInvariant, TimeSpan.FromSeconds(2));
var matches = magicNumberPattern.Matches(contents);
if (matches.Count > 5)
{
errors.Add("WARNING: Consider using named constants instead of magic numbers");
}
// Check for long methods (simple line count check)
Claude‑friendly edit tools + framed transport + live Unity NL test framework (#243) * CI: gate desktop-parity on Anthropic key; pass anthropic_api_key like NL suite * Add quickprobe prompt and CI workflow (mcp-quickprobe.md, unity-mcp-quickprobe.yml) * strictier tool use to prevent subagent spawning and force mcp tools * update workflow filesto reduce likelihood of subagent spawning * improve permissions for claude agent, fix mcpbridge timeout/token issue * increase max turns to 10 * ci: align NL suite to new permissions schema; prevent subagent drift * ci: NL suite -> mini prompt for e2e; add full NL/T prompt; server: ctx optional + project_root fallback; workflows: set UNITY_PROJECT_ROOT for CI * ci: add checks:write; revert local project hardcodes (manifest, ProjectVersion.txt) * tools: text-edit routing fixes (anchor_insert via text, CRLF calc); prompts: mini NL/T clarifications * ci: use absolute UNITY_PROJECT_ROOT; prompts target TestProjects; server: accept relative UNITY_PROJECT_ROOT and bare spec URI * ci: ignore Unity test project's packages-lock.json; remove from repo to avoid absolute paths * CI: start persistent Unity Editor for MCP (guarded by license) + allow batch-mode bridge via UNITY_MCP_ALLOW_BATCH * CI: hide license and pass via env to docker; fix invalid ref format * CI: readiness probe uses handshake on Unity MCP port (deterministic) * CI: fix YAML; use TCP handshake readiness probe (FRAMING=1) * CI: prime Unity license via game-ci; mount ULF into container; extend readiness timeout * CI: use ULF write + mount for Unity licensing; remove serial/email/pass from container * CI: entitlement activation (UNITY_SERIAL=''); verify host ULF cache; keep mount * CI: write ULF from secret and verify; drop entitlement activation step * CI: detect any licensing path; GameCI prime; status dir env; log+probe readiness; fix YAML * CI: add GameCI license prime; conditional ULF write; one-shot license validation; explicit status dir + license env * CI: fix YAML (inline python), add Anthropic key detect via GITHUB_ENV; ready to run happy path * CI: mount Unity token/ulf/cache dirs into container to share host license; create dirs before start * CI: fix YAML indentation; write ULF on host; activate in container with shared mounts; mount .config and .cache too * CI: gate Claude via outputs; mount all Unity license dirs; fix inline probe python; stabilize licensing flow * CI: normalize detect to step outputs; ensure license dirs mounted and validated; fix indentation * Bridge: honor UNITY_MCP_STATUS_DIR for heartbeat/status file (CI-friendly) * CI: guard project path for activation/start; align tool allowlist; run MCP server with python; tighten secret scoping * CI: finalize Unity licensing mounts + status dir; mode-detect (ULF/EBL); readiness logs+probe; Claude gating via outputs * CI: fix YAML probe (inline python -c) and finalize happy-path Unity licensing and MCP/Claude wiring * CI: inline python probe; unify Unity image and cache mounts; ready to test * CI: fix docker run IMAGE placement; ignore cache find perms; keep same editor image * CI: pass -manualLicenseFile to persistent Editor; keep mounts and single image * CI: mount full GameCI cache to /root in persistent Unity; set HOME=/root; add optional license check * CI: make -manualLicenseFile conditional; keep full /root mount and license check * CI: set HOME=/github/home; mount GameCI cache there; adjust manualLicenseFile path; expand license check * CI: EBL sign-in for persistent Unity (email/password/serial); revert HOME=/root and full /root mount; keep conditional manualLicenseFile and improved readiness * CI: run full NL/T suite prompt (nl-unity-suite-full.md) instead of mini * NL/T: require unified diffs + explicit verdicts in JUnit; CI: remove short sanity step, publish JUnit, upload artifacts * NL/T prompt: require CDATA wrapping for JUnit XML fields; guidance for splitting embedded ]]>; keep VERDICT in CDATA only * CI: remove in-container license check step; keep readiness and full suite * NL/T prompt: add version header, stricter JUnit schema, hashing/normalization, anchors, statuses, atomic semantics, tool logging * CI: increase Claude NL/T suite timeout to 30 minutes * CI: pre-create reports dir and result files to avoid tool approval prompts * CI: skip wait if container not running; skip Editor start if project missing; broaden MCP deps detection; expand allowed tools * fixies to harden ManageScript * CI: sanitize NL/T markdown report to avoid NUL/encoding issues * revert breaking yyaml changes * CI: prime license, robust Unity start/wait, sanitize markdown via heredoc * Resolve merge: accept upstream renames/installer (fix/installer-cleanup-v2) and keep local framing/script-editing - Restored upstream server.py, EditorWindow, uv.lock\n- Preserved ManageScript editing/validation; switched to atomic write + debounced refresh\n- Updated tools/__init__.py to keep script_edits/resources and adopt new logger name\n- All Python tests via uv: 7 passed, 6 skipped, 9 xpassed; Unity compile OK * Fix Claude Desktop config path and atomic write issues - Fix macOS path for Claude Desktop config: use ~/Library/Application Support/Claude/ instead of ~/.config/Claude/ - Improve atomic write pattern with backup/restore safety - Replace File.Replace() with File.Move() for better macOS compatibility - Add proper error handling and cleanup for file operations - Resolves issue where installer couldn't find Claude Desktop config on macOS * Editor: use macConfigPath on macOS for MCP client config writes (Claude Desktop, etc.). Fallback to linuxConfigPath only if mac path missing. * Models: add macConfigPath to McpClient for macOS config path selection (fixes CS1061 in editor window). * Editor: on macOS, prefer macConfigPath in ManualConfigEditorWindow (fallback to linux path); Linux/Windows unchanged. * Fix McpClient: align with upstream/main, prep for framing split * NL suite: shard workflow; tighten bridge readiness; add MCP preflight; use env-based shard vars * NL suite: fix shard step indentation; move shard vars to env; remove invalid inputs * MCP clients: split VSCode Copilot config paths into macConfigPath and linuxConfigPath * Unity bridge: clean stale status; bind host; robust wait probe with IPv4/IPv6 + diagnostics * CI: use MCPForUnity.Editor.MCPForUnityBridge.StartAutoConnect as executeMethod * Action wiring: inline mcpServers in settings for all shards; remove redundant .claude/mcp.json step * CI: embed mcpServers in settings for all shards; fix startup sanity step; lint clean * CI: pin claude-code-base-action to e6f32c8; use claude_args --mcp-config; switch to allowed_tools; ensure MCP config per step * CI: unpin claude-code-base-action to @beta (commit ref not found) * CI: align with claude-code-base-action @beta; pass MCP via claude_args and allowedTools * Editor: Fix apply_text_edits heuristic when edits shift positions; recompute method span on candidate text with fallback delta adjustment * CI: unify MCP wiring across workflows; write .claude/mcp.json; switch to claude_args with --mcp-config/--allowedTools; remove unsupported inputs * CI: collapse NL suite shards into a single run to avoid repeated test execution * CI: minimize allowedTools for NL suite to essential Unity MCP + Bash("git:*") + Write * CI: mkdir -p reports before run; remove unsupported --timeout-minutes from claude_args * CI: broaden allowedTools to include find_in_file and mcp__unity__* * CI: enable use_node_cache and switch NL suite model to claude-3-7-haiku-20250219 * CI: disable use_node_cache to avoid setup-node lockfile error * CI: set NL suite model to claude-3-haiku-20240307 * CI: cap Haiku output with --max-tokens 2048 for NL suite * CI: switch to claude-3-7-sonnet-latest and remove unsupported --max-tokens * CI: update allowedTools to Bash(*) and explicit Unity MCP tool list * CI: update NL suite workflow (latest tweaks) * Tests: tighten NL suite prompt for logging, hash discipline, stale retry, evidence windows, diff cap, and VERDICT line * Add disallowed tools to NL suite workflow * docs: clarify stale write retry * Add fallback JUnit report and adjust publisher * Indent fallback JUnit XML in workflow * fix: correct fallback JUnit report generation * Update mcp-quickprobe.md Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> * Update mcp-quickprobe.md Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> * Update Response.cs Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> * Update MCPForUnityBridge.cs Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> * fix: correct McpTypes reference * Add directory existence checks for symlink and XDG paths * fix: only set installation flag after successful server install * Update resource_tools.py Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> * fix: respect mac config paths * Use File.Replace for atomic config write * Remove unused imports in manage_script * bump server version * Tests: update NL suite prompt and workflows; remove deprecated smoke/desktop-parity; quickprobe tidy * Editor: atomic config write via File.Replace fallback; remove redundant backups and racey exists checks * CI: harden NL suite - idempotent docker, gate on unity_ok, safer port probe, least-priv perms * Editor: make atomic config write restoration safe (flag writeDone; copy-overwrite restore; cleanup in finally) * CI: fix fallback JUnit heredoc by using printf lines (no EOF delimiter issues) * CI: switch NL suite to mini prompt; mini prompt honors / and NL discipline * CI: replace claude_args with allowed_tools/model/mcp_config per action schema * CI: expand UNITY_PROJECT_ROOT via in MCP config heredoc * EditorWindow: add cross-platform fallback for File.Replace; macOS-insensitive PathsEqual; safer uv resolve; honor macConfigPath * CI: strengthen JUnit publishing for NL mini suite (normalize, debug list, publish both, fail_on_parse_error) * CI: set job-wide JUNIT_OUT/MD_OUT; normalization uses env; publish references env and ungroup reports * CI: publish a single normalized JUnit (reports/junit-for-actions.xml); fallback writes same; avoid checkName/reportPaths mismatch * CI: align mini prompt report filenames; redact Unity log tail in diagnostics * chore: sync workflow and mini prompt; redacted logs; JUnit normalization/publish tweaks * CI: redact sensitive tokens in Stop Unity; docs: CI usage + edit tools * prompts: update nl-unity-suite-full (mini-style setup + reporting discipline); remove obsolete prompts * CI: harden NL workflows (timeout_minutes, robust normalization); prompts: unify JUnit suite name and reporting discipline * prompts: add guarded write pattern (LF hash, stale_file retry) to full suite * prompts: enforce continue-on-failure, driver flow, and status handling in full suite * Make test list more explicit in prompt. Get rid of old test prompts for hygeine. * prompts: add stale fast-retry (server hash) + in-memory buf guidance * CI: standardize JUNIT_OUT to reports/junit-nl-suite.xml; fix artifact upload indentation; prompt copy cleanups * prompts: reporting discipline — append-only fragments, batch writes, no model round-trip * prompts: stale fast-retry preference, buffer/sha carry, snapshot revert, essential logging * workflows(nl-suite): precreate report skeletons, assemble junit, synthesize markdown; restrict allowed_tools to append-only Bash + MCP tools * thsis too * Update README-DEV.md Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update .github/workflows/claude-nl-suite-mini.yml Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update .github/workflows/claude-nl-suite.yml Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * workflows(nl-mini): fix YAML indentation/trailing spaces under with: and cleanup heredoc spacing * workflows(nl-suite): fix indentation on docker logs redaction line (YAML lint) * Add write to allowlist * nl-suite: harden reporting discipline (fragment-only writes, forbid alt paths); workflow: clean stray junit-*updated*.xml * nl-suite: enforce end-of-suite single Write (no bash redirection); workflow: restrict allowed_tools to Write+MCP only * prompts(nl-full): end-of-suite results must be valid XML with single <cases> root and only <testcase> children; no raw text outside CDATA * workflows(nl-suite): make Claude step non-fatal; tolerant normalizer extracts <testcase> via regex on bad fragments * nl-suite: fix stale classname to UnityMCP.NL-T in mini fallback; prompt: require re-read after every revert; correct PLAN/PROGRESS to 15 * nl-suite: fix fallback JUnit classname to UnityMCP.NL-T; prompt: forbid create_script and env/mkdir checks, enforce single baseline-byte revert flow and post-revert re-read; add corruption-handling guidance * prompts(nl-full): after each write re-read raw bytes to refresh pre_sha; prefer script_apply_edits for anchors; avoid header/using changes * prompts(nl-full): canonicalize outputs to /; allow small fragment appends via Write or Bash(printf/echo); forbid wrappers and full-file round-trips * prompts(nl-full): finalize markdown formatting for guarded write, execution order, specs, status * workflows(nl-suite, mini): header/lint fixes and constrained Bash append path; align allowed_tools * prompts(nl-full): format Fast Restore, Guarded Write, Execution, Specs, Status as proper markdown lists and code fences * workflows(nl-suite): keep header tidy and append-path alignment with prompt * minor fix * workflows(nl-suite): fix indentation and dispatch; align allowed_tools and revert helper * prompts(nl-full): switch to read_resource for buf/sha; re-read only when needed; convert 'Print this once' to heading; note snapshot helper creates parent dirs * workflows(nl-suite): normalize step removes bootstrap when real testcases present; recompute tests/failures * workflows(nl-suite): enrich Markdown summary by extracting per-test <system-out> blocks (truncated) * clarify prompt resilience instructions * ci(nl-suite): revert prompt and workflow to known-good e0f8a72 for green run; remove extra MD details * ci(nl-suite): minimal fixes — no-mkdir guard in prompt; drop bootstrap and recompute JUnit counts * ci(nl-suite): richer JUnit→Markdown report (per-test system-out) * Small guard to incorret asset read call. * ci(nl-suite): refine MD builder — unescape XML entities, safe code fences, PASS/FAIL badges * Update UnityMcpBridge/UnityMcpServer~/src/tools/resource_tools.py Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update UnityMcpBridge/UnityMcpServer~/src/unity_connection.py Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update UnityMcpBridge/UnityMcpServer~/src/tools/manage_script_edits.py Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update .github/scripts/mark_skipped.py Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update .github/scripts/mark_skipped.py Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update .github/scripts/mark_skipped.py Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> * server(manage_script): robust URI handling — percent-decode file://, normalize, strip host/leading slashes, return Assets-relative if present * Update .claude/prompts/nl-unity-suite-full.md Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> * tests(framing): reduce handshake poll window, nonblocking peek to avoid disconnect race; still enforce pre-handshake data drop * tests(manage_script): add _split_uri tests for unity://path, file:// URLs (decoded/Assets-relative), and plain paths * server+tests: fix handshake syntax error; robust file:// URI normalization in manage_script; add _split_uri tests; adjust stdout scan to ignore venv/site-packages * bridge(framing): accept zero-length frames (treat as empty keepalive) * tests(logging): use errors='replace' on decode fallback to avoid silent drops * resources(list): restrict to Assets/, resolve symlinks, enforce .cs; add traversal/outside-path tests * Update .claude/prompts/nl-unity-suite-full.md Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update UnityMcpBridge/UnityMcpServer~/src/unity_connection.py Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * misc: framing keepalive (zero-length), regex preview consistency, resource.list hardening, URI parsing, legacy update routing, test cleanups * docs(tools): richer MCP tool descriptions; tests accept decorator kwargs; resource URI parsing hardened * Update .claude/prompts/nl-unity-suite-full.md Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update UnityMcpBridge/UnityMcpServer~/src/tools/resource_tools.py Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update UnityMcpBridge/UnityMcpServer~/src/unity_connection.py Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * net+docs: hard-reject zero-length frames; TCP_NODELAY on connect; Assets detection case-insensitive; NL prompt statuses aligned * prompt(nl-suite): constrain Write destinations under reports/, forbid traversal * prompt+net: harden Write path rules; use monotonic deadline and plain-text advisory for non-framed peers * unity_connection: restore recv timeout via try/finally; make global connection getter thread-safe with module lock and double-checked init * NL/T prompt: pin structured edit ops for T-D/T-E; add schema-error guarded write behavior; keep existing path/URI and revert rules * unity_connection: add FRAMED_MAX; use ValueError for framed length violations; lower framed receive log to debug; serialize connect() with per-instance lock * ManageScript: use UTF8Encoding(without BOM) for atomic writes in ApplyTextEdits/EditScript to align with Create/Update and avoid BOM-related diffs/hash mismatches * NL/T prompt: make helper deletion regex multiline-safe ((?ms) so ^ anchors line starts) * ManageScript: emit structured overlap status {status:"overlap"} for overlapping edit ranges in apply_text_edits and edit paths * NL/T prompt: clarify fallback vs failure — fallback only for unsupported/missing_field; treat bad_request as failure; note unsupported after fallback as failure * NL/T prompt: pin deterministic overlap probe (apply_text_edits two ranges from same snapshot); gate too_large behind RUN_TOO_LARGE env hint * TB update * NL/T prompt: harden Output Rules — constrain Bash(printf|echo) to stdout-only; forbid redirection/here-docs/tee; only scripts/nlt-revert.sh may mutate FS * Prompt: enumerate allowed script_apply_edits ops; add manage_editor/read_console guidance; fix T‑F atomic batch to single script_apply_edits. ManageScript: regex timeout for diagnostics; symlink ancestor guard; complete allowed-modes list. * Fixes * ManageScript: add rich overlap diagnostics (conflicts + hint) for both text range and structured batch paths * ManageScript: return structured {status:"validation_failed"} diagnostics in create/update/edits and validate before commit * ManageScript: echo canonical uri in responses (create/read/update/apply_text_edits/structured edits) to reinforce resource identity * improve clarity of capabilities message * Framing: allow zero-length frames on both ends (C# bridge, Python server). Prompt: harden T-F to single text-range apply_text_edits batch (descending order, one snapshot). URI: normalize file:// outside Assets by stripping leading slash. * ManageScript: include new sha256 in success payload for apply_text_edits; harden TryResolveUnderAssets by rejecting symlinked ancestors up to Assets/. * remove claudetest dir * manage_script_edits: normalize method-anchored anchor_insert to insert_method (map text->replacement); improves CI compatibility for T‑A/T‑E without changing Editor behavior. * tighten testing protocol around mkdir * manage_script: validate create_script inputs (Assets/.cs/name/no traversal); add Assets/ guard to delete_script; validate level+Assets in validate_script; make legacy manage_script optional params; harden legacy update routing with base64 reuse and payload size preflight. * Tighten prompt for testing * Update .claude/prompts/nl-unity-suite-full.md Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update .claude/prompts/nl-unity-suite-full.md Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update UnityMcpBridge/Editor/Tools/ManageScript.cs Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * manage_script_edits: honor ignore_case on anchor_insert and regex_replace in both direct and text-conversion paths (MULTILINE|IGNORECASE). * remove extra file * workflow: use python3 for inline scripts and port detection on ubuntu-latest. * Tighten prompt + manage_script * Update UnityMcpBridge/UnityMcpServer~/src/tools/manage_script_edits.py Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update UnityMcpBridge/UnityMcpServer~/src/tools/manage_script_edits.py Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update .claude/prompts/nl-unity-suite-full.md Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update UnityMcpBridge/Editor/Tools/ManageScript.cs Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update .claude/prompts/nl-unity-suite-full.md Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * manage_script: improve file:// UNC handling; preserve POSIX absolute semantics internally; keep test-expected slash stripping for non-Assets paths. * ManageScript.cs: add TimeSpan timeouts to all Regex uses (IsMatch/Match/new Regex) and keep CultureInvariant/Multiline options; reduces risk of catastrophic backtracking stalls. * workflow: ensure reports/ exists in markdown build step to avoid FileNotFoundError when writing MD_OUT. * fix brace * manage_script_edits: expand backrefs for regex_replace in preview->text conversion and translate to \g<n> in local apply; keeps previews and actual edits consistent. * anchor_insert: default to position=after, normalize surrounding newlines in Python conversion paths; C# path ensures trailing newline and skips duplicate insertion within class. * feat(mcp): add get_sha tool; apply_text_edits normalization+overlap preflight+strict; no-op evidence in C#; update NL suite prompt; add unit tests * feat(frames): accept zero-length heartbeat frames in client; add heartbeat test * feat(edits): guard destructive regex_replace with structural preflight; add robust tests; prompt uses delete_method for temp helper * feat(frames): bound heartbeat loop with timeout/threshold; align zero-length response with C#; update test * SDK hardening: atomic multi-span text edits; stop forcing sequential for structured ops; forward options on apply_text_edits; add validate=relaxed support and scoped checks; update NL/T prompt; add tests for options forwarding, relaxed mode, and atomic batches * Router: default applyMode=atomic for multi-span apply_text_edits; add tests * CI prompt: pass options.validate=relaxed for T-B/C; options.applyMode=atomic for T-F; emphasize always writing testcase and restoring on errors * Validation & DX: add validate=syntax (scoped), standardize evidence windows; early regex compile with hints; debug_preview for apply_text_edits * Update UnityMcpBridge/Editor/Windows/MCPForUnityEditorWindow.cs Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * NL/T suite-driven edits: LongUnityScriptClaudeTest, bridge helpers, server_version; prepare framing tests * Fix duplicate macConfigPath field in McpClient to resolve CS0102 * Editor threading: run EnsureServerInstalled on main thread; marshal EditorPrefs/DeleteKey + logging via delayCall * Docs(apply_text_edits): strengthen guidance on 1-based positions, verify-before-edit, and recommend anchors/structured edits * Docs(script_apply_edits): add safety guidance (anchors, method ops, validators) and recommended practices * Framed VerifyBridgePing in editor window; docs hardening for apply_text_edits and script_apply_edits --------- Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
2025-08-31 00:55:38 +08:00
var methodPattern = new Regex(@"(public|private|protected|internal)?\s*(static)?\s*\w+\s+\w+\s*\([^)]*\)\s*{", RegexOptions.CultureInvariant, TimeSpan.FromSeconds(2));
var methodMatches = methodPattern.Matches(contents);
foreach (Match match in methodMatches)
{
int startIndex = match.Index;
int braceCount = 0;
int lineCount = 0;
bool inMethod = false;
for (int i = startIndex; i < contents.Length; i++)
{
if (contents[i] == '{')
{
braceCount++;
inMethod = true;
}
else if (contents[i] == '}')
{
braceCount--;
if (braceCount == 0 && inMethod)
break;
}
else if (contents[i] == '\n' && inMethod)
{
lineCount++;
}
}
if (lineCount > 50)
{
errors.Add("WARNING: Method is very long, consider breaking it into smaller methods");
break; // Only report once
}
}
// Check for proper exception handling
if (contents.Contains("catch") && contents.Contains("catch()"))
{
errors.Add("WARNING: Empty catch blocks should be avoided");
}
// Check for proper async/await usage
if (contents.Contains("async ") && !contents.Contains("await"))
{
errors.Add("WARNING: Async method should contain await or return Task");
}
// Check for hardcoded tags and layers
if (contents.Contains("\"Player\"") || contents.Contains("\"Enemy\""))
{
errors.Add("WARNING: Consider using constants for tags instead of hardcoded strings");
}
}
//TODO: A easier way for users to update incorrect scripts (now duplicated with the updateScript method and need to also update server side, put aside for now)
/// <summary>
/// Public method to validate script syntax with configurable validation level
/// Returns detailed validation results including errors and warnings
/// </summary>
// public static object ValidateScript(JObject @params)
// {
// string contents = @params["contents"]?.ToString();
// string validationLevel = @params["validationLevel"]?.ToString() ?? "standard";
// if (string.IsNullOrEmpty(contents))
// {
// return Response.Error("Contents parameter is required for validation.");
// }
// // Parse validation level
// ValidationLevel level = ValidationLevel.Standard;
// switch (validationLevel.ToLower())
// {
// case "basic": level = ValidationLevel.Basic; break;
// case "standard": level = ValidationLevel.Standard; break;
// case "comprehensive": level = ValidationLevel.Comprehensive; break;
// case "strict": level = ValidationLevel.Strict; break;
// default:
// return Response.Error($"Invalid validation level: '{validationLevel}'. Valid levels are: basic, standard, comprehensive, strict.");
// }
// // Perform validation
// bool isValid = ValidateScriptSyntax(contents, level, out string[] validationErrors);
// var errors = validationErrors?.Where(e => e.StartsWith("ERROR:")).ToArray() ?? new string[0];
// var warnings = validationErrors?.Where(e => e.StartsWith("WARNING:")).ToArray() ?? new string[0];
// var result = new
// {
// isValid = isValid,
// validationLevel = validationLevel,
// errorCount = errors.Length,
// warningCount = warnings.Length,
// errors = errors,
// warnings = warnings,
// summary = isValid
// ? (warnings.Length > 0 ? $"Validation passed with {warnings.Length} warnings" : "Validation passed with no issues")
// : $"Validation failed with {errors.Length} errors and {warnings.Length} warnings"
// };
// if (isValid)
// {
// return Response.Success("Script validation completed successfully.", result);
// }
// else
// {
// return Response.Error("Script validation failed.", result);
// }
// }
2025-03-31 03:58:01 +08:00
}
}
Claude‑friendly edit tools + framed transport + live Unity NL test framework (#243) * CI: gate desktop-parity on Anthropic key; pass anthropic_api_key like NL suite * Add quickprobe prompt and CI workflow (mcp-quickprobe.md, unity-mcp-quickprobe.yml) * strictier tool use to prevent subagent spawning and force mcp tools * update workflow filesto reduce likelihood of subagent spawning * improve permissions for claude agent, fix mcpbridge timeout/token issue * increase max turns to 10 * ci: align NL suite to new permissions schema; prevent subagent drift * ci: NL suite -> mini prompt for e2e; add full NL/T prompt; server: ctx optional + project_root fallback; workflows: set UNITY_PROJECT_ROOT for CI * ci: add checks:write; revert local project hardcodes (manifest, ProjectVersion.txt) * tools: text-edit routing fixes (anchor_insert via text, CRLF calc); prompts: mini NL/T clarifications * ci: use absolute UNITY_PROJECT_ROOT; prompts target TestProjects; server: accept relative UNITY_PROJECT_ROOT and bare spec URI * ci: ignore Unity test project's packages-lock.json; remove from repo to avoid absolute paths * CI: start persistent Unity Editor for MCP (guarded by license) + allow batch-mode bridge via UNITY_MCP_ALLOW_BATCH * CI: hide license and pass via env to docker; fix invalid ref format * CI: readiness probe uses handshake on Unity MCP port (deterministic) * CI: fix YAML; use TCP handshake readiness probe (FRAMING=1) * CI: prime Unity license via game-ci; mount ULF into container; extend readiness timeout * CI: use ULF write + mount for Unity licensing; remove serial/email/pass from container * CI: entitlement activation (UNITY_SERIAL=''); verify host ULF cache; keep mount * CI: write ULF from secret and verify; drop entitlement activation step * CI: detect any licensing path; GameCI prime; status dir env; log+probe readiness; fix YAML * CI: add GameCI license prime; conditional ULF write; one-shot license validation; explicit status dir + license env * CI: fix YAML (inline python), add Anthropic key detect via GITHUB_ENV; ready to run happy path * CI: mount Unity token/ulf/cache dirs into container to share host license; create dirs before start * CI: fix YAML indentation; write ULF on host; activate in container with shared mounts; mount .config and .cache too * CI: gate Claude via outputs; mount all Unity license dirs; fix inline probe python; stabilize licensing flow * CI: normalize detect to step outputs; ensure license dirs mounted and validated; fix indentation * Bridge: honor UNITY_MCP_STATUS_DIR for heartbeat/status file (CI-friendly) * CI: guard project path for activation/start; align tool allowlist; run MCP server with python; tighten secret scoping * CI: finalize Unity licensing mounts + status dir; mode-detect (ULF/EBL); readiness logs+probe; Claude gating via outputs * CI: fix YAML probe (inline python -c) and finalize happy-path Unity licensing and MCP/Claude wiring * CI: inline python probe; unify Unity image and cache mounts; ready to test * CI: fix docker run IMAGE placement; ignore cache find perms; keep same editor image * CI: pass -manualLicenseFile to persistent Editor; keep mounts and single image * CI: mount full GameCI cache to /root in persistent Unity; set HOME=/root; add optional license check * CI: make -manualLicenseFile conditional; keep full /root mount and license check * CI: set HOME=/github/home; mount GameCI cache there; adjust manualLicenseFile path; expand license check * CI: EBL sign-in for persistent Unity (email/password/serial); revert HOME=/root and full /root mount; keep conditional manualLicenseFile and improved readiness * CI: run full NL/T suite prompt (nl-unity-suite-full.md) instead of mini * NL/T: require unified diffs + explicit verdicts in JUnit; CI: remove short sanity step, publish JUnit, upload artifacts * NL/T prompt: require CDATA wrapping for JUnit XML fields; guidance for splitting embedded ]]>; keep VERDICT in CDATA only * CI: remove in-container license check step; keep readiness and full suite * NL/T prompt: add version header, stricter JUnit schema, hashing/normalization, anchors, statuses, atomic semantics, tool logging * CI: increase Claude NL/T suite timeout to 30 minutes * CI: pre-create reports dir and result files to avoid tool approval prompts * CI: skip wait if container not running; skip Editor start if project missing; broaden MCP deps detection; expand allowed tools * fixies to harden ManageScript * CI: sanitize NL/T markdown report to avoid NUL/encoding issues * revert breaking yyaml changes * CI: prime license, robust Unity start/wait, sanitize markdown via heredoc * Resolve merge: accept upstream renames/installer (fix/installer-cleanup-v2) and keep local framing/script-editing - Restored upstream server.py, EditorWindow, uv.lock\n- Preserved ManageScript editing/validation; switched to atomic write + debounced refresh\n- Updated tools/__init__.py to keep script_edits/resources and adopt new logger name\n- All Python tests via uv: 7 passed, 6 skipped, 9 xpassed; Unity compile OK * Fix Claude Desktop config path and atomic write issues - Fix macOS path for Claude Desktop config: use ~/Library/Application Support/Claude/ instead of ~/.config/Claude/ - Improve atomic write pattern with backup/restore safety - Replace File.Replace() with File.Move() for better macOS compatibility - Add proper error handling and cleanup for file operations - Resolves issue where installer couldn't find Claude Desktop config on macOS * Editor: use macConfigPath on macOS for MCP client config writes (Claude Desktop, etc.). Fallback to linuxConfigPath only if mac path missing. * Models: add macConfigPath to McpClient for macOS config path selection (fixes CS1061 in editor window). * Editor: on macOS, prefer macConfigPath in ManualConfigEditorWindow (fallback to linux path); Linux/Windows unchanged. * Fix McpClient: align with upstream/main, prep for framing split * NL suite: shard workflow; tighten bridge readiness; add MCP preflight; use env-based shard vars * NL suite: fix shard step indentation; move shard vars to env; remove invalid inputs * MCP clients: split VSCode Copilot config paths into macConfigPath and linuxConfigPath * Unity bridge: clean stale status; bind host; robust wait probe with IPv4/IPv6 + diagnostics * CI: use MCPForUnity.Editor.MCPForUnityBridge.StartAutoConnect as executeMethod * Action wiring: inline mcpServers in settings for all shards; remove redundant .claude/mcp.json step * CI: embed mcpServers in settings for all shards; fix startup sanity step; lint clean * CI: pin claude-code-base-action to e6f32c8; use claude_args --mcp-config; switch to allowed_tools; ensure MCP config per step * CI: unpin claude-code-base-action to @beta (commit ref not found) * CI: align with claude-code-base-action @beta; pass MCP via claude_args and allowedTools * Editor: Fix apply_text_edits heuristic when edits shift positions; recompute method span on candidate text with fallback delta adjustment * CI: unify MCP wiring across workflows; write .claude/mcp.json; switch to claude_args with --mcp-config/--allowedTools; remove unsupported inputs * CI: collapse NL suite shards into a single run to avoid repeated test execution * CI: minimize allowedTools for NL suite to essential Unity MCP + Bash("git:*") + Write * CI: mkdir -p reports before run; remove unsupported --timeout-minutes from claude_args * CI: broaden allowedTools to include find_in_file and mcp__unity__* * CI: enable use_node_cache and switch NL suite model to claude-3-7-haiku-20250219 * CI: disable use_node_cache to avoid setup-node lockfile error * CI: set NL suite model to claude-3-haiku-20240307 * CI: cap Haiku output with --max-tokens 2048 for NL suite * CI: switch to claude-3-7-sonnet-latest and remove unsupported --max-tokens * CI: update allowedTools to Bash(*) and explicit Unity MCP tool list * CI: update NL suite workflow (latest tweaks) * Tests: tighten NL suite prompt for logging, hash discipline, stale retry, evidence windows, diff cap, and VERDICT line * Add disallowed tools to NL suite workflow * docs: clarify stale write retry * Add fallback JUnit report and adjust publisher * Indent fallback JUnit XML in workflow * fix: correct fallback JUnit report generation * Update mcp-quickprobe.md Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> * Update mcp-quickprobe.md Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> * Update Response.cs Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> * Update MCPForUnityBridge.cs Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> * fix: correct McpTypes reference * Add directory existence checks for symlink and XDG paths * fix: only set installation flag after successful server install * Update resource_tools.py Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> * fix: respect mac config paths * Use File.Replace for atomic config write * Remove unused imports in manage_script * bump server version * Tests: update NL suite prompt and workflows; remove deprecated smoke/desktop-parity; quickprobe tidy * Editor: atomic config write via File.Replace fallback; remove redundant backups and racey exists checks * CI: harden NL suite - idempotent docker, gate on unity_ok, safer port probe, least-priv perms * Editor: make atomic config write restoration safe (flag writeDone; copy-overwrite restore; cleanup in finally) * CI: fix fallback JUnit heredoc by using printf lines (no EOF delimiter issues) * CI: switch NL suite to mini prompt; mini prompt honors / and NL discipline * CI: replace claude_args with allowed_tools/model/mcp_config per action schema * CI: expand UNITY_PROJECT_ROOT via in MCP config heredoc * EditorWindow: add cross-platform fallback for File.Replace; macOS-insensitive PathsEqual; safer uv resolve; honor macConfigPath * CI: strengthen JUnit publishing for NL mini suite (normalize, debug list, publish both, fail_on_parse_error) * CI: set job-wide JUNIT_OUT/MD_OUT; normalization uses env; publish references env and ungroup reports * CI: publish a single normalized JUnit (reports/junit-for-actions.xml); fallback writes same; avoid checkName/reportPaths mismatch * CI: align mini prompt report filenames; redact Unity log tail in diagnostics * chore: sync workflow and mini prompt; redacted logs; JUnit normalization/publish tweaks * CI: redact sensitive tokens in Stop Unity; docs: CI usage + edit tools * prompts: update nl-unity-suite-full (mini-style setup + reporting discipline); remove obsolete prompts * CI: harden NL workflows (timeout_minutes, robust normalization); prompts: unify JUnit suite name and reporting discipline * prompts: add guarded write pattern (LF hash, stale_file retry) to full suite * prompts: enforce continue-on-failure, driver flow, and status handling in full suite * Make test list more explicit in prompt. Get rid of old test prompts for hygeine. * prompts: add stale fast-retry (server hash) + in-memory buf guidance * CI: standardize JUNIT_OUT to reports/junit-nl-suite.xml; fix artifact upload indentation; prompt copy cleanups * prompts: reporting discipline — append-only fragments, batch writes, no model round-trip * prompts: stale fast-retry preference, buffer/sha carry, snapshot revert, essential logging * workflows(nl-suite): precreate report skeletons, assemble junit, synthesize markdown; restrict allowed_tools to append-only Bash + MCP tools * thsis too * Update README-DEV.md Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update .github/workflows/claude-nl-suite-mini.yml Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update .github/workflows/claude-nl-suite.yml Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * workflows(nl-mini): fix YAML indentation/trailing spaces under with: and cleanup heredoc spacing * workflows(nl-suite): fix indentation on docker logs redaction line (YAML lint) * Add write to allowlist * nl-suite: harden reporting discipline (fragment-only writes, forbid alt paths); workflow: clean stray junit-*updated*.xml * nl-suite: enforce end-of-suite single Write (no bash redirection); workflow: restrict allowed_tools to Write+MCP only * prompts(nl-full): end-of-suite results must be valid XML with single <cases> root and only <testcase> children; no raw text outside CDATA * workflows(nl-suite): make Claude step non-fatal; tolerant normalizer extracts <testcase> via regex on bad fragments * nl-suite: fix stale classname to UnityMCP.NL-T in mini fallback; prompt: require re-read after every revert; correct PLAN/PROGRESS to 15 * nl-suite: fix fallback JUnit classname to UnityMCP.NL-T; prompt: forbid create_script and env/mkdir checks, enforce single baseline-byte revert flow and post-revert re-read; add corruption-handling guidance * prompts(nl-full): after each write re-read raw bytes to refresh pre_sha; prefer script_apply_edits for anchors; avoid header/using changes * prompts(nl-full): canonicalize outputs to /; allow small fragment appends via Write or Bash(printf/echo); forbid wrappers and full-file round-trips * prompts(nl-full): finalize markdown formatting for guarded write, execution order, specs, status * workflows(nl-suite, mini): header/lint fixes and constrained Bash append path; align allowed_tools * prompts(nl-full): format Fast Restore, Guarded Write, Execution, Specs, Status as proper markdown lists and code fences * workflows(nl-suite): keep header tidy and append-path alignment with prompt * minor fix * workflows(nl-suite): fix indentation and dispatch; align allowed_tools and revert helper * prompts(nl-full): switch to read_resource for buf/sha; re-read only when needed; convert 'Print this once' to heading; note snapshot helper creates parent dirs * workflows(nl-suite): normalize step removes bootstrap when real testcases present; recompute tests/failures * workflows(nl-suite): enrich Markdown summary by extracting per-test <system-out> blocks (truncated) * clarify prompt resilience instructions * ci(nl-suite): revert prompt and workflow to known-good e0f8a72 for green run; remove extra MD details * ci(nl-suite): minimal fixes — no-mkdir guard in prompt; drop bootstrap and recompute JUnit counts * ci(nl-suite): richer JUnit→Markdown report (per-test system-out) * Small guard to incorret asset read call. * ci(nl-suite): refine MD builder — unescape XML entities, safe code fences, PASS/FAIL badges * Update UnityMcpBridge/UnityMcpServer~/src/tools/resource_tools.py Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update UnityMcpBridge/UnityMcpServer~/src/unity_connection.py Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update UnityMcpBridge/UnityMcpServer~/src/tools/manage_script_edits.py Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update .github/scripts/mark_skipped.py Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update .github/scripts/mark_skipped.py Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update .github/scripts/mark_skipped.py Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> * server(manage_script): robust URI handling — percent-decode file://, normalize, strip host/leading slashes, return Assets-relative if present * Update .claude/prompts/nl-unity-suite-full.md Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> * tests(framing): reduce handshake poll window, nonblocking peek to avoid disconnect race; still enforce pre-handshake data drop * tests(manage_script): add _split_uri tests for unity://path, file:// URLs (decoded/Assets-relative), and plain paths * server+tests: fix handshake syntax error; robust file:// URI normalization in manage_script; add _split_uri tests; adjust stdout scan to ignore venv/site-packages * bridge(framing): accept zero-length frames (treat as empty keepalive) * tests(logging): use errors='replace' on decode fallback to avoid silent drops * resources(list): restrict to Assets/, resolve symlinks, enforce .cs; add traversal/outside-path tests * Update .claude/prompts/nl-unity-suite-full.md Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update UnityMcpBridge/UnityMcpServer~/src/unity_connection.py Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * misc: framing keepalive (zero-length), regex preview consistency, resource.list hardening, URI parsing, legacy update routing, test cleanups * docs(tools): richer MCP tool descriptions; tests accept decorator kwargs; resource URI parsing hardened * Update .claude/prompts/nl-unity-suite-full.md Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update UnityMcpBridge/UnityMcpServer~/src/tools/resource_tools.py Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update UnityMcpBridge/UnityMcpServer~/src/unity_connection.py Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * net+docs: hard-reject zero-length frames; TCP_NODELAY on connect; Assets detection case-insensitive; NL prompt statuses aligned * prompt(nl-suite): constrain Write destinations under reports/, forbid traversal * prompt+net: harden Write path rules; use monotonic deadline and plain-text advisory for non-framed peers * unity_connection: restore recv timeout via try/finally; make global connection getter thread-safe with module lock and double-checked init * NL/T prompt: pin structured edit ops for T-D/T-E; add schema-error guarded write behavior; keep existing path/URI and revert rules * unity_connection: add FRAMED_MAX; use ValueError for framed length violations; lower framed receive log to debug; serialize connect() with per-instance lock * ManageScript: use UTF8Encoding(without BOM) for atomic writes in ApplyTextEdits/EditScript to align with Create/Update and avoid BOM-related diffs/hash mismatches * NL/T prompt: make helper deletion regex multiline-safe ((?ms) so ^ anchors line starts) * ManageScript: emit structured overlap status {status:"overlap"} for overlapping edit ranges in apply_text_edits and edit paths * NL/T prompt: clarify fallback vs failure — fallback only for unsupported/missing_field; treat bad_request as failure; note unsupported after fallback as failure * NL/T prompt: pin deterministic overlap probe (apply_text_edits two ranges from same snapshot); gate too_large behind RUN_TOO_LARGE env hint * TB update * NL/T prompt: harden Output Rules — constrain Bash(printf|echo) to stdout-only; forbid redirection/here-docs/tee; only scripts/nlt-revert.sh may mutate FS * Prompt: enumerate allowed script_apply_edits ops; add manage_editor/read_console guidance; fix T‑F atomic batch to single script_apply_edits. ManageScript: regex timeout for diagnostics; symlink ancestor guard; complete allowed-modes list. * Fixes * ManageScript: add rich overlap diagnostics (conflicts + hint) for both text range and structured batch paths * ManageScript: return structured {status:"validation_failed"} diagnostics in create/update/edits and validate before commit * ManageScript: echo canonical uri in responses (create/read/update/apply_text_edits/structured edits) to reinforce resource identity * improve clarity of capabilities message * Framing: allow zero-length frames on both ends (C# bridge, Python server). Prompt: harden T-F to single text-range apply_text_edits batch (descending order, one snapshot). URI: normalize file:// outside Assets by stripping leading slash. * ManageScript: include new sha256 in success payload for apply_text_edits; harden TryResolveUnderAssets by rejecting symlinked ancestors up to Assets/. * remove claudetest dir * manage_script_edits: normalize method-anchored anchor_insert to insert_method (map text->replacement); improves CI compatibility for T‑A/T‑E without changing Editor behavior. * tighten testing protocol around mkdir * manage_script: validate create_script inputs (Assets/.cs/name/no traversal); add Assets/ guard to delete_script; validate level+Assets in validate_script; make legacy manage_script optional params; harden legacy update routing with base64 reuse and payload size preflight. * Tighten prompt for testing * Update .claude/prompts/nl-unity-suite-full.md Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update .claude/prompts/nl-unity-suite-full.md Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update UnityMcpBridge/Editor/Tools/ManageScript.cs Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * manage_script_edits: honor ignore_case on anchor_insert and regex_replace in both direct and text-conversion paths (MULTILINE|IGNORECASE). * remove extra file * workflow: use python3 for inline scripts and port detection on ubuntu-latest. * Tighten prompt + manage_script * Update UnityMcpBridge/UnityMcpServer~/src/tools/manage_script_edits.py Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update UnityMcpBridge/UnityMcpServer~/src/tools/manage_script_edits.py Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update .claude/prompts/nl-unity-suite-full.md Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update UnityMcpBridge/Editor/Tools/ManageScript.cs Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update .claude/prompts/nl-unity-suite-full.md Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * manage_script: improve file:// UNC handling; preserve POSIX absolute semantics internally; keep test-expected slash stripping for non-Assets paths. * ManageScript.cs: add TimeSpan timeouts to all Regex uses (IsMatch/Match/new Regex) and keep CultureInvariant/Multiline options; reduces risk of catastrophic backtracking stalls. * workflow: ensure reports/ exists in markdown build step to avoid FileNotFoundError when writing MD_OUT. * fix brace * manage_script_edits: expand backrefs for regex_replace in preview->text conversion and translate to \g<n> in local apply; keeps previews and actual edits consistent. * anchor_insert: default to position=after, normalize surrounding newlines in Python conversion paths; C# path ensures trailing newline and skips duplicate insertion within class. * feat(mcp): add get_sha tool; apply_text_edits normalization+overlap preflight+strict; no-op evidence in C#; update NL suite prompt; add unit tests * feat(frames): accept zero-length heartbeat frames in client; add heartbeat test * feat(edits): guard destructive regex_replace with structural preflight; add robust tests; prompt uses delete_method for temp helper * feat(frames): bound heartbeat loop with timeout/threshold; align zero-length response with C#; update test * SDK hardening: atomic multi-span text edits; stop forcing sequential for structured ops; forward options on apply_text_edits; add validate=relaxed support and scoped checks; update NL/T prompt; add tests for options forwarding, relaxed mode, and atomic batches * Router: default applyMode=atomic for multi-span apply_text_edits; add tests * CI prompt: pass options.validate=relaxed for T-B/C; options.applyMode=atomic for T-F; emphasize always writing testcase and restoring on errors * Validation & DX: add validate=syntax (scoped), standardize evidence windows; early regex compile with hints; debug_preview for apply_text_edits * Update UnityMcpBridge/Editor/Windows/MCPForUnityEditorWindow.cs Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * NL/T suite-driven edits: LongUnityScriptClaudeTest, bridge helpers, server_version; prepare framing tests * Fix duplicate macConfigPath field in McpClient to resolve CS0102 * Editor threading: run EnsureServerInstalled on main thread; marshal EditorPrefs/DeleteKey + logging via delayCall * Docs(apply_text_edits): strengthen guidance on 1-based positions, verify-before-edit, and recommend anchors/structured edits * Docs(script_apply_edits): add safety guidance (anchors, method ops, validators) and recommended practices * Framed VerifyBridgePing in editor window; docs hardening for apply_text_edits and script_apply_edits --------- Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
2025-08-31 00:55:38 +08:00
// Debounced refresh/compile scheduler to coalesce bursts of edits
static class RefreshDebounce
{
private static int _pending;
private static readonly object _lock = new object();
private static readonly HashSet<string> _paths = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
// The timestamp of the most recent schedule request.
private static DateTime _lastRequest;
// Guard to ensure we only have a single ticking callback running.
private static bool _scheduled;
public static void Schedule(string relPath, TimeSpan window)
{
// Record that work is pending and track the path in a threadsafe way.
Interlocked.Exchange(ref _pending, 1);
lock (_lock)
{
_paths.Add(relPath);
_lastRequest = DateTime.UtcNow;
// If a debounce timer is already scheduled it will pick up the new request.
if (_scheduled)
return;
_scheduled = true;
}
// Kick off a ticking callback that waits until the window has elapsed
// from the last request before performing the refresh.
EditorApplication.delayCall += () => Tick(window);
}
private static void Tick(TimeSpan window)
{
bool ready;
lock (_lock)
{
// Only proceed once the debounce window has fully elapsed.
ready = (DateTime.UtcNow - _lastRequest) >= window;
if (ready)
{
_scheduled = false;
}
}
if (!ready)
{
// Window has not yet elapsed; check again on the next editor tick.
EditorApplication.delayCall += () => Tick(window);
return;
}
if (Interlocked.Exchange(ref _pending, 0) == 1)
{
string[] toImport;
lock (_lock) { toImport = _paths.ToArray(); _paths.Clear(); }
foreach (var p in toImport)
AssetDatabase.ImportAsset(p, ImportAssetOptions.ForceUpdate);
#if UNITY_EDITOR
UnityEditor.Compilation.CompilationPipeline.RequestScriptCompilation();
#endif
// Fallback if needed:
// AssetDatabase.Refresh();
}
}
}
static class ManageScriptRefreshHelpers
{
public static void ScheduleScriptRefresh(string relPath)
{
RefreshDebounce.Schedule(relPath, TimeSpan.FromMilliseconds(200));
}
}