aidp 0.5.0 → 0.8.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/README.md +128 -151
- data/bin/aidp +1 -1
- data/lib/aidp/analysis/kb_inspector.rb +471 -0
- data/lib/aidp/analysis/seams.rb +159 -0
- data/lib/aidp/analysis/tree_sitter_grammar_loader.rb +480 -0
- data/lib/aidp/analysis/tree_sitter_scan.rb +686 -0
- data/lib/aidp/analyze/error_handler.rb +2 -78
- data/lib/aidp/analyze/json_file_storage.rb +292 -0
- data/lib/aidp/analyze/progress.rb +12 -0
- data/lib/aidp/analyze/progress_visualizer.rb +12 -17
- data/lib/aidp/analyze/ruby_maat_integration.rb +13 -31
- data/lib/aidp/analyze/runner.rb +256 -87
- data/lib/aidp/analyze/steps.rb +6 -0
- data/lib/aidp/cli/jobs_command.rb +103 -435
- data/lib/aidp/cli.rb +317 -191
- data/lib/aidp/config.rb +298 -10
- data/lib/aidp/debug_logger.rb +195 -0
- data/lib/aidp/debug_mixin.rb +187 -0
- data/lib/aidp/execute/progress.rb +9 -0
- data/lib/aidp/execute/runner.rb +221 -40
- data/lib/aidp/execute/steps.rb +17 -7
- data/lib/aidp/execute/workflow_selector.rb +211 -0
- data/lib/aidp/harness/completion_checker.rb +268 -0
- data/lib/aidp/harness/condition_detector.rb +1526 -0
- data/lib/aidp/harness/config_loader.rb +373 -0
- data/lib/aidp/harness/config_manager.rb +382 -0
- data/lib/aidp/harness/config_schema.rb +1006 -0
- data/lib/aidp/harness/config_validator.rb +355 -0
- data/lib/aidp/harness/configuration.rb +477 -0
- data/lib/aidp/harness/enhanced_runner.rb +494 -0
- data/lib/aidp/harness/error_handler.rb +616 -0
- data/lib/aidp/harness/provider_config.rb +423 -0
- data/lib/aidp/harness/provider_factory.rb +306 -0
- data/lib/aidp/harness/provider_manager.rb +1269 -0
- data/lib/aidp/harness/provider_type_checker.rb +88 -0
- data/lib/aidp/harness/runner.rb +411 -0
- data/lib/aidp/harness/state/errors.rb +28 -0
- data/lib/aidp/harness/state/metrics.rb +219 -0
- data/lib/aidp/harness/state/persistence.rb +128 -0
- data/lib/aidp/harness/state/provider_state.rb +132 -0
- data/lib/aidp/harness/state/ui_state.rb +68 -0
- data/lib/aidp/harness/state/workflow_state.rb +123 -0
- data/lib/aidp/harness/state_manager.rb +586 -0
- data/lib/aidp/harness/status_display.rb +888 -0
- data/lib/aidp/harness/ui/base.rb +16 -0
- data/lib/aidp/harness/ui/enhanced_tui.rb +545 -0
- data/lib/aidp/harness/ui/enhanced_workflow_selector.rb +252 -0
- data/lib/aidp/harness/ui/error_handler.rb +132 -0
- data/lib/aidp/harness/ui/frame_manager.rb +361 -0
- data/lib/aidp/harness/ui/job_monitor.rb +500 -0
- data/lib/aidp/harness/ui/navigation/main_menu.rb +311 -0
- data/lib/aidp/harness/ui/navigation/menu_formatter.rb +120 -0
- data/lib/aidp/harness/ui/navigation/menu_item.rb +142 -0
- data/lib/aidp/harness/ui/navigation/menu_state.rb +139 -0
- data/lib/aidp/harness/ui/navigation/submenu.rb +202 -0
- data/lib/aidp/harness/ui/navigation/workflow_selector.rb +176 -0
- data/lib/aidp/harness/ui/progress_display.rb +280 -0
- data/lib/aidp/harness/ui/question_collector.rb +141 -0
- data/lib/aidp/harness/ui/spinner_group.rb +184 -0
- data/lib/aidp/harness/ui/spinner_helper.rb +152 -0
- data/lib/aidp/harness/ui/status_manager.rb +312 -0
- data/lib/aidp/harness/ui/status_widget.rb +280 -0
- data/lib/aidp/harness/ui/workflow_controller.rb +312 -0
- data/lib/aidp/harness/user_interface.rb +2381 -0
- data/lib/aidp/provider_manager.rb +131 -7
- data/lib/aidp/providers/anthropic.rb +28 -109
- data/lib/aidp/providers/base.rb +170 -0
- data/lib/aidp/providers/cursor.rb +52 -183
- data/lib/aidp/providers/gemini.rb +24 -109
- data/lib/aidp/providers/macos_ui.rb +99 -5
- data/lib/aidp/providers/opencode.rb +194 -0
- data/lib/aidp/storage/csv_storage.rb +172 -0
- data/lib/aidp/storage/file_manager.rb +214 -0
- data/lib/aidp/storage/json_storage.rb +140 -0
- data/lib/aidp/version.rb +1 -1
- data/lib/aidp.rb +56 -35
- data/templates/ANALYZE/06a_tree_sitter_scan.md +217 -0
- data/templates/COMMON/AGENT_BASE.md +11 -0
- data/templates/EXECUTE/00_PRD.md +4 -4
- data/templates/EXECUTE/02_ARCHITECTURE.md +5 -4
- data/templates/EXECUTE/07_TEST_PLAN.md +4 -1
- data/templates/EXECUTE/08_TASKS.md +4 -4
- data/templates/EXECUTE/10_IMPLEMENTATION_AGENT.md +4 -4
- data/templates/README.md +279 -0
- data/templates/aidp-development.yml.example +373 -0
- data/templates/aidp-minimal.yml.example +48 -0
- data/templates/aidp-production.yml.example +475 -0
- data/templates/aidp.yml.example +598 -0
- metadata +106 -64
- data/lib/aidp/analyze/agent_personas.rb +0 -71
- data/lib/aidp/analyze/agent_tool_executor.rb +0 -445
- data/lib/aidp/analyze/data_retention_manager.rb +0 -426
- data/lib/aidp/analyze/database.rb +0 -260
- data/lib/aidp/analyze/dependencies.rb +0 -335
- data/lib/aidp/analyze/export_manager.rb +0 -425
- data/lib/aidp/analyze/focus_guidance.rb +0 -517
- data/lib/aidp/analyze/incremental_analyzer.rb +0 -543
- data/lib/aidp/analyze/language_analysis_strategies.rb +0 -897
- data/lib/aidp/analyze/large_analysis_progress.rb +0 -504
- data/lib/aidp/analyze/memory_manager.rb +0 -365
- data/lib/aidp/analyze/metrics_storage.rb +0 -336
- data/lib/aidp/analyze/parallel_processor.rb +0 -460
- data/lib/aidp/analyze/performance_optimizer.rb +0 -694
- data/lib/aidp/analyze/repository_chunker.rb +0 -704
- data/lib/aidp/analyze/static_analysis_detector.rb +0 -577
- data/lib/aidp/analyze/storage.rb +0 -662
- data/lib/aidp/analyze/tool_configuration.rb +0 -456
- data/lib/aidp/analyze/tool_modernization.rb +0 -750
- data/lib/aidp/database/pg_adapter.rb +0 -148
- data/lib/aidp/database_config.rb +0 -69
- data/lib/aidp/database_connection.rb +0 -72
- data/lib/aidp/database_migration.rb +0 -158
- data/lib/aidp/job_manager.rb +0 -41
- data/lib/aidp/jobs/base_job.rb +0 -47
- data/lib/aidp/jobs/provider_execution_job.rb +0 -96
- data/lib/aidp/project_detector.rb +0 -117
- data/lib/aidp/providers/agent_supervisor.rb +0 -348
- data/lib/aidp/providers/supervised_base.rb +0 -317
- data/lib/aidp/providers/supervised_cursor.rb +0 -22
- data/lib/aidp/sync.rb +0 -13
- data/lib/aidp/workspace.rb +0 -19
@@ -1,317 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require_relative "agent_supervisor"
|
4
|
-
|
5
|
-
module Aidp
|
6
|
-
module Providers
|
7
|
-
# Base class for providers that use the agent supervisor
|
8
|
-
class SupervisedBase
|
9
|
-
# Timeout constants are now configurable via environment variables for flexibility
|
10
|
-
DEFAULT_TIMEOUT = Integer(ENV.fetch("AIDP_DEFAULT_TIMEOUT", "300")) # 5 minutes for general operations
|
11
|
-
QUICK_MODE_TIMEOUT = Integer(ENV.fetch("AIDP_QUICK_MODE_TIMEOUT", "120")) # 2 minutes for testing
|
12
|
-
REPOSITORY_ANALYSIS_TIMEOUT = Integer(ENV.fetch("AIDP_REPOSITORY_ANALYSIS_TIMEOUT", "180")) # 3 minutes
|
13
|
-
ARCHITECTURE_ANALYSIS_TIMEOUT = Integer(ENV.fetch("AIDP_ARCHITECTURE_ANALYSIS_TIMEOUT", "600")) # 10 minutes
|
14
|
-
TEST_ANALYSIS_TIMEOUT = Integer(ENV.fetch("AIDP_TEST_ANALYSIS_TIMEOUT", "300")) # 5 minutes
|
15
|
-
FUNCTIONALITY_ANALYSIS_TIMEOUT = Integer(ENV.fetch("AIDP_FUNCTIONALITY_ANALYSIS_TIMEOUT", "600")) # 10 minutes
|
16
|
-
DOCUMENTATION_ANALYSIS_TIMEOUT = Integer(ENV.fetch("AIDP_DOCUMENTATION_ANALYSIS_TIMEOUT", "300")) # 5 minutes
|
17
|
-
STATIC_ANALYSIS_TIMEOUT = Integer(ENV.fetch("AIDP_STATIC_ANALYSIS_TIMEOUT", "450")) # 7.5 minutes
|
18
|
-
REFACTORING_RECOMMENDATIONS_TIMEOUT = Integer(ENV.fetch("AIDP_REFACTORING_RECOMMENDATIONS_TIMEOUT", "600")) # 10 minutes
|
19
|
-
ADAPTIVE_TIMEOUT_BUFFER = Float(ENV.fetch("AIDP_ADAPTIVE_TIMEOUT_BUFFER", "1.2")) # 20% buffer for adaptive timeouts
|
20
|
-
attr_reader :name, :last_execution_result, :metrics
|
21
|
-
|
22
|
-
def initialize
|
23
|
-
@last_execution_result = nil
|
24
|
-
@metrics = {
|
25
|
-
total_executions: 0,
|
26
|
-
successful_executions: 0,
|
27
|
-
timeout_count: 0,
|
28
|
-
failure_count: 0,
|
29
|
-
average_duration: 0.0,
|
30
|
-
total_duration: 0.0
|
31
|
-
}
|
32
|
-
@job_context = nil
|
33
|
-
end
|
34
|
-
|
35
|
-
# Abstract method - must be implemented by subclasses
|
36
|
-
def command
|
37
|
-
raise NotImplementedError, "#{self.class} must implement #command"
|
38
|
-
end
|
39
|
-
|
40
|
-
# Abstract method - must be implemented by subclasses
|
41
|
-
def provider_name
|
42
|
-
raise NotImplementedError, "#{self.class} must implement #provider_name"
|
43
|
-
end
|
44
|
-
|
45
|
-
# Set job context for background execution
|
46
|
-
def set_job_context(job_id:, execution_id:, job_manager:)
|
47
|
-
@job_context = {
|
48
|
-
job_id: job_id,
|
49
|
-
execution_id: execution_id,
|
50
|
-
job_manager: job_manager
|
51
|
-
}
|
52
|
-
end
|
53
|
-
|
54
|
-
# Execute with supervision and recovery
|
55
|
-
def send(prompt:, session: nil)
|
56
|
-
timeout_seconds = calculate_timeout
|
57
|
-
debug = ENV["AIDP_DEBUG"] == "1"
|
58
|
-
|
59
|
-
log_info("Executing with #{provider_name} provider (timeout: #{timeout_seconds}s)")
|
60
|
-
|
61
|
-
# Create supervisor
|
62
|
-
supervisor = AgentSupervisor.new(
|
63
|
-
command,
|
64
|
-
timeout_seconds: timeout_seconds,
|
65
|
-
debug: debug
|
66
|
-
)
|
67
|
-
|
68
|
-
begin
|
69
|
-
# Execute with supervision
|
70
|
-
result = supervisor.execute(prompt)
|
71
|
-
|
72
|
-
# Update metrics
|
73
|
-
update_metrics(supervisor, result)
|
74
|
-
|
75
|
-
# Store result for debugging
|
76
|
-
@last_execution_result = result
|
77
|
-
|
78
|
-
if result[:success]
|
79
|
-
log_info("#{provider_name} completed successfully in #{format_duration(result[:duration])}")
|
80
|
-
result[:output]
|
81
|
-
else
|
82
|
-
handle_execution_failure(result, supervisor)
|
83
|
-
end
|
84
|
-
rescue => e
|
85
|
-
log_error("#{provider_name} execution error: #{e.message}")
|
86
|
-
|
87
|
-
# Try to kill the process if it's still running
|
88
|
-
supervisor.kill! if supervisor.active?
|
89
|
-
|
90
|
-
raise
|
91
|
-
end
|
92
|
-
end
|
93
|
-
|
94
|
-
# Get execution statistics
|
95
|
-
def stats
|
96
|
-
@metrics.dup
|
97
|
-
end
|
98
|
-
|
99
|
-
# Reset statistics
|
100
|
-
def reset_stats!
|
101
|
-
@metrics = {
|
102
|
-
total_executions: 0,
|
103
|
-
successful_executions: 0,
|
104
|
-
timeout_count: 0,
|
105
|
-
failure_count: 0,
|
106
|
-
average_duration: 0.0,
|
107
|
-
total_duration: 0.0
|
108
|
-
}
|
109
|
-
end
|
110
|
-
|
111
|
-
# Check if provider supports activity monitoring
|
112
|
-
def supports_activity_monitoring?
|
113
|
-
true # Supervised providers always support activity monitoring
|
114
|
-
end
|
115
|
-
|
116
|
-
# Get activity summary for metrics (compatibility with old interface)
|
117
|
-
def activity_summary
|
118
|
-
return {} unless @last_execution_result
|
119
|
-
|
120
|
-
{
|
121
|
-
provider: provider_name,
|
122
|
-
step_name: ENV["AIDP_CURRENT_STEP"],
|
123
|
-
start_time: @last_execution_result[:start_time],
|
124
|
-
end_time: @last_execution_result[:end_time],
|
125
|
-
duration: @last_execution_result[:duration],
|
126
|
-
final_state: @last_execution_result[:state],
|
127
|
-
stuck_detected: false, # Supervisor handles this differently
|
128
|
-
output_count: @last_execution_result[:output_count] || 0
|
129
|
-
}
|
130
|
-
end
|
131
|
-
|
132
|
-
# Compatibility methods for old activity monitoring interface
|
133
|
-
def setup_activity_monitoring(step_name, callback = nil, timeout = nil)
|
134
|
-
# No-op for supervised providers - supervisor handles this
|
135
|
-
end
|
136
|
-
|
137
|
-
def record_activity(message = nil)
|
138
|
-
# No-op for supervised providers - supervisor handles this
|
139
|
-
end
|
140
|
-
|
141
|
-
def mark_completed
|
142
|
-
# No-op for supervised providers - supervisor handles this
|
143
|
-
end
|
144
|
-
|
145
|
-
def mark_failed(message = nil)
|
146
|
-
# No-op for supervised providers - supervisor handles this
|
147
|
-
end
|
148
|
-
|
149
|
-
private
|
150
|
-
|
151
|
-
def calculate_timeout
|
152
|
-
# Priority order for timeout calculation:
|
153
|
-
# 1. Quick mode (for testing)
|
154
|
-
# 2. Environment variable override
|
155
|
-
# 3. Adaptive timeout based on step type
|
156
|
-
# 4. Default timeout
|
157
|
-
|
158
|
-
if ENV["AIDP_QUICK_MODE"]
|
159
|
-
log_info("Quick mode enabled - #{QUICK_MODE_TIMEOUT / 60} minute timeout")
|
160
|
-
return QUICK_MODE_TIMEOUT
|
161
|
-
end
|
162
|
-
|
163
|
-
provider_timeout_var = "AIDP_#{provider_name.upcase}_TIMEOUT"
|
164
|
-
if ENV[provider_timeout_var]
|
165
|
-
return ENV[provider_timeout_var].to_i
|
166
|
-
end
|
167
|
-
|
168
|
-
# Adaptive timeout based on step type
|
169
|
-
step_timeout = get_adaptive_timeout
|
170
|
-
if step_timeout
|
171
|
-
log_info("Using adaptive timeout: #{step_timeout} seconds")
|
172
|
-
return step_timeout
|
173
|
-
end
|
174
|
-
|
175
|
-
# Default timeout for interactive use
|
176
|
-
log_info("Using default timeout: #{DEFAULT_TIMEOUT / 60} minutes")
|
177
|
-
DEFAULT_TIMEOUT
|
178
|
-
end
|
179
|
-
|
180
|
-
def get_adaptive_timeout
|
181
|
-
# Try to get timeout recommendations from metrics storage
|
182
|
-
begin
|
183
|
-
require_relative "../analyze/metrics_storage"
|
184
|
-
storage = Aidp::Analyze::MetricsStorage.new(Dir.pwd)
|
185
|
-
recommendations = storage.calculate_timeout_recommendations
|
186
|
-
|
187
|
-
# Get current step name from environment or context
|
188
|
-
step_name = ENV["AIDP_CURRENT_STEP"] || "unknown"
|
189
|
-
|
190
|
-
if recommendations[step_name]
|
191
|
-
recommended = recommendations[step_name][:recommended_timeout]
|
192
|
-
# Add buffer for safety
|
193
|
-
return (recommended * ADAPTIVE_TIMEOUT_BUFFER).ceil
|
194
|
-
end
|
195
|
-
rescue => e
|
196
|
-
log_warning("Could not get adaptive timeout: #{e.message}") if ENV["AIDP_DEBUG"]
|
197
|
-
end
|
198
|
-
|
199
|
-
# Fallback timeouts based on step type patterns
|
200
|
-
step_name = ENV["AIDP_CURRENT_STEP"] || ""
|
201
|
-
|
202
|
-
case step_name
|
203
|
-
when /REPOSITORY_ANALYSIS/
|
204
|
-
REPOSITORY_ANALYSIS_TIMEOUT
|
205
|
-
when /ARCHITECTURE_ANALYSIS/
|
206
|
-
ARCHITECTURE_ANALYSIS_TIMEOUT
|
207
|
-
when /TEST_ANALYSIS/
|
208
|
-
TEST_ANALYSIS_TIMEOUT
|
209
|
-
when /FUNCTIONALITY_ANALYSIS/
|
210
|
-
FUNCTIONALITY_ANALYSIS_TIMEOUT
|
211
|
-
when /DOCUMENTATION_ANALYSIS/
|
212
|
-
DOCUMENTATION_ANALYSIS_TIMEOUT
|
213
|
-
when /STATIC_ANALYSIS/
|
214
|
-
STATIC_ANALYSIS_TIMEOUT
|
215
|
-
when /REFACTORING_RECOMMENDATIONS/
|
216
|
-
REFACTORING_RECOMMENDATIONS_TIMEOUT
|
217
|
-
else
|
218
|
-
nil # Use default
|
219
|
-
end
|
220
|
-
end
|
221
|
-
|
222
|
-
def update_metrics(supervisor, result)
|
223
|
-
@metrics[:total_executions] += 1
|
224
|
-
@metrics[:total_duration] += supervisor.duration
|
225
|
-
@metrics[:average_duration] = @metrics[:total_duration] / @metrics[:total_executions]
|
226
|
-
|
227
|
-
case result[:state]
|
228
|
-
when :completed
|
229
|
-
@metrics[:successful_executions] += 1
|
230
|
-
when :timeout
|
231
|
-
@metrics[:timeout_count] += 1
|
232
|
-
when :failed, :killed
|
233
|
-
@metrics[:failure_count] += 1
|
234
|
-
end
|
235
|
-
|
236
|
-
# Log metrics update if in job context
|
237
|
-
if @job_context
|
238
|
-
@job_context[:job_manager].log_message(
|
239
|
-
@job_context[:job_id],
|
240
|
-
@job_context[:execution_id],
|
241
|
-
"Updated execution metrics",
|
242
|
-
"debug",
|
243
|
-
@metrics
|
244
|
-
)
|
245
|
-
end
|
246
|
-
end
|
247
|
-
|
248
|
-
def handle_execution_failure(result, supervisor)
|
249
|
-
case result[:reason]
|
250
|
-
when "user_aborted"
|
251
|
-
message = "#{provider_name} was aborted by user after #{format_duration(result[:duration])}"
|
252
|
-
log_error(message)
|
253
|
-
raise Interrupt, message
|
254
|
-
when "non_zero_exit"
|
255
|
-
error_msg = result[:error_output].empty? ? "Unknown error" : result[:error_output].strip
|
256
|
-
message = "#{provider_name} failed with exit code #{result[:exit_code]}: #{error_msg}"
|
257
|
-
log_error(message)
|
258
|
-
raise message
|
259
|
-
else
|
260
|
-
message = "#{provider_name} failed: #{result[:reason] || "Unknown error"}"
|
261
|
-
log_error(message)
|
262
|
-
raise message
|
263
|
-
end
|
264
|
-
end
|
265
|
-
|
266
|
-
def format_duration(seconds)
|
267
|
-
minutes = (seconds / 60).to_i
|
268
|
-
secs = (seconds % 60).to_i
|
269
|
-
|
270
|
-
if minutes > 0
|
271
|
-
"#{minutes}m #{secs}s"
|
272
|
-
else
|
273
|
-
"#{secs}s"
|
274
|
-
end
|
275
|
-
end
|
276
|
-
|
277
|
-
def log_info(message)
|
278
|
-
if @job_context
|
279
|
-
@job_context[:job_manager].log_message(
|
280
|
-
@job_context[:job_id],
|
281
|
-
@job_context[:execution_id],
|
282
|
-
message,
|
283
|
-
"info"
|
284
|
-
)
|
285
|
-
else
|
286
|
-
puts message
|
287
|
-
end
|
288
|
-
end
|
289
|
-
|
290
|
-
def log_warning(message)
|
291
|
-
if @job_context
|
292
|
-
@job_context[:job_manager].log_message(
|
293
|
-
@job_context[:job_id],
|
294
|
-
@job_context[:execution_id],
|
295
|
-
message,
|
296
|
-
"warning"
|
297
|
-
)
|
298
|
-
else
|
299
|
-
puts "⚠️ #{message}"
|
300
|
-
end
|
301
|
-
end
|
302
|
-
|
303
|
-
def log_error(message)
|
304
|
-
if @job_context
|
305
|
-
@job_context[:job_manager].log_message(
|
306
|
-
@job_context[:job_id],
|
307
|
-
@job_context[:execution_id],
|
308
|
-
message,
|
309
|
-
"error"
|
310
|
-
)
|
311
|
-
else
|
312
|
-
puts "❌ #{message}"
|
313
|
-
end
|
314
|
-
end
|
315
|
-
end
|
316
|
-
end
|
317
|
-
end
|
@@ -1,22 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require_relative "supervised_base"
|
4
|
-
require_relative "../util"
|
5
|
-
|
6
|
-
module Aidp
|
7
|
-
module Providers
|
8
|
-
class SupervisedCursor < SupervisedBase
|
9
|
-
def self.available?
|
10
|
-
!!Aidp::Util.which("cursor-agent")
|
11
|
-
end
|
12
|
-
|
13
|
-
def provider_name
|
14
|
-
"cursor"
|
15
|
-
end
|
16
|
-
|
17
|
-
def command
|
18
|
-
["cursor-agent", "-p"]
|
19
|
-
end
|
20
|
-
end
|
21
|
-
end
|
22
|
-
end
|
data/lib/aidp/sync.rb
DELETED
data/lib/aidp/workspace.rb
DELETED
@@ -1,19 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require "fileutils"
|
4
|
-
require "digest"
|
5
|
-
|
6
|
-
module Aidp
|
7
|
-
# Workspace management utilities
|
8
|
-
class Workspace
|
9
|
-
def self.current
|
10
|
-
Dir.pwd
|
11
|
-
end
|
12
|
-
|
13
|
-
def self.ensure_project_root
|
14
|
-
unless Aidp::Util.project_root?
|
15
|
-
raise "Not in a project root directory. Please run from a directory with .git, package.json, Gemfile, etc."
|
16
|
-
end
|
17
|
-
end
|
18
|
-
end
|
19
|
-
end
|