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.
@@ -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 = {
@@ -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
- # Adaptive timeout based on step type
200
- step_timeout = get_adaptive_timeout
201
- if step_timeout
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 get_adaptive_timeout
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
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
- # Try agent command first (better for large prompts), fallback to -p mode
65
- begin
66
- result = debug_execute_command("cursor-agent", args: ["agent"], input: prompt, timeout: timeout_seconds, streaming: streaming_enabled)
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
- # Adaptive timeout based on step type
115
- step_timeout = get_adaptive_timeout
116
- if step_timeout
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 get_adaptive_timeout
127
- # Timeout recommendations based on step type patterns
128
- step_name = ENV["AIDP_CURRENT_STEP"] || ""
129
-
130
- case step_name
131
- when /REPOSITORY_ANALYSIS/
132
- TIMEOUT_REPOSITORY_ANALYSIS
133
- when /ARCHITECTURE_ANALYSIS/
134
- TIMEOUT_ARCHITECTURE_ANALYSIS
135
- when /TEST_ANALYSIS/
136
- TIMEOUT_TEST_ANALYSIS
137
- when /FUNCTIONALITY_ANALYSIS/
138
- TIMEOUT_FUNCTIONALITY_ANALYSIS
139
- when /DOCUMENTATION_ANALYSIS/
140
- TIMEOUT_DOCUMENTATION_ANALYSIS
141
- when /STATIC_ANALYSIS/
142
- TIMEOUT_STATIC_ANALYSIS
143
- when /REFACTORING_RECOMMENDATIONS/
144
- TIMEOUT_REFACTORING_RECOMMENDATIONS
145
- else
146
- nil # Use default
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
- # Adaptive timeout based on step type
215
- step_timeout = get_adaptive_timeout
216
- if step_timeout
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 get_adaptive_timeout
227
- # Timeout recommendations based on step type patterns
228
- step_name = ENV["AIDP_CURRENT_STEP"] || ""
229
-
230
- case step_name
231
- when /REPOSITORY_ANALYSIS/
232
- TIMEOUT_REPOSITORY_ANALYSIS
233
- when /ARCHITECTURE_ANALYSIS/
234
- TIMEOUT_ARCHITECTURE_ANALYSIS
235
- when /TEST_ANALYSIS/
236
- TIMEOUT_TEST_ANALYSIS
237
- when /FUNCTIONALITY_ANALYSIS/
238
- TIMEOUT_FUNCTIONALITY_ANALYSIS
239
- when /DOCUMENTATION_ANALYSIS/
240
- TIMEOUT_DOCUMENTATION_ANALYSIS
241
- when /STATIC_ANALYSIS/
242
- TIMEOUT_STATIC_ANALYSIS
243
- when /REFACTORING_RECOMMENDATIONS/
244
- TIMEOUT_REFACTORING_RECOMMENDATIONS
245
- else
246
- nil # Use default
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
- # Fallback to simple dialog
33
- fallback_dialog(prompt)
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
- # Adaptive timeout based on step type
115
- step_timeout = get_adaptive_timeout
116
- if step_timeout
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 get_adaptive_timeout
127
- # Timeout recommendations based on step type patterns
128
- step_name = ENV["AIDP_CURRENT_STEP"] || ""
129
-
130
- case step_name
131
- when /REPOSITORY_ANALYSIS/
132
- TIMEOUT_REPOSITORY_ANALYSIS
133
- when /ARCHITECTURE_ANALYSIS/
134
- TIMEOUT_ARCHITECTURE_ANALYSIS
135
- when /TEST_ANALYSIS/
136
- TIMEOUT_TEST_ANALYSIS
137
- when /FUNCTIONALITY_ANALYSIS/
138
- TIMEOUT_FUNCTIONALITY_ANALYSIS
139
- when /DOCUMENTATION_ANALYSIS/
140
- TIMEOUT_DOCUMENTATION_ANALYSIS
141
- when /STATIC_ANALYSIS/
142
- TIMEOUT_STATIC_ANALYSIS
143
- when /REFACTORING_RECOMMENDATIONS/
144
- TIMEOUT_REFACTORING_RECOMMENDATIONS
145
- else
146
- nil # Use default
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
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Aidp
4
- VERSION = "0.12.1"
4
+ VERSION = "0.13.0"
5
5
  end