# Sprint 4b — Editor Power Tools: Combined Specification

## Overview

Implement 4 editor tools that transform GodotIQ from "observer" to "competent developer". After this sprint: **21 MCP tools** total (13 Phase 1 + 4 Sprint 4a bridge + 4 Sprint 4b editor).

**Philosophy**: 1 tool call = complete action + validation + context. The agent says "move this node" and gets back "done, validated, no conflicts" or "blocked, here's why".

## Architecture

```
Sprint 4b tools split into two categories:

BRIDGE TOOLS (editor-side, via WebSocket):
  Tool 1: godotiq_scene_tree (A02) — read live editor scene tree
  Tool 2: godotiq_node_ops (A05) — batch node operations with undo

FILESYSTEM TOOLS (Python-side, no addon needed):
  Tool 3: godotiq_script_ops (A06) — read/write/patch scripts
  Tool 4: godotiq_file_ops (A07) — list/search/read/write files
```

## Files Modified

### GDScript (Godot addon):
- `godot-addon/addons/godotiq/godotiq_server.gd` — add `scene_tree` and `node_ops` handlers
- `godot-addon/addons/godotiq/godotiq_plugin.gd` — wire `undo_redo` reference to server

### Python:
- `src/godotiq/tools/bridge/scene_tree.py` — new: scene_tree implementation
- `src/godotiq/tools/bridge/node_ops.py` — new: node_ops implementation
- `src/godotiq/tools/bridge/script_ops.py` — new: script_ops implementation (filesystem)
- `src/godotiq/tools/bridge/file_ops.py` — new: file_ops implementation (filesystem)
- `src/godotiq/tools/bridge/__init__.py` — register 4 new MCP tools
- `src/godotiq/bridge/protocol.py` — add timeouts for new methods

### Tests:
- `tests/test_bridge/test_scene_tree.py` — new: scene_tree tests
- `tests/test_bridge/test_node_ops.py` — new: node_ops tests
- `tests/test_bridge/test_script_ops.py` — new: script_ops tests
- `tests/test_bridge/test_file_ops.py` — new: file_ops tests

### DO NOT TOUCH:
- `src/godotiq/parsers/` — Phase 1 parsers
- `src/godotiq/tools/code/`, `spatial/`, `animation/`, `assets/`, `memory/` — Phase 1 tools
- `src/godotiq/resolvers/` — Phase 1 resolvers
- `godot-addon/addons/godotiq/godotiq_runtime.gd` — Sprint 4a (game-side only)
- `godot-addon/addons/godotiq/godotiq_debugger.gd` — Sprint 4a
- Existing test files — only ADD new ones

## Tool 1: `godotiq_scene_tree` (A02)

**Purpose**: Read the LIVE editor scene tree with spatial, script, group, and visibility context per node. Different from Phase 1's `scene_map` (which reads .tscn files from disk).

**Runs**: Editor-side (WebSocket → godotiq_server.gd → EditorInterface)

**Parameters**:
- `root`: Node path relative to scene root (empty = entire scene)
- `depth`: Max tree depth (1-10, default 3)
- `filter_type`: Only include nodes of this type (e.g. "Node3D", "Control")
- `include`: Data to include per node. Default: ["transform", "script", "groups", "visibility"]

**Response**: Dict with `root`, `scene_path`, `total_nodes`, `returned_nodes`, `tree` (nested array of node dicts with `n`, `t`, `p`, `r`, `s`, `script`, `groups`, `visible`, `children`/`children_count`)

**GDScript**: Recursive `_walk_tree()` function with depth limit, type filtering, and configurable includes. Uses `EditorInterface.get_edited_scene_root()`.

## Tool 2: `godotiq_node_ops` (A05)

**Purpose**: Batch node operations with EditorUndoRedoManager for Ctrl+Z support. N operations in 1 call, all grouped as one undo action.

**Runs**: Editor-side (WebSocket → godotiq_server.gd → EditorUndoRedoManager)

**Operations**: `move`, `rotate`, `scale`, `set_property`, `add_child`, `delete`, `duplicate`, `reparent`

**Parameters**:
- `operations`: List of operation dicts, each with `op`, `node` (name or path), and operation-specific params

**Response**: Dict with `results` (per-operation status), `scene_modified`, `undo_available`, `action_name`

**GDScript**: Single `_handle_node_ops()` handler that creates one undo action, iterates operations via `_execute_node_op()`, commits. Helper: `_find_node_by_name_or_path()` (tries path first, then recursive name search). Value conversion via `_convert_value()` for JSON → Godot types (Vector3, Vector2, Color).

**Critical**: `undo_redo` reference passed from `plugin.gd` via `_server.undo_redo = get_undo_redo()` in `_enter_tree()`.

## Tool 3: `godotiq_script_ops` (A06)

**Purpose**: Intelligent script reading/writing/patching. Python filesystem tool (no addon needed).

**Modes**: `read`, `write`, `patch` (find-and-replace), `create`

**Parameters**:
- `op`: "read"|"write"|"patch"|"create"
- `path`: File path (res:// or relative)
- `content`: File content (for write/create)
- `patches`: List of {"search", "replace"} dicts (for patch mode)
- `validate_before_write`: Check conventions (default True)
- `auto_fix`: Auto-fix trivial issues (default False)
- `dry_run`: Validate only, don't write (default False)

**Key features**:
- Patch mode requires unique search strings (prevents accidental multiple replacements)
- Protected file checking (project.godot, .godot/, *.import, saves/)
- Basic GDScript validation (type hints, conventions)
- Path resolution from `GODOTIQ_PROJECT_ROOT` env var

## Tool 4: `godotiq_file_ops` (A07)

**Purpose**: Filesystem operations within the Godot project. Python filesystem tool (no addon needed).

**Operations**: `list`, `read`, `write`, `move`, `delete`, `search`, `tree`

**Parameters**:
- `op`: Operation name
- `path`: File or directory path
- `query`: Text search query (for search)
- `filter`: Type filter: scenes, scripts, images, audio, fonts, models, shaders, resources, all
- `recursive`, `context_lines`, `max_depth`, `show_sizes`, `content`, `destination`

**Key features**:
- Type-based filtering (scenes, scripts, images, audio, etc.)
- Search with context lines (grep-like)
- Tree listing with depth control
- Protected file enforcement
- Excludes `.godot`, `.git`, `__pycache__`, etc.

## UndoRedo Integration

The `EditorUndoRedoManager` is accessed via reference from plugin.gd:

```gdscript
# plugin.gd _enter_tree():
_server.undo_redo = get_undo_redo()

# server.gd:
var undo_redo  # set by plugin.gd
```

All node_ops operations use this for undo support:
- `create_action("description")` → add do/undo ops → `commit_action()`
- `add_do_reference()` / `add_undo_reference()` to prevent GC
- Setting `owner = scene_root` after `add_child()` is critical for persistence

## Protocol Additions

New timeouts in `protocol.py`:
```python
"scene_tree": 5.0,
"node_ops": 10.0,
```

## Testing Strategy

Python unit tests with `AsyncMock` for bridge tools:
- Test default params, param validation/clamping
- Test correct bridge request method and params
- Test error handling for BridgeConnectionError, BridgeTimeoutError, BridgeError

For filesystem tools (script_ops, file_ops):
- Test with temp directories and real files
- Test path resolution, protected file checks
- Test each operation mode
- Test edge cases (missing files, binary files, etc.)

GDScript testing is manual via live bridge connection.

## Dependencies

- No new dependencies needed
- `websockets>=14.0` already installed from Sprint 4a
- `mcp>=1.0.0` already installed
