aidp 0.9.6 → 0.11.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 +194 -25
- data/lib/aidp/analyze/error_handler.rb +4 -2
- data/lib/aidp/{analysis → analyze}/kb_inspector.rb +93 -89
- data/lib/aidp/analyze/prioritizer.rb +3 -2
- data/lib/aidp/analyze/progress.rb +2 -1
- data/lib/aidp/analyze/ruby_maat_integration.rb +7 -3
- data/lib/aidp/analyze/runner.rb +73 -11
- data/lib/aidp/{analysis → analyze}/seams.rb +1 -1
- data/lib/aidp/analyze/steps.rb +10 -8
- data/lib/aidp/{analysis → analyze}/tree_sitter_grammar_loader.rb +11 -5
- data/lib/aidp/{analysis → analyze}/tree_sitter_scan.rb +21 -15
- data/lib/aidp/cli/checkpoint_command.rb +98 -0
- data/lib/aidp/cli/first_run_wizard.rb +83 -103
- data/lib/aidp/cli/jobs_command.rb +270 -36
- data/lib/aidp/cli/terminal_io.rb +3 -3
- data/lib/aidp/cli.rb +411 -69
- data/lib/aidp/config.rb +5 -8
- data/lib/aidp/debug_logger.rb +4 -4
- data/lib/aidp/debug_mixin.rb +11 -4
- data/lib/aidp/execute/checkpoint.rb +282 -0
- data/lib/aidp/execute/checkpoint_display.rb +221 -0
- data/lib/aidp/execute/progress.rb +2 -1
- data/lib/aidp/execute/prompt_manager.rb +62 -0
- data/lib/aidp/execute/runner.rb +67 -20
- data/lib/aidp/execute/steps.rb +36 -27
- data/lib/aidp/execute/work_loop_runner.rb +308 -0
- data/lib/aidp/execute/workflow_selector.rb +50 -26
- data/lib/aidp/harness/condition_detector.rb +4 -4
- data/lib/aidp/harness/config_schema.rb +40 -0
- data/lib/aidp/harness/config_validator.rb +3 -6
- data/lib/aidp/harness/configuration.rb +35 -1
- data/lib/aidp/harness/enhanced_runner.rb +25 -4
- data/lib/aidp/harness/error_handler.rb +103 -28
- data/lib/aidp/harness/provider_factory.rb +6 -1
- data/lib/aidp/harness/provider_manager.rb +273 -19
- data/lib/aidp/harness/runner.rb +14 -6
- data/lib/aidp/harness/simple_user_interface.rb +6 -4
- data/lib/aidp/harness/status_display.rb +118 -106
- data/lib/aidp/harness/test_runner.rb +83 -0
- data/lib/aidp/harness/ui/enhanced_tui.rb +7 -5
- data/lib/aidp/harness/ui/enhanced_workflow_selector.rb +22 -4
- data/lib/aidp/harness/ui/error_handler.rb +7 -2
- data/lib/aidp/harness/ui/frame_manager.rb +61 -39
- data/lib/aidp/harness/ui/job_monitor.rb +2 -0
- data/lib/aidp/harness/ui/navigation/main_menu.rb +27 -16
- data/lib/aidp/harness/ui/navigation/menu_item.rb +1 -0
- data/lib/aidp/harness/ui/navigation/menu_state.rb +1 -0
- data/lib/aidp/harness/ui/navigation/submenu.rb +1 -0
- data/lib/aidp/harness/ui/navigation/workflow_selector.rb +2 -0
- data/lib/aidp/harness/ui/progress_display.rb +26 -7
- data/lib/aidp/harness/ui/question_collector.rb +2 -0
- data/lib/aidp/harness/ui/spinner_group.rb +2 -0
- data/lib/aidp/harness/ui/spinner_helper.rb +1 -1
- data/lib/aidp/harness/ui/status_manager.rb +4 -2
- data/lib/aidp/harness/ui/status_widget.rb +20 -9
- data/lib/aidp/harness/ui/workflow_controller.rb +27 -9
- data/lib/aidp/harness/user_interface.rb +338 -330
- data/lib/aidp/jobs/background_runner.rb +278 -0
- data/lib/aidp/message_display.rb +48 -0
- data/lib/aidp/provider_manager.rb +13 -7
- data/lib/aidp/providers/anthropic.rb +101 -18
- data/lib/aidp/providers/base.rb +51 -1
- data/lib/aidp/providers/codex.rb +248 -0
- data/lib/aidp/providers/cursor.rb +39 -48
- data/lib/aidp/providers/gemini.rb +26 -16
- data/lib/aidp/providers/github_copilot.rb +263 -0
- data/lib/aidp/providers/opencode.rb +38 -47
- data/lib/aidp/version.rb +1 -1
- data/lib/aidp/workflows/definitions.rb +357 -0
- data/lib/aidp/workflows/selector.rb +171 -0
- data/lib/aidp.rb +16 -4
- data/templates/planning/generate_llm_style_guide.md +119 -0
- metadata +43 -31
- data/lib/aidp/analyze/progress_visualizer.rb +0 -314
- /data/templates/{ANALYZE/02_ARCHITECTURE_ANALYSIS.md → analysis/analyze_architecture.md} +0 -0
- /data/templates/{ANALYZE/05_DOCUMENTATION_ANALYSIS.md → analysis/analyze_documentation.md} +0 -0
- /data/templates/{ANALYZE/04_FUNCTIONALITY_ANALYSIS.md → analysis/analyze_functionality.md} +0 -0
- /data/templates/{ANALYZE/01_REPOSITORY_ANALYSIS.md → analysis/analyze_repository.md} +0 -0
- /data/templates/{ANALYZE/06_STATIC_ANALYSIS.md → analysis/analyze_static_code.md} +0 -0
- /data/templates/{ANALYZE/03_TEST_ANALYSIS.md → analysis/analyze_tests.md} +0 -0
- /data/templates/{ANALYZE/07_REFACTORING_RECOMMENDATIONS.md → analysis/recommend_refactoring.md} +0 -0
- /data/templates/{ANALYZE/06a_tree_sitter_scan.md → analysis/scan_with_tree_sitter.md} +0 -0
- /data/templates/{EXECUTE/11_STATIC_ANALYSIS.md → implementation/configure_static_analysis.md} +0 -0
- /data/templates/{EXECUTE/14_DOCS_PORTAL.md → implementation/create_documentation_portal.md} +0 -0
- /data/templates/{EXECUTE/10_IMPLEMENTATION_AGENT.md → implementation/implement_features.md} +0 -0
- /data/templates/{EXECUTE/13_DELIVERY_ROLLOUT.md → implementation/plan_delivery.md} +0 -0
- /data/templates/{EXECUTE/15_POST_RELEASE.md → implementation/review_post_release.md} +0 -0
- /data/templates/{EXECUTE/09_SCAFFOLDING_DEVEX.md → implementation/setup_scaffolding.md} +0 -0
- /data/templates/{EXECUTE/02A_ARCH_GATE_QUESTIONS.md → planning/ask_architecture_questions.md} +0 -0
- /data/templates/{EXECUTE/00_PRD.md → planning/create_prd.md} +0 -0
- /data/templates/{EXECUTE/08_TASKS.md → planning/create_tasks.md} +0 -0
- /data/templates/{EXECUTE/04_DOMAIN_DECOMPOSITION.md → planning/decompose_domain.md} +0 -0
- /data/templates/{EXECUTE/01_NFRS.md → planning/define_nfrs.md} +0 -0
- /data/templates/{EXECUTE/05_CONTRACTS.md → planning/design_apis.md} +0 -0
- /data/templates/{EXECUTE/02_ARCHITECTURE.md → planning/design_architecture.md} +0 -0
- /data/templates/{EXECUTE/06_THREAT_MODEL.md → planning/design_data_model.md} +0 -0
- /data/templates/{EXECUTE/03_ADR_FACTORY.md → planning/generate_adrs.md} +0 -0
- /data/templates/{EXECUTE/12_OBSERVABILITY_SLOS.md → planning/plan_observability.md} +0 -0
- /data/templates/{EXECUTE/07_TEST_PLAN.md → planning/plan_testing.md} +0 -0
|
@@ -2,12 +2,16 @@
|
|
|
2
2
|
|
|
3
3
|
require "json"
|
|
4
4
|
require "tty-box"
|
|
5
|
+
require "tty-prompt"
|
|
5
6
|
|
|
6
7
|
module Aidp
|
|
7
|
-
module
|
|
8
|
+
module Analyze
|
|
8
9
|
class KBInspector
|
|
9
|
-
|
|
10
|
+
include Aidp::MessageDisplay
|
|
11
|
+
|
|
12
|
+
def initialize(kb_dir = ".aidp/kb", prompt: TTY::Prompt.new)
|
|
10
13
|
@kb_dir = File.expand_path(kb_dir)
|
|
14
|
+
@prompt = prompt
|
|
11
15
|
@data = load_kb_data
|
|
12
16
|
end
|
|
13
17
|
|
|
@@ -28,8 +32,8 @@ module Aidp
|
|
|
28
32
|
when "summary"
|
|
29
33
|
show_summary(format)
|
|
30
34
|
else
|
|
31
|
-
|
|
32
|
-
|
|
35
|
+
display_message("Unknown KB type: #{type}", type: :error)
|
|
36
|
+
display_message("Available types: seams, hotspots, cycles, apis, symbols, imports, summary", type: :info)
|
|
33
37
|
end
|
|
34
38
|
end
|
|
35
39
|
|
|
@@ -42,8 +46,8 @@ module Aidp
|
|
|
42
46
|
when "cycles"
|
|
43
47
|
generate_cycle_graph(format, output)
|
|
44
48
|
else
|
|
45
|
-
|
|
46
|
-
|
|
49
|
+
display_message("Unknown graph type: #{type}", type: :error)
|
|
50
|
+
display_message("Available types: imports, calls, cycles", type: :info)
|
|
47
51
|
end
|
|
48
52
|
end
|
|
49
53
|
|
|
@@ -73,7 +77,7 @@ module Aidp
|
|
|
73
77
|
border: :thick,
|
|
74
78
|
padding: [1, 2]
|
|
75
79
|
)
|
|
76
|
-
|
|
80
|
+
display_message(box)
|
|
77
81
|
end
|
|
78
82
|
|
|
79
83
|
def load_kb_data
|
|
@@ -87,7 +91,7 @@ module Aidp
|
|
|
87
91
|
rescue JSON::ParserError => e
|
|
88
92
|
# Suppress warnings in test mode to avoid CI failures
|
|
89
93
|
unless ENV["RACK_ENV"] == "test" || defined?(RSpec)
|
|
90
|
-
|
|
94
|
+
display_message("Warning: Could not parse #{file_path}: #{e.message}", type: :warn)
|
|
91
95
|
end
|
|
92
96
|
data[type.to_sym] = []
|
|
93
97
|
end
|
|
@@ -100,42 +104,42 @@ module Aidp
|
|
|
100
104
|
end
|
|
101
105
|
|
|
102
106
|
def show_summary(_format)
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
107
|
+
display_message("\n📊 Knowledge Base Summary", type: :highlight)
|
|
108
|
+
display_message("=" * 50, type: :info)
|
|
109
|
+
|
|
110
|
+
display_message("📁 KB Directory: #{@kb_dir}", type: :info)
|
|
111
|
+
display_message("📄 Files analyzed: #{count_files}", type: :info)
|
|
112
|
+
display_message("🏗️ Symbols: #{@data[:symbols]&.length || 0}", type: :info)
|
|
113
|
+
display_message("📦 Imports: #{@data[:imports]&.length || 0}", type: :info)
|
|
114
|
+
display_message("🔗 Calls: #{@data[:calls]&.length || 0}", type: :info)
|
|
115
|
+
display_message("📏 Metrics: #{@data[:metrics]&.length || 0}", type: :info)
|
|
116
|
+
display_message("🔧 Seams: #{@data[:seams]&.length || 0}", type: :info)
|
|
117
|
+
display_message("🔥 Hotspots: #{@data[:hotspots]&.length || 0}", type: :info)
|
|
118
|
+
display_message("🧪 Tests: #{@data[:tests]&.length || 0}", type: :info)
|
|
119
|
+
display_message("🔄 Cycles: #{@data[:cycles]&.length || 0}", type: :info)
|
|
116
120
|
|
|
117
121
|
if @data[:seams]&.any?
|
|
118
|
-
|
|
122
|
+
display_message("\n🔧 Seam Types:", type: :info)
|
|
119
123
|
seam_types = @data[:seams].group_by { |s| s[:kind] }
|
|
120
124
|
seam_types.each do |type, seams|
|
|
121
|
-
|
|
125
|
+
display_message(" #{type}: #{seams.length}", type: :info)
|
|
122
126
|
end
|
|
123
127
|
end
|
|
124
128
|
|
|
125
129
|
if @data[:hotspots]&.any?
|
|
126
|
-
|
|
130
|
+
display_message("\n🔥 Top 5 Hotspots:", type: :info)
|
|
127
131
|
@data[:hotspots].first(5).each_with_index do |hotspot, i|
|
|
128
|
-
|
|
132
|
+
display_message(" #{i + 1}. #{hotspot[:file]}:#{hotspot[:method]} (score: #{hotspot[:score]})", type: :info)
|
|
129
133
|
end
|
|
130
134
|
end
|
|
131
135
|
end
|
|
132
136
|
|
|
133
137
|
def show_seams(format)
|
|
134
|
-
return
|
|
138
|
+
return display_message("No seams data available") unless @data[:seams]&.any?
|
|
135
139
|
|
|
136
140
|
case format
|
|
137
141
|
when "json"
|
|
138
|
-
|
|
142
|
+
display_message(JSON.pretty_generate(@data[:seams]))
|
|
139
143
|
when "table"
|
|
140
144
|
show_seams_table
|
|
141
145
|
else
|
|
@@ -144,8 +148,8 @@ module Aidp
|
|
|
144
148
|
end
|
|
145
149
|
|
|
146
150
|
def show_seams_table
|
|
147
|
-
|
|
148
|
-
|
|
151
|
+
display_message("\n🔧 Seams Analysis")
|
|
152
|
+
display_message("=" * 80)
|
|
149
153
|
|
|
150
154
|
create_table(
|
|
151
155
|
["Type", "File", "Line", "Symbol", "Suggestion"],
|
|
@@ -162,34 +166,34 @@ module Aidp
|
|
|
162
166
|
end
|
|
163
167
|
|
|
164
168
|
def show_seams_summary
|
|
165
|
-
|
|
166
|
-
|
|
169
|
+
display_message("\n🔧 Seams Analysis")
|
|
170
|
+
display_message("=" * 50)
|
|
167
171
|
|
|
168
172
|
seam_types = @data[:seams].group_by { |s| s[:kind] }
|
|
169
173
|
|
|
170
174
|
seam_types.each do |type, seams|
|
|
171
|
-
|
|
172
|
-
|
|
175
|
+
display_message("\n📌 #{type.upcase} (#{seams.length} found)")
|
|
176
|
+
display_message("-" * 30)
|
|
173
177
|
|
|
174
178
|
seams.first(10).each do |seam|
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
+
display_message(" #{seam[:file]}:#{seam[:line]}")
|
|
180
|
+
display_message(" Symbol: #{seam[:symbol_id]&.split(":")&.last}")
|
|
181
|
+
display_message(" Suggestion: #{seam[:suggestion]}")
|
|
182
|
+
display_message("")
|
|
179
183
|
end
|
|
180
184
|
|
|
181
185
|
if seams.length > 10
|
|
182
|
-
|
|
186
|
+
display_message(" ... and #{seams.length - 10} more")
|
|
183
187
|
end
|
|
184
188
|
end
|
|
185
189
|
end
|
|
186
190
|
|
|
187
191
|
def show_hotspots(format)
|
|
188
|
-
return
|
|
192
|
+
return display_message("No hotspots data available") unless @data[:hotspots]&.any?
|
|
189
193
|
|
|
190
194
|
case format
|
|
191
195
|
when "json"
|
|
192
|
-
|
|
196
|
+
display_message(JSON.pretty_generate(@data[:hotspots]))
|
|
193
197
|
when "table"
|
|
194
198
|
show_hotspots_table
|
|
195
199
|
else
|
|
@@ -198,8 +202,8 @@ module Aidp
|
|
|
198
202
|
end
|
|
199
203
|
|
|
200
204
|
def show_hotspots_table
|
|
201
|
-
|
|
202
|
-
|
|
205
|
+
display_message("\n🔥 Code Hotspots")
|
|
206
|
+
display_message("=" * 80)
|
|
203
207
|
|
|
204
208
|
create_table(
|
|
205
209
|
["Rank", "File", "Method", "Score", "Complexity", "Touches"],
|
|
@@ -217,81 +221,81 @@ module Aidp
|
|
|
217
221
|
end
|
|
218
222
|
|
|
219
223
|
def show_hotspots_summary
|
|
220
|
-
|
|
221
|
-
|
|
224
|
+
display_message("\n🔥 Code Hotspots (Top 20)")
|
|
225
|
+
display_message("=" * 50)
|
|
222
226
|
|
|
223
227
|
@data[:hotspots].each_with_index do |hotspot, i|
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
228
|
+
display_message("#{i + 1}. #{hotspot[:file]}:#{hotspot[:method]}")
|
|
229
|
+
display_message(" Score: #{hotspot[:score]} (Complexity: #{hotspot[:complexity]}, Touches: #{hotspot[:touches]})")
|
|
230
|
+
display_message("")
|
|
227
231
|
end
|
|
228
232
|
end
|
|
229
233
|
|
|
230
234
|
def show_cycles(format)
|
|
231
|
-
return
|
|
235
|
+
return display_message("No cycles data available") unless @data[:cycles]&.any?
|
|
232
236
|
|
|
233
237
|
case format
|
|
234
238
|
when "json"
|
|
235
|
-
|
|
239
|
+
display_message(JSON.pretty_generate(@data[:cycles]))
|
|
236
240
|
else
|
|
237
241
|
show_cycles_summary
|
|
238
242
|
end
|
|
239
243
|
end
|
|
240
244
|
|
|
241
245
|
def show_cycles_summary
|
|
242
|
-
|
|
243
|
-
|
|
246
|
+
display_message("\n🔄 Import Cycles")
|
|
247
|
+
display_message("=" * 50)
|
|
244
248
|
|
|
245
249
|
@data[:cycles].each_with_index do |cycle, i|
|
|
246
|
-
|
|
250
|
+
display_message("Cycle #{i + 1}:")
|
|
247
251
|
cycle[:members].each do |member|
|
|
248
|
-
|
|
252
|
+
display_message(" - #{member}")
|
|
249
253
|
end
|
|
250
|
-
|
|
251
|
-
|
|
254
|
+
display_message(" Weight: #{cycle[:weight]}") if cycle[:weight]
|
|
255
|
+
display_message("")
|
|
252
256
|
end
|
|
253
257
|
end
|
|
254
258
|
|
|
255
259
|
def show_apis(format)
|
|
256
|
-
return
|
|
260
|
+
return display_message("No APIs data available") unless @data[:tests]&.any?
|
|
257
261
|
|
|
258
262
|
untested_apis = @data[:tests].select { |t| t[:tests].empty? }
|
|
259
263
|
|
|
260
264
|
case format
|
|
261
265
|
when "json"
|
|
262
|
-
|
|
266
|
+
display_message(JSON.pretty_generate(untested_apis))
|
|
263
267
|
else
|
|
264
268
|
show_apis_summary(untested_apis)
|
|
265
269
|
end
|
|
266
270
|
end
|
|
267
271
|
|
|
268
272
|
def show_apis_summary(untested_apis)
|
|
269
|
-
|
|
270
|
-
|
|
273
|
+
display_message("\n🧪 Untested Public APIs")
|
|
274
|
+
display_message("=" * 50)
|
|
271
275
|
|
|
272
276
|
if untested_apis.empty?
|
|
273
|
-
|
|
277
|
+
display_message("✅ All public APIs have associated tests!")
|
|
274
278
|
else
|
|
275
|
-
|
|
276
|
-
|
|
279
|
+
display_message("Found #{untested_apis.length} untested public APIs:")
|
|
280
|
+
display_message("")
|
|
277
281
|
|
|
278
282
|
untested_apis.each do |api|
|
|
279
283
|
symbol = @data[:symbols]&.find { |s| s[:id] == api[:symbol_id] }
|
|
280
284
|
if symbol
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
285
|
+
display_message(" #{symbol[:file]}:#{symbol[:line]} - #{symbol[:name]}")
|
|
286
|
+
display_message(" Suggestion: Create characterization tests")
|
|
287
|
+
display_message("")
|
|
284
288
|
end
|
|
285
289
|
end
|
|
286
290
|
end
|
|
287
291
|
end
|
|
288
292
|
|
|
289
293
|
def show_symbols(format)
|
|
290
|
-
return
|
|
294
|
+
return display_message("No symbols data available") unless @data[:symbols]&.any?
|
|
291
295
|
|
|
292
296
|
case format
|
|
293
297
|
when "json"
|
|
294
|
-
|
|
298
|
+
display_message(JSON.pretty_generate(@data[:symbols]))
|
|
295
299
|
when "table"
|
|
296
300
|
show_symbols_table
|
|
297
301
|
else
|
|
@@ -300,8 +304,8 @@ module Aidp
|
|
|
300
304
|
end
|
|
301
305
|
|
|
302
306
|
def show_symbols_table
|
|
303
|
-
|
|
304
|
-
|
|
307
|
+
display_message("\n🏗️ Symbols")
|
|
308
|
+
display_message("=" * 80)
|
|
305
309
|
|
|
306
310
|
create_table(
|
|
307
311
|
["Type", "Name", "File", "Line", "Visibility"],
|
|
@@ -318,22 +322,22 @@ module Aidp
|
|
|
318
322
|
end
|
|
319
323
|
|
|
320
324
|
def show_symbols_summary
|
|
321
|
-
|
|
322
|
-
|
|
325
|
+
display_message("\n🏗️ Symbols Summary")
|
|
326
|
+
display_message("=" * 50)
|
|
323
327
|
|
|
324
328
|
symbol_types = @data[:symbols].group_by { |s| s[:kind] }
|
|
325
329
|
|
|
326
330
|
symbol_types.each do |type, symbols|
|
|
327
|
-
|
|
331
|
+
display_message("#{type.capitalize}: #{symbols.length}")
|
|
328
332
|
end
|
|
329
333
|
end
|
|
330
334
|
|
|
331
335
|
def show_imports(format)
|
|
332
|
-
return
|
|
336
|
+
return display_message("No imports data available") unless @data[:imports]&.any?
|
|
333
337
|
|
|
334
338
|
case format
|
|
335
339
|
when "json"
|
|
336
|
-
|
|
340
|
+
display_message(JSON.pretty_generate(@data[:imports]))
|
|
337
341
|
when "table"
|
|
338
342
|
show_imports_table
|
|
339
343
|
else
|
|
@@ -342,8 +346,8 @@ module Aidp
|
|
|
342
346
|
end
|
|
343
347
|
|
|
344
348
|
def show_imports_table
|
|
345
|
-
|
|
346
|
-
|
|
349
|
+
display_message("\n📦 Imports")
|
|
350
|
+
display_message("=" * 80)
|
|
347
351
|
|
|
348
352
|
create_table(
|
|
349
353
|
["Type", "Target", "File", "Line"],
|
|
@@ -359,18 +363,18 @@ module Aidp
|
|
|
359
363
|
end
|
|
360
364
|
|
|
361
365
|
def show_imports_summary
|
|
362
|
-
|
|
363
|
-
|
|
366
|
+
display_message("\n📦 Imports Summary")
|
|
367
|
+
display_message("=" * 50)
|
|
364
368
|
|
|
365
369
|
import_types = @data[:imports].group_by { |i| i[:kind] }
|
|
366
370
|
|
|
367
371
|
import_types.each do |type, imports|
|
|
368
|
-
|
|
372
|
+
display_message("#{type.capitalize}: #{imports.length}")
|
|
369
373
|
end
|
|
370
374
|
end
|
|
371
375
|
|
|
372
376
|
def generate_import_graph(format, output)
|
|
373
|
-
|
|
377
|
+
display_message("Generating import graph in #{format} format...")
|
|
374
378
|
|
|
375
379
|
case format
|
|
376
380
|
when "dot"
|
|
@@ -380,7 +384,7 @@ module Aidp
|
|
|
380
384
|
when "json"
|
|
381
385
|
generate_json_graph(output)
|
|
382
386
|
else
|
|
383
|
-
|
|
387
|
+
display_message("Unsupported graph format: #{format}")
|
|
384
388
|
end
|
|
385
389
|
end
|
|
386
390
|
|
|
@@ -399,9 +403,9 @@ module Aidp
|
|
|
399
403
|
|
|
400
404
|
if output
|
|
401
405
|
File.write(output, content.join("\n"))
|
|
402
|
-
|
|
406
|
+
display_message("Graph written to #{output}")
|
|
403
407
|
else
|
|
404
|
-
|
|
408
|
+
display_message(content.join("\n"))
|
|
405
409
|
end
|
|
406
410
|
end
|
|
407
411
|
|
|
@@ -416,9 +420,9 @@ module Aidp
|
|
|
416
420
|
|
|
417
421
|
if output
|
|
418
422
|
File.write(output, content.join("\n"))
|
|
419
|
-
|
|
423
|
+
display_message("Graph written to #{output}")
|
|
420
424
|
else
|
|
421
|
-
|
|
425
|
+
display_message(content.join("\n"))
|
|
422
426
|
end
|
|
423
427
|
end
|
|
424
428
|
|
|
@@ -447,20 +451,20 @@ module Aidp
|
|
|
447
451
|
|
|
448
452
|
if output
|
|
449
453
|
File.write(output, JSON.pretty_generate(graph_data))
|
|
450
|
-
|
|
454
|
+
display_message("Graph written to #{output}")
|
|
451
455
|
else
|
|
452
|
-
|
|
456
|
+
display_message(JSON.pretty_generate(graph_data))
|
|
453
457
|
end
|
|
454
458
|
end
|
|
455
459
|
|
|
456
460
|
def generate_call_graph(_format, _output)
|
|
457
461
|
# Similar to import graph but for method calls
|
|
458
|
-
|
|
462
|
+
display_message("Call graph generation not yet implemented")
|
|
459
463
|
end
|
|
460
464
|
|
|
461
465
|
def generate_cycle_graph(_format, _output)
|
|
462
466
|
# Generate graph showing only the cycles
|
|
463
|
-
|
|
467
|
+
display_message("Cycle graph generation not yet implemented")
|
|
464
468
|
end
|
|
465
469
|
|
|
466
470
|
def count_files
|
|
@@ -1,14 +1,15 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
+
require "tty-prompt"
|
|
3
4
|
require_relative "ruby_maat_integration"
|
|
4
5
|
require_relative "feature_analyzer"
|
|
5
6
|
|
|
6
7
|
module Aidp
|
|
7
8
|
module Analyze
|
|
8
9
|
class Prioritizer
|
|
9
|
-
def initialize(project_dir = Dir.pwd)
|
|
10
|
+
def initialize(project_dir = Dir.pwd, prompt: TTY::Prompt.new)
|
|
10
11
|
@project_dir = project_dir
|
|
11
|
-
@code_maat = Aidp::Analyze::RubyMaatIntegration.new(project_dir)
|
|
12
|
+
@code_maat = Aidp::Analyze::RubyMaatIntegration.new(project_dir, prompt: prompt)
|
|
12
13
|
@feature_analyzer = Aidp::Analyze::FeatureAnalyzer.new(project_dir)
|
|
13
14
|
end
|
|
14
15
|
|
|
@@ -11,7 +11,7 @@ module Aidp
|
|
|
11
11
|
|
|
12
12
|
def initialize(project_dir)
|
|
13
13
|
@project_dir = project_dir
|
|
14
|
-
@progress_file = File.join(project_dir, ".aidp
|
|
14
|
+
@progress_file = File.join(project_dir, ".aidp", "progress", "analyze.yml")
|
|
15
15
|
load_progress
|
|
16
16
|
end
|
|
17
17
|
|
|
@@ -80,6 +80,7 @@ module Aidp
|
|
|
80
80
|
# In test mode, skip file operations to avoid hanging
|
|
81
81
|
return if ENV["RACK_ENV"] == "test" || defined?(RSpec)
|
|
82
82
|
|
|
83
|
+
FileUtils.mkdir_p(File.dirname(@progress_file))
|
|
83
84
|
File.write(@progress_file, @progress.to_yaml)
|
|
84
85
|
end
|
|
85
86
|
end
|
|
@@ -1,14 +1,18 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
require "tty-command"
|
|
4
|
+
require "tty-prompt"
|
|
4
5
|
require "json"
|
|
5
6
|
require "fileutils"
|
|
6
7
|
|
|
7
8
|
module Aidp
|
|
8
9
|
module Analyze
|
|
9
10
|
class RubyMaatIntegration
|
|
10
|
-
|
|
11
|
+
include Aidp::MessageDisplay
|
|
12
|
+
|
|
13
|
+
def initialize(project_dir = Dir.pwd, prompt: TTY::Prompt.new)
|
|
11
14
|
@project_dir = project_dir
|
|
15
|
+
@prompt = prompt
|
|
12
16
|
end
|
|
13
17
|
|
|
14
18
|
# Check if RubyMaat gem is available and accessible
|
|
@@ -80,7 +84,7 @@ module Aidp
|
|
|
80
84
|
|
|
81
85
|
# Run analysis on large repositories using chunking
|
|
82
86
|
def run_chunked_analysis(git_log_file)
|
|
83
|
-
|
|
87
|
+
display_message("Large repository detected. Running chunked analysis...", type: :info)
|
|
84
88
|
|
|
85
89
|
# Split analysis into chunks
|
|
86
90
|
chunks = create_analysis_chunks(git_log_file)
|
|
@@ -93,7 +97,7 @@ module Aidp
|
|
|
93
97
|
}
|
|
94
98
|
|
|
95
99
|
chunks.each_with_index do |chunk, index|
|
|
96
|
-
|
|
100
|
+
display_message("Processing chunk #{index + 1}/#{chunks.length}...", type: :info)
|
|
97
101
|
|
|
98
102
|
chunk_results = analyze_chunk(chunk)
|
|
99
103
|
|
data/lib/aidp/analyze/runner.rb
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
+
require "tty-prompt"
|
|
3
4
|
require_relative "steps"
|
|
4
5
|
require_relative "progress"
|
|
5
6
|
require_relative "../storage/file_manager"
|
|
@@ -9,18 +10,24 @@ module Aidp
|
|
|
9
10
|
module Analyze
|
|
10
11
|
class Runner
|
|
11
12
|
include Aidp::DebugMixin
|
|
13
|
+
include Aidp::MessageDisplay
|
|
12
14
|
|
|
13
|
-
def initialize(project_dir, harness_runner = nil)
|
|
15
|
+
def initialize(project_dir, harness_runner = nil, prompt: TTY::Prompt.new)
|
|
14
16
|
@project_dir = project_dir
|
|
15
17
|
@harness_runner = harness_runner
|
|
16
18
|
@is_harness_mode = !harness_runner.nil?
|
|
17
19
|
@file_manager = Aidp::Storage::FileManager.new(File.join(project_dir, ".aidp"))
|
|
20
|
+
@prompt = prompt
|
|
18
21
|
end
|
|
19
22
|
|
|
20
23
|
def progress
|
|
21
24
|
@progress ||= Aidp::Analyze::Progress.new(@project_dir)
|
|
22
25
|
end
|
|
23
26
|
|
|
27
|
+
private
|
|
28
|
+
|
|
29
|
+
public
|
|
30
|
+
|
|
24
31
|
def run_step(step_name, options = {})
|
|
25
32
|
# Always validate step exists first
|
|
26
33
|
step_spec = Aidp::Analyze::Steps::SPEC[step_name]
|
|
@@ -42,7 +49,7 @@ module Aidp
|
|
|
42
49
|
# Harness-aware step execution
|
|
43
50
|
def run_step_with_harness(step_name, options = {})
|
|
44
51
|
# Get current provider from harness
|
|
45
|
-
current_provider =
|
|
52
|
+
current_provider = get_harness_provider_safely
|
|
46
53
|
provider_type = current_provider || "cursor"
|
|
47
54
|
|
|
48
55
|
debug_step(step_name, "Harness execution", {
|
|
@@ -72,7 +79,7 @@ module Aidp
|
|
|
72
79
|
|
|
73
80
|
# Standalone step execution (simplified - synchronous)
|
|
74
81
|
def run_step_standalone(step_name, options = {})
|
|
75
|
-
|
|
82
|
+
display_message("🚀 Running step synchronously: #{step_name}", type: :info)
|
|
76
83
|
|
|
77
84
|
start_time = Time.now
|
|
78
85
|
prompt = composed_prompt(step_name, options)
|
|
@@ -85,7 +92,7 @@ module Aidp
|
|
|
85
92
|
# Store execution metrics
|
|
86
93
|
@file_manager.record_step_execution(step_name, "cursor", duration, result[:status] == "completed")
|
|
87
94
|
|
|
88
|
-
|
|
95
|
+
display_message("✅ Step completed in #{duration.round(2)}s", type: :success)
|
|
89
96
|
result
|
|
90
97
|
end
|
|
91
98
|
|
|
@@ -180,7 +187,10 @@ module Aidp
|
|
|
180
187
|
|
|
181
188
|
def template_search_paths
|
|
182
189
|
[
|
|
183
|
-
File.join(@project_dir, "templates",
|
|
190
|
+
File.join(@project_dir, "templates"), # Root templates folder
|
|
191
|
+
File.join(@project_dir, "templates", "analysis"),
|
|
192
|
+
File.join(@project_dir, "templates", "planning"),
|
|
193
|
+
File.join(@project_dir, "templates", "implementation"),
|
|
184
194
|
File.join(@project_dir, "templates", "COMMON")
|
|
185
195
|
]
|
|
186
196
|
end
|
|
@@ -223,11 +233,11 @@ module Aidp
|
|
|
223
233
|
# Add current execution context
|
|
224
234
|
context_parts << "## Analysis Context"
|
|
225
235
|
context_parts << "Project Directory: #{@project_dir}"
|
|
226
|
-
context_parts << "Current Step: #{
|
|
227
|
-
context_parts << "Current Provider: #{
|
|
236
|
+
context_parts << "Current Step: #{get_harness_current_step_safely}"
|
|
237
|
+
context_parts << "Current Provider: #{get_harness_provider_safely}"
|
|
228
238
|
|
|
229
239
|
# Add user input context
|
|
230
|
-
user_input =
|
|
240
|
+
user_input = get_harness_user_input_safely
|
|
231
241
|
if user_input && !user_input.empty?
|
|
232
242
|
context_parts << "\n## Previous User Input"
|
|
233
243
|
user_input.each do |key, value|
|
|
@@ -236,7 +246,7 @@ module Aidp
|
|
|
236
246
|
end
|
|
237
247
|
|
|
238
248
|
# Add execution history context
|
|
239
|
-
execution_log =
|
|
249
|
+
execution_log = get_harness_execution_log_safely
|
|
240
250
|
if execution_log && !execution_log.empty?
|
|
241
251
|
context_parts << "\n## Analysis History"
|
|
242
252
|
recent_logs = execution_log.last(5) # Last 5 entries
|
|
@@ -250,8 +260,9 @@ module Aidp
|
|
|
250
260
|
|
|
251
261
|
# Execute step with harness provider management
|
|
252
262
|
def execute_with_harness_provider(provider_type, prompt, step_name, _options)
|
|
253
|
-
# Get provider manager from harness
|
|
254
|
-
provider_manager =
|
|
263
|
+
# Get provider manager from harness safely
|
|
264
|
+
provider_manager = get_harness_provider_manager_safely
|
|
265
|
+
return {status: "failed", error: "No provider manager available"} unless provider_manager
|
|
255
266
|
|
|
256
267
|
# Execute with provider
|
|
257
268
|
provider_manager.execute_with_provider(provider_type, prompt, {
|
|
@@ -325,6 +336,57 @@ module Aidp
|
|
|
325
336
|
})
|
|
326
337
|
end
|
|
327
338
|
end
|
|
339
|
+
|
|
340
|
+
# Safely get current provider from harness runner
|
|
341
|
+
def get_harness_provider_safely
|
|
342
|
+
return "cursor" unless @harness_runner
|
|
343
|
+
return "cursor" unless @harness_runner.respond_to?(:current_provider)
|
|
344
|
+
|
|
345
|
+
@harness_runner.current_provider || "cursor"
|
|
346
|
+
rescue => e
|
|
347
|
+
debug_log("⚠️ Failed to get current provider from harness", level: :warn, data: {error: e.message})
|
|
348
|
+
"cursor"
|
|
349
|
+
end
|
|
350
|
+
|
|
351
|
+
def get_harness_current_step_safely
|
|
352
|
+
return "unknown" unless @harness_runner
|
|
353
|
+
return "unknown" unless @harness_runner.respond_to?(:current_step)
|
|
354
|
+
|
|
355
|
+
@harness_runner.current_step || "unknown"
|
|
356
|
+
rescue => e
|
|
357
|
+
debug_log("⚠️ Failed to get current step from harness", level: :warn, data: {error: e.message})
|
|
358
|
+
"unknown"
|
|
359
|
+
end
|
|
360
|
+
|
|
361
|
+
def get_harness_user_input_safely
|
|
362
|
+
return {} unless @harness_runner
|
|
363
|
+
return {} unless @harness_runner.respond_to?(:user_input)
|
|
364
|
+
|
|
365
|
+
@harness_runner.user_input || {}
|
|
366
|
+
rescue => e
|
|
367
|
+
debug_log("⚠️ Failed to get user input from harness", level: :warn, data: {error: e.message})
|
|
368
|
+
{}
|
|
369
|
+
end
|
|
370
|
+
|
|
371
|
+
def get_harness_execution_log_safely
|
|
372
|
+
return [] unless @harness_runner
|
|
373
|
+
return [] unless @harness_runner.respond_to?(:execution_log)
|
|
374
|
+
|
|
375
|
+
@harness_runner.execution_log || []
|
|
376
|
+
rescue => e
|
|
377
|
+
debug_log("⚠️ Failed to get execution log from harness", level: :warn, data: {error: e.message})
|
|
378
|
+
[]
|
|
379
|
+
end
|
|
380
|
+
|
|
381
|
+
def get_harness_provider_manager_safely
|
|
382
|
+
return nil unless @harness_runner
|
|
383
|
+
return nil unless @harness_runner.respond_to?(:provider_manager)
|
|
384
|
+
|
|
385
|
+
@harness_runner.provider_manager
|
|
386
|
+
rescue => e
|
|
387
|
+
debug_log("⚠️ Failed to get provider manager from harness", level: :warn, data: {error: e.message})
|
|
388
|
+
nil
|
|
389
|
+
end
|
|
328
390
|
end
|
|
329
391
|
end
|
|
330
392
|
end
|