aidp 0.12.1 → 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 +1 -7
- 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/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 +9 -9
- data/lib/aidp/harness/configuration.rb +28 -28
- 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 +2 -1
data/lib/aidp/providers/base.rb
CHANGED
@@ -73,6 +73,19 @@ module Aidp
|
|
73
73
|
raise NotImplementedError, "#{self.class} must implement #send"
|
74
74
|
end
|
75
75
|
|
76
|
+
# Fetch MCP servers configured for this provider
|
77
|
+
# Returns an array of server hashes with keys: :name, :status, :description, :enabled
|
78
|
+
# Override in subclasses to provide provider-specific MCP server detection
|
79
|
+
def fetch_mcp_servers
|
80
|
+
[]
|
81
|
+
end
|
82
|
+
|
83
|
+
# Check if this provider supports MCP servers
|
84
|
+
# Override in subclasses to provide accurate MCP support detection
|
85
|
+
def supports_mcp?
|
86
|
+
false
|
87
|
+
end
|
88
|
+
|
76
89
|
# Set job context for background execution
|
77
90
|
def set_job_context(job_id:, execution_id:, job_manager:)
|
78
91
|
@job_context = {
|
data/lib/aidp/providers/codex.rb
CHANGED
@@ -120,8 +120,9 @@ module Aidp
|
|
120
120
|
args += ["--model", model]
|
121
121
|
end
|
122
122
|
|
123
|
-
# Add approval flag
|
123
|
+
# Add approval flag - but warn about interactive behavior
|
124
124
|
if ask_for_approval
|
125
|
+
debug_log("⚠️ WARNING: --ask-for-approval flag may cause interactive prompts that could hang AIDP", level: :warn)
|
125
126
|
args += ["--ask-for-approval"]
|
126
127
|
end
|
127
128
|
|
@@ -196,11 +197,9 @@ module Aidp
|
|
196
197
|
return ENV["AIDP_CODEX_TIMEOUT"].to_i
|
197
198
|
end
|
198
199
|
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
display_message("🧠 Using adaptive timeout: #{step_timeout} seconds", type: :info)
|
203
|
-
return step_timeout
|
200
|
+
if adaptive_timeout
|
201
|
+
display_message("🧠 Using adaptive timeout: #{adaptive_timeout} seconds", type: :info)
|
202
|
+
return adaptive_timeout
|
204
203
|
end
|
205
204
|
|
206
205
|
# Default timeout
|
@@ -208,27 +207,29 @@ module Aidp
|
|
208
207
|
TIMEOUT_DEFAULT
|
209
208
|
end
|
210
209
|
|
211
|
-
def
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
210
|
+
def adaptive_timeout
|
211
|
+
@adaptive_timeout ||= begin
|
212
|
+
# Timeout recommendations based on step type patterns
|
213
|
+
step_name = ENV["AIDP_CURRENT_STEP"] || ""
|
214
|
+
|
215
|
+
case step_name
|
216
|
+
when /REPOSITORY_ANALYSIS/
|
217
|
+
TIMEOUT_REPOSITORY_ANALYSIS
|
218
|
+
when /ARCHITECTURE_ANALYSIS/
|
219
|
+
TIMEOUT_ARCHITECTURE_ANALYSIS
|
220
|
+
when /TEST_ANALYSIS/
|
221
|
+
TIMEOUT_TEST_ANALYSIS
|
222
|
+
when /FUNCTIONALITY_ANALYSIS/
|
223
|
+
TIMEOUT_FUNCTIONALITY_ANALYSIS
|
224
|
+
when /DOCUMENTATION_ANALYSIS/
|
225
|
+
TIMEOUT_DOCUMENTATION_ANALYSIS
|
226
|
+
when /STATIC_ANALYSIS/
|
227
|
+
TIMEOUT_STATIC_ANALYSIS
|
228
|
+
when /REFACTORING_RECOMMENDATIONS/
|
229
|
+
TIMEOUT_REFACTORING_RECOMMENDATIONS
|
230
|
+
else
|
231
|
+
nil # Use default
|
232
|
+
end
|
232
233
|
end
|
233
234
|
end
|
234
235
|
|
@@ -22,6 +22,15 @@ module Aidp
|
|
22
22
|
"Cursor AI"
|
23
23
|
end
|
24
24
|
|
25
|
+
def supports_mcp?
|
26
|
+
true
|
27
|
+
end
|
28
|
+
|
29
|
+
def fetch_mcp_servers
|
30
|
+
# Try cursor-agent CLI first, then fallback to config file
|
31
|
+
fetch_mcp_servers_cli || fetch_mcp_servers_config
|
32
|
+
end
|
33
|
+
|
25
34
|
def send(prompt:, session: nil)
|
26
35
|
raise "cursor-agent not available" unless self.class.available?
|
27
36
|
|
@@ -61,14 +70,9 @@ module Aidp
|
|
61
70
|
|
62
71
|
begin
|
63
72
|
# Use debug_execute_command for better debugging
|
64
|
-
#
|
65
|
-
|
66
|
-
|
67
|
-
rescue => e
|
68
|
-
# Fallback to -p mode if agent command fails
|
69
|
-
debug_log("🔄 Falling back to -p mode: #{e.message}", level: :warn)
|
70
|
-
result = debug_execute_command("cursor-agent", args: ["-p"], input: prompt, timeout: timeout_seconds, streaming: streaming_enabled)
|
71
|
-
end
|
73
|
+
# Use -p mode (designed for non-interactive/script use)
|
74
|
+
# No fallback to interactive modes - they would hang AIDP's automation workflow
|
75
|
+
result = debug_execute_command("cursor-agent", args: ["-p"], input: prompt, timeout: timeout_seconds, streaming: streaming_enabled)
|
72
76
|
|
73
77
|
# Log the results
|
74
78
|
debug_command("cursor-agent", args: ["-p"], input: prompt, output: result.out, error: result.err, exit_code: result.exit_status)
|
@@ -111,11 +115,9 @@ module Aidp
|
|
111
115
|
return ENV["AIDP_CURSOR_TIMEOUT"].to_i
|
112
116
|
end
|
113
117
|
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
display_message("🧠 Using adaptive timeout: #{step_timeout} seconds", type: :info)
|
118
|
-
return step_timeout
|
118
|
+
if adaptive_timeout
|
119
|
+
display_message("🧠 Using adaptive timeout: #{adaptive_timeout} seconds", type: :info)
|
120
|
+
return adaptive_timeout
|
119
121
|
end
|
120
122
|
|
121
123
|
# Default timeout
|
@@ -123,27 +125,29 @@ module Aidp
|
|
123
125
|
TIMEOUT_DEFAULT
|
124
126
|
end
|
125
127
|
|
126
|
-
def
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
128
|
+
def adaptive_timeout
|
129
|
+
@adaptive_timeout ||= begin
|
130
|
+
# Timeout recommendations based on step type patterns
|
131
|
+
step_name = ENV["AIDP_CURRENT_STEP"] || ""
|
132
|
+
|
133
|
+
case step_name
|
134
|
+
when /REPOSITORY_ANALYSIS/
|
135
|
+
TIMEOUT_REPOSITORY_ANALYSIS
|
136
|
+
when /ARCHITECTURE_ANALYSIS/
|
137
|
+
TIMEOUT_ARCHITECTURE_ANALYSIS
|
138
|
+
when /TEST_ANALYSIS/
|
139
|
+
TIMEOUT_TEST_ANALYSIS
|
140
|
+
when /FUNCTIONALITY_ANALYSIS/
|
141
|
+
TIMEOUT_FUNCTIONALITY_ANALYSIS
|
142
|
+
when /DOCUMENTATION_ANALYSIS/
|
143
|
+
TIMEOUT_DOCUMENTATION_ANALYSIS
|
144
|
+
when /STATIC_ANALYSIS/
|
145
|
+
TIMEOUT_STATIC_ANALYSIS
|
146
|
+
when /REFACTORING_RECOMMENDATIONS/
|
147
|
+
TIMEOUT_REFACTORING_RECOMMENDATIONS
|
148
|
+
else
|
149
|
+
nil # Use default
|
150
|
+
end
|
147
151
|
end
|
148
152
|
end
|
149
153
|
|
@@ -159,6 +163,109 @@ module Aidp
|
|
159
163
|
display_message("\n❌ cursor failed: #{message}", type: :error)
|
160
164
|
end
|
161
165
|
end
|
166
|
+
|
167
|
+
# Try to get MCP servers via cursor-agent CLI
|
168
|
+
def fetch_mcp_servers_cli
|
169
|
+
return nil unless self.class.available?
|
170
|
+
|
171
|
+
begin
|
172
|
+
# Try cursor-agent mcp list (if such command exists)
|
173
|
+
result = debug_execute_command("cursor-agent", args: ["mcp", "list"], timeout: 5)
|
174
|
+
return nil unless result.exit_status == 0
|
175
|
+
|
176
|
+
parse_mcp_servers_output(result.out)
|
177
|
+
rescue => e
|
178
|
+
debug_log("Failed to fetch MCP servers via CLI: #{e.message}", level: :debug)
|
179
|
+
nil
|
180
|
+
end
|
181
|
+
end
|
182
|
+
|
183
|
+
# Fallback to reading Cursor's config file
|
184
|
+
def fetch_mcp_servers_config
|
185
|
+
cursor_config_path = File.expand_path("~/.cursor/mcp.json")
|
186
|
+
return [] unless File.exist?(cursor_config_path)
|
187
|
+
|
188
|
+
begin
|
189
|
+
require "json"
|
190
|
+
config_content = File.read(cursor_config_path)
|
191
|
+
config = JSON.parse(config_content)
|
192
|
+
|
193
|
+
servers = []
|
194
|
+
mcp_servers = config["mcpServers"] || {}
|
195
|
+
|
196
|
+
mcp_servers.each do |name, server_config|
|
197
|
+
# Build command description
|
198
|
+
command_parts = [server_config["command"]]
|
199
|
+
command_parts.concat(server_config["args"]) if server_config["args"]
|
200
|
+
command_description = command_parts.join(" ")
|
201
|
+
|
202
|
+
servers << {
|
203
|
+
name: name,
|
204
|
+
status: "configured",
|
205
|
+
description: command_description,
|
206
|
+
enabled: true,
|
207
|
+
source: "cursor_config",
|
208
|
+
env_vars: server_config["env"] || {}
|
209
|
+
}
|
210
|
+
end
|
211
|
+
|
212
|
+
servers
|
213
|
+
rescue JSON::ParserError => e
|
214
|
+
debug_log("Failed to parse Cursor MCP configuration: #{e.message}", level: :debug)
|
215
|
+
[]
|
216
|
+
rescue => e
|
217
|
+
debug_log("Failed to parse Cursor MCP configuration: #{e.message}", level: :debug)
|
218
|
+
[]
|
219
|
+
end
|
220
|
+
end
|
221
|
+
|
222
|
+
# Parse MCP server output from CLI commands
|
223
|
+
def parse_mcp_servers_output(output)
|
224
|
+
servers = []
|
225
|
+
return servers unless output
|
226
|
+
|
227
|
+
lines = output.lines
|
228
|
+
lines.reject! { |line| /checking mcp server health/i.match?(line) }
|
229
|
+
|
230
|
+
lines.each do |line|
|
231
|
+
line = line.strip
|
232
|
+
next if line.empty?
|
233
|
+
|
234
|
+
# Try to parse cursor-agent format: "name: status"
|
235
|
+
if line =~ /^([^:]+):\s*(.+)$/
|
236
|
+
name = Regexp.last_match(1).strip
|
237
|
+
status = Regexp.last_match(2).strip
|
238
|
+
|
239
|
+
servers << {
|
240
|
+
name: name,
|
241
|
+
status: status,
|
242
|
+
description: "MCP server managed by cursor-agent",
|
243
|
+
enabled: status == "ready" || status == "connected",
|
244
|
+
source: "cursor_cli"
|
245
|
+
}
|
246
|
+
next
|
247
|
+
end
|
248
|
+
|
249
|
+
# Also try to parse extended format: "name: command - ✓ Connected" (for future compatibility)
|
250
|
+
if line =~ /^([^:]+):\s*(.+?)\s*-\s*(✓|✗)\s*(.+)$/
|
251
|
+
name = Regexp.last_match(1).strip
|
252
|
+
command = Regexp.last_match(2).strip
|
253
|
+
status_symbol = Regexp.last_match(3)
|
254
|
+
status_text = Regexp.last_match(4).strip
|
255
|
+
|
256
|
+
servers << {
|
257
|
+
name: name,
|
258
|
+
status: (status_symbol == "✓") ? "connected" : "error",
|
259
|
+
description: command,
|
260
|
+
enabled: status_symbol == "✓",
|
261
|
+
error: (status_symbol == "✗") ? status_text : nil,
|
262
|
+
source: "cursor_cli"
|
263
|
+
}
|
264
|
+
end
|
265
|
+
end
|
266
|
+
|
267
|
+
servers
|
268
|
+
end
|
162
269
|
end
|
163
270
|
end
|
164
271
|
end
|
@@ -211,11 +211,9 @@ module Aidp
|
|
211
211
|
return ENV["AIDP_GITHUB_COPILOT_TIMEOUT"].to_i
|
212
212
|
end
|
213
213
|
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
display_message("🧠 Using adaptive timeout: #{step_timeout} seconds", type: :info)
|
218
|
-
return step_timeout
|
214
|
+
if adaptive_timeout
|
215
|
+
display_message("🧠 Using adaptive timeout: #{adaptive_timeout} seconds", type: :info)
|
216
|
+
return adaptive_timeout
|
219
217
|
end
|
220
218
|
|
221
219
|
# Default timeout
|
@@ -223,27 +221,29 @@ module Aidp
|
|
223
221
|
TIMEOUT_DEFAULT
|
224
222
|
end
|
225
223
|
|
226
|
-
def
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
|
236
|
-
|
237
|
-
|
238
|
-
|
239
|
-
|
240
|
-
|
241
|
-
|
242
|
-
|
243
|
-
|
244
|
-
|
245
|
-
|
246
|
-
|
224
|
+
def adaptive_timeout
|
225
|
+
@adaptive_timeout ||= begin
|
226
|
+
# Timeout recommendations based on step type patterns
|
227
|
+
step_name = ENV["AIDP_CURRENT_STEP"] || ""
|
228
|
+
|
229
|
+
case step_name
|
230
|
+
when /REPOSITORY_ANALYSIS/
|
231
|
+
TIMEOUT_REPOSITORY_ANALYSIS
|
232
|
+
when /ARCHITECTURE_ANALYSIS/
|
233
|
+
TIMEOUT_ARCHITECTURE_ANALYSIS
|
234
|
+
when /TEST_ANALYSIS/
|
235
|
+
TIMEOUT_TEST_ANALYSIS
|
236
|
+
when /FUNCTIONALITY_ANALYSIS/
|
237
|
+
TIMEOUT_FUNCTIONALITY_ANALYSIS
|
238
|
+
when /DOCUMENTATION_ANALYSIS/
|
239
|
+
TIMEOUT_DOCUMENTATION_ANALYSIS
|
240
|
+
when /STATIC_ANALYSIS/
|
241
|
+
TIMEOUT_STATIC_ANALYSIS
|
242
|
+
when /REFACTORING_RECOMMENDATIONS/
|
243
|
+
TIMEOUT_REFACTORING_RECOMMENDATIONS
|
244
|
+
else
|
245
|
+
nil # Use default
|
246
|
+
end
|
247
247
|
end
|
248
248
|
end
|
249
249
|
|
@@ -29,8 +29,8 @@ module Aidp
|
|
29
29
|
result[:response]
|
30
30
|
else
|
31
31
|
debug_log("❌ Failed to interact with Cursor: #{result[:error]}", level: :warn)
|
32
|
-
#
|
33
|
-
|
32
|
+
# No interactive fallback - would hang AIDP's automation workflow
|
33
|
+
raise "Cursor interaction failed and no non-interactive fallback available: #{result[:error]}"
|
34
34
|
end
|
35
35
|
end
|
36
36
|
|
@@ -97,22 +97,6 @@ module Aidp
|
|
97
97
|
# Must escape backslashes first to avoid double-escaping
|
98
98
|
text.gsub("\\", "\\\\").gsub('"', '\\"').gsub("'", "\\'").gsub("\n", "\\n")
|
99
99
|
end
|
100
|
-
|
101
|
-
def fallback_dialog(prompt)
|
102
|
-
# Fallback to simple dialog
|
103
|
-
truncated_prompt = (prompt.length > 200) ? prompt[0..200] + "..." : prompt
|
104
|
-
|
105
|
-
script = <<~APPLESCRIPT
|
106
|
-
display dialog "#{escape_for_applescript(truncated_prompt)}" with title "Aidp - Cursor Integration" buttons {"OK", "Open Cursor"} default button "Open Cursor"
|
107
|
-
set buttonPressed to button returned of result
|
108
|
-
if buttonPressed is "Open Cursor" then
|
109
|
-
tell application "Cursor" to activate
|
110
|
-
end if
|
111
|
-
APPLESCRIPT
|
112
|
-
|
113
|
-
system("osascript", "-e", script)
|
114
|
-
"Dialog shown - please use Cursor manually"
|
115
|
-
end
|
116
100
|
end
|
117
101
|
end
|
118
102
|
end
|
@@ -111,11 +111,9 @@ module Aidp
|
|
111
111
|
return ENV["AIDP_OPENCODE_TIMEOUT"].to_i
|
112
112
|
end
|
113
113
|
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
display_message("🧠 Using adaptive timeout: #{step_timeout} seconds", type: :info)
|
118
|
-
return step_timeout
|
114
|
+
if adaptive_timeout
|
115
|
+
display_message("🧠 Using adaptive timeout: #{adaptive_timeout} seconds", type: :info)
|
116
|
+
return adaptive_timeout
|
119
117
|
end
|
120
118
|
|
121
119
|
# Default timeout
|
@@ -123,27 +121,29 @@ module Aidp
|
|
123
121
|
TIMEOUT_DEFAULT
|
124
122
|
end
|
125
123
|
|
126
|
-
def
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
124
|
+
def adaptive_timeout
|
125
|
+
@adaptive_timeout ||= begin
|
126
|
+
# Timeout recommendations based on step type patterns
|
127
|
+
step_name = ENV["AIDP_CURRENT_STEP"] || ""
|
128
|
+
|
129
|
+
case step_name
|
130
|
+
when /REPOSITORY_ANALYSIS/
|
131
|
+
TIMEOUT_REPOSITORY_ANALYSIS
|
132
|
+
when /ARCHITECTURE_ANALYSIS/
|
133
|
+
TIMEOUT_ARCHITECTURE_ANALYSIS
|
134
|
+
when /TEST_ANALYSIS/
|
135
|
+
TIMEOUT_TEST_ANALYSIS
|
136
|
+
when /FUNCTIONALITY_ANALYSIS/
|
137
|
+
TIMEOUT_FUNCTIONALITY_ANALYSIS
|
138
|
+
when /DOCUMENTATION_ANALYSIS/
|
139
|
+
TIMEOUT_DOCUMENTATION_ANALYSIS
|
140
|
+
when /STATIC_ANALYSIS/
|
141
|
+
TIMEOUT_STATIC_ANALYSIS
|
142
|
+
when /REFACTORING_RECOMMENDATIONS/
|
143
|
+
TIMEOUT_REFACTORING_RECOMMENDATIONS
|
144
|
+
else
|
145
|
+
nil # Use default
|
146
|
+
end
|
147
147
|
end
|
148
148
|
end
|
149
149
|
|
data/lib/aidp/version.rb
CHANGED