aidp 0.27.0 → 0.28.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.
Files changed (90) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +89 -0
  3. data/lib/aidp/cli/models_command.rb +5 -6
  4. data/lib/aidp/cli.rb +10 -8
  5. data/lib/aidp/config.rb +54 -0
  6. data/lib/aidp/debug_mixin.rb +23 -1
  7. data/lib/aidp/execute/agent_signal_parser.rb +22 -0
  8. data/lib/aidp/execute/repl_macros.rb +2 -2
  9. data/lib/aidp/execute/steps.rb +94 -1
  10. data/lib/aidp/execute/work_loop_runner.rb +209 -17
  11. data/lib/aidp/execute/workflow_selector.rb +2 -25
  12. data/lib/aidp/firewall/provider_requirements_collector.rb +262 -0
  13. data/lib/aidp/harness/ai_decision_engine.rb +35 -2
  14. data/lib/aidp/harness/config_manager.rb +0 -5
  15. data/lib/aidp/harness/config_schema.rb +8 -0
  16. data/lib/aidp/harness/configuration.rb +27 -19
  17. data/lib/aidp/harness/enhanced_runner.rb +1 -4
  18. data/lib/aidp/harness/error_handler.rb +1 -72
  19. data/lib/aidp/harness/provider_factory.rb +11 -2
  20. data/lib/aidp/harness/state_manager.rb +0 -7
  21. data/lib/aidp/harness/thinking_depth_manager.rb +47 -68
  22. data/lib/aidp/harness/ui/enhanced_tui.rb +8 -18
  23. data/lib/aidp/harness/ui/enhanced_workflow_selector.rb +0 -18
  24. data/lib/aidp/harness/ui/progress_display.rb +6 -2
  25. data/lib/aidp/harness/user_interface.rb +0 -58
  26. data/lib/aidp/init/runner.rb +7 -2
  27. data/lib/aidp/planning/analyzers/feedback_analyzer.rb +365 -0
  28. data/lib/aidp/planning/builders/agile_plan_builder.rb +387 -0
  29. data/lib/aidp/planning/builders/project_plan_builder.rb +193 -0
  30. data/lib/aidp/planning/generators/gantt_generator.rb +190 -0
  31. data/lib/aidp/planning/generators/iteration_plan_generator.rb +392 -0
  32. data/lib/aidp/planning/generators/legacy_research_planner.rb +473 -0
  33. data/lib/aidp/planning/generators/marketing_report_generator.rb +348 -0
  34. data/lib/aidp/planning/generators/mvp_scope_generator.rb +310 -0
  35. data/lib/aidp/planning/generators/user_test_plan_generator.rb +373 -0
  36. data/lib/aidp/planning/generators/wbs_generator.rb +259 -0
  37. data/lib/aidp/planning/mappers/persona_mapper.rb +163 -0
  38. data/lib/aidp/planning/parsers/document_parser.rb +141 -0
  39. data/lib/aidp/planning/parsers/feedback_data_parser.rb +252 -0
  40. data/lib/aidp/provider_manager.rb +8 -32
  41. data/lib/aidp/providers/aider.rb +264 -0
  42. data/lib/aidp/providers/anthropic.rb +74 -2
  43. data/lib/aidp/providers/base.rb +25 -1
  44. data/lib/aidp/providers/codex.rb +26 -3
  45. data/lib/aidp/providers/cursor.rb +16 -0
  46. data/lib/aidp/providers/gemini.rb +13 -0
  47. data/lib/aidp/providers/github_copilot.rb +17 -0
  48. data/lib/aidp/providers/kilocode.rb +11 -0
  49. data/lib/aidp/providers/opencode.rb +11 -0
  50. data/lib/aidp/setup/wizard.rb +249 -39
  51. data/lib/aidp/version.rb +1 -1
  52. data/lib/aidp/watch/build_processor.rb +211 -30
  53. data/lib/aidp/watch/change_request_processor.rb +128 -14
  54. data/lib/aidp/watch/ci_fix_processor.rb +103 -37
  55. data/lib/aidp/watch/ci_log_extractor.rb +258 -0
  56. data/lib/aidp/watch/github_state_extractor.rb +177 -0
  57. data/lib/aidp/watch/implementation_verifier.rb +284 -0
  58. data/lib/aidp/watch/plan_generator.rb +7 -43
  59. data/lib/aidp/watch/plan_processor.rb +7 -6
  60. data/lib/aidp/watch/repository_client.rb +245 -17
  61. data/lib/aidp/watch/review_processor.rb +98 -17
  62. data/lib/aidp/watch/reviewers/base_reviewer.rb +1 -1
  63. data/lib/aidp/watch/runner.rb +181 -29
  64. data/lib/aidp/watch/state_store.rb +22 -1
  65. data/lib/aidp/workflows/definitions.rb +147 -0
  66. data/lib/aidp/workstream_cleanup.rb +245 -0
  67. data/lib/aidp/worktree.rb +19 -0
  68. data/templates/aidp.yml.example +57 -0
  69. data/templates/implementation/generate_tdd_specs.md +213 -0
  70. data/templates/implementation/iterative_implementation.md +122 -0
  71. data/templates/planning/agile/analyze_feedback.md +183 -0
  72. data/templates/planning/agile/generate_iteration_plan.md +179 -0
  73. data/templates/planning/agile/generate_legacy_research_plan.md +171 -0
  74. data/templates/planning/agile/generate_marketing_report.md +162 -0
  75. data/templates/planning/agile/generate_mvp_scope.md +127 -0
  76. data/templates/planning/agile/generate_user_test_plan.md +143 -0
  77. data/templates/planning/agile/ingest_feedback.md +174 -0
  78. data/templates/planning/assemble_project_plan.md +113 -0
  79. data/templates/planning/assign_personas.md +108 -0
  80. data/templates/planning/create_tasks.md +52 -6
  81. data/templates/planning/generate_gantt.md +86 -0
  82. data/templates/planning/generate_wbs.md +85 -0
  83. data/templates/planning/initialize_planning_mode.md +70 -0
  84. data/templates/skills/README.md +2 -2
  85. data/templates/skills/marketing_strategist/SKILL.md +279 -0
  86. data/templates/skills/product_manager/SKILL.md +177 -0
  87. data/templates/skills/ruby_aidp_planning/SKILL.md +497 -0
  88. data/templates/skills/ruby_rspec_tdd/SKILL.md +514 -0
  89. data/templates/skills/ux_researcher/SKILL.md +222 -0
  90. metadata +39 -1
