aidp 0.7.0 → 0.8.1
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 +60 -214
- data/bin/aidp +1 -1
- data/lib/aidp/analysis/kb_inspector.rb +38 -23
- data/lib/aidp/analysis/seams.rb +2 -31
- data/lib/aidp/analysis/tree_sitter_grammar_loader.rb +1 -13
- data/lib/aidp/analysis/tree_sitter_scan.rb +3 -20
- data/lib/aidp/analyze/error_handler.rb +2 -75
- 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/cli/jobs_command.rb +100 -432
- data/lib/aidp/cli.rb +309 -239
- 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 -103
- data/lib/aidp/providers/base.rb +170 -0
- data/lib/aidp/providers/cursor.rb +52 -181
- data/lib/aidp/providers/gemini.rb +24 -107
- 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 +54 -39
- 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 +93 -69
- data/lib/aidp/analyze/agent_personas.rb +0 -71
- data/lib/aidp/analyze/agent_tool_executor.rb +0 -439
- data/lib/aidp/analyze/data_retention_manager.rb +0 -421
- data/lib/aidp/analyze/database.rb +0 -260
- data/lib/aidp/analyze/dependencies.rb +0 -335
- data/lib/aidp/analyze/export_manager.rb +0 -418
- data/lib/aidp/analyze/focus_guidance.rb +0 -517
- data/lib/aidp/analyze/incremental_analyzer.rb +0 -533
- data/lib/aidp/analyze/language_analysis_strategies.rb +0 -897
- data/lib/aidp/analyze/large_analysis_progress.rb +0 -499
- data/lib/aidp/analyze/memory_manager.rb +0 -339
- data/lib/aidp/analyze/metrics_storage.rb +0 -336
- data/lib/aidp/analyze/parallel_processor.rb +0 -454
- data/lib/aidp/analyze/performance_optimizer.rb +0 -691
- data/lib/aidp/analyze/repository_chunker.rb +0 -697
- data/lib/aidp/analyze/static_analysis_detector.rb +0 -577
- data/lib/aidp/analyze/storage.rb +0 -655
- data/lib/aidp/analyze/tool_configuration.rb +0 -441
- 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/job_manager.rb +0 -41
- data/lib/aidp/jobs/base_job.rb +0 -45
- data/lib/aidp/jobs/provider_execution_job.rb +0 -83
- 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,533 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require "json"
|
4
|
-
require "yaml"
|
5
|
-
require_relative "storage"
|
6
|
-
|
7
|
-
module Aidp
|
8
|
-
module Analyze
|
9
|
-
class IncrementalAnalyzer
|
10
|
-
# Analysis granularity levels
|
11
|
-
GRANULARITY_LEVELS = %w[file directory component feature module].freeze
|
12
|
-
|
13
|
-
def initialize(project_dir = Dir.pwd, config = {})
|
14
|
-
@project_dir = project_dir
|
15
|
-
@config = config
|
16
|
-
@storage = config[:storage] || Aidp::AnalysisStorage.new(project_dir)
|
17
|
-
@progress_file = config[:progress_file] || File.join(project_dir, ".aidp-incremental-progress.yml")
|
18
|
-
end
|
19
|
-
|
20
|
-
# Perform incremental analysis
|
21
|
-
def analyze_incrementally(analysis_type, options = {})
|
22
|
-
granularity = options[:granularity] || "file"
|
23
|
-
force_full = options[:force_full] || false
|
24
|
-
|
25
|
-
# Load previous analysis state
|
26
|
-
previous_state = load_analysis_state(analysis_type)
|
27
|
-
|
28
|
-
# Determine what needs to be analyzed
|
29
|
-
analysis_plan = if force_full
|
30
|
-
create_full_analysis_plan(analysis_type, granularity)
|
31
|
-
else
|
32
|
-
create_incremental_analysis_plan(analysis_type, granularity, previous_state)
|
33
|
-
end
|
34
|
-
|
35
|
-
# Execute analysis plan
|
36
|
-
results = execute_analysis_plan(analysis_plan, options)
|
37
|
-
|
38
|
-
# Update analysis state
|
39
|
-
new_state = update_analysis_state(analysis_type, previous_state, results)
|
40
|
-
save_analysis_state(analysis_type, new_state)
|
41
|
-
|
42
|
-
{
|
43
|
-
analysis_type: analysis_type,
|
44
|
-
granularity: granularity,
|
45
|
-
plan: analysis_plan,
|
46
|
-
results: results,
|
47
|
-
state: new_state,
|
48
|
-
incremental: !force_full
|
49
|
-
}
|
50
|
-
end
|
51
|
-
|
52
|
-
# Analyze specific components incrementally
|
53
|
-
def analyze_components_incrementally(components, analysis_type, options = {})
|
54
|
-
results = {}
|
55
|
-
|
56
|
-
components.each do |component|
|
57
|
-
component_result = analyze_component_incrementally(component, analysis_type, options)
|
58
|
-
results[component] = component_result
|
59
|
-
end
|
60
|
-
|
61
|
-
{
|
62
|
-
components: components,
|
63
|
-
analysis_type: analysis_type,
|
64
|
-
results: results,
|
65
|
-
summary: generate_component_summary(results)
|
66
|
-
}
|
67
|
-
end
|
68
|
-
|
69
|
-
# Analyze files incrementally
|
70
|
-
def analyze_files_incrementally(files, analysis_type, options = {})
|
71
|
-
results = {}
|
72
|
-
|
73
|
-
files.each do |file|
|
74
|
-
file_result = analyze_file_incrementally(file, analysis_type, options)
|
75
|
-
results[file] = file_result
|
76
|
-
end
|
77
|
-
|
78
|
-
{
|
79
|
-
files: files,
|
80
|
-
analysis_type: analysis_type,
|
81
|
-
results: results,
|
82
|
-
summary: generate_file_summary(results)
|
83
|
-
}
|
84
|
-
end
|
85
|
-
|
86
|
-
# Get incremental analysis status
|
87
|
-
def get_incremental_status(analysis_type)
|
88
|
-
state = load_analysis_state(analysis_type)
|
89
|
-
|
90
|
-
{
|
91
|
-
analysis_type: analysis_type,
|
92
|
-
last_analysis: state[:last_analysis],
|
93
|
-
total_components: state[:total_components] || 0,
|
94
|
-
analyzed_components: state[:analyzed_components] || 0,
|
95
|
-
pending_components: state[:pending_components] || 0,
|
96
|
-
analysis_coverage: calculate_coverage(state),
|
97
|
-
last_modified: state[:last_modified]
|
98
|
-
}
|
99
|
-
end
|
100
|
-
|
101
|
-
# Get analysis recommendations
|
102
|
-
def get_analysis_recommendations(analysis_type)
|
103
|
-
state = load_analysis_state(analysis_type)
|
104
|
-
recommendations = []
|
105
|
-
|
106
|
-
# Check for outdated analysis
|
107
|
-
if state[:last_analysis] && (Time.now - state[:last_analysis]) > 24 * 60 * 60 # 24 hours
|
108
|
-
recommendations << {
|
109
|
-
type: "outdated_analysis",
|
110
|
-
priority: "medium",
|
111
|
-
message: "Analysis is more than 24 hours old",
|
112
|
-
action: "Consider running full analysis"
|
113
|
-
}
|
114
|
-
end
|
115
|
-
|
116
|
-
# Check for low coverage
|
117
|
-
coverage = calculate_coverage(state)
|
118
|
-
if coverage < 0.8
|
119
|
-
recommendations << {
|
120
|
-
type: "low_coverage",
|
121
|
-
priority: "high",
|
122
|
-
message: "Analysis coverage is #{coverage * 100}%",
|
123
|
-
action: "Run incremental analysis to improve coverage"
|
124
|
-
}
|
125
|
-
end
|
126
|
-
|
127
|
-
# Check for pending components
|
128
|
-
if state[:pending_components] && state[:pending_components] > 0
|
129
|
-
recommendations << {
|
130
|
-
type: "pending_components",
|
131
|
-
priority: "medium",
|
132
|
-
message: "#{state[:pending_components]} components pending analysis",
|
133
|
-
action: "Run incremental analysis for pending components"
|
134
|
-
}
|
135
|
-
end
|
136
|
-
|
137
|
-
recommendations
|
138
|
-
end
|
139
|
-
|
140
|
-
# Reset incremental analysis state
|
141
|
-
def reset_incremental_state(analysis_type)
|
142
|
-
state_file = get_state_file_path(analysis_type)
|
143
|
-
File.delete(state_file) if File.exist?(state_file)
|
144
|
-
|
145
|
-
{
|
146
|
-
analysis_type: analysis_type,
|
147
|
-
reset: true,
|
148
|
-
timestamp: Time.now
|
149
|
-
}
|
150
|
-
end
|
151
|
-
|
152
|
-
# Get analysis history
|
153
|
-
def get_analysis_history(analysis_type, limit = 10)
|
154
|
-
state = load_analysis_state(analysis_type)
|
155
|
-
history = state[:history] || []
|
156
|
-
|
157
|
-
history.last(limit).map do |entry|
|
158
|
-
{
|
159
|
-
timestamp: entry[:timestamp],
|
160
|
-
type: entry[:type],
|
161
|
-
components_analyzed: entry[:components_analyzed],
|
162
|
-
duration: entry[:duration],
|
163
|
-
coverage: entry[:coverage]
|
164
|
-
}
|
165
|
-
end
|
166
|
-
end
|
167
|
-
|
168
|
-
private
|
169
|
-
|
170
|
-
def load_analysis_state(analysis_type)
|
171
|
-
state_file = get_state_file_path(analysis_type)
|
172
|
-
return create_initial_state(analysis_type) unless File.exist?(state_file)
|
173
|
-
|
174
|
-
YAML.load_file(state_file) || create_initial_state(analysis_type)
|
175
|
-
end
|
176
|
-
|
177
|
-
def save_analysis_state(analysis_type, state)
|
178
|
-
state_file = get_state_file_path(analysis_type)
|
179
|
-
state[:last_modified] = Time.now
|
180
|
-
|
181
|
-
File.write(state_file, YAML.dump(state))
|
182
|
-
end
|
183
|
-
|
184
|
-
def get_state_file_path(analysis_type)
|
185
|
-
File.join(@project_dir, ".aidp-#{analysis_type}-state.yml")
|
186
|
-
end
|
187
|
-
|
188
|
-
def create_initial_state(analysis_type)
|
189
|
-
{
|
190
|
-
analysis_type: analysis_type,
|
191
|
-
created_at: Time.now,
|
192
|
-
last_analysis: nil,
|
193
|
-
total_components: 0,
|
194
|
-
analyzed_components: 0,
|
195
|
-
pending_components: 0,
|
196
|
-
components: {},
|
197
|
-
history: []
|
198
|
-
}
|
199
|
-
end
|
200
|
-
|
201
|
-
def create_full_analysis_plan(analysis_type, granularity)
|
202
|
-
components = discover_components(granularity)
|
203
|
-
|
204
|
-
{
|
205
|
-
type: "full",
|
206
|
-
granularity: granularity,
|
207
|
-
components: components,
|
208
|
-
total_components: components.length,
|
209
|
-
estimated_duration: estimate_analysis_duration(components, analysis_type)
|
210
|
-
}
|
211
|
-
end
|
212
|
-
|
213
|
-
def create_incremental_analysis_plan(analysis_type, granularity, previous_state)
|
214
|
-
all_components = discover_components(granularity)
|
215
|
-
analyzed_components = previous_state[:components] || {}
|
216
|
-
|
217
|
-
# Identify components that need analysis
|
218
|
-
components_to_analyze = []
|
219
|
-
|
220
|
-
all_components.each do |component|
|
221
|
-
component_info = analyzed_components[component]
|
222
|
-
|
223
|
-
if !component_info || needs_reanalysis?(component, component_info, analysis_type)
|
224
|
-
components_to_analyze << component
|
225
|
-
end
|
226
|
-
end
|
227
|
-
|
228
|
-
{
|
229
|
-
type: "incremental",
|
230
|
-
granularity: granularity,
|
231
|
-
components: components_to_analyze,
|
232
|
-
total_components: all_components.length,
|
233
|
-
components_to_analyze: components_to_analyze.length,
|
234
|
-
estimated_duration: estimate_analysis_duration(components_to_analyze, analysis_type)
|
235
|
-
}
|
236
|
-
end
|
237
|
-
|
238
|
-
def discover_components(granularity)
|
239
|
-
case granularity
|
240
|
-
when "file"
|
241
|
-
discover_files
|
242
|
-
when "directory"
|
243
|
-
discover_directories
|
244
|
-
when "component"
|
245
|
-
discover_components_by_structure
|
246
|
-
when "feature"
|
247
|
-
discover_features
|
248
|
-
when "module"
|
249
|
-
discover_modules
|
250
|
-
else
|
251
|
-
discover_files # Default to file-level
|
252
|
-
end
|
253
|
-
end
|
254
|
-
|
255
|
-
def discover_files
|
256
|
-
files = []
|
257
|
-
|
258
|
-
Dir.glob(File.join(@project_dir, "**", "*.rb")).each do |file|
|
259
|
-
relative_path = file.sub(@project_dir + "/", "")
|
260
|
-
files << relative_path unless relative_path.start_with?(".")
|
261
|
-
end
|
262
|
-
|
263
|
-
files
|
264
|
-
end
|
265
|
-
|
266
|
-
def discover_directories
|
267
|
-
directories = []
|
268
|
-
|
269
|
-
Dir.glob(File.join(@project_dir, "**", "*/")).each do |dir|
|
270
|
-
relative_path = dir.sub(@project_dir + "/", "").chomp("/")
|
271
|
-
directories << relative_path unless relative_path.start_with?(".")
|
272
|
-
end
|
273
|
-
|
274
|
-
directories
|
275
|
-
end
|
276
|
-
|
277
|
-
def discover_components_by_structure
|
278
|
-
components = []
|
279
|
-
|
280
|
-
# Look for common component patterns
|
281
|
-
component_patterns = [
|
282
|
-
"app/models/**/*.rb",
|
283
|
-
"app/controllers/**/*.rb",
|
284
|
-
"app/services/**/*.rb",
|
285
|
-
"lib/**/*.rb",
|
286
|
-
"spec/**/*.rb"
|
287
|
-
]
|
288
|
-
|
289
|
-
component_patterns.each do |pattern|
|
290
|
-
Dir.glob(File.join(@project_dir, pattern)).each do |file|
|
291
|
-
relative_path = file.sub(@project_dir + "/", "")
|
292
|
-
components << relative_path
|
293
|
-
end
|
294
|
-
end
|
295
|
-
|
296
|
-
components
|
297
|
-
end
|
298
|
-
|
299
|
-
def discover_features
|
300
|
-
features = []
|
301
|
-
|
302
|
-
# Look for feature directories
|
303
|
-
feature_dirs = [
|
304
|
-
"app/features",
|
305
|
-
"features",
|
306
|
-
"app/views",
|
307
|
-
"app/controllers"
|
308
|
-
]
|
309
|
-
|
310
|
-
feature_dirs.each do |dir|
|
311
|
-
full_path = File.join(@project_dir, dir)
|
312
|
-
next unless Dir.exist?(full_path)
|
313
|
-
|
314
|
-
Dir.entries(full_path).each do |entry|
|
315
|
-
next if entry.start_with?(".")
|
316
|
-
|
317
|
-
feature_path = File.join(dir, entry)
|
318
|
-
features << feature_path if Dir.exist?(File.join(@project_dir, feature_path))
|
319
|
-
end
|
320
|
-
end
|
321
|
-
|
322
|
-
features
|
323
|
-
end
|
324
|
-
|
325
|
-
def discover_modules
|
326
|
-
modules = []
|
327
|
-
|
328
|
-
# Look for module files
|
329
|
-
Dir.glob(File.join(@project_dir, "**", "*.rb")).each do |file|
|
330
|
-
content = File.read(file)
|
331
|
-
if content.include?("module ") || content.include?("class ")
|
332
|
-
relative_path = file.sub(@project_dir + "/", "")
|
333
|
-
modules << relative_path
|
334
|
-
end
|
335
|
-
end
|
336
|
-
|
337
|
-
modules
|
338
|
-
end
|
339
|
-
|
340
|
-
def needs_reanalysis?(component, component_info, analysis_type)
|
341
|
-
return true unless component_info[:last_analysis]
|
342
|
-
|
343
|
-
# Check if component has been modified since last analysis
|
344
|
-
component_path = File.join(@project_dir, component)
|
345
|
-
return true unless File.exist?(component_path)
|
346
|
-
|
347
|
-
last_modified = File.mtime(component_path)
|
348
|
-
last_analysis = component_info[:last_analysis]
|
349
|
-
|
350
|
-
# Reanalyze if component was modified after last analysis
|
351
|
-
last_modified > last_analysis
|
352
|
-
end
|
353
|
-
|
354
|
-
def execute_analysis_plan(plan, options)
|
355
|
-
results = {
|
356
|
-
plan: plan,
|
357
|
-
start_time: Time.now,
|
358
|
-
results: {},
|
359
|
-
errors: []
|
360
|
-
}
|
361
|
-
|
362
|
-
plan[:components].each do |component|
|
363
|
-
component_result = analyze_component(component, plan[:analysis_type], options)
|
364
|
-
results[:results][component] = component_result
|
365
|
-
end
|
366
|
-
|
367
|
-
results[:end_time] = Time.now
|
368
|
-
results[:duration] = results[:end_time] - results[:start_time]
|
369
|
-
|
370
|
-
results
|
371
|
-
end
|
372
|
-
|
373
|
-
def analyze_component(component, analysis_type, options)
|
374
|
-
# This is a placeholder for actual analysis logic
|
375
|
-
# In a real implementation, this would call the appropriate analysis tools
|
376
|
-
|
377
|
-
{
|
378
|
-
component: component,
|
379
|
-
analysis_type: analysis_type,
|
380
|
-
analyzed_at: Time.now,
|
381
|
-
status: "completed",
|
382
|
-
metrics: generate_component_metrics(component, analysis_type),
|
383
|
-
findings: generate_component_findings(component, analysis_type)
|
384
|
-
}
|
385
|
-
end
|
386
|
-
|
387
|
-
def analyze_component_incrementally(component, analysis_type, options)
|
388
|
-
component_info = get_component_info(component)
|
389
|
-
|
390
|
-
if needs_reanalysis?(component, component_info, analysis_type)
|
391
|
-
result = analyze_component(component, analysis_type, options)
|
392
|
-
update_component_info(component, result)
|
393
|
-
result
|
394
|
-
else
|
395
|
-
{
|
396
|
-
component: component,
|
397
|
-
analysis_type: analysis_type,
|
398
|
-
status: "skipped",
|
399
|
-
reason: "No changes detected",
|
400
|
-
last_analysis: component_info[:last_analysis]
|
401
|
-
}
|
402
|
-
end
|
403
|
-
end
|
404
|
-
|
405
|
-
def analyze_file_incrementally(file, analysis_type, options)
|
406
|
-
file_info = get_file_info(file)
|
407
|
-
|
408
|
-
if needs_reanalysis?(file, file_info, analysis_type)
|
409
|
-
result = analyze_component(file, analysis_type, options)
|
410
|
-
update_file_info(file, result)
|
411
|
-
result
|
412
|
-
else
|
413
|
-
{
|
414
|
-
file: file,
|
415
|
-
analysis_type: analysis_type,
|
416
|
-
status: "skipped",
|
417
|
-
reason: "No changes detected",
|
418
|
-
last_analysis: file_info[:last_analysis]
|
419
|
-
}
|
420
|
-
end
|
421
|
-
end
|
422
|
-
|
423
|
-
def update_analysis_state(analysis_type, previous_state, results)
|
424
|
-
new_state = previous_state.dup
|
425
|
-
new_state[:last_analysis] = Time.now
|
426
|
-
new_state[:total_components] = results[:plan][:total_components]
|
427
|
-
|
428
|
-
# Update component information
|
429
|
-
results[:results].each do |component, result|
|
430
|
-
new_state[:components][component] = {
|
431
|
-
last_analysis: Time.now,
|
432
|
-
analysis_type: analysis_type,
|
433
|
-
status: result[:status],
|
434
|
-
metrics: result[:metrics]
|
435
|
-
}
|
436
|
-
end
|
437
|
-
|
438
|
-
new_state[:analyzed_components] = new_state[:components].length
|
439
|
-
new_state[:pending_components] = new_state[:total_components] - new_state[:analyzed_components]
|
440
|
-
|
441
|
-
# Add to history
|
442
|
-
new_state[:history] ||= []
|
443
|
-
new_state[:history] << {
|
444
|
-
timestamp: Time.now,
|
445
|
-
type: results[:plan][:type],
|
446
|
-
components_analyzed: results[:results].length,
|
447
|
-
duration: results[:duration],
|
448
|
-
coverage: calculate_coverage(new_state)
|
449
|
-
}
|
450
|
-
|
451
|
-
new_state
|
452
|
-
end
|
453
|
-
|
454
|
-
def calculate_coverage(state)
|
455
|
-
return 0.0 if state[:total_components] == 0
|
456
|
-
|
457
|
-
state[:analyzed_components].to_f / state[:total_components]
|
458
|
-
end
|
459
|
-
|
460
|
-
def estimate_analysis_duration(components, analysis_type)
|
461
|
-
# Simple estimation based on component count
|
462
|
-
base_duration_per_component = case analysis_type
|
463
|
-
when "static_analysis"
|
464
|
-
30 # seconds
|
465
|
-
when "security_analysis"
|
466
|
-
60 # seconds
|
467
|
-
when "performance_analysis"
|
468
|
-
45 # seconds
|
469
|
-
else
|
470
|
-
30 # seconds
|
471
|
-
end
|
472
|
-
|
473
|
-
components.length * base_duration_per_component
|
474
|
-
end
|
475
|
-
|
476
|
-
def generate_component_metrics(component, analysis_type)
|
477
|
-
# Placeholder for actual metrics generation
|
478
|
-
{
|
479
|
-
complexity: rand(1..10),
|
480
|
-
lines_of_code: rand(10..500),
|
481
|
-
maintainability_index: rand(50..100)
|
482
|
-
}
|
483
|
-
end
|
484
|
-
|
485
|
-
def generate_component_findings(component, analysis_type)
|
486
|
-
# Placeholder for actual findings generation
|
487
|
-
[]
|
488
|
-
end
|
489
|
-
|
490
|
-
def get_component_info(component)
|
491
|
-
state = load_analysis_state("general")
|
492
|
-
state[:components][component] || {}
|
493
|
-
end
|
494
|
-
|
495
|
-
def update_component_info(component, result)
|
496
|
-
state = load_analysis_state("general")
|
497
|
-
state[:components][component] = {
|
498
|
-
last_analysis: Time.now,
|
499
|
-
status: result[:status],
|
500
|
-
metrics: result[:metrics]
|
501
|
-
}
|
502
|
-
save_analysis_state("general", state)
|
503
|
-
end
|
504
|
-
|
505
|
-
def get_file_info(file)
|
506
|
-
get_component_info(file)
|
507
|
-
end
|
508
|
-
|
509
|
-
def update_file_info(file, result)
|
510
|
-
update_component_info(file, result)
|
511
|
-
end
|
512
|
-
|
513
|
-
def generate_component_summary(results)
|
514
|
-
total_components = results.length
|
515
|
-
analyzed_components = results.count { |_, result| result[:status] == "completed" }
|
516
|
-
skipped_components = results.count { |_, result| result[:status] == "skipped" }
|
517
|
-
failed_components = results.count { |_, result| result[:status] == "failed" }
|
518
|
-
|
519
|
-
{
|
520
|
-
total_components: total_components,
|
521
|
-
analyzed_components: analyzed_components,
|
522
|
-
skipped_components: skipped_components,
|
523
|
-
failed_components: failed_components,
|
524
|
-
success_rate: (total_components > 0) ? (analyzed_components.to_f / total_components * 100).round(2) : 0
|
525
|
-
}
|
526
|
-
end
|
527
|
-
|
528
|
-
def generate_file_summary(results)
|
529
|
-
generate_component_summary(results)
|
530
|
-
end
|
531
|
-
end
|
532
|
-
end
|
533
|
-
end
|