aidp 0.17.0 → 0.18.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +69 -0
- data/lib/aidp/analyze/kb_inspector.rb +2 -3
- data/lib/aidp/analyze/progress.rb +5 -10
- data/lib/aidp/cli/mcp_dashboard.rb +1 -1
- data/lib/aidp/cli.rb +64 -29
- data/lib/aidp/config.rb +9 -14
- data/lib/aidp/execute/progress.rb +5 -8
- data/lib/aidp/execute/prompt_manager.rb +128 -1
- data/lib/aidp/execute/repl_macros.rb +555 -0
- data/lib/aidp/execute/work_loop_runner.rb +108 -1
- data/lib/aidp/harness/ai_decision_engine.rb +376 -0
- data/lib/aidp/harness/capability_registry.rb +273 -0
- data/lib/aidp/harness/config_loader.rb +2 -2
- data/lib/aidp/harness/config_schema.rb +305 -1
- data/lib/aidp/harness/configuration.rb +452 -0
- data/lib/aidp/harness/enhanced_runner.rb +23 -8
- data/lib/aidp/harness/error_handler.rb +12 -5
- data/lib/aidp/harness/provider_factory.rb +0 -2
- data/lib/aidp/harness/provider_manager.rb +4 -19
- data/lib/aidp/harness/runner.rb +9 -3
- data/lib/aidp/harness/state/persistence.rb +9 -10
- data/lib/aidp/harness/state/workflow_state.rb +3 -2
- data/lib/aidp/harness/state_manager.rb +33 -97
- data/lib/aidp/harness/status_display.rb +22 -12
- data/lib/aidp/harness/thinking_depth_manager.rb +335 -0
- data/lib/aidp/harness/ui/enhanced_tui.rb +3 -4
- data/lib/aidp/harness/user_interface.rb +11 -6
- data/lib/aidp/harness/zfc_condition_detector.rb +395 -0
- data/lib/aidp/init/devcontainer_generator.rb +274 -0
- data/lib/aidp/init/runner.rb +37 -10
- data/lib/aidp/init.rb +1 -0
- data/lib/aidp/jobs/background_runner.rb +7 -1
- data/lib/aidp/logger.rb +1 -1
- data/lib/aidp/message_display.rb +9 -2
- data/lib/aidp/prompt_optimization/context_composer.rb +286 -0
- data/lib/aidp/prompt_optimization/optimizer.rb +335 -0
- data/lib/aidp/prompt_optimization/prompt_builder.rb +309 -0
- data/lib/aidp/prompt_optimization/relevance_scorer.rb +256 -0
- data/lib/aidp/prompt_optimization/source_code_fragmenter.rb +308 -0
- data/lib/aidp/prompt_optimization/style_guide_indexer.rb +240 -0
- data/lib/aidp/prompt_optimization/template_indexer.rb +250 -0
- data/lib/aidp/provider_manager.rb +0 -2
- data/lib/aidp/providers/anthropic.rb +20 -1
- data/lib/aidp/providers/base.rb +4 -4
- data/lib/aidp/providers/codex.rb +1 -1
- data/lib/aidp/providers/cursor.rb +1 -1
- data/lib/aidp/providers/gemini.rb +1 -1
- data/lib/aidp/providers/github_copilot.rb +1 -1
- data/lib/aidp/providers/opencode.rb +1 -1
- data/lib/aidp/setup/wizard.rb +299 -4
- data/lib/aidp/skills/wizard/prompter.rb +2 -2
- data/lib/aidp/utils/devcontainer_detector.rb +166 -0
- data/lib/aidp/version.rb +1 -1
- data/lib/aidp/watch/build_processor.rb +72 -6
- data/lib/aidp/watch/plan_generator.rb +1 -1
- data/lib/aidp/watch/repository_client.rb +15 -10
- data/lib/aidp/workflows/guided_agent.rb +2 -312
- data/lib/aidp/workstream_executor.rb +8 -2
- data/lib/aidp.rb +0 -1
- data/templates/aidp.yml.example +128 -0
- metadata +14 -2
- data/lib/aidp/providers/macos_ui.rb +0 -102
|
@@ -209,6 +209,86 @@ module Aidp
|
|
|
209
209
|
guards_config[:bypass] == true
|
|
210
210
|
end
|
|
211
211
|
|
|
212
|
+
# Get version control configuration
|
|
213
|
+
def version_control_config
|
|
214
|
+
work_loop_config[:version_control] || default_version_control_config
|
|
215
|
+
end
|
|
216
|
+
|
|
217
|
+
# Get VCS tool
|
|
218
|
+
def vcs_tool
|
|
219
|
+
version_control_config[:tool]
|
|
220
|
+
end
|
|
221
|
+
|
|
222
|
+
# Get VCS behavior (stage/commit/nothing)
|
|
223
|
+
def vcs_behavior
|
|
224
|
+
version_control_config[:behavior]
|
|
225
|
+
end
|
|
226
|
+
|
|
227
|
+
# Check if conventional commits are enabled
|
|
228
|
+
def conventional_commits?
|
|
229
|
+
version_control_config[:conventional_commits] == true
|
|
230
|
+
end
|
|
231
|
+
|
|
232
|
+
# Get coverage configuration
|
|
233
|
+
def coverage_config
|
|
234
|
+
work_loop_config[:coverage] || default_coverage_config
|
|
235
|
+
end
|
|
236
|
+
|
|
237
|
+
# Check if coverage is enabled
|
|
238
|
+
def coverage_enabled?
|
|
239
|
+
coverage_config[:enabled] == true
|
|
240
|
+
end
|
|
241
|
+
|
|
242
|
+
# Get coverage tool
|
|
243
|
+
def coverage_tool
|
|
244
|
+
coverage_config[:tool]
|
|
245
|
+
end
|
|
246
|
+
|
|
247
|
+
# Get coverage run command
|
|
248
|
+
def coverage_run_command
|
|
249
|
+
coverage_config[:run_command]
|
|
250
|
+
end
|
|
251
|
+
|
|
252
|
+
# Get coverage report paths
|
|
253
|
+
def coverage_report_paths
|
|
254
|
+
coverage_config[:report_paths] || []
|
|
255
|
+
end
|
|
256
|
+
|
|
257
|
+
# Check if should fail on coverage drop
|
|
258
|
+
def coverage_fail_on_drop?
|
|
259
|
+
coverage_config[:fail_on_drop] == true
|
|
260
|
+
end
|
|
261
|
+
|
|
262
|
+
# Get minimum coverage threshold
|
|
263
|
+
def coverage_minimum
|
|
264
|
+
coverage_config[:minimum_coverage]
|
|
265
|
+
end
|
|
266
|
+
|
|
267
|
+
# Get interactive testing configuration
|
|
268
|
+
def interactive_testing_config
|
|
269
|
+
work_loop_config[:interactive_testing] || default_interactive_testing_config
|
|
270
|
+
end
|
|
271
|
+
|
|
272
|
+
# Check if interactive testing is enabled
|
|
273
|
+
def interactive_testing_enabled?
|
|
274
|
+
interactive_testing_config[:enabled] == true
|
|
275
|
+
end
|
|
276
|
+
|
|
277
|
+
# Get interactive testing app type
|
|
278
|
+
def interactive_testing_app_type
|
|
279
|
+
interactive_testing_config[:app_type]
|
|
280
|
+
end
|
|
281
|
+
|
|
282
|
+
# Get interactive testing tools configuration
|
|
283
|
+
def interactive_testing_tools
|
|
284
|
+
interactive_testing_config[:tools] || {}
|
|
285
|
+
end
|
|
286
|
+
|
|
287
|
+
# Get model family for a provider
|
|
288
|
+
def model_family(provider_name)
|
|
289
|
+
provider_config(provider_name)[:model_family] || "auto"
|
|
290
|
+
end
|
|
291
|
+
|
|
212
292
|
# Get provider priority
|
|
213
293
|
def provider_priority(provider_name)
|
|
214
294
|
provider_config(provider_name)[:priority] || 0
|
|
@@ -259,6 +339,62 @@ module Aidp
|
|
|
259
339
|
harness_config[:logging] || default_logging_config
|
|
260
340
|
end
|
|
261
341
|
|
|
342
|
+
# Get thinking depth configuration
|
|
343
|
+
def thinking_config
|
|
344
|
+
@config[:thinking] || default_thinking_config
|
|
345
|
+
end
|
|
346
|
+
|
|
347
|
+
# Get default thinking tier
|
|
348
|
+
def default_tier
|
|
349
|
+
thinking_config[:default_tier] || "standard"
|
|
350
|
+
end
|
|
351
|
+
|
|
352
|
+
# Get maximum thinking tier
|
|
353
|
+
def max_tier
|
|
354
|
+
thinking_config[:max_tier] || "standard"
|
|
355
|
+
end
|
|
356
|
+
|
|
357
|
+
# Check if provider switching for tier is allowed
|
|
358
|
+
def allow_provider_switch_for_tier?
|
|
359
|
+
thinking_config[:allow_provider_switch] != false
|
|
360
|
+
end
|
|
361
|
+
|
|
362
|
+
# Get escalation configuration
|
|
363
|
+
def escalation_config
|
|
364
|
+
thinking_config[:escalation] || default_escalation_config
|
|
365
|
+
end
|
|
366
|
+
|
|
367
|
+
# Get fail attempts threshold for escalation
|
|
368
|
+
def escalation_fail_attempts
|
|
369
|
+
escalation_config[:on_fail_attempts] || 2
|
|
370
|
+
end
|
|
371
|
+
|
|
372
|
+
# Get complexity threshold configuration for escalation
|
|
373
|
+
def escalation_complexity_threshold
|
|
374
|
+
escalation_config[:on_complexity_threshold] || {}
|
|
375
|
+
end
|
|
376
|
+
|
|
377
|
+
# Get permissions by tier configuration
|
|
378
|
+
def permissions_by_tier
|
|
379
|
+
thinking_config[:permissions_by_tier] || {}
|
|
380
|
+
end
|
|
381
|
+
|
|
382
|
+
# Get permission level for a tier
|
|
383
|
+
def permission_for_tier(tier)
|
|
384
|
+
permissions_by_tier[tier] || permissions_by_tier[tier.to_sym] || "tools"
|
|
385
|
+
end
|
|
386
|
+
|
|
387
|
+
# Get thinking tier overrides
|
|
388
|
+
def thinking_overrides
|
|
389
|
+
thinking_config[:overrides] || {}
|
|
390
|
+
end
|
|
391
|
+
|
|
392
|
+
# Get tier override for a skill or template
|
|
393
|
+
# @param key [String] skill or template key (e.g., "skill.generate_tests", "template.large_refactor")
|
|
394
|
+
def tier_override_for(key)
|
|
395
|
+
thinking_overrides[key] || thinking_overrides[key.to_sym]
|
|
396
|
+
end
|
|
397
|
+
|
|
262
398
|
# Get fallback configuration
|
|
263
399
|
def fallback_config
|
|
264
400
|
harness_config[:fallback] || default_fallback_config
|
|
@@ -341,6 +477,209 @@ module Aidp
|
|
|
341
477
|
errors
|
|
342
478
|
end
|
|
343
479
|
|
|
480
|
+
# Check if auto-escalation is enabled
|
|
481
|
+
def auto_escalate?
|
|
482
|
+
thinking_config[:auto_escalate] != false
|
|
483
|
+
end
|
|
484
|
+
|
|
485
|
+
# Get escalation threshold
|
|
486
|
+
def escalation_threshold
|
|
487
|
+
thinking_config[:escalation_threshold] || 2
|
|
488
|
+
end
|
|
489
|
+
|
|
490
|
+
# Get tier overrides
|
|
491
|
+
def tier_overrides
|
|
492
|
+
thinking_config[:overrides] || {}
|
|
493
|
+
end
|
|
494
|
+
|
|
495
|
+
# Get ZFC configuration
|
|
496
|
+
def zfc_config
|
|
497
|
+
@config[:zfc] || default_zfc_config
|
|
498
|
+
end
|
|
499
|
+
|
|
500
|
+
# Check if ZFC is enabled
|
|
501
|
+
def zfc_enabled?
|
|
502
|
+
zfc_config[:enabled] == true
|
|
503
|
+
end
|
|
504
|
+
|
|
505
|
+
# Check if ZFC should fallback to legacy on failure
|
|
506
|
+
def zfc_fallback_to_legacy?
|
|
507
|
+
zfc_config[:fallback_to_legacy] != false
|
|
508
|
+
end
|
|
509
|
+
|
|
510
|
+
# Get ZFC decision configuration
|
|
511
|
+
def zfc_decision_config(decision_type)
|
|
512
|
+
zfc_config.dig(:decisions, decision_type.to_sym) || {}
|
|
513
|
+
end
|
|
514
|
+
|
|
515
|
+
# Check if specific ZFC decision type is enabled
|
|
516
|
+
def zfc_decision_enabled?(decision_type)
|
|
517
|
+
return false unless zfc_enabled?
|
|
518
|
+
decision_config = zfc_decision_config(decision_type)
|
|
519
|
+
decision_config[:enabled] == true
|
|
520
|
+
end
|
|
521
|
+
|
|
522
|
+
# Get ZFC decision tier
|
|
523
|
+
def zfc_decision_tier(decision_type)
|
|
524
|
+
zfc_decision_config(decision_type)[:tier] || "mini"
|
|
525
|
+
end
|
|
526
|
+
|
|
527
|
+
# Get ZFC decision cache TTL
|
|
528
|
+
def zfc_decision_cache_ttl(decision_type)
|
|
529
|
+
zfc_decision_config(decision_type)[:cache_ttl]
|
|
530
|
+
end
|
|
531
|
+
|
|
532
|
+
# Get ZFC decision confidence threshold
|
|
533
|
+
def zfc_decision_confidence_threshold(decision_type)
|
|
534
|
+
zfc_decision_config(decision_type)[:confidence_threshold] || 0.7
|
|
535
|
+
end
|
|
536
|
+
|
|
537
|
+
# Get ZFC cost limits
|
|
538
|
+
def zfc_cost_limits
|
|
539
|
+
zfc_config[:cost_limits] || default_zfc_cost_limits
|
|
540
|
+
end
|
|
541
|
+
|
|
542
|
+
# Get ZFC A/B testing configuration
|
|
543
|
+
def zfc_ab_testing_config
|
|
544
|
+
zfc_config[:ab_testing] || default_zfc_ab_testing_config
|
|
545
|
+
end
|
|
546
|
+
|
|
547
|
+
# Check if ZFC A/B testing is enabled
|
|
548
|
+
def zfc_ab_testing_enabled?
|
|
549
|
+
zfc_ab_testing_config[:enabled] == true
|
|
550
|
+
end
|
|
551
|
+
|
|
552
|
+
# Prompt optimization configuration methods
|
|
553
|
+
|
|
554
|
+
# Get prompt optimization configuration
|
|
555
|
+
def prompt_optimization_config
|
|
556
|
+
@config[:prompt_optimization] || default_prompt_optimization_config
|
|
557
|
+
end
|
|
558
|
+
|
|
559
|
+
# Check if prompt optimization is enabled
|
|
560
|
+
def prompt_optimization_enabled?
|
|
561
|
+
prompt_optimization_config[:enabled] == true
|
|
562
|
+
end
|
|
563
|
+
|
|
564
|
+
# Get maximum tokens for prompt
|
|
565
|
+
def prompt_max_tokens
|
|
566
|
+
prompt_optimization_config[:max_tokens] || 16000
|
|
567
|
+
end
|
|
568
|
+
|
|
569
|
+
# Get include threshold configuration
|
|
570
|
+
def prompt_include_thresholds
|
|
571
|
+
prompt_optimization_config[:include_threshold] || default_include_thresholds
|
|
572
|
+
end
|
|
573
|
+
|
|
574
|
+
# Get style guide include threshold
|
|
575
|
+
def prompt_style_guide_threshold
|
|
576
|
+
prompt_include_thresholds[:style_guide] || 0.75
|
|
577
|
+
end
|
|
578
|
+
|
|
579
|
+
# Get templates include threshold
|
|
580
|
+
def prompt_templates_threshold
|
|
581
|
+
prompt_include_thresholds[:templates] || 0.8
|
|
582
|
+
end
|
|
583
|
+
|
|
584
|
+
# Get source code include threshold
|
|
585
|
+
def prompt_source_threshold
|
|
586
|
+
prompt_include_thresholds[:source] || 0.7
|
|
587
|
+
end
|
|
588
|
+
|
|
589
|
+
# Check if dynamic adjustment is enabled
|
|
590
|
+
def prompt_dynamic_adjustment?
|
|
591
|
+
prompt_optimization_config[:dynamic_adjustment] != false
|
|
592
|
+
end
|
|
593
|
+
|
|
594
|
+
# Check if fragment logging is enabled
|
|
595
|
+
def prompt_log_fragments?
|
|
596
|
+
prompt_optimization_config[:log_selected_fragments] == true
|
|
597
|
+
end
|
|
598
|
+
|
|
599
|
+
# Devcontainer configuration methods
|
|
600
|
+
|
|
601
|
+
# Get devcontainer configuration
|
|
602
|
+
def devcontainer_config
|
|
603
|
+
@config[:devcontainer] || default_devcontainer_config
|
|
604
|
+
end
|
|
605
|
+
|
|
606
|
+
# Check if devcontainer features are enabled
|
|
607
|
+
def devcontainer_enabled?
|
|
608
|
+
devcontainer_config[:enabled] != false
|
|
609
|
+
end
|
|
610
|
+
|
|
611
|
+
# Check if full permissions should be granted in devcontainer
|
|
612
|
+
def full_permissions_in_devcontainer?
|
|
613
|
+
devcontainer_config[:full_permissions_when_in_devcontainer] == true
|
|
614
|
+
end
|
|
615
|
+
|
|
616
|
+
# Get forced detection value (nil for auto-detection)
|
|
617
|
+
def devcontainer_force_detection
|
|
618
|
+
devcontainer_config[:force_detection]
|
|
619
|
+
end
|
|
620
|
+
|
|
621
|
+
# Check if currently in devcontainer (with optional force override)
|
|
622
|
+
def in_devcontainer?
|
|
623
|
+
forced = devcontainer_force_detection
|
|
624
|
+
return forced unless forced.nil?
|
|
625
|
+
|
|
626
|
+
require_relative "../utils/devcontainer_detector"
|
|
627
|
+
Aidp::Utils::DevcontainerDetector.in_devcontainer?
|
|
628
|
+
end
|
|
629
|
+
|
|
630
|
+
# Get devcontainer permissions config
|
|
631
|
+
def devcontainer_permissions
|
|
632
|
+
devcontainer_config[:permissions] || {}
|
|
633
|
+
end
|
|
634
|
+
|
|
635
|
+
# Check if dangerous filesystem operations are allowed in devcontainer
|
|
636
|
+
def devcontainer_dangerous_ops_allowed?
|
|
637
|
+
devcontainer_permissions[:dangerous_filesystem_ops] == true
|
|
638
|
+
end
|
|
639
|
+
|
|
640
|
+
# Get list of providers that should skip permission checks in devcontainer
|
|
641
|
+
def devcontainer_skip_permission_checks
|
|
642
|
+
devcontainer_permissions[:skip_permission_checks] || []
|
|
643
|
+
end
|
|
644
|
+
|
|
645
|
+
# Check if a specific provider should skip permission checks in devcontainer
|
|
646
|
+
def devcontainer_skip_permissions_for?(provider_name)
|
|
647
|
+
devcontainer_skip_permission_checks.include?(provider_name.to_s)
|
|
648
|
+
end
|
|
649
|
+
|
|
650
|
+
# Get devcontainer settings
|
|
651
|
+
def devcontainer_settings
|
|
652
|
+
devcontainer_config[:settings] || {}
|
|
653
|
+
end
|
|
654
|
+
|
|
655
|
+
# Get timeout multiplier for devcontainer
|
|
656
|
+
def devcontainer_timeout_multiplier
|
|
657
|
+
devcontainer_settings[:timeout_multiplier] || 1.0
|
|
658
|
+
end
|
|
659
|
+
|
|
660
|
+
# Check if verbose logging is enabled in devcontainer
|
|
661
|
+
def devcontainer_verbose_logging?
|
|
662
|
+
devcontainer_settings[:verbose_logging] == true
|
|
663
|
+
end
|
|
664
|
+
|
|
665
|
+
# Get allowed domains for devcontainer firewall
|
|
666
|
+
def devcontainer_allowed_domains
|
|
667
|
+
devcontainer_settings[:allowed_domains] || []
|
|
668
|
+
end
|
|
669
|
+
|
|
670
|
+
# Check if provider should run with full permissions
|
|
671
|
+
# Combines devcontainer detection with configuration
|
|
672
|
+
def should_use_full_permissions?(provider_name)
|
|
673
|
+
return false unless devcontainer_enabled?
|
|
674
|
+
return false unless in_devcontainer?
|
|
675
|
+
|
|
676
|
+
# Check if full permissions are globally enabled for devcontainer
|
|
677
|
+
return true if full_permissions_in_devcontainer?
|
|
678
|
+
|
|
679
|
+
# Check if this specific provider should skip permissions
|
|
680
|
+
devcontainer_skip_permissions_for?(provider_name)
|
|
681
|
+
end
|
|
682
|
+
|
|
344
683
|
private
|
|
345
684
|
|
|
346
685
|
def validate_configuration!
|
|
@@ -557,6 +896,53 @@ module Aidp
|
|
|
557
896
|
}
|
|
558
897
|
end
|
|
559
898
|
|
|
899
|
+
def default_version_control_config
|
|
900
|
+
{
|
|
901
|
+
tool: "git",
|
|
902
|
+
behavior: "nothing",
|
|
903
|
+
conventional_commits: false
|
|
904
|
+
}
|
|
905
|
+
end
|
|
906
|
+
|
|
907
|
+
def default_coverage_config
|
|
908
|
+
{
|
|
909
|
+
enabled: false,
|
|
910
|
+
tool: nil,
|
|
911
|
+
run_command: nil,
|
|
912
|
+
report_paths: [],
|
|
913
|
+
fail_on_drop: false,
|
|
914
|
+
minimum_coverage: nil
|
|
915
|
+
}
|
|
916
|
+
end
|
|
917
|
+
|
|
918
|
+
def default_interactive_testing_config
|
|
919
|
+
{
|
|
920
|
+
enabled: false,
|
|
921
|
+
app_type: "web",
|
|
922
|
+
tools: {}
|
|
923
|
+
}
|
|
924
|
+
end
|
|
925
|
+
|
|
926
|
+
def default_thinking_config
|
|
927
|
+
{
|
|
928
|
+
default_tier: "mini", # Use mini tier by default for cost optimization
|
|
929
|
+
max_tier: "max",
|
|
930
|
+
allow_provider_switch: true,
|
|
931
|
+
auto_escalate: true,
|
|
932
|
+
escalation_threshold: 2,
|
|
933
|
+
escalation: default_escalation_config,
|
|
934
|
+
permissions_by_tier: {},
|
|
935
|
+
overrides: {}
|
|
936
|
+
}
|
|
937
|
+
end
|
|
938
|
+
|
|
939
|
+
def default_escalation_config
|
|
940
|
+
{
|
|
941
|
+
on_fail_attempts: 2,
|
|
942
|
+
on_complexity_threshold: {}
|
|
943
|
+
}
|
|
944
|
+
end
|
|
945
|
+
|
|
560
946
|
def default_logging_config
|
|
561
947
|
{
|
|
562
948
|
log_level: :info,
|
|
@@ -613,6 +999,72 @@ module Aidp
|
|
|
613
999
|
}
|
|
614
1000
|
end
|
|
615
1001
|
|
|
1002
|
+
# Default ZFC configuration
|
|
1003
|
+
def default_zfc_config
|
|
1004
|
+
{
|
|
1005
|
+
enabled: false, # Experimental feature - disabled by default
|
|
1006
|
+
fallback_to_legacy: true,
|
|
1007
|
+
decisions: {},
|
|
1008
|
+
cost_limits: default_zfc_cost_limits,
|
|
1009
|
+
ab_testing: default_zfc_ab_testing_config
|
|
1010
|
+
}
|
|
1011
|
+
end
|
|
1012
|
+
|
|
1013
|
+
# Default ZFC cost limits
|
|
1014
|
+
def default_zfc_cost_limits
|
|
1015
|
+
{
|
|
1016
|
+
max_daily_cost: 5.00,
|
|
1017
|
+
max_cost_per_decision: 0.01,
|
|
1018
|
+
alert_threshold: 0.8
|
|
1019
|
+
}
|
|
1020
|
+
end
|
|
1021
|
+
|
|
1022
|
+
# Default ZFC A/B testing configuration
|
|
1023
|
+
def default_zfc_ab_testing_config
|
|
1024
|
+
{
|
|
1025
|
+
enabled: false,
|
|
1026
|
+
sample_rate: 0.1,
|
|
1027
|
+
log_comparisons: true
|
|
1028
|
+
}
|
|
1029
|
+
end
|
|
1030
|
+
|
|
1031
|
+
# Default prompt optimization configuration
|
|
1032
|
+
def default_prompt_optimization_config
|
|
1033
|
+
{
|
|
1034
|
+
enabled: false, # Experimental feature - disabled by default
|
|
1035
|
+
max_tokens: 16000,
|
|
1036
|
+
include_threshold: default_include_thresholds,
|
|
1037
|
+
dynamic_adjustment: true,
|
|
1038
|
+
log_selected_fragments: false
|
|
1039
|
+
}
|
|
1040
|
+
end
|
|
1041
|
+
|
|
1042
|
+
# Default include thresholds for prompt optimization
|
|
1043
|
+
def default_include_thresholds
|
|
1044
|
+
{
|
|
1045
|
+
style_guide: 0.75,
|
|
1046
|
+
templates: 0.8,
|
|
1047
|
+
source: 0.7
|
|
1048
|
+
}
|
|
1049
|
+
end
|
|
1050
|
+
|
|
1051
|
+
def default_devcontainer_config
|
|
1052
|
+
{
|
|
1053
|
+
enabled: true,
|
|
1054
|
+
full_permissions_when_in_devcontainer: false,
|
|
1055
|
+
force_detection: nil,
|
|
1056
|
+
permissions: {
|
|
1057
|
+
dangerous_filesystem_ops: false,
|
|
1058
|
+
skip_permission_checks: []
|
|
1059
|
+
},
|
|
1060
|
+
settings: {
|
|
1061
|
+
timeout_multiplier: 1.0,
|
|
1062
|
+
verbose_logging: false,
|
|
1063
|
+
allowed_domains: []
|
|
1064
|
+
}
|
|
1065
|
+
}
|
|
1066
|
+
end
|
|
1067
|
+
|
|
616
1068
|
# Custom error class for configuration issues
|
|
617
1069
|
class ConfigurationError < StandardError; end
|
|
618
1070
|
end
|
|
@@ -22,10 +22,19 @@ module Aidp
|
|
|
22
22
|
error: "error"
|
|
23
23
|
}.freeze
|
|
24
24
|
|
|
25
|
-
|
|
25
|
+
# Simple sleeper abstraction for test control
|
|
26
|
+
class Sleeper
|
|
27
|
+
def sleep(duration)
|
|
28
|
+
Kernel.sleep(duration)
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def initialize(project_dir, mode = :analyze, options = {}, prompt: TTY::Prompt.new, sleeper: Sleeper.new)
|
|
26
33
|
@project_dir = project_dir
|
|
27
34
|
@mode = mode.to_sym
|
|
28
35
|
@options = options
|
|
36
|
+
@prompt = prompt
|
|
37
|
+
@sleeper = sleeper
|
|
29
38
|
@state = STATES[:idle]
|
|
30
39
|
@start_time = nil
|
|
31
40
|
@current_step = nil
|
|
@@ -49,8 +58,14 @@ module Aidp
|
|
|
49
58
|
# Initialize other components
|
|
50
59
|
@configuration = Configuration.new(project_dir)
|
|
51
60
|
@state_manager = StateManager.new(project_dir, @mode)
|
|
52
|
-
@
|
|
53
|
-
|
|
61
|
+
@provider_manager = ProviderManager.new(@configuration, prompt: @prompt)
|
|
62
|
+
|
|
63
|
+
# Use ZFC-enabled condition detector
|
|
64
|
+
# ZfcConditionDetector will create its own ProviderFactory if needed
|
|
65
|
+
# Falls back to legacy pattern matching when ZFC is disabled
|
|
66
|
+
require_relative "zfc_condition_detector"
|
|
67
|
+
@condition_detector = ZfcConditionDetector.new(@configuration)
|
|
68
|
+
|
|
54
69
|
@error_handler = ErrorHandler.new(@provider_manager, @configuration)
|
|
55
70
|
@completion_checker = CompletionChecker.new(@project_dir, @workflow_type)
|
|
56
71
|
end
|
|
@@ -240,7 +255,7 @@ module Aidp
|
|
|
240
255
|
# Remove job after a delay to show completion
|
|
241
256
|
# UI delay to let user see completion status before removal
|
|
242
257
|
Thread.new do
|
|
243
|
-
sleep
|
|
258
|
+
@sleeper.sleep(2) # UI timing delay
|
|
244
259
|
@tui.remove_job(step_job_id)
|
|
245
260
|
end
|
|
246
261
|
|
|
@@ -349,9 +364,9 @@ module Aidp
|
|
|
349
364
|
def get_mode_runner
|
|
350
365
|
case @mode
|
|
351
366
|
when :analyze
|
|
352
|
-
Aidp::Analyze::Runner.new(@project_dir, self, prompt:
|
|
367
|
+
Aidp::Analyze::Runner.new(@project_dir, self, prompt: @prompt)
|
|
353
368
|
when :execute
|
|
354
|
-
Aidp::Execute::Runner.new(@project_dir, self, prompt:
|
|
369
|
+
Aidp::Execute::Runner.new(@project_dir, self, prompt: @prompt)
|
|
355
370
|
else
|
|
356
371
|
raise ArgumentError, "Unsupported mode: #{@mode}"
|
|
357
372
|
end
|
|
@@ -376,7 +391,7 @@ module Aidp
|
|
|
376
391
|
def handle_pause_condition
|
|
377
392
|
case @state
|
|
378
393
|
when STATES[:paused]
|
|
379
|
-
sleep(1)
|
|
394
|
+
@sleeper.sleep(1)
|
|
380
395
|
when STATES[:waiting_for_user]
|
|
381
396
|
# User interface handles this
|
|
382
397
|
nil
|
|
@@ -503,7 +518,7 @@ module Aidp
|
|
|
503
518
|
while Time.now < reset_time && @state == STATES[:waiting_for_rate_limit]
|
|
504
519
|
remaining = reset_time - Time.now
|
|
505
520
|
@tui.show_message("⏳ Rate limit reset in #{remaining.to_i} seconds", :info)
|
|
506
|
-
sleep(1)
|
|
521
|
+
@sleeper.sleep(1)
|
|
507
522
|
end
|
|
508
523
|
end
|
|
509
524
|
|
|
@@ -10,10 +10,19 @@ module Aidp
|
|
|
10
10
|
class ErrorHandler
|
|
11
11
|
include Aidp::DebugMixin
|
|
12
12
|
|
|
13
|
-
|
|
13
|
+
# Simple wrapper to allow dependency injection of sleep behavior in tests
|
|
14
|
+
class Sleeper
|
|
15
|
+
def sleep(seconds)
|
|
16
|
+
Kernel.sleep(seconds)
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
# @param sleeper [#sleep] object responding to sleep(seconds); injectable for tests
|
|
21
|
+
def initialize(provider_manager, configuration, metrics_manager = nil, sleeper: nil)
|
|
14
22
|
@provider_manager = provider_manager
|
|
15
23
|
@configuration = configuration
|
|
16
24
|
@metrics_manager = metrics_manager
|
|
25
|
+
@sleeper = sleeper || Sleeper.new
|
|
17
26
|
@retry_strategies = {}
|
|
18
27
|
@retry_counts = {}
|
|
19
28
|
@error_history = []
|
|
@@ -112,7 +121,7 @@ module Aidp
|
|
|
112
121
|
if should_retry?(error_info, strategy)
|
|
113
122
|
delay = @backoff_calculator.calculate_delay(attempt, strategy[:backoff_strategy] || :exponential, 1, 10)
|
|
114
123
|
debug_log("🔁 Retry attempt #{attempt} for #{current_provider}", level: :info, data: {delay: delay, error_type: error_info[:error_type]})
|
|
115
|
-
sleep(delay) if delay > 0
|
|
124
|
+
@sleeper.sleep(delay) if delay > 0
|
|
116
125
|
retry
|
|
117
126
|
end
|
|
118
127
|
end
|
|
@@ -191,9 +200,7 @@ module Aidp
|
|
|
191
200
|
)
|
|
192
201
|
|
|
193
202
|
# Wait for backoff delay
|
|
194
|
-
if delay > 0
|
|
195
|
-
sleep(delay)
|
|
196
|
-
end
|
|
203
|
+
@sleeper.sleep(delay) if delay > 0
|
|
197
204
|
|
|
198
205
|
# Execute the retry
|
|
199
206
|
retry_result = execute_retry_attempt(error_info, strategy, context)
|
|
@@ -5,7 +5,6 @@ require_relative "../providers/base"
|
|
|
5
5
|
require_relative "../providers/cursor"
|
|
6
6
|
require_relative "../providers/anthropic"
|
|
7
7
|
require_relative "../providers/gemini"
|
|
8
|
-
require_relative "../providers/macos_ui"
|
|
9
8
|
require_relative "../providers/opencode"
|
|
10
9
|
require_relative "../providers/github_copilot"
|
|
11
10
|
require_relative "../providers/codex"
|
|
@@ -19,7 +18,6 @@ module Aidp
|
|
|
19
18
|
"anthropic" => Aidp::Providers::Anthropic,
|
|
20
19
|
"claude" => Aidp::Providers::Anthropic,
|
|
21
20
|
"gemini" => Aidp::Providers::Gemini,
|
|
22
|
-
"macos" => Aidp::Providers::MacOSUI,
|
|
23
21
|
"opencode" => Aidp::Providers::Opencode,
|
|
24
22
|
"github_copilot" => Aidp::Providers::GithubCopilot,
|
|
25
23
|
"codex" => Aidp::Providers::Codex
|
|
@@ -12,9 +12,10 @@ module Aidp
|
|
|
12
12
|
include Aidp::MessageDisplay
|
|
13
13
|
include Aidp::RescueLogging
|
|
14
14
|
|
|
15
|
-
def initialize(configuration, prompt: TTY::Prompt.new)
|
|
15
|
+
def initialize(configuration, prompt: TTY::Prompt.new, binary_checker: Aidp::Util)
|
|
16
16
|
@configuration = configuration
|
|
17
17
|
@prompt = prompt
|
|
18
|
+
@binary_checker = binary_checker
|
|
18
19
|
@current_provider = nil
|
|
19
20
|
@current_model = nil
|
|
20
21
|
@provider_history = []
|
|
@@ -1069,18 +1070,6 @@ module Aidp
|
|
|
1069
1070
|
def provider_cli_available?(provider_name)
|
|
1070
1071
|
normalized = normalize_provider_name(provider_name)
|
|
1071
1072
|
|
|
1072
|
-
# Handle test environment overrides
|
|
1073
|
-
if defined?(RSpec) || ENV["RSPEC_RUNNING"]
|
|
1074
|
-
# Force claude to be missing for testing
|
|
1075
|
-
if ENV["AIDP_FORCE_CLAUDE_MISSING"] == "1" && normalized == "claude"
|
|
1076
|
-
return [false, "binary_missing"]
|
|
1077
|
-
end
|
|
1078
|
-
# Force claude to be available for testing
|
|
1079
|
-
if ENV["AIDP_FORCE_CLAUDE_AVAILABLE"] == "1" && normalized == "claude"
|
|
1080
|
-
return [true, "available"]
|
|
1081
|
-
end
|
|
1082
|
-
end
|
|
1083
|
-
|
|
1084
1073
|
cache_key = "#{provider_name}:#{normalized}"
|
|
1085
1074
|
cached = @binary_check_cache[cache_key]
|
|
1086
1075
|
if cached && (Time.now - cached[:checked_at] < @binary_check_ttl)
|
|
@@ -1098,7 +1087,7 @@ module Aidp
|
|
|
1098
1087
|
return [true, nil]
|
|
1099
1088
|
end
|
|
1100
1089
|
path = begin
|
|
1101
|
-
|
|
1090
|
+
@binary_checker.which(binary)
|
|
1102
1091
|
rescue => e
|
|
1103
1092
|
log_rescue(e, component: "provider_manager", action: "locate_binary", fallback: nil, binary: binary)
|
|
1104
1093
|
nil
|
|
@@ -1164,10 +1153,6 @@ module Aidp
|
|
|
1164
1153
|
statuses = provider_health_status
|
|
1165
1154
|
metrics = all_metrics
|
|
1166
1155
|
configured = configured_providers
|
|
1167
|
-
# Ensure fresh binary probe results in test mode so stubs of Aidp::Util.which take effect
|
|
1168
|
-
if defined?(RSpec) || ENV["RSPEC_RUNNING"]
|
|
1169
|
-
@binary_check_cache.clear
|
|
1170
|
-
end
|
|
1171
1156
|
rows_by_normalized = {}
|
|
1172
1157
|
configured.each do |prov|
|
|
1173
1158
|
# Temporarily hide macos provider until it's user-configurable
|
|
@@ -1384,7 +1369,7 @@ module Aidp
|
|
|
1384
1369
|
@current_provider = provider_type
|
|
1385
1370
|
|
|
1386
1371
|
# Execute the prompt with the provider
|
|
1387
|
-
result = provider.
|
|
1372
|
+
result = provider.send_message(prompt: prompt, session: nil)
|
|
1388
1373
|
|
|
1389
1374
|
# Return structured result
|
|
1390
1375
|
{
|
data/lib/aidp/harness/runner.rb
CHANGED
|
@@ -52,8 +52,14 @@ module Aidp
|
|
|
52
52
|
# Initialize components
|
|
53
53
|
@config_manager = ConfigManager.new(project_dir)
|
|
54
54
|
@state_manager = StateManager.new(project_dir, @mode)
|
|
55
|
-
@condition_detector = ConditionDetector.new
|
|
56
55
|
@provider_manager = ProviderManager.new(@config_manager, prompt: @prompt)
|
|
56
|
+
|
|
57
|
+
# Use ZFC-enabled condition detector
|
|
58
|
+
# ZfcConditionDetector will create its own ProviderFactory if needed
|
|
59
|
+
# Falls back to legacy pattern matching when ZFC is disabled
|
|
60
|
+
require_relative "zfc_condition_detector"
|
|
61
|
+
@condition_detector = ZfcConditionDetector.new(@config_manager)
|
|
62
|
+
|
|
57
63
|
@user_interface = SimpleUserInterface.new
|
|
58
64
|
@error_handler = ErrorHandler.new(@provider_manager, @config_manager)
|
|
59
65
|
@status_display = StatusDisplay.new
|
|
@@ -188,9 +194,9 @@ module Aidp
|
|
|
188
194
|
def get_mode_runner
|
|
189
195
|
case @mode
|
|
190
196
|
when :analyze
|
|
191
|
-
Aidp::Analyze::Runner.new(@project_dir, self, prompt:
|
|
197
|
+
Aidp::Analyze::Runner.new(@project_dir, self, prompt: @prompt)
|
|
192
198
|
when :execute
|
|
193
|
-
Aidp::Execute::Runner.new(@project_dir, self, prompt:
|
|
199
|
+
Aidp::Execute::Runner.new(@project_dir, self, prompt: @prompt)
|
|
194
200
|
else
|
|
195
201
|
raise ArgumentError, "Unsupported mode: #{@mode}"
|
|
196
202
|
end
|