@@ -0,0 +1,473 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "../../logger"
4
+ require "find"
5
+
6
+ module Aidp
7
+ module Planning
8
+ module Generators
9
+ # Generates user research plan for existing/legacy codebases
10
+ # Analyzes code structure to identify features and suggest research priorities
11
+ # Uses Zero Framework Cognition (ZFC) for research question generation
12
+ class LegacyResearchPlanner
13
+ def initialize(ai_decision_engine:, prompt: nil, config: nil)
14
+ @ai_decision_engine = ai_decision_engine
15
+ @prompt = prompt || TTY::Prompt.new
16
+ @config = config || Aidp::Config.agile_config
17
+ end
18
+
19
+ # Generate legacy research plan from codebase analysis
20
+ # @param codebase_path [String] Path to codebase directory
21
+ # @param language [String] Primary language/framework (optional)
22
+ # @param known_users [String] Known user segments (optional)
23
+ # @return [Hash] Research plan structure
24
+ def generate(codebase_path:, language: nil, known_users: nil)
25
+ Aidp.log_debug("legacy_research_planner", "generate",
26
+ codebase_path: codebase_path,
27
+ language: language)
28
+
29
+ # Analyze codebase structure
30
+ codebase_analysis = analyze_codebase(codebase_path, language)
31
+
32
+ Aidp.log_debug("legacy_research_planner", "codebase_analyzed",
33
+ features: codebase_analysis[:features].size,
34
+ files: codebase_analysis[:file_count])
35
+
36
+ # Use AI to generate research plan
37
+ research_plan = generate_research_plan_with_ai(codebase_analysis, known_users)
38
+
39
+ {
40
+ overview: research_plan[:overview],
41
+ current_features: research_plan[:current_features],
42
+ research_questions: research_plan[:research_questions],
43
+ research_methods: research_plan[:research_methods],
44
+ testing_priorities: research_plan[:testing_priorities],
45
+ user_segments: research_plan[:user_segments],
46
+ improvement_opportunities: research_plan[:improvement_opportunities],
47
+ timeline: research_plan[:timeline],
48
+ codebase_summary: codebase_analysis[:summary],
49
+ metadata: {
50
+ generated_at: Time.now.iso8601,
51
+ codebase_path: codebase_path,
52
+ language: language,
53
+ feature_count: research_plan[:current_features]&.size || 0,
54
+ file_count: codebase_analysis[:file_count],
55
+ research_question_count: research_plan[:research_questions]&.size || 0
56
+ }
57
+ }
58
+ end
59
+
60
+ # Format research plan as markdown
61
+ # @param plan [Hash] Research plan structure
62
+ # @return [String] Markdown formatted research plan
63
+ def format_as_markdown(plan)
64
+ Aidp.log_debug("legacy_research_planner", "format_as_markdown")
65
+
66
+ output = ["# Legacy User Research Plan", ""]
67
+ output << "**Generated:** #{plan[:metadata][:generated_at]}"
68
+ output << "**Codebase:** #{plan[:metadata][:codebase_path]}"
69
+ output << "**Features Identified:** #{plan[:metadata][:feature_count]}"
70
+ output << "**Files Analyzed:** #{plan[:metadata][:file_count]}"
71
+ output << ""
72
+
73
+ output << "## Overview"
74
+ output << ""
75
+ output << plan[:overview]
76
+ output << ""
77
+
78
+ output << "## Codebase Summary"
79
+ output << ""
80
+ output << plan[:codebase_summary]
81
+ output << ""
82
+
83
+ output << "## Current Features"
84
+ output << ""
85
+ output << "Features identified in the codebase:"
86
+ output << ""
87
+ plan[:current_features].each_with_index do |feature, idx|
88
+ output << "### #{idx + 1}. #{feature[:name]}"
89
+ output << ""
90
+ output << "**Description:** #{feature[:description]}"
91
+ output << ""
92
+ output << "**Entry Points:** #{feature[:entry_points]&.join(", ") || "Unknown"}"
93
+ output << ""
94
+ output << "**Status:** #{feature[:status]}"
95
+ output << ""
96
+ end
97
+
98
+ output << "## Research Questions"
99
+ output << ""
100
+ output << "Key questions to answer about user experience:"
101
+ output << ""
102
+ plan[:research_questions].each_with_index do |question, idx|
103
+ output << "#{idx + 1}. #{question[:question]}"
104
+ output << " - **Category:** #{question[:category]}"
105
+ output << " - **Priority:** #{question[:priority]}"
106
+ output << ""
107
+ end
108
+
109
+ output << "## Recommended Research Methods"
110
+ output << ""
111
+ plan[:research_methods].each do |method|
112
+ output << "### #{method[:name]}"
113
+ output << ""
114
+ output << method[:description]
115
+ output << ""
116
+ output << "**When to Use:** #{method[:when_to_use]}"
117
+ output << ""
118
+ output << "**Expected Insights:** #{method[:expected_insights]}"
119
+ output << ""
120
+ end
121
+
122
+ output << "## Testing Priorities"
123
+ output << ""
124
+ output << "Features/flows to focus on first:"
125
+ output << ""
126
+ plan[:testing_priorities].each_with_index do |priority, idx|
127
+ output << "#{idx + 1}. **#{priority[:feature]}** (Priority: #{priority[:priority]})"
128
+ output << " - Rationale: #{priority[:rationale]}"
129
+ output << " - Focus Areas: #{priority[:focus_areas]&.join(", ")}"
130
+ output << ""
131
+ end
132
+
133
+ output << "## User Segments"
134
+ output << ""
135
+ plan[:user_segments].each do |segment|
136
+ output << "### #{segment[:name]}"
137
+ output << ""
138
+ output << segment[:description]
139
+ output << ""
140
+ output << "**Research Focus:** #{segment[:research_focus]}"
141
+ output << ""
142
+ end
143
+
144
+ output << "## Improvement Opportunities"
145
+ output << ""
146
+ output << "Based on codebase analysis:"
147
+ output << ""
148
+ plan[:improvement_opportunities].each_with_index do |opportunity, idx|
149
+ output << "#{idx + 1}. **#{opportunity[:title]}**"
150
+ output << " - Description: #{opportunity[:description]}"
151
+ output << " - Impact: #{opportunity[:impact]}"
152
+ output << " - Effort: #{opportunity[:effort]}"
153
+ output << ""
154
+ end
155
+
156
+ output << "## Research Timeline"
157
+ output << ""
158
+ plan[:timeline].each do |phase|
159
+ output << "- **#{phase[:phase]}:** #{phase[:duration]}"
160
+ end
161
+ output << ""
162
+
163
+ output.join("\n")
164
+ end
165
+
166
+ private
167
+
168
+ # Analyze codebase structure to extract features and patterns
169
+ def analyze_codebase(codebase_path, language)
170
+ Aidp.log_debug("legacy_research_planner", "analyze_codebase", path: codebase_path)
171
+
172
+ unless Dir.exist?(codebase_path)
173
+ raise ArgumentError, "Codebase path does not exist: #{codebase_path}"
174
+ end
175
+
176
+ # Collect basic codebase information
177
+ files = []
178
+ directories = []
179
+ readme_content = nil
180
+
181
+ Find.find(codebase_path) do |path|
182
+ # Skip common ignore patterns
183
+ if File.basename(path).start_with?(".") ||
184
+ path.include?("node_modules") ||
185
+ path.include?("vendor") ||
186
+ path.include?(".git")
187
+ Find.prune
188
+ end
189
+
190
+ if File.directory?(path)
191
+ directories << path
192
+ elsif File.file?(path)
193
+ files << path
194
+ # Try to read README for context
195
+ if File.basename(path).match?(/^README/i)
196
+ readme_content = begin
197
+ File.read(path)
198
+ rescue
199
+ nil
200
+ end
201
+ end
202
+ end
203
+ end
204
+
205
+ # Extract feature hints from directory structure and file names
206
+ features = extract_features_from_structure(files, directories, codebase_path)
207
+
208
+ {
209
+ features: features,
210
+ file_count: files.size,
211
+ directory_count: directories.size,
212
+ readme_content: readme_content,
213
+ language: language || detect_language(files),
214
+ summary: "Analyzed #{files.size} files in #{directories.size} directories. " \
215
+ "Identified #{features.size} potential features based on code structure."
216
+ }
217
+ end
218
+
219
+ # Extract potential features from codebase structure
220
+ def extract_features_from_structure(files, directories, base_path)
221
+ features = []
222
+
223
+ # Look for common patterns in directory names
224
+ directories.each do |dir|
225
+ dir_name = File.basename(dir)
226
+ relative_path = dir.sub("#{base_path}/", "")
227
+
228
+ # Skip common infrastructure directories
229
+ next if %w[lib spec test config bin vendor node_modules].include?(dir_name)
230
+
231
+ # Directories that might represent features
232
+ if relative_path.match?(/features?|components?|modules?|pages?|views?|controllers?|services?/i)
233
+ features << {
234
+ name: dir_name.gsub(/[-_]/, " ").capitalize,
235
+ type: :directory_based,
236
+ path: relative_path,
237
+ description: "Feature identified from directory: #{relative_path}"
238
+ }
239
+ end
240
+ end
241
+
242
+ # Look for controller/route files that indicate features
243
+ files.each do |file|
244
+ file_name = File.basename(file, ".*")
245
+ relative_path = file.sub("#{base_path}/", "")
246
+
247
+ if file.match?(/controller|router|routes|handler/i)
248
+ features << {
249
+ name: file_name.gsub(/[-_](controller|router|routes|handler)/, "").gsub(/[-_]/, " ").capitalize,
250
+ type: :route_based,
251
+ path: relative_path,
252
+ description: "Feature identified from routing/controller file: #{File.basename(file)}"
253
+ }
254
+ end
255
+ end
256
+
257
+ # Deduplicate by name
258
+ features.uniq { |f| f[:name].downcase }.take(20) # Limit to 20 features
259
+ end
260
+
261
+ # Detect primary language from file extensions
262
+ def detect_language(files)
263
+ extensions = files.map { |f| File.extname(f) }.compact
264
+ ext_counts = extensions.each_with_object(Hash.new(0)) { |ext, counts| counts[ext] += 1 }
265
+
266
+ language_map = {
267
+ ".rb" => "Ruby",
268
+ ".js" => "JavaScript",
269
+ ".ts" => "TypeScript",
270
+ ".py" => "Python",
271
+ ".go" => "Go",
272
+ ".java" => "Java",
273
+ ".cs" => "C#",
274
+ ".php" => "PHP",
275
+ ".swift" => "Swift",
276
+ ".kt" => "Kotlin"
277
+ }
278
+
279
+ most_common_ext = ext_counts.max_by { |_, count| count }&.first
280
+ language_map[most_common_ext] || "Unknown"
281
+ end
282
+
283
+ def generate_research_plan_with_ai(codebase_analysis, known_users)
284
+ Aidp.log_debug("legacy_research_planner", "generate_research_plan_with_ai")
285
+
286
+ prompt = build_research_plan_prompt(codebase_analysis, known_users)
287
+
288
+ schema = {
289
+ type: "object",
290
+ properties: {
291
+ overview: {type: "string"},
292
+ current_features: {
293
+ type: "array",
294
+ items: {
295
+ type: "object",
296
+ properties: {
297
+ name: {type: "string"},
298
+ description: {type: "string"},
299
+ entry_points: {type: "array", items: {type: "string"}},
300
+ status: {type: "string"}
301
+ }
302
+ }
303
+ },
304
+ research_questions: {
305
+ type: "array",
306
+ items: {
307
+ type: "object",
308
+ properties: {
309
+ question: {type: "string"},
310
+ category: {type: "string"},
311
+ priority: {type: "string"}
312
+ }
313
+ }
314
+ },
315
+ research_methods: {
316
+ type: "array",
317
+ items: {
318
+ type: "object",
319
+ properties: {
320
+ name: {type: "string"},
321
+ description: {type: "string"},
322
+ when_to_use: {type: "string"},
323
+ expected_insights: {type: "string"}
324
+ }
325
+ }
326
+ },
327
+ testing_priorities: {
328
+ type: "array",
329
+ items: {
330
+ type: "object",
331
+ properties: {
332
+ feature: {type: "string"},
333
+ priority: {type: "string"},
334
+ rationale: {type: "string"},
335
+ focus_areas: {type: "array", items: {type: "string"}}
336
+ }
337
+ }
338
+ },
339
+ user_segments: {
340
+ type: "array",
341
+ items: {
342
+ type: "object",
343
+ properties: {
344
+ name: {type: "string"},
345
+ description: {type: "string"},
346
+ research_focus: {type: "string"}
347
+ }
348
+ }
349
+ },
350
+ improvement_opportunities: {
351
+ type: "array",
352
+ items: {
353
+ type: "object",
354
+ properties: {
355
+ title: {type: "string"},
356
+ description: {type: "string"},
357
+ impact: {type: "string"},
358
+ effort: {type: "string"}
359
+ }
360
+ }
361
+ },
362
+ timeline: {
363
+ type: "array",
364
+ items: {
365
+ type: "object",
366
+ properties: {
367
+ phase: {type: "string"},
368
+ duration: {type: "string"}
369
+ }
370
+ }
371
+ }
372
+ },
373
+ required: ["overview", "current_features", "research_questions", "testing_priorities"]
374
+ }
375
+
376
+ decision = @ai_decision_engine.decide(
377
+ context: "legacy_research_plan_generation",
378
+ prompt: prompt,
379
+ data: {
380
+ codebase_analysis: codebase_analysis,
381
+ known_users: known_users
382
+ },
383
+ schema: schema
384
+ )
385
+
386
+ Aidp.log_debug("legacy_research_planner", "ai_plan_generated",
387
+ features: decision[:current_features]&.size || 0,
388
+ questions: decision[:research_questions]&.size || 0)
389
+
390
+ decision
391
+ end
392
+
393
+ def build_research_plan_prompt(codebase_analysis, known_users)
394
+ features_text = codebase_analysis[:features].map { |f|
395
+ "- #{f[:name]} (#{f[:type]}, #{f[:path]})"
396
+ }.join("\n")
397
+
398
+ readme_context = if codebase_analysis[:readme_content]
399
+ <<~README
400
+ README CONTENT (for context):
401
+ #{codebase_analysis[:readme_content][0..2000]}
402
+ README
403
+ else
404
+ ""
405
+ end
406
+
407
+ <<~PROMPT
408
+ Generate a comprehensive user research plan for an existing/legacy codebase.
409
+
410
+ CODEBASE ANALYSIS:
411
+ Language: #{codebase_analysis[:language]}
412
+ Files: #{codebase_analysis[:file_count]}
413
+ Directories: #{codebase_analysis[:directory_count]}
414
+
415
+ POTENTIAL FEATURES IDENTIFIED:
416
+ #{features_text}
417
+
418
+ #{readme_context}
419
+
420
+ KNOWN USER SEGMENTS:
421
+ #{known_users || "Not specified - suggest based on codebase"}
422
+
423
+ TASK:
424
+ Create a user research plan to understand how users experience this existing product:
425
+
426
+ 1. OVERVIEW
427
+ - Why user research is needed for this product
428
+ - What we hope to learn
429
+
430
+ 2. CURRENT FEATURES
431
+ - For each feature identified, provide:
432
+ - Clear name and description
433
+ - Likely entry points (how users access it)
434
+ - Status (active, deprecated, experimental)
435
+
436
+ 3. RESEARCH QUESTIONS (8-12 questions)
437
+ - Questions about user experience with current features
438
+ - Category (usability, value, workflow, pain_points, missing_features)
439
+ - Priority (high/medium/low)
440
+
441
+ 4. RECOMMENDED RESEARCH METHODS (3-4 methods)
442
+ - Method name (e.g., User Interviews, Surveys, Analytics Analysis)
443
+ - Description of the method
444
+ - When to use it
445
+ - Expected insights
446
+
447
+ 5. TESTING PRIORITIES
448
+ - Which features/flows to focus on first
449
+ - Priority level (critical/high/medium)
450
+ - Rationale for prioritization
451
+ - Focus areas for each
452
+
453
+ 6. USER SEGMENTS (2-3 segments)
454
+ - Different types of users to study
455
+ - Description of each segment
456
+ - Research focus for that segment
457
+
458
+ 7. IMPROVEMENT OPPORTUNITIES
459
+ - Based on code structure, what might need improvement
460
+ - Impact (high/medium/low)
461
+ - Effort estimate (low/medium/high)
462
+
463
+ 8. TIMELINE
464
+ - Research phases with duration estimates
465
+ - Codebase analysis, recruitment, data collection, analysis, reporting
466
+
467
+ Focus on understanding existing user experience and identifying improvement opportunities.
468
+ PROMPT
469
+ end
470
+ end
471
+ end
472
+ end
473
+ end