--- name: adapter-development description: Comprehensive guide for AIDB debug adapter development. Covers component-based architecture, language-specific patterns (Python/debugpy, JavaScript/vscode-js-debug, Java/java-debug), lifecycle hooks, process management, port management, launch orchestration, resource cleanup, child sessions, and common pitfalls. Essential for developing or maintaining AIDB debug adapters. --- # AIDB Adapter Development Skill ## Executive Summary AIDB debug adapters provide language-agnostic debugging capabilities through the Debug Adapter Protocol (DAP). The architecture is **component-based** - adapters delegate to specialized components rather than implementing everything in monolithic classes. **For comprehensive architecture details**, see `docs/developer-guide/overview.md` for the complete system architecture and data flow diagrams. ### Core Architecture ``` DebugAdapter (base class) ├── ProcessManager - Process lifecycle (launch, monitor, stop, cleanup) ├── PortManager - Port acquisition, verification, release ├── LaunchOrchestrator - Launch sequence coordination ├── TargetResolver - Target type detection and normalization ├── SourcePathResolver - Source path resolution for remote debugging └── AdapterHooksMixin - Lifecycle hooks for extension points ``` ### Key Principles 1. **Component Delegation**: Adapters delegate to focused components (ProcessManager, PortManager, LaunchOrchestrator) 1. **Lifecycle Hooks**: Customize behavior via hooks rather than overriding entire methods 1. **Resource Management**: Centralized cleanup via ResourceManager 1. **Human-Cadence Debugging**: Operations happen at human speed, not API speed 1. **Language-Agnostic API**: Same Python API works across Python, JavaScript, Java ## Resource Files This skill is organized into focused resource files for language-specific patterns: - **[python-adapter-patterns.md](resources/python-adapter-patterns.md)** - debugpy configuration, module vs script patterns - **[javascript-adapter-patterns.md](resources/javascript-adapter-patterns.md)** - vscode-js-debug, child sessions, Node.js patterns - **[java-adapter-patterns.md](resources/java-adapter-patterns.md)** - java-debug + JDT LS integration, compilation ## Related Skills When working on adapter development, you may also need: - **dap-protocol-guide** - Adapters heavily rely on DAP protocol types and request/response patterns - **testing-strategy** - Adapters must be tested using E2E patterns with DebugInterface abstraction - **code-reuse-enforcement** - Always check for existing utilities before implementing adapter components ## Quick Start: Creating a New Adapter ```python from aidb.adapters.base import DebugAdapter from aidb.adapters.base.config import AdapterConfig class MyLanguageAdapter(DebugAdapter): """My language debug adapter using component architecture.""" def __init__(self, session, ctx=None, config=None, **kwargs): if config is None: config = MyLanguageConfig() super().__init__( session=session, ctx=ctx, config=config, **kwargs ) # Register language-specific hooks self._register_my_language_hooks() def _register_my_language_hooks(self): """Register language-specific lifecycle hooks.""" self.register_hook( LifecycleHook.PRE_LAUNCH, self._validate_environment, priority=90 # High priority = runs first ) async def _validate_environment(self, context: HookContext): """Pre-launch hook to validate environment.""" # Validation logic here pass async def _build_launch_command(self, target, adapter_host, adapter_port, args=None): """Build the command to launch the debug adapter.""" return [ "/path/to/debug/adapter", "--host", adapter_host, "--port", str(adapter_port), target ] def _add_adapter_specific_vars(self, env: dict) -> dict: """Add language-specific environment variables.""" env["MY_LANG_DEBUG"] = "1" return env def _create_target_resolver(self) -> "TargetResolver": """Create language-specific target resolver.""" return MyLanguageTargetResolver(adapter=self, ctx=self.ctx) def _create_source_path_resolver(self) -> "SourcePathResolver": """Create language-specific source path resolver for remote debugging.""" return MyLanguageSourcePathResolver(adapter=self, ctx=self.ctx) def _get_process_name_pattern(self) -> str: """Get process name pattern for cleanup.""" return "my-language-debug" ``` ## Component Access Patterns ### ProcessManager Usage See `ProcessManager` in `src/aidb/adapters/base/components/process_manager.py` for full implementation. ```python from aidb.resources.process_tags import ProcessType # Launch subprocess with session tagging proc = await self._process_manager.launch_subprocess( cmd=cmd, env=env, session_id=self.session.id, language=self.config.language, process_type=ProcessType.ADAPTER, # String constant: "adapter", "debuggee", or "lsp_server" kwargs={} ) # Wait for adapter readiness await self._process_manager.wait_for_adapter_ready(port, start_time) # Get process status if self._process_manager.is_alive: pid = self._process_manager.pid ``` ### PortManager Usage See `PortManager` in `src/aidb/adapters/base/components/port_manager.py` for full implementation. Key methods: - `acquire(requested_port=None)` - Acquire and verify port availability - `release()` - Release the port - `port` property - Get current port ### LaunchOrchestrator Usage See `LaunchOrchestrator` in `src/aidb/adapters/base/components/launch_orchestrator.py` for full implementation. Key methods: - `launch(target, port, args)` - Simple launch with target file - `launch_with_config(launch_config, port, workspace_root)` - Launch with VS Code launch.json configuration ### SourcePathResolver Usage See `SourcePathResolver` in `src/aidb/adapters/base/source_path_resolver.py` for base implementation. Each language adapter implements its own resolver: - **Python**: `src/aidb/adapters/lang/python/source_path_resolver.py` - Handles site-packages, venv, egg paths - **JavaScript**: `src/aidb/adapters/lang/javascript/source_path_resolver.py` - Handles node_modules, webpack paths - **Java**: `src/aidb/adapters/lang/java/source_path_resolver.py` - Handles JAR notation, Maven layouts Key methods: - `extract_relative_path(file_path)` - Extract language-specific relative path from adapter-returned path - `resolve(file_path, source_paths)` - Resolve remote path to local source file ## Lifecycle Hooks Reference Hooks execute in priority order (lower number = runs first): ### Hook Priorities - **90-100**: Critical validation (environment, target file) - **70-80**: Setup/preparation (workspaces, configurations) - **50**: Default priority - **20-30**: Post-operation delays/waits - **10**: Cleanup operations ### Common Hooks ```python # Pre-launch validation self.register_hook( LifecycleHook.PRE_LAUNCH, self._validate_environment, priority=90 ) # Post-launch setup self.register_hook( LifecycleHook.POST_LAUNCH, self._wait_for_ready, priority=20 ) # Post-stop cleanup self.register_hook( LifecycleHook.POST_STOP, self._cleanup_resources, priority=10 ) ``` ## Code Reuse: Existing Utilities Before implementing new functionality, check these shared resources: ### Base Classes - **DebugAdapter** (`aidb/adapters/base/adapter.py`) - Base adapter with component architecture - **AdapterConfig** (`aidb/adapters/base/config.py`) - Configuration base class - **BaseLaunchConfig** (`aidb/adapters/base/launch.py`) - VS Code launch.json support ### Components - **ProcessManager** (`aidb/adapters/base/components/process_manager.py`) - **PortManager** (`aidb/adapters/base/components/port_manager.py`) - **LaunchOrchestrator** (`aidb/adapters/base/components/launch_orchestrator.py`) ### Utilities - **AdapterBinaryLocator** (`aidb/adapters/utils/binary_locator.py`) - Find adapter binaries - **AdapterOutputCapture** (`aidb/adapters/utils/output_capture.py`) - Capture stdout/stderr - **AdapterTraceLogManager** (`aidb/adapters/utils/trace_log.py`) - Trace log management ### Common Patterns (`aidb_common/`) See source code docstrings in `src/aidb_common/` for detailed API documentation. - **Obj** (`aidb_common/patterns/`) - Base class with context support - **normalize_path()** (`aidb_common/path.py`) - Path normalization - **config** (`aidb_common/config/`) - Environment variable reading - **Language** enum (`aidb_common/constants.py`) - Supported language constants ## Launch Configuration Patterns Adapters can support VS Code launch.json configurations: ```python def get_launch_configuration(self) -> dict[str, Any]: """Get launch configuration for DAP Launch request.""" config = { "type": "mylang", "request": "launch", "name": "Debug MyLang", "program": self._target_file, "args": self._target_args, "cwd": self._target_cwd, "env": self._target_env, } return config ``` ## Environment Variable Patterns See `src/aidb_common/env/` for environment handling utilities (reader.py, resolver.py). Use the template method pattern for environment preparation: ```python def _prepare_environment(self) -> dict[str, str]: """Prepare environment (base implementation).""" env = self._load_base_environment() env = self._add_trace_configuration(env) return self._add_adapter_specific_vars(env) def _add_adapter_specific_vars(self, env: dict) -> dict: """Add language-specific variables (override this).""" env["MY_LANG_HOME"] = "/path/to/lang" return env ``` ## Resource Cleanup Patterns Always implement proper cleanup in hooks: ```python async def stop(self) -> None: """Stop the debug adapter and clean up.""" context = await self.execute_hook(LifecycleHook.PRE_STOP) if not context.cancelled: # Stop process manager await self._process_manager.stop() # Release port if self.port: self._port_manager.release() # Cleanup auxiliary components if self._trace_manager: self._trace_manager.cleanup() await self.execute_hook(LifecycleHook.POST_STOP) ``` ## Process Tagging for Orphan Detection All AIDB-spawned processes are tagged with environment variables for safe cleanup: ```python from aidb.resources.process_tags import ProcessType # Automatically handled by ProcessManager proc = await self.process_manager.launch_subprocess( cmd=cmd, env=env, session_id=self.session.id, # Tags process with session ID language=self.config.language, # Tags with language process_type=ProcessType.ADAPTER, # String constant: "adapter", "debuggee", or "lsp_server" kwargs={} ) ``` Tags enable: - Safe orphan detection across sessions - Cleanup of only AIDB-owned processes - Session-to-process mapping ## DAP Protocol Reference The authoritative DAP protocol reference is in `src/aidb/dap/protocol/` - fully typed and always up-to-date. ```python from aidb.dap.protocol.types import ( Capabilities, InitializeRequest, LaunchRequest, SetBreakpointsRequest, ) ``` ## Testing Your Adapter Use the shared test infrastructure: ```python # Test with API directly session = await client.start_session( target="/path/to/file", language="mylang", breakpoints=[{"line": 10}] ) # Test with launch.json session = await client.start_session( target="/path/to/file", language="mylang", launch_config_name="Debug MyLang", workspace_root="/path/to/project" ) ``` ## Navigation to Resource Files For detailed language-specific patterns and examples: 1. **Python Adapter Patterns** → `resources/python-adapter-patterns.md` - debugpy configuration, module vs script patterns, trace logging 1. **JavaScript Adapter Patterns** → `resources/javascript-adapter-patterns.md` - vscode-js-debug, child sessions, Node.js debugging, breakpoint transfer 1. **Java Adapter Patterns** → `resources/java-adapter-patterns.md` - java-debug + JDT LS integration, compilation, pooling patterns ## Important Reminders 1. **Don't override entire methods** - Use lifecycle hooks for customization 1. **Don't manage processes directly** - Use ProcessManager component 1. **Don't handle ports manually** - Use PortManager component 1. **Don't forget cleanup** - Register POST_STOP hooks 1. **Don't block async operations** - Use await for I/O operations 1. **Check existing code first** - Look for reusable utilities before implementing ## File Paths Reference All file paths mentioned in this skill are relative to the repo root: - Base adapter: `src/aidb/adapters/base/adapter.py` - Components: `src/aidb/adapters/base/components/` - SourcePathResolver base: `src/aidb/adapters/base/source_path_resolver.py` - Python adapter: `src/aidb/adapters/lang/python/python.py` - Python source resolver: `src/aidb/adapters/lang/python/source_path_resolver.py` - JavaScript adapter: `src/aidb/adapters/lang/javascript/javascript.py` - JavaScript source resolver: `src/aidb/adapters/lang/javascript/source_path_resolver.py` - Java adapter: `src/aidb/adapters/lang/java/java.py` - Java source resolver: `src/aidb/adapters/lang/java/source_path_resolver.py` - DAP protocol: `src/aidb/dap/protocol/` (types.py, requests.py, responses.py, events.py, bodies.py, base.py)