aidp 0.16.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/error_handler.rb +32 -13
- data/lib/aidp/analyze/kb_inspector.rb +2 -3
- data/lib/aidp/analyze/progress.rb +6 -11
- data/lib/aidp/cli/mcp_dashboard.rb +1 -1
- data/lib/aidp/cli.rb +300 -33
- data/lib/aidp/config.rb +1 -1
- data/lib/aidp/execute/async_work_loop_runner.rb +2 -1
- data/lib/aidp/execute/checkpoint.rb +1 -1
- data/lib/aidp/execute/future_work_backlog.rb +1 -1
- data/lib/aidp/execute/progress.rb +6 -9
- data/lib/aidp/execute/repl_macros.rb +79 -10
- data/lib/aidp/harness/config_loader.rb +2 -2
- data/lib/aidp/harness/config_validator.rb +1 -1
- 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 +8 -2
- 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/registry.rb +31 -29
- data/lib/aidp/skills/router.rb +178 -0
- data/lib/aidp/skills/wizard/builder.rb +141 -0
- data/lib/aidp/skills/wizard/controller.rb +145 -0
- data/lib/aidp/skills/wizard/differ.rb +232 -0
- data/lib/aidp/skills/wizard/prompter.rb +317 -0
- data/lib/aidp/skills/wizard/template_library.rb +164 -0
- data/lib/aidp/skills/wizard/writer.rb +105 -0
- 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
- data/templates/skills/README.md +334 -0
- data/templates/skills/architecture_analyst/SKILL.md +173 -0
- data/templates/skills/product_strategist/SKILL.md +141 -0
- data/templates/skills/repository_analyst/SKILL.md +117 -0
- data/templates/skills/test_analyzer/SKILL.md +213 -0
- metadata +13 -1
|
@@ -40,7 +40,7 @@ module Aidp
|
|
|
40
40
|
# Get the latest checkpoint data
|
|
41
41
|
def latest_checkpoint
|
|
42
42
|
return nil unless File.exist?(@checkpoint_file)
|
|
43
|
-
YAML.
|
|
43
|
+
YAML.safe_load_file(@checkpoint_file, permitted_classes: [Date, Time, Symbol], aliases: true)
|
|
44
44
|
end
|
|
45
45
|
|
|
46
46
|
# Get checkpoint history for analysis
|
|
@@ -218,7 +218,7 @@ module Aidp
|
|
|
218
218
|
def load_existing_backlog
|
|
219
219
|
return unless File.exist?(@backlog_file)
|
|
220
220
|
|
|
221
|
-
data = YAML.
|
|
221
|
+
data = YAML.safe_load_file(@backlog_file, permitted_classes: [Date, Time, Symbol], aliases: true)
|
|
222
222
|
@entries = data["entries"] || [] if data.is_a?(Hash)
|
|
223
223
|
@entries = symbolize_keys_deep(@entries)
|
|
224
224
|
rescue => e
|
|
@@ -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,23 +62,19 @@ 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
|
-
|
|
71
|
-
YAML.load_file(@progress_file) || {}
|
|
69
|
+
@progress = if !@skip_persistence && File.exist?(@progress_file)
|
|
70
|
+
YAML.safe_load_file(@progress_file, permitted_classes: [Date, Time, Symbol], aliases: true) || {}
|
|
72
71
|
else
|
|
73
72
|
{}
|
|
74
73
|
end
|
|
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,7 +9,7 @@ module Aidp
|
|
|
9
9
|
# - /split - Divide work into smaller contracts
|
|
10
10
|
# - /halt-on <pattern> - Pause on specific test failures
|
|
11
11
|
class ReplMacros
|
|
12
|
-
attr_reader :pinned_files, :focus_patterns, :halt_patterns, :split_mode, :current_workstream
|
|
12
|
+
attr_reader :pinned_files, :focus_patterns, :halt_patterns, :split_mode, :current_workstream, :current_skill
|
|
13
13
|
|
|
14
14
|
def initialize(project_dir: Dir.pwd)
|
|
15
15
|
@pinned_files = Set.new
|
|
@@ -18,6 +18,7 @@ module Aidp
|
|
|
18
18
|
@split_mode = false
|
|
19
19
|
@project_dir = project_dir
|
|
20
20
|
@current_workstream = nil
|
|
21
|
+
@current_skill = nil
|
|
21
22
|
@commands = register_commands
|
|
22
23
|
end
|
|
23
24
|
|
|
@@ -65,6 +66,7 @@ module Aidp
|
|
|
65
66
|
halt_patterns: @halt_patterns,
|
|
66
67
|
split_mode: @split_mode,
|
|
67
68
|
current_workstream: @current_workstream,
|
|
69
|
+
current_skill: @current_skill,
|
|
68
70
|
active_constraints: active_constraints_count
|
|
69
71
|
}
|
|
70
72
|
end
|
|
@@ -113,6 +115,30 @@ module Aidp
|
|
|
113
115
|
true
|
|
114
116
|
end
|
|
115
117
|
|
|
118
|
+
# Retrieve the current skill object, or nil if none is selected
|
|
119
|
+
#
|
|
120
|
+
# This method provides access to the full skill object (with content, providers, etc.)
|
|
121
|
+
# for the currently selected skill via `/skill use <id>`.
|
|
122
|
+
#
|
|
123
|
+
# @return [Aidp::Skills::Skill, nil] The current skill object or nil
|
|
124
|
+
#
|
|
125
|
+
# @example
|
|
126
|
+
# repl = ReplMacros.new(project_dir: Dir.pwd)
|
|
127
|
+
# repl.execute("/skill use repository_analyst")
|
|
128
|
+
# skill = repl.current_skill_object
|
|
129
|
+
# puts skill.content if skill # => skill's markdown content
|
|
130
|
+
def current_skill_object
|
|
131
|
+
return nil unless @current_skill
|
|
132
|
+
|
|
133
|
+
require_relative "../skills"
|
|
134
|
+
registry = Aidp::Skills::Registry.new(project_dir: @project_dir)
|
|
135
|
+
registry.load_skills
|
|
136
|
+
registry.find(@current_skill)
|
|
137
|
+
rescue => e
|
|
138
|
+
Aidp.log_error("repl_macros", "Failed to load current skill object", error: e.message)
|
|
139
|
+
nil
|
|
140
|
+
end
|
|
141
|
+
|
|
116
142
|
private
|
|
117
143
|
|
|
118
144
|
# Register all available REPL commands
|
|
@@ -1257,25 +1283,25 @@ module Aidp
|
|
|
1257
1283
|
lines = ["Available Skills:", ""]
|
|
1258
1284
|
by_source = registry.by_source
|
|
1259
1285
|
|
|
1260
|
-
if by_source[:
|
|
1261
|
-
lines << "
|
|
1262
|
-
by_source[:
|
|
1286
|
+
if by_source[:template].any?
|
|
1287
|
+
lines << "Template Skills:"
|
|
1288
|
+
by_source[:template].each do |skill_id|
|
|
1263
1289
|
skill = registry.find(skill_id)
|
|
1264
1290
|
lines << " • #{skill_id} - #{skill.description}"
|
|
1265
1291
|
end
|
|
1266
1292
|
lines << ""
|
|
1267
1293
|
end
|
|
1268
1294
|
|
|
1269
|
-
if by_source[:
|
|
1270
|
-
lines << "
|
|
1271
|
-
by_source[:
|
|
1295
|
+
if by_source[:project].any?
|
|
1296
|
+
lines << "Project Skills:"
|
|
1297
|
+
by_source[:project].each do |skill_id|
|
|
1272
1298
|
skill = registry.find(skill_id)
|
|
1273
|
-
lines << " • #{skill_id} - #{skill.description} [
|
|
1299
|
+
lines << " • #{skill_id} - #{skill.description} [PROJECT]"
|
|
1274
1300
|
end
|
|
1275
1301
|
lines << ""
|
|
1276
1302
|
end
|
|
1277
1303
|
|
|
1278
|
-
lines << "Use '/skill show <id>' for details"
|
|
1304
|
+
lines << "Use '/skill show <id>' for details or '/skill use <id>' to activate"
|
|
1279
1305
|
|
|
1280
1306
|
{
|
|
1281
1307
|
success: true,
|
|
@@ -1412,10 +1438,53 @@ module Aidp
|
|
|
1412
1438
|
}
|
|
1413
1439
|
end
|
|
1414
1440
|
|
|
1441
|
+
when "use"
|
|
1442
|
+
# Switch to a specific skill
|
|
1443
|
+
skill_id = args.shift
|
|
1444
|
+
|
|
1445
|
+
unless skill_id
|
|
1446
|
+
return {
|
|
1447
|
+
success: false,
|
|
1448
|
+
message: "Usage: /skill use <skill-id>",
|
|
1449
|
+
action: :none
|
|
1450
|
+
}
|
|
1451
|
+
end
|
|
1452
|
+
|
|
1453
|
+
begin
|
|
1454
|
+
registry = Aidp::Skills::Registry.new(project_dir: @project_dir)
|
|
1455
|
+
registry.load_skills
|
|
1456
|
+
|
|
1457
|
+
skill = registry.find(skill_id)
|
|
1458
|
+
|
|
1459
|
+
unless skill
|
|
1460
|
+
return {
|
|
1461
|
+
success: false,
|
|
1462
|
+
message: "Skill not found: #{skill_id}\nUse '/skill list' to see available skills",
|
|
1463
|
+
action: :none
|
|
1464
|
+
}
|
|
1465
|
+
end
|
|
1466
|
+
|
|
1467
|
+
# Store the current skill for the session
|
|
1468
|
+
@current_skill = skill_id
|
|
1469
|
+
|
|
1470
|
+
{
|
|
1471
|
+
success: true,
|
|
1472
|
+
message: "✓ Now using skill: #{skill.name} (#{skill_id})\n\n#{skill.description}",
|
|
1473
|
+
action: :switch_skill,
|
|
1474
|
+
data: {skill_id: skill_id, skill: skill}
|
|
1475
|
+
}
|
|
1476
|
+
rescue => e
|
|
1477
|
+
{
|
|
1478
|
+
success: false,
|
|
1479
|
+
message: "Failed to switch skill: #{e.message}",
|
|
1480
|
+
action: :none
|
|
1481
|
+
}
|
|
1482
|
+
end
|
|
1483
|
+
|
|
1415
1484
|
else
|
|
1416
1485
|
{
|
|
1417
1486
|
success: false,
|
|
1418
|
-
message: "Usage: /skill <command> [args]\n\nCommands:\n list - List all available skills\n show <id> - Show detailed skill information\n search <query> - Search skills by keyword\n\nExamples:\n /skill list\n /skill show repository_analyst\n /skill search git",
|
|
1487
|
+
message: "Usage: /skill <command> [args]\n\nCommands:\n list - List all available skills\n show <id> - Show detailed skill information\n search <query> - Search skills by keyword\n use <id> - Switch to a specific skill\n\nExamples:\n /skill list\n /skill show repository_analyst\n /skill search git\n /skill use repository_analyst",
|
|
1419
1488
|
action: :none
|
|
1420
1489
|
}
|
|
1421
1490
|
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:}
|
|
@@ -256,7 +256,7 @@ module Aidp
|
|
|
256
256
|
return unless @config_file
|
|
257
257
|
|
|
258
258
|
begin
|
|
259
|
-
@config = YAML.
|
|
259
|
+
@config = YAML.safe_load_file(@config_file, permitted_classes: [Date, Time, Symbol], aliases: true) || {}
|
|
260
260
|
rescue => e
|
|
261
261
|
@config = {}
|
|
262
262
|
@validation_result = {
|
|
@@ -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
|