This document provides essential guidelines for AI coding agents working on the Parallax Windows CLI codebase.
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.
Platform: Windows 10 Version 2004+ / Windows 11
Architecture: x86_64
Language: C++17
Build System: CMake 3.6+
Compiler: MSVC (Visual Studio)
# From the repository root
cd src/parallax
cmake -B build -S . -G "Visual Studio 17 2022" -A x64
cmake --build build --config Release
# Or use Visual Studio directly after generating project files- Binary location:
src/parallax/build/x64/Release/parallax.exe - Log file:
parallax.log(created in the same directory as the executable)
Note: This is for development/testing only. Production builds should use MSVC on Windows.
# From the project root
cd docker
./build.sh
# Output: src/parallax/build-mingw/parallax.exeSee docker/README.md for detailed Docker build instructions.
# From the installer directory (Windows only)
cd installer
.\build-nim.bat
# Output: installer/Output/Parallax_Setup.exe- Ensure MSVC toolchain is installed and in PATH (Windows builds)
- For Docker builds, ensure Docker is installed and running
- Unicode definitions are automatically set:
-DUNICODE -D_UNICODE - Windows SDK minimum version: Windows 10 SDK (0x0601)
Note: This project currently has no automated test suite. Testing is done manually through:
# Run environment check
parallax.exe check
# Run with help to verify commands
parallax.exe --help
parallax.exe config --help
parallax.exe install --helpWhen adding new features, manually test all affected commands with various argument combinations.
src/parallax/
├── main.cpp # Entry point
├── cli/ # Command-line interface
│ ├── command_parser.* # Command parsing and routing
│ └── commands/ # Individual command implementations
├── config/ # Configuration management
├── environment/ # Environment installation components
├── utils/ # Utility functions
└── tinylog/ # Logging system
- Classes: PascalCase (e.g.,
ConfigManager,BaseCommand) - Functions/Methods: PascalCase (e.g.,
GetInstance(),Execute()) - Variables: snake*case (e.g.,
config_path*,stdout_output) - Constants: UPPER_SNAKE_CASE (e.g.,
KEY_PROXY_URL,DEFAULT_CONFIG_PATH) - Namespaces: lowercase (e.g.,
parallax,config,utils,commands) - Private members: Suffix with underscore (e.g.,
config_values_,mutex_)
- Always use
#pragma oncefor header guards - Include order:
- Corresponding header (for .cpp files)
- Standard library headers (
<iostream>,<string>, etc.) - Windows API headers (
<windows.h>) - Project headers (relative paths with quotes)
Example:
#include "config_manager.h" // Corresponding header
#include <fstream> // Standard library
#include <string>
#include <windows.h> // Windows API
#include "../tinylog/tinylog.h" // Project headers
#include "../utils/utils.h"Minimize includes in headers. Use forward declarations when possible:
// In header:
namespace parallax { namespace config { class ConfigManager; } }
// In implementation:
#include "config/config_manager.h"All code must be within the parallax namespace with appropriate sub-namespaces:
namespace parallax {
namespace commands {
// Code here
} // namespace commands
} // namespace parallaxUsed for compile-time polymorphism with zero runtime overhead:
template <typename Derived>
class BaseCommand : public ICommand {
public:
CommandResult Execute(const std::vector<std::string>& args) override final {
// ...
return static_cast<Derived*>(this)->ExecuteImpl(context);
}
};
class CheckCommand : public AdminCommand<CheckCommand> {
CommandResult ExecuteImpl(const CommandContext& context) {
// Implementation
}
};Define execution flow in base class, specific implementation in derived:
// Base class defines the template:
// 1. ValidateArgs → 2. PrepareEnvironment → 3. ExecuteImpl
// Derived classes override:
CommandResult ValidateArgsImpl(CommandContext& context) override;
CommandResult ExecuteImpl(const CommandContext& context) override;
void ShowHelpImpl() override;- Use exceptions sparingly; prefer return codes (
CommandResultenum) - Always log errors with
error_log()before returning error codes - Check return values from Windows API calls
- Provide user-friendly error messages to console via
ShowError()
if (!result) {
error_log("Failed to execute command: %s", error_msg.c_str());
ShowError("Command execution failed. Check logs for details.");
return CommandResult::ExecutionError;
}Use the tinylog system for all logging:
#include "tinylog/tinylog.h"
debug_log("Debug information: %s", debug_info.c_str());
info_log("Operation started: %s", operation.c_str());
warn_log("Warning: %s", warning_msg.c_str());
error_log("Error occurred: %s", error_msg.c_str());
crit_log("Critical failure: %s", critical_msg.c_str());Log levels:
debug_log: Verbose debugging informationinfo_log: General information about program executionwarn_log: Warning messages that don't prevent executionerror_log: Error conditions that affect functionalitycrit_log: Critical failures requiring immediate attention
- Use
/** ... */for public API documentation - Use
//for inline comments - Document complex algorithms and non-obvious code
- Include parameter descriptions for non-trivial functions
/**
* @brief Execute command line and get output result (synchronous version)
*
* @param cmd Command to execute
* @param timeout Timeout in seconds
* @param stdout_output Standard output content
* @param stderr_output Standard error output content
* @return Command execution return code, <0 indicates execution failure
*/
int ExecCommandEx(const std::string& cmd, int timeout,
std::string& stdout_output, std::string& stderr_output);- Prefer stack allocation over heap when possible
- Use smart pointers (
std::unique_ptr,std::shared_ptr) for dynamic allocation - Avoid raw
new/delete - Use RAII for resource management
Be mindful of Windows encoding issues:
// Use utility functions for encoding conversion
std::string utf8_str = UnicodeToUtf8(wide_str);
std::wstring wide_str = Utf8ToUnicode(utf8_str);
// PowerShell output requires special handling
std::string converted = ConvertPowerShellOutputToUtf8(raw_output);- Define configuration keys as constants in
config_manager.h:extern const std::string KEY_PROXY_URL;
- Initialize in
config_manager.cpp:const std::string KEY_PROXY_URL = "proxy_url";
To add a new command:
- Create header/source files in
src/parallax/cli/commands/ - Inherit from appropriate base class (
BaseCommand,AdminCommand,WSLCommand) - Implement required methods:
ValidateArgsImpl(),ExecuteImpl(),ShowHelpImpl() - Register command in
command_parser.cpp - Add files to
CMakeLists.txtin appropriate group - Update README.md with command documentation
- Encoding Issues: Always convert PowerShell/WSL output using utility functions
- Administrator Privileges: Use
IsAdmin()check for operations requiring elevation - WSL Integration: Use
BuildWSLCommand()helpers for proper WSL command construction - Thread Safety: Use
std::lock_guardfor shared resources (e.g., ConfigManager) - Resource Cleanup: Ensure proper cleanup in destructors and error paths
- Unicode: All strings should be UTF-8 internally; convert at boundaries
// Path operations
std::string exe_dir = parallax::utils::GetAppBinDir();
std::string path = parallax::utils::JoinPath(dir, filename);
// Admin check
bool is_admin = parallax::utils::IsAdmin();
// Process execution
int result = parallax::utils::ExecCommandEx(cmd, timeout, stdout_out, stderr_out);
// Configuration access
auto& config = parallax::config::ConfigManager::GetInstance();
std::string value = config.GetConfigValue(KEY_PROXY_URL);- CMake files in
common_make/define compilation/linking properties - NSIS installer scripts in
installer/SetupScripts/ - Split large source files into parts (e.g.,
windows_feature_manager.cppandwindows_feature_manager2.cpp) - Group related functionality using
source_group()in CMakeLists for Visual Studio organization
- README.md: User-facing documentation and feature overview
- CHANGELOG.md: Track all changes following semantic versioning
- LICENSE: Apache 2.0 license