aidp 0.12.0 → 0.13.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/lib/aidp/analyze/json_file_storage.rb +21 -21
- data/lib/aidp/cli/enhanced_input.rb +114 -0
- data/lib/aidp/cli/first_run_wizard.rb +12 -14
- data/lib/aidp/cli/mcp_dashboard.rb +3 -3
- data/lib/aidp/cli/terminal_io.rb +26 -0
- data/lib/aidp/cli.rb +4 -4
- data/lib/aidp/config/paths.rb +131 -0
- data/lib/aidp/config.rb +18 -4
- data/lib/aidp/harness/condition_detector.rb +6 -6
- data/lib/aidp/harness/config_loader.rb +23 -23
- data/lib/aidp/harness/config_manager.rb +61 -61
- data/lib/aidp/harness/config_validator.rb +13 -12
- data/lib/aidp/harness/configuration.rb +30 -29
- data/lib/aidp/harness/error_handler.rb +13 -13
- data/lib/aidp/harness/provider_config.rb +79 -79
- data/lib/aidp/harness/provider_factory.rb +40 -40
- data/lib/aidp/harness/provider_info.rb +37 -20
- data/lib/aidp/harness/provider_manager.rb +58 -53
- data/lib/aidp/harness/provider_type_checker.rb +6 -6
- data/lib/aidp/harness/runner.rb +7 -7
- data/lib/aidp/harness/status_display.rb +33 -46
- data/lib/aidp/harness/ui/enhanced_workflow_selector.rb +2 -1
- data/lib/aidp/harness/ui/job_monitor.rb +7 -7
- data/lib/aidp/harness/user_interface.rb +43 -43
- data/lib/aidp/providers/anthropic.rb +100 -26
- data/lib/aidp/providers/base.rb +13 -0
- data/lib/aidp/providers/codex.rb +28 -27
- data/lib/aidp/providers/cursor.rb +141 -34
- data/lib/aidp/providers/github_copilot.rb +26 -26
- data/lib/aidp/providers/macos_ui.rb +2 -18
- data/lib/aidp/providers/opencode.rb +26 -26
- data/lib/aidp/version.rb +1 -1
- data/lib/aidp/workflows/guided_agent.rb +344 -23
- metadata +3 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 0f6484f93a1d57d07f223f49abab2f1a919490d4cb25e6623e76ca85b430a0be
|
|
4
|
+
data.tar.gz: 6f765c07f09d77cf3ffab88c36aa9a04acf90c39fc44d326a594b7ff4b67759b
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: e3219a59423ae33fc74bfaf38ac3ecebc3a157ac4f789c22252527652f02f63a1d98078de3db8b277d323073bf5cec8b86c97e9e7749f9a4e3097c6d849a4c2e
|
|
7
|
+
data.tar.gz: 3ec1273d7a35839fef07a02fa3a77e9340c008146c87ae790c8829f851f668af5fe1a1df12e28244b2b78c3313dd4ca667cb5e794232a3c4507f09f540d46cd9
|
|
@@ -14,7 +14,7 @@ module Aidp
|
|
|
14
14
|
|
|
15
15
|
# Store data in a JSON file
|
|
16
16
|
def store_data(filename, data)
|
|
17
|
-
file_path =
|
|
17
|
+
file_path = file_path(filename)
|
|
18
18
|
|
|
19
19
|
# Ensure directory exists
|
|
20
20
|
FileUtils.mkdir_p(File.dirname(file_path))
|
|
@@ -31,8 +31,8 @@ module Aidp
|
|
|
31
31
|
end
|
|
32
32
|
|
|
33
33
|
# Retrieve data from a JSON file
|
|
34
|
-
def
|
|
35
|
-
file_path =
|
|
34
|
+
def data(filename)
|
|
35
|
+
file_path = file_path(filename)
|
|
36
36
|
|
|
37
37
|
return nil unless File.exist?(file_path)
|
|
38
38
|
|
|
@@ -45,12 +45,12 @@ module Aidp
|
|
|
45
45
|
|
|
46
46
|
# Check if a JSON file exists
|
|
47
47
|
def data_exists?(filename)
|
|
48
|
-
File.exist?(
|
|
48
|
+
File.exist?(file_path(filename))
|
|
49
49
|
end
|
|
50
50
|
|
|
51
51
|
# Delete a JSON file
|
|
52
52
|
def delete_data(filename)
|
|
53
|
-
file_path =
|
|
53
|
+
file_path = file_path(filename)
|
|
54
54
|
|
|
55
55
|
if File.exist?(file_path)
|
|
56
56
|
File.delete(file_path)
|
|
@@ -89,8 +89,8 @@ module Aidp
|
|
|
89
89
|
end
|
|
90
90
|
|
|
91
91
|
# Get project configuration
|
|
92
|
-
def
|
|
93
|
-
|
|
92
|
+
def project_config
|
|
93
|
+
data("project_config.json")
|
|
94
94
|
end
|
|
95
95
|
|
|
96
96
|
# Store runtime status
|
|
@@ -99,8 +99,8 @@ module Aidp
|
|
|
99
99
|
end
|
|
100
100
|
|
|
101
101
|
# Get runtime status
|
|
102
|
-
def
|
|
103
|
-
|
|
102
|
+
def runtime_status
|
|
103
|
+
data("runtime_status.json")
|
|
104
104
|
end
|
|
105
105
|
|
|
106
106
|
# Store simple metrics
|
|
@@ -109,8 +109,8 @@ module Aidp
|
|
|
109
109
|
end
|
|
110
110
|
|
|
111
111
|
# Get simple metrics
|
|
112
|
-
def
|
|
113
|
-
|
|
112
|
+
def simple_metrics
|
|
113
|
+
data("simple_metrics.json")
|
|
114
114
|
end
|
|
115
115
|
|
|
116
116
|
# Store analysis session data
|
|
@@ -119,8 +119,8 @@ module Aidp
|
|
|
119
119
|
end
|
|
120
120
|
|
|
121
121
|
# Get analysis session data
|
|
122
|
-
def
|
|
123
|
-
|
|
122
|
+
def analysis_session(session_id)
|
|
123
|
+
data("sessions/#{session_id}.json")
|
|
124
124
|
end
|
|
125
125
|
|
|
126
126
|
# List analysis sessions
|
|
@@ -145,8 +145,8 @@ module Aidp
|
|
|
145
145
|
end
|
|
146
146
|
|
|
147
147
|
# Get user preferences
|
|
148
|
-
def
|
|
149
|
-
|
|
148
|
+
def user_preferences
|
|
149
|
+
data("user_preferences.json")
|
|
150
150
|
end
|
|
151
151
|
|
|
152
152
|
# Store cache data
|
|
@@ -161,8 +161,8 @@ module Aidp
|
|
|
161
161
|
end
|
|
162
162
|
|
|
163
163
|
# Get cache data (respects TTL)
|
|
164
|
-
def
|
|
165
|
-
cache_file_data =
|
|
164
|
+
def cache(cache_key)
|
|
165
|
+
cache_file_data = data("cache/#{cache_key}.json")
|
|
166
166
|
return nil unless cache_file_data
|
|
167
167
|
|
|
168
168
|
# Check TTL if specified
|
|
@@ -203,7 +203,7 @@ module Aidp
|
|
|
203
203
|
end
|
|
204
204
|
|
|
205
205
|
# Get storage statistics
|
|
206
|
-
def
|
|
206
|
+
def storage_statistics
|
|
207
207
|
files = list_files
|
|
208
208
|
|
|
209
209
|
{
|
|
@@ -226,7 +226,7 @@ module Aidp
|
|
|
226
226
|
|
|
227
227
|
files = list_files
|
|
228
228
|
files.each do |file_info|
|
|
229
|
-
data =
|
|
229
|
+
data = data(file_info[:filename])
|
|
230
230
|
export_data["files"][file_info[:filename]] = {
|
|
231
231
|
"data" => data,
|
|
232
232
|
"metadata" => {
|
|
@@ -249,7 +249,7 @@ module Aidp
|
|
|
249
249
|
|
|
250
250
|
# Import data from an exported JSON file
|
|
251
251
|
def import_data(import_filename)
|
|
252
|
-
import_path =
|
|
252
|
+
import_path = file_path(import_filename)
|
|
253
253
|
|
|
254
254
|
unless File.exist?(import_path)
|
|
255
255
|
raise "Import file does not exist: #{import_filename}"
|
|
@@ -280,7 +280,7 @@ module Aidp
|
|
|
280
280
|
|
|
281
281
|
private
|
|
282
282
|
|
|
283
|
-
def
|
|
283
|
+
def file_path(filename)
|
|
284
284
|
File.join(@storage_dir, filename)
|
|
285
285
|
end
|
|
286
286
|
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "tty-prompt"
|
|
4
|
+
require "reline"
|
|
5
|
+
|
|
6
|
+
module Aidp
|
|
7
|
+
class CLI
|
|
8
|
+
# Enhanced input handler with full readline-style key bindings using Reline
|
|
9
|
+
class EnhancedInput
|
|
10
|
+
# Standard key bindings supported by Reline:
|
|
11
|
+
# - Ctrl-A: Move to beginning of line
|
|
12
|
+
# - Ctrl-E: Move to end of line
|
|
13
|
+
# - Ctrl-W: Delete word backward
|
|
14
|
+
# - Ctrl-K: Kill to end of line
|
|
15
|
+
# - Ctrl-U: Kill to beginning of line
|
|
16
|
+
# - Ctrl-D: Delete character forward
|
|
17
|
+
# - Ctrl-H/Backspace: Delete character backward
|
|
18
|
+
# - Left/Right arrows: Move cursor
|
|
19
|
+
# - Alt-F/Alt-B: Move forward/backward by word
|
|
20
|
+
# - Home/End: Jump to beginning/end
|
|
21
|
+
# - Ctrl-T: Transpose characters
|
|
22
|
+
# - And many more Emacs-style bindings
|
|
23
|
+
|
|
24
|
+
def initialize(prompt: nil, input: nil, output: nil, use_reline: true)
|
|
25
|
+
@use_reline = use_reline
|
|
26
|
+
@input = input || $stdin
|
|
27
|
+
@output = output || $stdout
|
|
28
|
+
@prompt = prompt || TTY::Prompt.new(
|
|
29
|
+
input: @input,
|
|
30
|
+
output: @output,
|
|
31
|
+
enable_color: true,
|
|
32
|
+
interrupt: :exit
|
|
33
|
+
)
|
|
34
|
+
@show_hints = false
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
# Ask a question with full readline support
|
|
38
|
+
# Uses Reline for readline-style editing when use_reline is true
|
|
39
|
+
def ask(question, **options)
|
|
40
|
+
# If reline is enabled and we're in a TTY, use reline for better editing
|
|
41
|
+
if @use_reline && @input.tty?
|
|
42
|
+
default = options[:default]
|
|
43
|
+
required = options[:required] || false
|
|
44
|
+
|
|
45
|
+
# Display helpful hint on first use
|
|
46
|
+
if @show_hints
|
|
47
|
+
@output.puts "💡 Hint: Use Ctrl-A (start), Ctrl-E (end), Ctrl-W (delete word), Ctrl-K (kill line)"
|
|
48
|
+
@show_hints = false
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
# Use Reline for input with full key binding support
|
|
52
|
+
loop do
|
|
53
|
+
prompt_text = question.to_s
|
|
54
|
+
prompt_text += " (#{default})" if default
|
|
55
|
+
prompt_text += " "
|
|
56
|
+
|
|
57
|
+
# Reline provides full readline editing capabilities
|
|
58
|
+
Reline.output = @output
|
|
59
|
+
Reline.input = @input
|
|
60
|
+
Reline.completion_append_character = " "
|
|
61
|
+
|
|
62
|
+
answer = Reline.readline(prompt_text, false)
|
|
63
|
+
|
|
64
|
+
# Handle Ctrl-D (nil return)
|
|
65
|
+
if answer.nil?
|
|
66
|
+
@output.puts
|
|
67
|
+
raise Interrupt
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
answer = answer.strip
|
|
71
|
+
answer = default if answer.empty? && default
|
|
72
|
+
|
|
73
|
+
if required && (answer.nil? || answer.empty?)
|
|
74
|
+
@output.puts " Value required."
|
|
75
|
+
next
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
return answer
|
|
79
|
+
end
|
|
80
|
+
else
|
|
81
|
+
# Fall back to TTY::Prompt's ask
|
|
82
|
+
@prompt.ask(question, **options)
|
|
83
|
+
end
|
|
84
|
+
rescue Interrupt
|
|
85
|
+
@output.puts
|
|
86
|
+
raise
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
# Enable hints for key bindings
|
|
90
|
+
def enable_hints!
|
|
91
|
+
@show_hints = true
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
# Disable Reline (fall back to TTY::Prompt)
|
|
95
|
+
def disable_reline!
|
|
96
|
+
@use_reline = false
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
# Enable Reline
|
|
100
|
+
def enable_reline!
|
|
101
|
+
@use_reline = true
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
# Delegate other methods to underlying prompt
|
|
105
|
+
def method_missing(method, *args, **kwargs, &block)
|
|
106
|
+
@prompt.send(method, *args, **kwargs, &block)
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
def respond_to_missing?(method, include_private = false)
|
|
110
|
+
@prompt.respond_to?(method, include_private) || super
|
|
111
|
+
end
|
|
112
|
+
end
|
|
113
|
+
end
|
|
114
|
+
end
|
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
require "yaml"
|
|
5
5
|
require "tty-prompt"
|
|
6
6
|
require_relative "../harness/provider_factory"
|
|
7
|
+
require_relative "../config/paths"
|
|
7
8
|
|
|
8
9
|
module Aidp
|
|
9
10
|
class CLI
|
|
@@ -96,13 +97,14 @@ module Aidp
|
|
|
96
97
|
display_message("Template not found: #{filename}", type: :error)
|
|
97
98
|
return nil
|
|
98
99
|
end
|
|
99
|
-
dest =
|
|
100
|
+
dest = Aidp::ConfigPaths.config_file(@project_dir)
|
|
101
|
+
Aidp::ConfigPaths.ensure_config_dir(@project_dir)
|
|
100
102
|
File.write(dest, File.read(src))
|
|
101
103
|
dest
|
|
102
104
|
end
|
|
103
105
|
|
|
104
106
|
def write_minimal_config(project_dir)
|
|
105
|
-
dest =
|
|
107
|
+
dest = Aidp::ConfigPaths.config_file(project_dir)
|
|
106
108
|
return dest if File.exist?(dest)
|
|
107
109
|
data = {
|
|
108
110
|
"harness" => {
|
|
@@ -118,26 +120,23 @@ module Aidp
|
|
|
118
120
|
}
|
|
119
121
|
}
|
|
120
122
|
}
|
|
121
|
-
|
|
123
|
+
Aidp::ConfigPaths.ensure_config_dir(project_dir)
|
|
122
124
|
File.write(dest, YAML.dump(data))
|
|
123
125
|
dest
|
|
124
126
|
end
|
|
125
127
|
|
|
126
128
|
def write_example_config(project_dir)
|
|
127
129
|
Aidp::Config.create_example_config(project_dir)
|
|
128
|
-
|
|
130
|
+
Aidp::ConfigPaths.config_file(project_dir)
|
|
129
131
|
end
|
|
130
132
|
|
|
131
133
|
def run_custom
|
|
132
|
-
dest =
|
|
134
|
+
dest = Aidp::ConfigPaths.config_file(@project_dir)
|
|
133
135
|
return dest if File.exist?(dest)
|
|
134
136
|
|
|
135
137
|
@prompt.say("Interactive custom configuration: press Enter to accept defaults shown in [brackets].")
|
|
136
138
|
@prompt.say("")
|
|
137
139
|
|
|
138
|
-
# Get available providers for validation
|
|
139
|
-
available_providers = get_available_providers
|
|
140
|
-
|
|
141
140
|
# Use TTY::Prompt select for primary provider
|
|
142
141
|
# Find the formatted string that matches the default
|
|
143
142
|
default_option = available_providers.find { |option| option.start_with?("cursor -") } || available_providers.first
|
|
@@ -169,12 +168,13 @@ module Aidp
|
|
|
169
168
|
},
|
|
170
169
|
"providers" => provider_section
|
|
171
170
|
}
|
|
171
|
+
Aidp::ConfigPaths.ensure_config_dir(@project_dir)
|
|
172
172
|
File.write(dest, YAML.dump(data))
|
|
173
173
|
dest
|
|
174
174
|
end
|
|
175
175
|
|
|
176
176
|
def run_custom_with_defaults(existing_config)
|
|
177
|
-
dest =
|
|
177
|
+
dest = Aidp::ConfigPaths.config_file(@project_dir)
|
|
178
178
|
|
|
179
179
|
# Extract current values from existing config
|
|
180
180
|
harness_config = existing_config[:harness] || existing_config["harness"] || {}
|
|
@@ -188,9 +188,6 @@ module Aidp
|
|
|
188
188
|
@prompt.say("Interactive configuration update: press Enter to keep current values shown in [brackets].")
|
|
189
189
|
@prompt.say("")
|
|
190
190
|
|
|
191
|
-
# Get available providers for validation
|
|
192
|
-
available_providers = get_available_providers
|
|
193
|
-
|
|
194
191
|
# Use TTY::Prompt select for primary provider
|
|
195
192
|
# Find the formatted string that matches the current default
|
|
196
193
|
default_option = available_providers.find { |option| option.start_with?("#{current_default} -") } || available_providers.first
|
|
@@ -240,12 +237,13 @@ module Aidp
|
|
|
240
237
|
"providers" => provider_section
|
|
241
238
|
}
|
|
242
239
|
|
|
240
|
+
Aidp::ConfigPaths.ensure_config_dir(@project_dir)
|
|
243
241
|
File.write(dest, YAML.dump(data))
|
|
244
242
|
dest
|
|
245
243
|
end
|
|
246
244
|
|
|
247
245
|
def load_existing_config
|
|
248
|
-
config_file =
|
|
246
|
+
config_file = Aidp::ConfigPaths.config_file(@project_dir)
|
|
249
247
|
return nil unless File.exist?(config_file)
|
|
250
248
|
|
|
251
249
|
begin
|
|
@@ -274,7 +272,7 @@ module Aidp
|
|
|
274
272
|
end
|
|
275
273
|
|
|
276
274
|
# Get available providers for validation
|
|
277
|
-
def
|
|
275
|
+
def available_providers
|
|
278
276
|
# Get all supported providers from the factory (single source of truth)
|
|
279
277
|
all_providers = Aidp::Harness::ProviderFactory::PROVIDER_CLASSES.keys
|
|
280
278
|
|
|
@@ -57,7 +57,7 @@ module Aidp
|
|
|
57
57
|
server_matrix = build_server_matrix
|
|
58
58
|
eligible_providers = []
|
|
59
59
|
|
|
60
|
-
@configuration.
|
|
60
|
+
@configuration.provider_names.each do |provider|
|
|
61
61
|
provider_servers = server_matrix[:provider_servers][provider] || []
|
|
62
62
|
enabled_servers = provider_servers.select { |s| s[:enabled] }.map { |s| s[:name] }
|
|
63
63
|
|
|
@@ -70,7 +70,7 @@ module Aidp
|
|
|
70
70
|
{
|
|
71
71
|
required_servers: required_servers,
|
|
72
72
|
eligible_providers: eligible_providers,
|
|
73
|
-
total_providers: @configuration.
|
|
73
|
+
total_providers: @configuration.provider_names.size
|
|
74
74
|
}
|
|
75
75
|
end
|
|
76
76
|
|
|
@@ -96,7 +96,7 @@ module Aidp
|
|
|
96
96
|
private
|
|
97
97
|
|
|
98
98
|
def build_server_matrix
|
|
99
|
-
providers = @configuration.
|
|
99
|
+
providers = @configuration.provider_names
|
|
100
100
|
all_servers = {} # server_name => {providers: {provider_name => server_info}}
|
|
101
101
|
provider_servers = {} # provider_name => [server_info]
|
|
102
102
|
|
data/lib/aidp/cli/terminal_io.rb
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
require "stringio"
|
|
4
|
+
require "tty-reader"
|
|
4
5
|
|
|
5
6
|
module Aidp
|
|
6
7
|
class CLI
|
|
@@ -32,6 +33,31 @@ module Aidp
|
|
|
32
33
|
@input.gets
|
|
33
34
|
end
|
|
34
35
|
|
|
36
|
+
# Enhanced readline-style input with standard key combinations
|
|
37
|
+
# Supports: Ctrl-A (beginning), Ctrl-E (end), Ctrl-W (delete word), etc.
|
|
38
|
+
def readline(prompt = "", default: nil)
|
|
39
|
+
# Use StringIO for testing, otherwise use TTY::Reader for real input
|
|
40
|
+
if @input.is_a?(StringIO)
|
|
41
|
+
@output.print(prompt)
|
|
42
|
+
@output.flush
|
|
43
|
+
line = @input.gets
|
|
44
|
+
return line&.chomp if line
|
|
45
|
+
return default
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
reader = TTY::Reader.new(
|
|
49
|
+
input: @input,
|
|
50
|
+
output: @output,
|
|
51
|
+
interrupt: :exit
|
|
52
|
+
)
|
|
53
|
+
|
|
54
|
+
# Read line with full readline support (Ctrl-A, Ctrl-E, Ctrl-W, etc.)
|
|
55
|
+
result = reader.read_line(prompt, default: default || "")
|
|
56
|
+
result&.chomp
|
|
57
|
+
rescue TTY::Reader::InputInterrupt
|
|
58
|
+
raise Interrupt
|
|
59
|
+
end
|
|
60
|
+
|
|
35
61
|
def write(str)
|
|
36
62
|
@output.write(str)
|
|
37
63
|
end
|
data/lib/aidp/cli.rb
CHANGED
|
@@ -618,8 +618,8 @@ module Aidp
|
|
|
618
618
|
false
|
|
619
619
|
end
|
|
620
620
|
end
|
|
621
|
-
|
|
622
|
-
pm = Aidp::Harness::ProviderManager.new(
|
|
621
|
+
config_manager = Aidp::Harness::ConfigManager.new(Dir.pwd)
|
|
622
|
+
pm = Aidp::Harness::ProviderManager.new(config_manager, prompt: TTY::Prompt.new)
|
|
623
623
|
|
|
624
624
|
# Use TTY::Spinner for progress indication
|
|
625
625
|
require "tty-spinner"
|
|
@@ -772,11 +772,11 @@ module Aidp
|
|
|
772
772
|
require "tty-spinner"
|
|
773
773
|
|
|
774
774
|
provider_name = args.shift
|
|
775
|
-
|
|
775
|
+
config_manager = Aidp::Harness::ConfigManager.new(Dir.pwd)
|
|
776
776
|
providers_to_refresh = if provider_name
|
|
777
777
|
[provider_name]
|
|
778
778
|
else
|
|
779
|
-
|
|
779
|
+
config_manager.provider_names
|
|
780
780
|
end
|
|
781
781
|
|
|
782
782
|
display_message("Refreshing provider information...", type: :info)
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "fileutils"
|
|
4
|
+
|
|
5
|
+
module Aidp
|
|
6
|
+
# Centralized path management for all AIDP internal files
|
|
7
|
+
# Ensures consistent file locations and prevents path-related bugs
|
|
8
|
+
module ConfigPaths
|
|
9
|
+
# Get the main AIDP directory for a project
|
|
10
|
+
def self.aidp_dir(project_dir = Dir.pwd)
|
|
11
|
+
File.join(project_dir, ".aidp")
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
# Get the main configuration file path
|
|
15
|
+
def self.config_file(project_dir = Dir.pwd)
|
|
16
|
+
File.join(aidp_dir(project_dir), "aidp.yml")
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
# Get the configuration directory path
|
|
20
|
+
def self.config_dir(project_dir = Dir.pwd)
|
|
21
|
+
aidp_dir(project_dir)
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
# Get the progress directory path
|
|
25
|
+
def self.progress_dir(project_dir = Dir.pwd)
|
|
26
|
+
File.join(aidp_dir(project_dir), "progress")
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
# Get the execute progress file path
|
|
30
|
+
def self.execute_progress_file(project_dir = Dir.pwd)
|
|
31
|
+
File.join(progress_dir(project_dir), "execute.yml")
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
# Get the analyze progress file path
|
|
35
|
+
def self.analyze_progress_file(project_dir = Dir.pwd)
|
|
36
|
+
File.join(progress_dir(project_dir), "analyze.yml")
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
# Get the harness state directory path
|
|
40
|
+
def self.harness_state_dir(project_dir = Dir.pwd)
|
|
41
|
+
File.join(aidp_dir(project_dir), "harness")
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
# Get the harness state file path for a specific mode
|
|
45
|
+
def self.harness_state_file(mode, project_dir = Dir.pwd)
|
|
46
|
+
File.join(harness_state_dir(project_dir), "#{mode}_state.json")
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
# Get the providers directory path
|
|
50
|
+
def self.providers_dir(project_dir = Dir.pwd)
|
|
51
|
+
File.join(aidp_dir(project_dir), "providers")
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
# Get the provider info file path
|
|
55
|
+
def self.provider_info_file(provider_name, project_dir = Dir.pwd)
|
|
56
|
+
File.join(providers_dir(project_dir), "#{provider_name}_info.yml")
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
# Get the jobs directory path
|
|
60
|
+
def self.jobs_dir(project_dir = Dir.pwd)
|
|
61
|
+
File.join(aidp_dir(project_dir), "jobs")
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
# Get the checkpoint file path
|
|
65
|
+
def self.checkpoint_file(project_dir = Dir.pwd)
|
|
66
|
+
File.join(aidp_dir(project_dir), "checkpoint.yml")
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
# Get the checkpoint history file path
|
|
70
|
+
def self.checkpoint_history_file(project_dir = Dir.pwd)
|
|
71
|
+
File.join(aidp_dir(project_dir), "checkpoint_history.jsonl")
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
# Get the JSON storage directory path
|
|
75
|
+
def self.json_storage_dir(project_dir = Dir.pwd)
|
|
76
|
+
File.join(aidp_dir(project_dir), "json")
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
# Check if the main configuration file exists
|
|
80
|
+
def self.config_exists?(project_dir = Dir.pwd)
|
|
81
|
+
File.exist?(config_file(project_dir))
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
# Ensure the main AIDP directory exists
|
|
85
|
+
def self.ensure_aidp_dir(project_dir = Dir.pwd)
|
|
86
|
+
dir = aidp_dir(project_dir)
|
|
87
|
+
FileUtils.mkdir_p(dir) unless Dir.exist?(dir)
|
|
88
|
+
dir
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
# Ensure the configuration directory exists
|
|
92
|
+
def self.ensure_config_dir(project_dir = Dir.pwd)
|
|
93
|
+
ensure_aidp_dir(project_dir)
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
# Ensure the progress directory exists
|
|
97
|
+
def self.ensure_progress_dir(project_dir = Dir.pwd)
|
|
98
|
+
dir = progress_dir(project_dir)
|
|
99
|
+
FileUtils.mkdir_p(dir) unless Dir.exist?(dir)
|
|
100
|
+
dir
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
# Ensure the harness state directory exists
|
|
104
|
+
def self.ensure_harness_state_dir(project_dir = Dir.pwd)
|
|
105
|
+
dir = harness_state_dir(project_dir)
|
|
106
|
+
FileUtils.mkdir_p(dir) unless Dir.exist?(dir)
|
|
107
|
+
dir
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
# Ensure the providers directory exists
|
|
111
|
+
def self.ensure_providers_dir(project_dir = Dir.pwd)
|
|
112
|
+
dir = providers_dir(project_dir)
|
|
113
|
+
FileUtils.mkdir_p(dir) unless Dir.exist?(dir)
|
|
114
|
+
dir
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
# Ensure the jobs directory exists
|
|
118
|
+
def self.ensure_jobs_dir(project_dir = Dir.pwd)
|
|
119
|
+
dir = jobs_dir(project_dir)
|
|
120
|
+
FileUtils.mkdir_p(dir) unless Dir.exist?(dir)
|
|
121
|
+
dir
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
# Ensure the JSON storage directory exists
|
|
125
|
+
def self.ensure_json_storage_dir(project_dir = Dir.pwd)
|
|
126
|
+
dir = json_storage_dir(project_dir)
|
|
127
|
+
FileUtils.mkdir_p(dir) unless Dir.exist?(dir)
|
|
128
|
+
dir
|
|
129
|
+
end
|
|
130
|
+
end
|
|
131
|
+
end
|
data/lib/aidp/config.rb
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
require "yaml"
|
|
4
|
+
require_relative "config/paths"
|
|
4
5
|
|
|
5
6
|
module Aidp
|
|
6
7
|
# Configuration management for both execute and analyze modes
|
|
@@ -165,7 +166,7 @@ module Aidp
|
|
|
165
166
|
}.freeze
|
|
166
167
|
|
|
167
168
|
def self.load(project_dir = Dir.pwd)
|
|
168
|
-
config_file =
|
|
169
|
+
config_file = ConfigPaths.config_file(project_dir)
|
|
169
170
|
|
|
170
171
|
if File.exist?(config_file)
|
|
171
172
|
load_yaml_config(config_file)
|
|
@@ -244,15 +245,15 @@ module Aidp
|
|
|
244
245
|
|
|
245
246
|
# Check if configuration file exists
|
|
246
247
|
def self.config_exists?(project_dir = Dir.pwd)
|
|
247
|
-
|
|
248
|
+
ConfigPaths.config_exists?(project_dir)
|
|
248
249
|
end
|
|
249
250
|
|
|
250
251
|
# Create example configuration file
|
|
251
252
|
def self.create_example_config(project_dir = Dir.pwd)
|
|
252
|
-
config_path =
|
|
253
|
+
config_path = ConfigPaths.config_file(project_dir)
|
|
253
254
|
return false if File.exist?(config_path)
|
|
254
255
|
|
|
255
|
-
|
|
256
|
+
ConfigPaths.ensure_config_dir(project_dir)
|
|
256
257
|
|
|
257
258
|
example_config = {
|
|
258
259
|
harness: {
|
|
@@ -283,6 +284,19 @@ module Aidp
|
|
|
283
284
|
true
|
|
284
285
|
end
|
|
285
286
|
|
|
287
|
+
# Expose path methods for convenience
|
|
288
|
+
def self.config_file(project_dir = Dir.pwd)
|
|
289
|
+
ConfigPaths.config_file(project_dir)
|
|
290
|
+
end
|
|
291
|
+
|
|
292
|
+
def self.config_dir(project_dir = Dir.pwd)
|
|
293
|
+
ConfigPaths.config_dir(project_dir)
|
|
294
|
+
end
|
|
295
|
+
|
|
296
|
+
def self.aidp_dir(project_dir = Dir.pwd)
|
|
297
|
+
ConfigPaths.aidp_dir(project_dir)
|
|
298
|
+
end
|
|
299
|
+
|
|
286
300
|
private_class_method def self.load_yaml_config(config_file)
|
|
287
301
|
YAML.load_file(config_file) || {}
|
|
288
302
|
rescue => e
|
|
@@ -1425,7 +1425,7 @@ module Aidp
|
|
|
1425
1425
|
end
|
|
1426
1426
|
|
|
1427
1427
|
# Get completion confidence level
|
|
1428
|
-
def
|
|
1428
|
+
def completion_confidence(completion_info)
|
|
1429
1429
|
return 0.0 unless completion_info && completion_info[:confidence]
|
|
1430
1430
|
|
|
1431
1431
|
completion_info[:confidence]
|
|
@@ -1433,23 +1433,23 @@ module Aidp
|
|
|
1433
1433
|
|
|
1434
1434
|
# Check if completion is high confidence
|
|
1435
1435
|
def high_confidence_completion?(completion_info)
|
|
1436
|
-
|
|
1436
|
+
completion_confidence(completion_info) >= 0.8
|
|
1437
1437
|
end
|
|
1438
1438
|
|
|
1439
1439
|
# Check if completion is medium confidence
|
|
1440
1440
|
def medium_confidence_completion?(completion_info)
|
|
1441
|
-
confidence =
|
|
1441
|
+
confidence = completion_confidence(completion_info)
|
|
1442
1442
|
confidence >= 0.5 && confidence < 0.8
|
|
1443
1443
|
end
|
|
1444
1444
|
|
|
1445
1445
|
# Check if completion is low confidence
|
|
1446
1446
|
def low_confidence_completion?(completion_info)
|
|
1447
|
-
confidence =
|
|
1447
|
+
confidence = completion_confidence(completion_info)
|
|
1448
1448
|
confidence > 0.0 && confidence < 0.5
|
|
1449
1449
|
end
|
|
1450
1450
|
|
|
1451
1451
|
# Get next actions from completion info
|
|
1452
|
-
def
|
|
1452
|
+
def next_actions(completion_info)
|
|
1453
1453
|
return [] unless completion_info && completion_info[:next_actions]
|
|
1454
1454
|
|
|
1455
1455
|
completion_info[:next_actions]
|
|
@@ -1495,7 +1495,7 @@ module Aidp
|
|
|
1495
1495
|
end
|
|
1496
1496
|
|
|
1497
1497
|
# Get progress status description
|
|
1498
|
-
def
|
|
1498
|
+
def progress_status_description(completion_info)
|
|
1499
1499
|
return "unknown" unless completion_info
|
|
1500
1500
|
|
|
1501
1501
|
case completion_info[:progress_status]
|