# Refactoring Notes ## Architecture Reference: debugger-cli The `debugger-cli` project at `~/git/debugger-cli` provides a good pattern for daemon-based CLIs: ### Key Patterns Used 1. **IPC via Local Sockets** (`src/ipc/`) - Uses `interprocess` crate for cross-platform Unix sockets / Windows named pipes - Length-prefixed JSON messages (4-byte little-endian length + payload) - Separate `protocol.rs`, `transport.rs`, and `client.rs` modules 2. **Daemon Architecture** (`src/daemon/`) - `server.rs` - Main event loop with IPC listener - `handler.rs` - Command routing and execution - `session.rs` - State management for debug sessions 3. **Clean Separation** - IPC protocol defines its own `Command` enum (not reusing CLI args) - Handler translates protocol commands to domain operations - Session holds the actual debug adapter connection --- ## Implementation Progress ### Phase 1: Bridge Script ✅ - Created `src/ghidra/scripts/bridge.py` - persistent TCP server inside Ghidra - Implements handlers: `ping`, `program_info`, `list_functions`, `decompile`, `list_strings`, `list_imports`, `list_exports`, `memory_map`, `xrefs_to`, `xrefs_from` - Uses `---GHIDRA_CLI_START---` / `---GHIDRA_CLI_END---` markers for ready signal ### Phase 2: Output Markers ✅ - Updated all 8 Python scripts in `scripts.rs` with delimiters - Updated `headless.rs` to use marker-based extraction instead of fragile brace-counting ### Phase 3: IPC Layer ✅ - Added `interprocess` crate to `Cargo.toml` - Created `src/ipc/mod.rs` with: - `protocol.rs` - Typed `Command` enum, `Request`, `Response` structures - `transport.rs` - Cross-platform socket wrapper with length-prefixed framing - `client.rs` - `DaemonClient` for CLI-to-daemon communication ### Phase 4: Bridge Manager ✅ - Created `src/ghidra/bridge.rs` with `GhidraBridge` struct - Manages Ghidra process lifecycle (spawn, monitor, shutdown) - TCP connection to Python bridge script - `BridgeResponse` typed response handling - Embeds bridge.py via `include_str!` macro ### Phase 5: Daemon Update 🚧 - Status: Not yet wired up - Remaining: Refactor daemon to use new IPC layer and bridge ### Phase 6: Typed Responses ⚙️ - `BridgeResponse` created in `bridge.rs` - Remaining: Update all response handling ### Phase 7: GUI Integration (Optional) - Status: Not started - Future work --- ## Files Created/Modified ### New Files - `src/ghidra/scripts/bridge.py` - Persistent Python bridge server - `src/ghidra/bridge.rs` - Rust bridge manager - `src/ipc/mod.rs` - IPC module root - `src/ipc/protocol.rs` - Typed protocol definitions - `src/ipc/transport.rs` - Socket transport layer - `src/ipc/client.rs` - Daemon client ### Modified Files - `Cargo.toml` - Added `interprocess` crate - `src/main.rs` - Added `mod ipc` - `src/ghidra/mod.rs` - Added `mod bridge`, `#[derive(Debug)]` on `GhidraClient` - `src/ghidra/scripts.rs` - All scripts now have output markers - `src/ghidra/headless.rs` - Marker-based JSON extraction --- ## Remaining Work To complete the refactoring: 1. **Wire up bridge to daemon** - Modify `daemon/mod.rs` to hold `GhidraBridge` 2. **Route commands through bridge** - Update `daemon/queue.rs` to use bridge instead of spawning headless 3. **Switch to IPC layer** - Replace TCP RPC with local socket IPC 4. **Remove one-shot execution** - Clean up legacy headless spawning code 5. **Manual testing** - Test with actual Ghidra installation --- ## Build Status ``` ✅ cargo check - PASSED ✅ cargo test - 30 passed, 1 pre-existing failure (test_parse_hex) ```