Class: Aidp::Config
- Inherits:
-
Object
- Object
- Aidp::Config
- Defined in:
- lib/aidp/config.rb
Overview
Configuration management for both execute and analyze modes
Constant Summary collapse
- DEFAULT_HARNESS_CONFIG =
Default configuration for harness
{ harness: { max_retries: 2, default_provider: "cursor", fallback_providers: ["cursor"], no_api_keys_required: false, provider_weights: { "cursor" => 3, "anthropic" => 2 }, circuit_breaker: { enabled: true, failure_threshold: 5, timeout: 300, half_open_max_calls: 3 }, retry: { enabled: true, max_attempts: 3, base_delay: 1.0, max_delay: 60.0, exponential_base: 2.0, jitter: true }, rate_limit: { enabled: true, default_reset_time: 3600, burst_limit: 10, sustained_limit: 5 }, load_balancing: { enabled: true, strategy: "weighted_round_robin", health_check_interval: 30, unhealthy_threshold: 3 }, model_switching: { enabled: true, auto_switch_on_error: true, auto_switch_on_rate_limit: true, fallback_strategy: "sequential" }, health_check: { enabled: true, interval: 60, timeout: 10, failure_threshold: 3, success_threshold: 2 }, metrics: { enabled: true, retention_days: 30, aggregation_interval: 300, export_interval: 3600 }, session: { enabled: true, timeout: 1800, sticky_sessions: true, session_affinity: "provider_model" } }, providers: { cursor: { type: "subscription", priority: 1, model_family: "auto", default_flags: [], models: ["cursor-default", "cursor-fast", "cursor-precise"], model_weights: { "cursor-default" => 3, "cursor-fast" => 2, "cursor-precise" => 1 }, models_config: { "cursor-default" => { flags: [], timeout: 600 }, "cursor-fast" => { flags: ["--fast"], timeout: 300 }, "cursor-precise" => { flags: ["--precise"], timeout: 900 } }, features: { file_upload: true, code_generation: true, analysis: true }, monitoring: { enabled: true, metrics_interval: 60 } }, anthropic: { type: "usage_based", priority: 2, model_family: "claude", max_tokens: 100_000, default_flags: ["--dangerously-skip-permissions"], models: ["claude-3-5-sonnet-20241022", "claude-3-5-haiku-20241022"], model_weights: { "claude-3-5-sonnet-20241022" => 3, "claude-3-5-haiku-20241022" => 2 }, models_config: { "claude-3-5-sonnet-20241022" => { flags: ["--dangerously-skip-permissions"], max_tokens: 200_000, timeout: 300 }, "claude-3-5-haiku-20241022" => { flags: ["--dangerously-skip-permissions"], max_tokens: 200_000, timeout: 180 } }, auth: { api_key_env: "ANTHROPIC_API_KEY" }, endpoints: { default: "https://api.anthropic.com/v1/messages" }, features: { file_upload: true, code_generation: true, analysis: true, vision: true }, monitoring: { enabled: true, metrics_interval: 60 } } }, skills: { search_paths: [], default_provider_filter: true, enable_custom_skills: true }, waterfall: { enabled: true, docs_directory: ".aidp/docs", generate_decisions_md: true, gantt_format: "mermaid", wbs_phases: [ "Requirements", "Design", "Implementation", "Testing", "Deployment" ], effort_estimation: { method: "llm_relative", units: "story_points" }, persona_assignment: { method: "zfc_automatic", allow_parallel: true } }, evaluations: { enabled: true, prompt_after_work_loop: false, capture_full_context: true, directory: ".aidp/evaluations" }, security: { rule_of_two: { enabled: true, policy: "strict" # strict or relaxed }, secrets_proxy: { enabled: true, token_ttl: 300 # seconds }, watch_mode: { max_retry_attempts: 3, fail_forward_enabled: true, needs_input_label: "aidp-needs-input" } }, watch: { enabled: false, polling_interval: 30, labels: { plan_trigger: "aidp-plan", build_trigger: "aidp-build", review_trigger: "aidp-review", fix_ci_trigger: "aidp-fix-ci", change_request_trigger: "aidp-request-changes", auto_trigger: "aidp-auto", parent_pr: "aidp-parent-pr", sub_pr: "aidp-sub-pr" }, projects: { enabled: false, default_project_id: nil, field_mappings: { status: "Status", priority: "Priority", skills: "Skills", personas: "Personas", blocking: "Blocking" }, auto_create_fields: true, sync_interval: 60, default_status_values: ["Backlog", "Todo", "In Progress", "In Review", "Done"], default_priority_values: ["Low", "Medium", "High", "Critical"] }, auto_merge: { enabled: true, sub_issue_prs_only: true, require_ci_success: true, require_reviews: 0, merge_method: "squash", delete_branch: true } } }.freeze
Class Method Summary collapse
-
.agile_config(project_dir = Dir.pwd) ⇒ Object
Get agile configuration.
- .aidp_dir(project_dir = Dir.pwd) ⇒ Object
- .config_dir(project_dir = Dir.pwd) ⇒ Object
-
.config_exists?(project_dir = Dir.pwd) ⇒ Boolean
Check if configuration file exists.
-
.config_file(project_dir = Dir.pwd) ⇒ Object
Expose path methods for convenience.
-
.configured_providers(project_dir = Dir.pwd) ⇒ Object
Get all configured providers.
-
.create_example_config(project_dir = Dir.pwd) ⇒ Object
Create example configuration file.
-
.evaluations_config(project_dir = Dir.pwd) ⇒ Object
Get evaluations configuration.
-
.harness_config(project_dir = Dir.pwd) ⇒ Object
Get harness configuration.
- .load(project_dir = Dir.pwd) ⇒ Object
-
.load_harness_config(project_dir = Dir.pwd) ⇒ Object
Load harness configuration with defaults.
-
.provider_config(provider_name, project_dir = Dir.pwd) ⇒ Object
Get provider configuration.
-
.rule_of_two_enabled?(project_dir = Dir.pwd) ⇒ Boolean
Check if Rule of Two enforcement is enabled.
-
.secrets_proxy_enabled?(project_dir = Dir.pwd) ⇒ Boolean
Check if Secrets Proxy is enabled.
-
.security_config(project_dir = Dir.pwd) ⇒ Object
Get security configuration.
-
.skills_config(project_dir = Dir.pwd) ⇒ Object
Get skills configuration.
-
.tool_metadata_config(project_dir = Dir.pwd) ⇒ Object
Get tool metadata configuration.
-
.validate_harness_config(config, project_dir = Dir.pwd) ⇒ Object
Validate harness configuration.
-
.waterfall_config(project_dir = Dir.pwd) ⇒ Object
Get waterfall configuration.
Class Method Details
.agile_config(project_dir = Dir.pwd) ⇒ Object
Get agile configuration
331 332 333 334 335 336 337 |
# File 'lib/aidp/config.rb', line 331 def self.agile_config(project_dir = Dir.pwd) config = load_harness_config(project_dir) agile_section = config[:agile] || config["agile"] || {} # Convert string keys to symbols for consistency symbolize_keys(agile_section) end |
.aidp_dir(project_dir = Dir.pwd) ⇒ Object
439 440 441 |
# File 'lib/aidp/config.rb', line 439 def self.aidp_dir(project_dir = Dir.pwd) ConfigPaths.aidp_dir(project_dir) end |
.config_dir(project_dir = Dir.pwd) ⇒ Object
435 436 437 |
# File 'lib/aidp/config.rb', line 435 def self.config_dir(project_dir = Dir.pwd) ConfigPaths.config_dir(project_dir) end |
.config_exists?(project_dir = Dir.pwd) ⇒ Boolean
Check if configuration file exists
381 382 383 |
# File 'lib/aidp/config.rb', line 381 def self.config_exists?(project_dir = Dir.pwd) ConfigPaths.config_exists?(project_dir) end |
.config_file(project_dir = Dir.pwd) ⇒ Object
Expose path methods for convenience
431 432 433 |
# File 'lib/aidp/config.rb', line 431 def self.config_file(project_dir = Dir.pwd) ConfigPaths.config_file(project_dir) end |
.configured_providers(project_dir = Dir.pwd) ⇒ Object
Get all configured providers
306 307 308 309 310 |
# File 'lib/aidp/config.rb', line 306 def self.configured_providers(project_dir = Dir.pwd) config = load_harness_config(project_dir) providers_section = config[:providers] || config["providers"] || {} providers_section.keys.map(&:to_s) end |
.create_example_config(project_dir = Dir.pwd) ⇒ Object
Create example configuration file
386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 |
# File 'lib/aidp/config.rb', line 386 def self.create_example_config(project_dir = Dir.pwd) config_path = ConfigPaths.config_file(project_dir) return false if File.exist?(config_path) ConfigPaths.ensure_config_dir(project_dir) example_config = { harness: { max_retries: 2, default_provider: "cursor", fallback_providers: ["cursor"], no_api_keys_required: false }, providers: { cursor: { type: "subscription", default_flags: [] }, claude: { type: "usage_based", max_tokens: 100_000, default_flags: ["--dangerously-skip-permissions"] }, gemini: { type: "usage_based", max_tokens: 50_000, default_flags: [] } }, agile: { mvp_first: true, feedback_loops: true, auto_iteration: false, research_enabled: true, marketing_enabled: true, legacy_analysis: true, personas: ["product_manager", "ux_researcher", "architect", "senior_developer", "qa_engineer", "devops_engineer", "tech_writer", "marketing_strategist"] } } File.write(config_path, YAML.dump(example_config)) true end |
.evaluations_config(project_dir = Dir.pwd) ⇒ Object
Get evaluations configuration
349 350 351 352 353 354 355 |
# File 'lib/aidp/config.rb', line 349 def self.evaluations_config(project_dir = Dir.pwd) config = load_harness_config(project_dir) evaluations_section = config[:evaluations] || config["evaluations"] || {} # Convert string keys to symbols for consistency symbolize_keys(evaluations_section) end |
.harness_config(project_dir = Dir.pwd) ⇒ Object
Get harness configuration
288 289 290 291 292 293 294 |
# File 'lib/aidp/config.rb', line 288 def self.harness_config(project_dir = Dir.pwd) config = load_harness_config(project_dir) harness_section = config[:harness] || config["harness"] || {} # Convert string keys to symbols for consistency symbolize_keys(harness_section) end |
.load(project_dir = Dir.pwd) ⇒ Object
234 235 236 237 238 239 240 241 242 |
# File 'lib/aidp/config.rb', line 234 def self.load(project_dir = Dir.pwd) config_file = ConfigPaths.config_file(project_dir) if File.exist?(config_file) load_yaml_config(config_file) else {} end end |
.load_harness_config(project_dir = Dir.pwd) ⇒ Object
Load harness configuration with defaults
245 246 247 248 |
# File 'lib/aidp/config.rb', line 245 def self.load_harness_config(project_dir = Dir.pwd) config = load(project_dir) merge_harness_defaults(config) end |
.provider_config(provider_name, project_dir = Dir.pwd) ⇒ Object
Get provider configuration
297 298 299 300 301 302 303 |
# File 'lib/aidp/config.rb', line 297 def self.provider_config(provider_name, project_dir = Dir.pwd) config = load_harness_config(project_dir) providers_section = config[:providers] || config["providers"] || {} provider_config = providers_section[provider_name.to_s] || providers_section[provider_name.to_sym] || {} symbolize_keys(provider_config) end |
.rule_of_two_enabled?(project_dir = Dir.pwd) ⇒ Boolean
Check if Rule of Two enforcement is enabled
367 368 369 370 371 |
# File 'lib/aidp/config.rb', line 367 def self.rule_of_two_enabled?(project_dir = Dir.pwd) sec_config = security_config(project_dir) rule_of_two = sec_config[:rule_of_two] || {} rule_of_two.fetch(:enabled, true) end |
.secrets_proxy_enabled?(project_dir = Dir.pwd) ⇒ Boolean
Check if Secrets Proxy is enabled
374 375 376 377 378 |
# File 'lib/aidp/config.rb', line 374 def self.secrets_proxy_enabled?(project_dir = Dir.pwd) sec_config = security_config(project_dir) proxy_config = sec_config[:secrets_proxy] || {} proxy_config.fetch(:enabled, true) end |
.security_config(project_dir = Dir.pwd) ⇒ Object
Get security configuration
358 359 360 361 362 363 364 |
# File 'lib/aidp/config.rb', line 358 def self.security_config(project_dir = Dir.pwd) config = load_harness_config(project_dir) security_section = config[:security] || config["security"] || {} # Convert string keys to symbols for consistency symbolize_keys(security_section) end |
.skills_config(project_dir = Dir.pwd) ⇒ Object
Get skills configuration
313 314 315 316 317 318 319 |
# File 'lib/aidp/config.rb', line 313 def self.skills_config(project_dir = Dir.pwd) config = load_harness_config(project_dir) skills_section = config[:skills] || config["skills"] || {} # Convert string keys to symbols for consistency symbolize_keys(skills_section) end |
.tool_metadata_config(project_dir = Dir.pwd) ⇒ Object
Get tool metadata configuration
340 341 342 343 344 345 346 |
# File 'lib/aidp/config.rb', line 340 def self.(project_dir = Dir.pwd) config = load_harness_config(project_dir) = config[:tool_metadata] || config["tool_metadata"] || {} # Convert string keys to symbols for consistency symbolize_keys() end |
.validate_harness_config(config, project_dir = Dir.pwd) ⇒ Object
Validate harness configuration
251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 |
# File 'lib/aidp/config.rb', line 251 def self.validate_harness_config(config, project_dir = Dir.pwd) errors = [] # Validate harness section (check the merged config, not original) harness_config = config[:harness] || config["harness"] if harness_config unless harness_config[:default_provider] || harness_config["default_provider"] errors << "Default provider not specified in harness config" end end # Validate providers section using config_validator # Only validate providers that exist in the original YAML file, not merged defaults original_config = load(project_dir) original_providers = original_config[:providers] || original_config["providers"] if original_providers&.any? require_relative "harness/config_validator" validator = Aidp::Harness::ConfigValidator.new(project_dir) # Only validate if the config file exists # Skip validation if we're validating a simple test config (no project_dir specified or simple config) should_validate = validator.config_exists? && (project_dir != Dir.pwd || config[:harness]&.keys&.size.to_i > 2) if should_validate original_providers.each do |provider_name, _provider_config| validation_result = validator.validate_provider(provider_name) unless validation_result[:valid] errors.concat(validation_result[:errors]) end end end end errors end |
.waterfall_config(project_dir = Dir.pwd) ⇒ Object
Get waterfall configuration
322 323 324 325 326 327 328 |
# File 'lib/aidp/config.rb', line 322 def self.waterfall_config(project_dir = Dir.pwd) config = load_harness_config(project_dir) waterfall_section = config[:waterfall] || config["waterfall"] || {} # Convert string keys to symbols for consistency symbolize_keys(waterfall_section) end |