|
| 1 | +# AGENTS.md - Developer Guide for AI Coding Agents |
| 2 | + |
| 3 | +This document provides essential guidelines for AI coding agents working on the Parallax Windows CLI codebase. |
| 4 | + |
| 5 | +## Project Overview |
| 6 | + |
| 7 | +Parallax Windows CLI is a Windows development environment configuration tool written in modern C++ (C++17). It provides automated detection and installation of WSL2, CUDA toolkit, and development tools through an NSIS-built installer. The project uses CMake as its build system and follows modern C++ design patterns including CRTP, Template Method, and Command patterns. |
| 8 | + |
| 9 | +**Platform:** Windows 10 Version 2004+ / Windows 11 |
| 10 | +**Architecture:** x86_64 |
| 11 | +**Language:** C++17 |
| 12 | +**Build System:** CMake 3.6+ |
| 13 | +**Compiler:** MSVC (Visual Studio) |
| 14 | + |
| 15 | +## Build Commands |
| 16 | + |
| 17 | +### Building on Windows (Primary Method) |
| 18 | + |
| 19 | +```bash |
| 20 | +# From the repository root |
| 21 | +cd src/parallax |
| 22 | +cmake -B build -S . -G "Visual Studio 17 2022" -A x64 |
| 23 | +cmake --build build --config Release |
| 24 | + |
| 25 | +# Or use Visual Studio directly after generating project files |
| 26 | +``` |
| 27 | + |
| 28 | +### Build Output |
| 29 | + |
| 30 | +- Binary location: `src/parallax/build/x64/Release/parallax.exe` |
| 31 | +- Log file: `parallax.log` (created in the same directory as the executable) |
| 32 | + |
| 33 | +### Building on Mac/Linux (Docker Cross-Compilation) |
| 34 | + |
| 35 | +**Note:** This is for development/testing only. Production builds should use MSVC on Windows. |
| 36 | + |
| 37 | +```bash |
| 38 | +# From the project root |
| 39 | +cd docker |
| 40 | +./build.sh |
| 41 | + |
| 42 | +# Output: src/parallax/build-mingw/parallax.exe |
| 43 | +``` |
| 44 | + |
| 45 | +See [docker/README.md](docker/README.md) for detailed Docker build instructions. |
| 46 | + |
| 47 | +### Building the Installer |
| 48 | + |
| 49 | +```bash |
| 50 | +# From the installer directory (Windows only) |
| 51 | +cd installer |
| 52 | +.\build-nim.bat |
| 53 | +# Output: installer/Output/Parallax_Setup.exe |
| 54 | +``` |
| 55 | + |
| 56 | +### Common Build Issues |
| 57 | + |
| 58 | +- Ensure MSVC toolchain is installed and in PATH (Windows builds) |
| 59 | +- For Docker builds, ensure Docker is installed and running |
| 60 | +- Unicode definitions are automatically set: `-DUNICODE -D_UNICODE` |
| 61 | +- Windows SDK minimum version: Windows 10 SDK (0x0601) |
| 62 | + |
| 63 | +## Testing |
| 64 | + |
| 65 | +**Note:** This project currently has no automated test suite. Testing is done manually through: |
| 66 | + |
| 67 | +```bash |
| 68 | +# Run environment check |
| 69 | +parallax.exe check |
| 70 | + |
| 71 | +# Run with help to verify commands |
| 72 | +parallax.exe --help |
| 73 | +parallax.exe config --help |
| 74 | +parallax.exe install --help |
| 75 | +``` |
| 76 | + |
| 77 | +When adding new features, manually test all affected commands with various argument combinations. |
| 78 | + |
| 79 | +## Code Style Guidelines |
| 80 | + |
| 81 | +### File Organization |
| 82 | + |
| 83 | +``` |
| 84 | +src/parallax/ |
| 85 | +├── main.cpp # Entry point |
| 86 | +├── cli/ # Command-line interface |
| 87 | +│ ├── command_parser.* # Command parsing and routing |
| 88 | +│ └── commands/ # Individual command implementations |
| 89 | +├── config/ # Configuration management |
| 90 | +├── environment/ # Environment installation components |
| 91 | +├── utils/ # Utility functions |
| 92 | +└── tinylog/ # Logging system |
| 93 | +``` |
| 94 | + |
| 95 | +### Naming Conventions |
| 96 | + |
| 97 | +- **Classes:** PascalCase (e.g., `ConfigManager`, `BaseCommand`) |
| 98 | +- **Functions/Methods:** PascalCase (e.g., `GetInstance()`, `Execute()`) |
| 99 | +- **Variables:** snake*case (e.g., `config_path*`, `stdout_output`) |
| 100 | +- **Constants:** UPPER_SNAKE_CASE (e.g., `KEY_PROXY_URL`, `DEFAULT_CONFIG_PATH`) |
| 101 | +- **Namespaces:** lowercase (e.g., `parallax`, `config`, `utils`, `commands`) |
| 102 | +- **Private members:** Suffix with underscore (e.g., `config_values_`, `mutex_`) |
| 103 | + |
| 104 | +### Header Files |
| 105 | + |
| 106 | +- Always use `#pragma once` for header guards |
| 107 | +- Include order: |
| 108 | + 1. Corresponding header (for .cpp files) |
| 109 | + 2. Standard library headers (`<iostream>`, `<string>`, etc.) |
| 110 | + 3. Windows API headers (`<windows.h>`) |
| 111 | + 4. Project headers (relative paths with quotes) |
| 112 | + |
| 113 | +Example: |
| 114 | + |
| 115 | +```cpp |
| 116 | +#include "config_manager.h" // Corresponding header |
| 117 | +#include <fstream> // Standard library |
| 118 | +#include <string> |
| 119 | +#include <windows.h> // Windows API |
| 120 | +#include "../tinylog/tinylog.h" // Project headers |
| 121 | +#include "../utils/utils.h" |
| 122 | +``` |
| 123 | + |
| 124 | +### Includes in Headers |
| 125 | + |
| 126 | +Minimize includes in headers. Use forward declarations when possible: |
| 127 | + |
| 128 | +```cpp |
| 129 | +// In header: |
| 130 | +namespace parallax { namespace config { class ConfigManager; } } |
| 131 | + |
| 132 | +// In implementation: |
| 133 | +#include "config/config_manager.h" |
| 134 | +``` |
| 135 | +
|
| 136 | +### Namespaces |
| 137 | +
|
| 138 | +All code must be within the `parallax` namespace with appropriate sub-namespaces: |
| 139 | +
|
| 140 | +```cpp |
| 141 | +namespace parallax { |
| 142 | +namespace commands { |
| 143 | +
|
| 144 | +// Code here |
| 145 | +
|
| 146 | +} // namespace commands |
| 147 | +} // namespace parallax |
| 148 | +``` |
| 149 | + |
| 150 | +### Class Design Patterns |
| 151 | + |
| 152 | +#### CRTP (Curiously Recurring Template Pattern) |
| 153 | + |
| 154 | +Used for compile-time polymorphism with zero runtime overhead: |
| 155 | + |
| 156 | +```cpp |
| 157 | +template <typename Derived> |
| 158 | +class BaseCommand : public ICommand { |
| 159 | +public: |
| 160 | + CommandResult Execute(const std::vector<std::string>& args) override final { |
| 161 | + // ... |
| 162 | + return static_cast<Derived*>(this)->ExecuteImpl(context); |
| 163 | + } |
| 164 | +}; |
| 165 | + |
| 166 | +class CheckCommand : public AdminCommand<CheckCommand> { |
| 167 | + CommandResult ExecuteImpl(const CommandContext& context) { |
| 168 | + // Implementation |
| 169 | + } |
| 170 | +}; |
| 171 | +``` |
| 172 | +
|
| 173 | +#### Template Method Pattern |
| 174 | +
|
| 175 | +Define execution flow in base class, specific implementation in derived: |
| 176 | +
|
| 177 | +```cpp |
| 178 | +// Base class defines the template: |
| 179 | +// 1. ValidateArgs → 2. PrepareEnvironment → 3. ExecuteImpl |
| 180 | +
|
| 181 | +// Derived classes override: |
| 182 | +CommandResult ValidateArgsImpl(CommandContext& context) override; |
| 183 | +CommandResult ExecuteImpl(const CommandContext& context) override; |
| 184 | +void ShowHelpImpl() override; |
| 185 | +``` |
| 186 | + |
| 187 | +### Error Handling |
| 188 | + |
| 189 | +- Use exceptions sparingly; prefer return codes (`CommandResult` enum) |
| 190 | +- Always log errors with `error_log()` before returning error codes |
| 191 | +- Check return values from Windows API calls |
| 192 | +- Provide user-friendly error messages to console via `ShowError()` |
| 193 | + |
| 194 | +```cpp |
| 195 | +if (!result) { |
| 196 | + error_log("Failed to execute command: %s", error_msg.c_str()); |
| 197 | + ShowError("Command execution failed. Check logs for details."); |
| 198 | + return CommandResult::ExecutionError; |
| 199 | +} |
| 200 | +``` |
| 201 | + |
| 202 | +### Logging |
| 203 | + |
| 204 | +Use the tinylog system for all logging: |
| 205 | + |
| 206 | +```cpp |
| 207 | +#include "tinylog/tinylog.h" |
| 208 | + |
| 209 | +debug_log("Debug information: %s", debug_info.c_str()); |
| 210 | +info_log("Operation started: %s", operation.c_str()); |
| 211 | +warn_log("Warning: %s", warning_msg.c_str()); |
| 212 | +error_log("Error occurred: %s", error_msg.c_str()); |
| 213 | +crit_log("Critical failure: %s", critical_msg.c_str()); |
| 214 | +``` |
| 215 | +
|
| 216 | +Log levels: |
| 217 | +
|
| 218 | +- `debug_log`: Verbose debugging information |
| 219 | +- `info_log`: General information about program execution |
| 220 | +- `warn_log`: Warning messages that don't prevent execution |
| 221 | +- `error_log`: Error conditions that affect functionality |
| 222 | +- `crit_log`: Critical failures requiring immediate attention |
| 223 | +
|
| 224 | +### Comments and Documentation |
| 225 | +
|
| 226 | +- Use `/** ... */` for public API documentation |
| 227 | +- Use `//` for inline comments |
| 228 | +- Document complex algorithms and non-obvious code |
| 229 | +- Include parameter descriptions for non-trivial functions |
| 230 | +
|
| 231 | +```cpp |
| 232 | +/** |
| 233 | + * @brief Execute command line and get output result (synchronous version) |
| 234 | + * |
| 235 | + * @param cmd Command to execute |
| 236 | + * @param timeout Timeout in seconds |
| 237 | + * @param stdout_output Standard output content |
| 238 | + * @param stderr_output Standard error output content |
| 239 | + * @return Command execution return code, <0 indicates execution failure |
| 240 | + */ |
| 241 | +int ExecCommandEx(const std::string& cmd, int timeout, |
| 242 | + std::string& stdout_output, std::string& stderr_output); |
| 243 | +``` |
| 244 | + |
| 245 | +### Memory Management |
| 246 | + |
| 247 | +- Prefer stack allocation over heap when possible |
| 248 | +- Use smart pointers (`std::unique_ptr`, `std::shared_ptr`) for dynamic allocation |
| 249 | +- Avoid raw `new`/`delete` |
| 250 | +- Use RAII for resource management |
| 251 | + |
| 252 | +### String Handling |
| 253 | + |
| 254 | +Be mindful of Windows encoding issues: |
| 255 | + |
| 256 | +```cpp |
| 257 | +// Use utility functions for encoding conversion |
| 258 | +std::string utf8_str = UnicodeToUtf8(wide_str); |
| 259 | +std::wstring wide_str = Utf8ToUnicode(utf8_str); |
| 260 | + |
| 261 | +// PowerShell output requires special handling |
| 262 | +std::string converted = ConvertPowerShellOutputToUtf8(raw_output); |
| 263 | +``` |
| 264 | + |
| 265 | +### Constants and Configuration |
| 266 | + |
| 267 | +- Define configuration keys as constants in `config_manager.h`: |
| 268 | + ```cpp |
| 269 | + extern const std::string KEY_PROXY_URL; |
| 270 | + ``` |
| 271 | +- Initialize in `config_manager.cpp`: |
| 272 | + ```cpp |
| 273 | + const std::string KEY_PROXY_URL = "proxy_url"; |
| 274 | + ``` |
| 275 | + |
| 276 | +## Adding New Commands |
| 277 | + |
| 278 | +To add a new command: |
| 279 | + |
| 280 | +1. Create header/source files in `src/parallax/cli/commands/` |
| 281 | +2. Inherit from appropriate base class (`BaseCommand`, `AdminCommand`, `WSLCommand`) |
| 282 | +3. Implement required methods: `ValidateArgsImpl()`, `ExecuteImpl()`, `ShowHelpImpl()` |
| 283 | +4. Register command in `command_parser.cpp` |
| 284 | +5. Add files to `CMakeLists.txt` in appropriate group |
| 285 | +6. Update README.md with command documentation |
| 286 | + |
| 287 | +## Common Pitfalls |
| 288 | + |
| 289 | +- **Encoding Issues:** Always convert PowerShell/WSL output using utility functions |
| 290 | +- **Administrator Privileges:** Use `IsAdmin()` check for operations requiring elevation |
| 291 | +- **WSL Integration:** Use `BuildWSLCommand()` helpers for proper WSL command construction |
| 292 | +- **Thread Safety:** Use `std::lock_guard` for shared resources (e.g., ConfigManager) |
| 293 | +- **Resource Cleanup:** Ensure proper cleanup in destructors and error paths |
| 294 | +- **Unicode:** All strings should be UTF-8 internally; convert at boundaries |
| 295 | + |
| 296 | +## Useful Utilities |
| 297 | + |
| 298 | +```cpp |
| 299 | +// Path operations |
| 300 | +std::string exe_dir = parallax::utils::GetAppBinDir(); |
| 301 | +std::string path = parallax::utils::JoinPath(dir, filename); |
| 302 | + |
| 303 | +// Admin check |
| 304 | +bool is_admin = parallax::utils::IsAdmin(); |
| 305 | + |
| 306 | +// Process execution |
| 307 | +int result = parallax::utils::ExecCommandEx(cmd, timeout, stdout_out, stderr_out); |
| 308 | + |
| 309 | +// Configuration access |
| 310 | +auto& config = parallax::config::ConfigManager::GetInstance(); |
| 311 | +std::string value = config.GetConfigValue(KEY_PROXY_URL); |
| 312 | +``` |
| 313 | + |
| 314 | +## Project Structure Notes |
| 315 | + |
| 316 | +- CMake files in `common_make/` define compilation/linking properties |
| 317 | +- NSIS installer scripts in `installer/SetupScripts/` |
| 318 | +- Split large source files into parts (e.g., `windows_feature_manager.cpp` and `windows_feature_manager2.cpp`) |
| 319 | +- Group related functionality using `source_group()` in CMakeLists for Visual Studio organization |
| 320 | + |
| 321 | +## Additional Resources |
| 322 | + |
| 323 | +- README.md: User-facing documentation and feature overview |
| 324 | +- CHANGELOG.md: Track all changes following semantic versioning |
| 325 | +- LICENSE: Apache 2.0 license |
0 commit comments