aidp 0.17.0 → 0.17.1
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/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 +21 -27
- data/lib/aidp/execute/progress.rb +5 -8
- data/lib/aidp/harness/config_loader.rb +2 -2
- data/lib/aidp/harness/enhanced_runner.rb +16 -7
- data/lib/aidp/harness/error_handler.rb +12 -5
- data/lib/aidp/harness/provider_manager.rb +4 -19
- data/lib/aidp/harness/runner.rb +2 -2
- 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/ui/enhanced_tui.rb +3 -4
- data/lib/aidp/harness/user_interface.rb +11 -6
- 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/providers/anthropic.rb +1 -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/macos_ui.rb +1 -1
- data/lib/aidp/providers/opencode.rb +1 -1
- data/lib/aidp/skills/wizard/prompter.rb +2 -2
- data/lib/aidp/version.rb +1 -1
- data/lib/aidp/watch/plan_generator.rb +1 -1
- data/lib/aidp/watch/repository_client.rb +13 -9
- data/lib/aidp/workflows/guided_agent.rb +2 -312
- data/lib/aidp/workstream_executor.rb +8 -2
- metadata +1 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 949670fdea4721406643f4fd8da096e943740effbd836407311b812350919b14
|
|
4
|
+
data.tar.gz: 8034a3c798571e4626b273c4a9abe9a5da38cef5dd4f25de8794a0ef63bf6022
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: cdabc6ba04d06a89dbc4ad19b27a64862e960daa350029db4fada5a4f6d32d3fba27cb32dda291871a79ad8f319d27e7dd1348ddcb7fdb8b0f0a1390b9493fc1
|
|
7
|
+
data.tar.gz: 39c384f4c01bf00bef550ac9190d27ddd268437be92fc4cdfcdeac3dff09c79c055b2e5b5582e553af6fa838b3f904cce354e9db62ee3638f658eec05673e4f5
|
|
@@ -80,7 +80,7 @@ module Aidp
|
|
|
80
80
|
display_message(box)
|
|
81
81
|
end
|
|
82
82
|
|
|
83
|
-
def load_kb_data
|
|
83
|
+
def load_kb_data(suppress_parse_warnings: false)
|
|
84
84
|
data = {}
|
|
85
85
|
|
|
86
86
|
%w[symbols imports calls metrics seams hotspots tests cycles].each do |type|
|
|
@@ -89,8 +89,7 @@ module Aidp
|
|
|
89
89
|
begin
|
|
90
90
|
data[type.to_sym] = JSON.parse(File.read(file_path), symbolize_names: true)
|
|
91
91
|
rescue JSON::ParserError => e
|
|
92
|
-
|
|
93
|
-
unless ENV["RACK_ENV"] == "test" || defined?(RSpec)
|
|
92
|
+
unless suppress_parse_warnings
|
|
94
93
|
display_message("Warning: Could not parse #{file_path}: #{e.message}", type: :warn)
|
|
95
94
|
end
|
|
96
95
|
data[type.to_sym] = []
|
|
@@ -9,9 +9,10 @@ module Aidp
|
|
|
9
9
|
class Progress
|
|
10
10
|
attr_reader :project_dir, :progress_file
|
|
11
11
|
|
|
12
|
-
def initialize(project_dir)
|
|
12
|
+
def initialize(project_dir, skip_persistence: false)
|
|
13
13
|
@project_dir = project_dir
|
|
14
14
|
@progress_file = File.join(project_dir, ".aidp", "progress", "analyze.yml")
|
|
15
|
+
@skip_persistence = skip_persistence
|
|
15
16
|
load_progress
|
|
16
17
|
end
|
|
17
18
|
|
|
@@ -60,26 +61,20 @@ module Aidp
|
|
|
60
61
|
private
|
|
61
62
|
|
|
62
63
|
def load_progress
|
|
63
|
-
|
|
64
|
-
if (ENV["RACK_ENV"] == "test" || defined?(RSpec)) && !File.exist?(@progress_file)
|
|
64
|
+
if @skip_persistence && !File.exist?(@progress_file)
|
|
65
65
|
@progress = {}
|
|
66
66
|
return
|
|
67
67
|
end
|
|
68
|
-
|
|
69
|
-
@progress = if File.exist?(@progress_file)
|
|
68
|
+
@progress = if !@skip_persistence && File.exist?(@progress_file)
|
|
70
69
|
YAML.safe_load_file(@progress_file, permitted_classes: [Date, Time, Symbol], aliases: true) || {}
|
|
71
70
|
else
|
|
72
71
|
{}
|
|
73
72
|
end
|
|
74
|
-
|
|
75
|
-
# Ensure @progress is never nil
|
|
76
73
|
@progress = {} if @progress.nil?
|
|
77
74
|
end
|
|
78
75
|
|
|
79
76
|
def save_progress
|
|
80
|
-
|
|
81
|
-
return if ENV["RACK_ENV"] == "test" || defined?(RSpec)
|
|
82
|
-
|
|
77
|
+
return if @skip_persistence
|
|
83
78
|
FileUtils.mkdir_p(File.dirname(@progress_file))
|
|
84
79
|
File.write(@progress_file, @progress.to_yaml)
|
|
85
80
|
end
|
data/lib/aidp/cli.rb
CHANGED
|
@@ -147,6 +147,10 @@ module Aidp
|
|
|
147
147
|
class << self
|
|
148
148
|
extend Aidp::MessageDisplay::ClassMethods
|
|
149
149
|
|
|
150
|
+
def create_prompt
|
|
151
|
+
::TTY::Prompt.new
|
|
152
|
+
end
|
|
153
|
+
|
|
150
154
|
def run(args = ARGV)
|
|
151
155
|
# Handle subcommands first (status, jobs, kb, harness)
|
|
152
156
|
return run_subcommand(args) if subcommand?(args)
|
|
@@ -173,7 +177,7 @@ module Aidp
|
|
|
173
177
|
|
|
174
178
|
# Handle configuration setup
|
|
175
179
|
# Create a prompt for the wizard
|
|
176
|
-
prompt =
|
|
180
|
+
prompt = create_prompt
|
|
177
181
|
|
|
178
182
|
if options[:setup_config]
|
|
179
183
|
# Force setup/reconfigure even if config exists
|
|
@@ -398,7 +402,7 @@ module Aidp
|
|
|
398
402
|
|
|
399
403
|
def run_jobs_command(args = [])
|
|
400
404
|
require_relative "cli/jobs_command"
|
|
401
|
-
jobs_cmd = Aidp::CLI::JobsCommand.new(prompt:
|
|
405
|
+
jobs_cmd = Aidp::CLI::JobsCommand.new(prompt: create_prompt)
|
|
402
406
|
subcommand = args.shift
|
|
403
407
|
jobs_cmd.run(subcommand, args)
|
|
404
408
|
end
|
|
@@ -504,21 +508,6 @@ module Aidp
|
|
|
504
508
|
if step
|
|
505
509
|
display_message("Running #{mode} step '#{step}' with enhanced TUI harness", type: :highlight)
|
|
506
510
|
display_message("progress indicators", type: :info)
|
|
507
|
-
if step.start_with?("00_PRD") && (defined?(RSpec) || ENV["RSPEC_RUNNING"])
|
|
508
|
-
# Simulate questions & completion similar to TUI test mode
|
|
509
|
-
root = ENV["AIDP_ROOT"] || Dir.pwd
|
|
510
|
-
file = Dir.glob(File.join(root, "templates", (mode == :execute) ? "EXECUTE" : "ANALYZE", "00_PRD*.md")).first
|
|
511
|
-
if file && File.file?(file)
|
|
512
|
-
content = File.read(file)
|
|
513
|
-
questions_section = content.split(/## Questions/i)[1]
|
|
514
|
-
if questions_section
|
|
515
|
-
questions_section.lines.select { |l| l.strip.start_with?("-") }.each do |line|
|
|
516
|
-
display_message(line.strip.sub(/^-\s*/, ""), type: :info)
|
|
517
|
-
end
|
|
518
|
-
end
|
|
519
|
-
end
|
|
520
|
-
display_message("PRD completed", type: :success)
|
|
521
|
-
end
|
|
522
511
|
return
|
|
523
512
|
end
|
|
524
513
|
display_message("Starting enhanced TUI harness", type: :highlight)
|
|
@@ -601,7 +590,7 @@ module Aidp
|
|
|
601
590
|
when "clear"
|
|
602
591
|
force = args.include?("--force")
|
|
603
592
|
unless force
|
|
604
|
-
prompt =
|
|
593
|
+
prompt = create_prompt
|
|
605
594
|
confirm = prompt.yes?("Are you sure you want to clear all checkpoint data?")
|
|
606
595
|
return unless confirm
|
|
607
596
|
end
|
|
@@ -696,7 +685,7 @@ module Aidp
|
|
|
696
685
|
end
|
|
697
686
|
end
|
|
698
687
|
config_manager = Aidp::Harness::ConfigManager.new(Dir.pwd)
|
|
699
|
-
pm = Aidp::Harness::ProviderManager.new(config_manager, prompt:
|
|
688
|
+
pm = Aidp::Harness::ProviderManager.new(config_manager, prompt: create_prompt)
|
|
700
689
|
|
|
701
690
|
# Use TTY::Spinner for progress indication
|
|
702
691
|
require "tty-spinner"
|
|
@@ -738,7 +727,12 @@ module Aidp
|
|
|
738
727
|
end
|
|
739
728
|
tokens = (r[:total_tokens].to_i > 0) ? r[:total_tokens].to_s : "0"
|
|
740
729
|
reason = r[:unhealthy_reason] || "-"
|
|
741
|
-
|
|
730
|
+
is_tty = begin
|
|
731
|
+
$stdout.respond_to?(:tty?) && $stdout.tty?
|
|
732
|
+
rescue
|
|
733
|
+
false
|
|
734
|
+
end
|
|
735
|
+
if no_color || !is_tty
|
|
742
736
|
[r[:provider], r[:status], (r[:available] ? "yes" : "no"), cb, rl, tokens, last_used, reason]
|
|
743
737
|
else
|
|
744
738
|
[
|
|
@@ -757,7 +751,7 @@ module Aidp
|
|
|
757
751
|
table = TTY::Table.new header, table_rows
|
|
758
752
|
display_message(table.render(:basic), type: :info)
|
|
759
753
|
rescue => e
|
|
760
|
-
|
|
754
|
+
Aidp.logger.warn("cli", "Failed to display provider health", error_class: e.class.name, error_message: e.message)
|
|
761
755
|
display_message("Failed to display provider health: #{e.message}", type: :error)
|
|
762
756
|
end
|
|
763
757
|
|
|
@@ -777,7 +771,7 @@ module Aidp
|
|
|
777
771
|
display_message("=" * 60, type: :muted)
|
|
778
772
|
|
|
779
773
|
provider_info = Aidp::Harness::ProviderInfo.new(provider_name, Dir.pwd)
|
|
780
|
-
info = provider_info.
|
|
774
|
+
info = provider_info.info(force_refresh: force_refresh)
|
|
781
775
|
|
|
782
776
|
if info.nil?
|
|
783
777
|
display_message("No information available for provider: #{provider_name}", type: :error)
|
|
@@ -1044,7 +1038,7 @@ module Aidp
|
|
|
1044
1038
|
return
|
|
1045
1039
|
end
|
|
1046
1040
|
|
|
1047
|
-
wizard = Aidp::Setup::Wizard.new(Dir.pwd, prompt:
|
|
1041
|
+
wizard = Aidp::Setup::Wizard.new(Dir.pwd, prompt: create_prompt, dry_run: dry_run)
|
|
1048
1042
|
wizard.run
|
|
1049
1043
|
end
|
|
1050
1044
|
|
|
@@ -1071,7 +1065,7 @@ module Aidp
|
|
|
1071
1065
|
end
|
|
1072
1066
|
|
|
1073
1067
|
require_relative "init/runner"
|
|
1074
|
-
runner = Aidp::Init::Runner.new(Dir.pwd, prompt:
|
|
1068
|
+
runner = Aidp::Init::Runner.new(Dir.pwd, prompt: create_prompt, options: options)
|
|
1075
1069
|
runner.run
|
|
1076
1070
|
end
|
|
1077
1071
|
|
|
@@ -1127,7 +1121,7 @@ module Aidp
|
|
|
1127
1121
|
project_dir: Dir.pwd,
|
|
1128
1122
|
once: once,
|
|
1129
1123
|
use_workstreams: use_workstreams,
|
|
1130
|
-
prompt:
|
|
1124
|
+
prompt: create_prompt
|
|
1131
1125
|
)
|
|
1132
1126
|
runner.start
|
|
1133
1127
|
rescue ArgumentError => e
|
|
@@ -1244,7 +1238,7 @@ module Aidp
|
|
|
1244
1238
|
|
|
1245
1239
|
# Confirm removal unless --force
|
|
1246
1240
|
unless force
|
|
1247
|
-
prompt =
|
|
1241
|
+
prompt = create_prompt
|
|
1248
1242
|
confirm = prompt.yes?("Remove workstream '#{slug}'?#{" (will also delete branch)" if delete_branch}")
|
|
1249
1243
|
return unless confirm
|
|
1250
1244
|
end
|
|
@@ -2124,7 +2118,7 @@ module Aidp
|
|
|
2124
2118
|
|
|
2125
2119
|
# Confirm deletion
|
|
2126
2120
|
require "tty-prompt"
|
|
2127
|
-
prompt =
|
|
2121
|
+
prompt = create_prompt
|
|
2128
2122
|
confirmed = prompt.yes?("Delete skill '#{skill.name}' (#{skill_id})? This cannot be undone.")
|
|
2129
2123
|
|
|
2130
2124
|
unless confirmed
|
|
@@ -9,9 +9,10 @@ module Aidp
|
|
|
9
9
|
class Progress
|
|
10
10
|
attr_reader :project_dir, :progress_file
|
|
11
11
|
|
|
12
|
-
def initialize(project_dir)
|
|
12
|
+
def initialize(project_dir, skip_persistence: false)
|
|
13
13
|
@project_dir = project_dir
|
|
14
14
|
@progress_file = File.join(project_dir, ".aidp", "progress", "execute.yml")
|
|
15
|
+
@skip_persistence = skip_persistence
|
|
15
16
|
load_progress
|
|
16
17
|
end
|
|
17
18
|
|
|
@@ -61,13 +62,11 @@ module Aidp
|
|
|
61
62
|
private
|
|
62
63
|
|
|
63
64
|
def load_progress
|
|
64
|
-
|
|
65
|
-
if (ENV["RACK_ENV"] == "test" || defined?(RSpec)) && !File.exist?(@progress_file)
|
|
65
|
+
if @skip_persistence && !File.exist?(@progress_file)
|
|
66
66
|
@progress = {}
|
|
67
67
|
return
|
|
68
68
|
end
|
|
69
|
-
|
|
70
|
-
@progress = if File.exist?(@progress_file)
|
|
69
|
+
@progress = if !@skip_persistence && File.exist?(@progress_file)
|
|
71
70
|
YAML.safe_load_file(@progress_file, permitted_classes: [Date, Time, Symbol], aliases: true) || {}
|
|
72
71
|
else
|
|
73
72
|
{}
|
|
@@ -75,9 +74,7 @@ module Aidp
|
|
|
75
74
|
end
|
|
76
75
|
|
|
77
76
|
def save_progress
|
|
78
|
-
|
|
79
|
-
return if ENV["RACK_ENV"] == "test" || defined?(RSpec)
|
|
80
|
-
|
|
77
|
+
return if @skip_persistence
|
|
81
78
|
FileUtils.mkdir_p(File.dirname(@progress_file))
|
|
82
79
|
File.write(@progress_file, @progress.to_yaml)
|
|
83
80
|
end
|
|
@@ -9,9 +9,9 @@ module Aidp
|
|
|
9
9
|
module Harness
|
|
10
10
|
# Enhanced configuration loader for harness
|
|
11
11
|
class ConfigLoader
|
|
12
|
-
def initialize(project_dir = Dir.pwd)
|
|
12
|
+
def initialize(project_dir = Dir.pwd, validator: nil)
|
|
13
13
|
@project_dir = project_dir
|
|
14
|
-
@validator = ConfigValidator.new(project_dir)
|
|
14
|
+
@validator = validator || ConfigValidator.new(project_dir)
|
|
15
15
|
@config_cache = nil
|
|
16
16
|
@last_loaded = nil
|
|
17
17
|
@last_signature = nil # stores {mtime:, size:, hash:}
|
|
@@ -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
|
|
@@ -50,7 +59,7 @@ module Aidp
|
|
|
50
59
|
@configuration = Configuration.new(project_dir)
|
|
51
60
|
@state_manager = StateManager.new(project_dir, @mode)
|
|
52
61
|
@condition_detector = ConditionDetector.new
|
|
53
|
-
@provider_manager = ProviderManager.new(@configuration, prompt:
|
|
62
|
+
@provider_manager = ProviderManager.new(@configuration, prompt: @prompt)
|
|
54
63
|
@error_handler = ErrorHandler.new(@provider_manager, @configuration)
|
|
55
64
|
@completion_checker = CompletionChecker.new(@project_dir, @workflow_type)
|
|
56
65
|
end
|
|
@@ -240,7 +249,7 @@ module Aidp
|
|
|
240
249
|
# Remove job after a delay to show completion
|
|
241
250
|
# UI delay to let user see completion status before removal
|
|
242
251
|
Thread.new do
|
|
243
|
-
sleep
|
|
252
|
+
@sleeper.sleep(2) # UI timing delay
|
|
244
253
|
@tui.remove_job(step_job_id)
|
|
245
254
|
end
|
|
246
255
|
|
|
@@ -349,9 +358,9 @@ module Aidp
|
|
|
349
358
|
def get_mode_runner
|
|
350
359
|
case @mode
|
|
351
360
|
when :analyze
|
|
352
|
-
Aidp::Analyze::Runner.new(@project_dir, self, prompt:
|
|
361
|
+
Aidp::Analyze::Runner.new(@project_dir, self, prompt: @prompt)
|
|
353
362
|
when :execute
|
|
354
|
-
Aidp::Execute::Runner.new(@project_dir, self, prompt:
|
|
363
|
+
Aidp::Execute::Runner.new(@project_dir, self, prompt: @prompt)
|
|
355
364
|
else
|
|
356
365
|
raise ArgumentError, "Unsupported mode: #{@mode}"
|
|
357
366
|
end
|
|
@@ -376,7 +385,7 @@ module Aidp
|
|
|
376
385
|
def handle_pause_condition
|
|
377
386
|
case @state
|
|
378
387
|
when STATES[:paused]
|
|
379
|
-
sleep(1)
|
|
388
|
+
@sleeper.sleep(1)
|
|
380
389
|
when STATES[:waiting_for_user]
|
|
381
390
|
# User interface handles this
|
|
382
391
|
nil
|
|
@@ -503,7 +512,7 @@ module Aidp
|
|
|
503
512
|
while Time.now < reset_time && @state == STATES[:waiting_for_rate_limit]
|
|
504
513
|
remaining = reset_time - Time.now
|
|
505
514
|
@tui.show_message("⏳ Rate limit reset in #{remaining.to_i} seconds", :info)
|
|
506
|
-
sleep(1)
|
|
515
|
+
@sleeper.sleep(1)
|
|
507
516
|
end
|
|
508
517
|
end
|
|
509
518
|
|
|
@@ -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)
|
|
@@ -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
|
@@ -188,9 +188,9 @@ module Aidp
|
|
|
188
188
|
def get_mode_runner
|
|
189
189
|
case @mode
|
|
190
190
|
when :analyze
|
|
191
|
-
Aidp::Analyze::Runner.new(@project_dir, self, prompt:
|
|
191
|
+
Aidp::Analyze::Runner.new(@project_dir, self, prompt: @prompt)
|
|
192
192
|
when :execute
|
|
193
|
-
Aidp::Execute::Runner.new(@project_dir, self, prompt:
|
|
193
|
+
Aidp::Execute::Runner.new(@project_dir, self, prompt: @prompt)
|
|
194
194
|
else
|
|
195
195
|
raise ArgumentError, "Unsupported mode: #{@mode}"
|
|
196
196
|
end
|
|
@@ -8,22 +8,25 @@ module Aidp
|
|
|
8
8
|
module State
|
|
9
9
|
# Handles file I/O and persistence for state management
|
|
10
10
|
class Persistence
|
|
11
|
-
def initialize(project_dir, mode)
|
|
11
|
+
def initialize(project_dir, mode, skip_persistence: false)
|
|
12
12
|
@project_dir = project_dir
|
|
13
13
|
@mode = mode
|
|
14
14
|
@state_dir = File.join(project_dir, ".aidp", "harness")
|
|
15
15
|
@state_file = File.join(@state_dir, "#{mode}_state.json")
|
|
16
16
|
@lock_file = File.join(@state_dir, "#{mode}_state.lock")
|
|
17
|
+
# Use explicit skip_persistence flag for dependency injection
|
|
18
|
+
# Callers should set skip_persistence: true for test/dry-run scenarios
|
|
19
|
+
@skip_persistence = skip_persistence
|
|
17
20
|
ensure_state_directory
|
|
18
21
|
end
|
|
19
22
|
|
|
20
23
|
def has_state?
|
|
21
|
-
return false if
|
|
24
|
+
return false if @skip_persistence
|
|
22
25
|
File.exist?(@state_file)
|
|
23
26
|
end
|
|
24
27
|
|
|
25
28
|
def load_state
|
|
26
|
-
return {} if
|
|
29
|
+
return {} if @skip_persistence || !has_state?
|
|
27
30
|
|
|
28
31
|
with_lock do
|
|
29
32
|
content = File.read(@state_file)
|
|
@@ -35,7 +38,7 @@ module Aidp
|
|
|
35
38
|
end
|
|
36
39
|
|
|
37
40
|
def save_state(state_data)
|
|
38
|
-
return if
|
|
41
|
+
return if @skip_persistence
|
|
39
42
|
|
|
40
43
|
with_lock do
|
|
41
44
|
state_with_metadata = add_metadata(state_data)
|
|
@@ -44,7 +47,7 @@ module Aidp
|
|
|
44
47
|
end
|
|
45
48
|
|
|
46
49
|
def clear_state
|
|
47
|
-
return if
|
|
50
|
+
return if @skip_persistence
|
|
48
51
|
|
|
49
52
|
with_lock do
|
|
50
53
|
File.delete(@state_file) if File.exist?(@state_file)
|
|
@@ -53,10 +56,6 @@ module Aidp
|
|
|
53
56
|
|
|
54
57
|
private
|
|
55
58
|
|
|
56
|
-
def test_mode?
|
|
57
|
-
ENV["RACK_ENV"] == "test" || defined?(RSpec)
|
|
58
|
-
end
|
|
59
|
-
|
|
60
59
|
def add_metadata(state_data)
|
|
61
60
|
state_data.merge(
|
|
62
61
|
mode: @mode,
|
|
@@ -76,7 +75,7 @@ module Aidp
|
|
|
76
75
|
end
|
|
77
76
|
|
|
78
77
|
def with_lock(&block)
|
|
79
|
-
return yield if
|
|
78
|
+
return yield if @skip_persistence
|
|
80
79
|
|
|
81
80
|
acquire_lock_with_timeout(&block)
|
|
82
81
|
ensure
|
|
@@ -10,11 +10,12 @@ module Aidp
|
|
|
10
10
|
module State
|
|
11
11
|
# Manages workflow-specific state and progress tracking
|
|
12
12
|
class WorkflowState
|
|
13
|
-
def initialize(persistence, project_dir, mode)
|
|
13
|
+
def initialize(persistence, project_dir, mode, progress_tracker_factory: nil)
|
|
14
14
|
@persistence = persistence
|
|
15
15
|
@project_dir = project_dir
|
|
16
16
|
@mode = mode
|
|
17
|
-
@
|
|
17
|
+
@progress_tracker_factory = progress_tracker_factory
|
|
18
|
+
@progress_tracker = @progress_tracker_factory ? @progress_tracker_factory.call : create_progress_tracker
|
|
18
19
|
end
|
|
19
20
|
|
|
20
21
|
def completed_steps
|