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.
- checksums.yaml +4 -4
- data/README.md +89 -0
- data/lib/aidp/cli/models_command.rb +5 -6
- data/lib/aidp/cli.rb +10 -8
- data/lib/aidp/config.rb +54 -0
- data/lib/aidp/debug_mixin.rb +23 -1
- data/lib/aidp/execute/agent_signal_parser.rb +22 -0
- data/lib/aidp/execute/repl_macros.rb +2 -2
- data/lib/aidp/execute/steps.rb +94 -1
- data/lib/aidp/execute/work_loop_runner.rb +209 -17
- data/lib/aidp/execute/workflow_selector.rb +2 -25
- data/lib/aidp/firewall/provider_requirements_collector.rb +262 -0
- data/lib/aidp/harness/ai_decision_engine.rb +35 -2
- data/lib/aidp/harness/config_manager.rb +0 -5
- data/lib/aidp/harness/config_schema.rb +8 -0
- data/lib/aidp/harness/configuration.rb +27 -19
- data/lib/aidp/harness/enhanced_runner.rb +1 -4
- data/lib/aidp/harness/error_handler.rb +1 -72
- data/lib/aidp/harness/provider_factory.rb +11 -2
- data/lib/aidp/harness/state_manager.rb +0 -7
- data/lib/aidp/harness/thinking_depth_manager.rb +47 -68
- data/lib/aidp/harness/ui/enhanced_tui.rb +8 -18
- data/lib/aidp/harness/ui/enhanced_workflow_selector.rb +0 -18
- data/lib/aidp/harness/ui/progress_display.rb +6 -2
- data/lib/aidp/harness/user_interface.rb +0 -58
- data/lib/aidp/init/runner.rb +7 -2
- data/lib/aidp/planning/analyzers/feedback_analyzer.rb +365 -0
- data/lib/aidp/planning/builders/agile_plan_builder.rb +387 -0
- data/lib/aidp/planning/builders/project_plan_builder.rb +193 -0
- data/lib/aidp/planning/generators/gantt_generator.rb +190 -0
- data/lib/aidp/planning/generators/iteration_plan_generator.rb +392 -0
- data/lib/aidp/planning/generators/legacy_research_planner.rb +473 -0
- data/lib/aidp/planning/generators/marketing_report_generator.rb +348 -0
- data/lib/aidp/planning/generators/mvp_scope_generator.rb +310 -0
- data/lib/aidp/planning/generators/user_test_plan_generator.rb +373 -0
- data/lib/aidp/planning/generators/wbs_generator.rb +259 -0
- data/lib/aidp/planning/mappers/persona_mapper.rb +163 -0
- data/lib/aidp/planning/parsers/document_parser.rb +141 -0
- data/lib/aidp/planning/parsers/feedback_data_parser.rb +252 -0
- data/lib/aidp/provider_manager.rb +8 -32
- data/lib/aidp/providers/aider.rb +264 -0
- data/lib/aidp/providers/anthropic.rb +74 -2
- data/lib/aidp/providers/base.rb +25 -1
- data/lib/aidp/providers/codex.rb +26 -3
- data/lib/aidp/providers/cursor.rb +16 -0
- data/lib/aidp/providers/gemini.rb +13 -0
- data/lib/aidp/providers/github_copilot.rb +17 -0
- data/lib/aidp/providers/kilocode.rb +11 -0
- data/lib/aidp/providers/opencode.rb +11 -0
- data/lib/aidp/setup/wizard.rb +249 -39
- data/lib/aidp/version.rb +1 -1
- data/lib/aidp/watch/build_processor.rb +211 -30
- data/lib/aidp/watch/change_request_processor.rb +128 -14
- data/lib/aidp/watch/ci_fix_processor.rb +103 -37
- data/lib/aidp/watch/ci_log_extractor.rb +258 -0
- data/lib/aidp/watch/github_state_extractor.rb +177 -0
- data/lib/aidp/watch/implementation_verifier.rb +284 -0
- data/lib/aidp/watch/plan_generator.rb +7 -43
- data/lib/aidp/watch/plan_processor.rb +7 -6
- data/lib/aidp/watch/repository_client.rb +245 -17
- data/lib/aidp/watch/review_processor.rb +98 -17
- data/lib/aidp/watch/reviewers/base_reviewer.rb +1 -1
- data/lib/aidp/watch/runner.rb +181 -29
- data/lib/aidp/watch/state_store.rb +22 -1
- data/lib/aidp/workflows/definitions.rb +147 -0
- data/lib/aidp/workstream_cleanup.rb +245 -0
- data/lib/aidp/worktree.rb +19 -0
- data/templates/aidp.yml.example +57 -0
- data/templates/implementation/generate_tdd_specs.md +213 -0
- data/templates/implementation/iterative_implementation.md +122 -0
- data/templates/planning/agile/analyze_feedback.md +183 -0
- data/templates/planning/agile/generate_iteration_plan.md +179 -0
- data/templates/planning/agile/generate_legacy_research_plan.md +171 -0
- data/templates/planning/agile/generate_marketing_report.md +162 -0
- data/templates/planning/agile/generate_mvp_scope.md +127 -0
- data/templates/planning/agile/generate_user_test_plan.md +143 -0
- data/templates/planning/agile/ingest_feedback.md +174 -0
- data/templates/planning/assemble_project_plan.md +113 -0
- data/templates/planning/assign_personas.md +108 -0
- data/templates/planning/create_tasks.md +52 -6
- data/templates/planning/generate_gantt.md +86 -0
- data/templates/planning/generate_wbs.md +85 -0
- data/templates/planning/initialize_planning_mode.md +70 -0
- data/templates/skills/README.md +2 -2
- data/templates/skills/marketing_strategist/SKILL.md +279 -0
- data/templates/skills/product_manager/SKILL.md +177 -0
- data/templates/skills/ruby_aidp_planning/SKILL.md +497 -0
- data/templates/skills/ruby_rspec_tdd/SKILL.md +514 -0
- data/templates/skills/ux_researcher/SKILL.md +222 -0
- metadata +39 -1
|
@@ -0,0 +1,365 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "../../logger"
|
|
4
|
+
|
|
5
|
+
module Aidp
|
|
6
|
+
module Planning
|
|
7
|
+
module Analyzers
|
|
8
|
+
# Analyzes user feedback using AI to extract insights and recommendations
|
|
9
|
+
# Uses Zero Framework Cognition (ZFC) - NO regex, heuristics, or keyword matching
|
|
10
|
+
# All semantic analysis delegated to AI Decision Engine
|
|
11
|
+
class FeedbackAnalyzer
|
|
12
|
+
def initialize(ai_decision_engine:, config: nil)
|
|
13
|
+
@ai_decision_engine = ai_decision_engine
|
|
14
|
+
@config = config || Aidp::Config.agile_config
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
# Analyze feedback data and generate insights
|
|
18
|
+
# @param feedback_data [Hash] Parsed feedback data from FeedbackDataParser
|
|
19
|
+
# @return [Hash] Analysis results with findings and recommendations
|
|
20
|
+
def analyze(feedback_data)
|
|
21
|
+
Aidp.log_debug("feedback_analyzer", "analyze",
|
|
22
|
+
response_count: feedback_data[:response_count],
|
|
23
|
+
format: feedback_data[:format])
|
|
24
|
+
|
|
25
|
+
# Use AI to perform semantic analysis
|
|
26
|
+
analysis = analyze_with_ai(feedback_data)
|
|
27
|
+
|
|
28
|
+
{
|
|
29
|
+
summary: analysis[:summary],
|
|
30
|
+
findings: analysis[:findings],
|
|
31
|
+
trends: analysis[:trends],
|
|
32
|
+
insights: analysis[:insights],
|
|
33
|
+
sentiment_breakdown: analysis[:sentiment_breakdown],
|
|
34
|
+
feature_feedback: analysis[:feature_feedback],
|
|
35
|
+
recommendations: analysis[:recommendations],
|
|
36
|
+
priority_issues: analysis[:priority_issues],
|
|
37
|
+
positive_highlights: analysis[:positive_highlights],
|
|
38
|
+
metadata: {
|
|
39
|
+
generated_at: Time.now.iso8601,
|
|
40
|
+
responses_analyzed: feedback_data[:response_count],
|
|
41
|
+
source_file: feedback_data[:source_file],
|
|
42
|
+
source_format: feedback_data[:format]
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
# Format feedback analysis as markdown
|
|
48
|
+
# @param analysis [Hash] Feedback analysis structure
|
|
49
|
+
# @return [String] Markdown formatted analysis
|
|
50
|
+
def format_as_markdown(analysis)
|
|
51
|
+
Aidp.log_debug("feedback_analyzer", "format_as_markdown")
|
|
52
|
+
|
|
53
|
+
output = ["# User Feedback Analysis", ""]
|
|
54
|
+
output << "**Generated:** #{analysis[:metadata][:generated_at]}"
|
|
55
|
+
output << "**Responses Analyzed:** #{analysis[:metadata][:responses_analyzed]}"
|
|
56
|
+
output << "**Source:** #{analysis[:metadata][:source_file]}"
|
|
57
|
+
output << ""
|
|
58
|
+
|
|
59
|
+
output << "## Executive Summary"
|
|
60
|
+
output << ""
|
|
61
|
+
output << analysis[:summary]
|
|
62
|
+
output << ""
|
|
63
|
+
|
|
64
|
+
output << "## Sentiment Breakdown"
|
|
65
|
+
output << ""
|
|
66
|
+
output << "| Sentiment | Count | Percentage |"
|
|
67
|
+
output << "|-----------|-------|------------|"
|
|
68
|
+
analysis[:sentiment_breakdown].each do |sentiment|
|
|
69
|
+
output << "| #{sentiment[:type]} | #{sentiment[:count]} | #{sentiment[:percentage]}% |"
|
|
70
|
+
end
|
|
71
|
+
output << ""
|
|
72
|
+
|
|
73
|
+
output << "## Key Findings"
|
|
74
|
+
output << ""
|
|
75
|
+
analysis[:findings].each_with_index do |finding, idx|
|
|
76
|
+
output << "### #{idx + 1}. #{finding[:title]}"
|
|
77
|
+
output << ""
|
|
78
|
+
output << finding[:description]
|
|
79
|
+
output << ""
|
|
80
|
+
output << "**Evidence:**"
|
|
81
|
+
finding[:evidence].each do |evidence|
|
|
82
|
+
output << "- #{evidence}"
|
|
83
|
+
end
|
|
84
|
+
output << ""
|
|
85
|
+
output << "**Impact:** #{finding[:impact]}"
|
|
86
|
+
output << ""
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
output << "## Trends and Patterns"
|
|
90
|
+
output << ""
|
|
91
|
+
analysis[:trends].each_with_index do |trend, idx|
|
|
92
|
+
output << "### #{idx + 1}. #{trend[:title]}"
|
|
93
|
+
output << ""
|
|
94
|
+
output << trend[:description]
|
|
95
|
+
output << ""
|
|
96
|
+
output << "**Frequency:** #{trend[:frequency]}"
|
|
97
|
+
output << ""
|
|
98
|
+
output << "**Implication:** #{trend[:implication]}"
|
|
99
|
+
output << ""
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
output << "## Insights"
|
|
103
|
+
output << ""
|
|
104
|
+
analysis[:insights].each do |insight|
|
|
105
|
+
output << "- **#{insight[:category]}:** #{insight[:description]}"
|
|
106
|
+
output << ""
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
output << "## Feature-Specific Feedback"
|
|
110
|
+
output << ""
|
|
111
|
+
analysis[:feature_feedback].each do |feedback|
|
|
112
|
+
output << "### #{feedback[:feature_name]}"
|
|
113
|
+
output << ""
|
|
114
|
+
output << "**Overall Sentiment:** #{feedback[:sentiment]}"
|
|
115
|
+
output << ""
|
|
116
|
+
output << "**Positive Feedback:**"
|
|
117
|
+
feedback[:positive].each do |pos|
|
|
118
|
+
output << "- #{pos}"
|
|
119
|
+
end
|
|
120
|
+
output << ""
|
|
121
|
+
output << "**Negative Feedback:**"
|
|
122
|
+
feedback[:negative].each do |neg|
|
|
123
|
+
output << "- #{neg}"
|
|
124
|
+
end
|
|
125
|
+
output << ""
|
|
126
|
+
output << "**Suggested Improvements:**"
|
|
127
|
+
feedback[:improvements].each do |imp|
|
|
128
|
+
output << "- #{imp}"
|
|
129
|
+
end
|
|
130
|
+
output << ""
|
|
131
|
+
end
|
|
132
|
+
|
|
133
|
+
output << "## Priority Issues"
|
|
134
|
+
output << ""
|
|
135
|
+
output << "Issues requiring immediate attention:"
|
|
136
|
+
output << ""
|
|
137
|
+
analysis[:priority_issues].each_with_index do |issue, idx|
|
|
138
|
+
output << "#{idx + 1}. **#{issue[:title]}** (Priority: #{issue[:priority]})"
|
|
139
|
+
output << " - Impact: #{issue[:impact]}"
|
|
140
|
+
output << " - Affected Users: #{issue[:affected_users]}"
|
|
141
|
+
output << " - Recommended Action: #{issue[:action]}"
|
|
142
|
+
output << ""
|
|
143
|
+
end
|
|
144
|
+
|
|
145
|
+
output << "## Positive Highlights"
|
|
146
|
+
output << ""
|
|
147
|
+
output << "What users loved:"
|
|
148
|
+
output << ""
|
|
149
|
+
analysis[:positive_highlights].each do |highlight|
|
|
150
|
+
output << "- #{highlight}"
|
|
151
|
+
end
|
|
152
|
+
output << ""
|
|
153
|
+
|
|
154
|
+
output << "## Recommendations"
|
|
155
|
+
output << ""
|
|
156
|
+
analysis[:recommendations].each_with_index do |rec, idx|
|
|
157
|
+
output << "### #{idx + 1}. #{rec[:title]}"
|
|
158
|
+
output << ""
|
|
159
|
+
output << rec[:description]
|
|
160
|
+
output << ""
|
|
161
|
+
output << "**Rationale:** #{rec[:rationale]}"
|
|
162
|
+
output << ""
|
|
163
|
+
output << "**Effort:** #{rec[:effort]}"
|
|
164
|
+
output << ""
|
|
165
|
+
output << "**Expected Impact:** #{rec[:impact]}"
|
|
166
|
+
output << ""
|
|
167
|
+
end
|
|
168
|
+
|
|
169
|
+
output.join("\n")
|
|
170
|
+
end
|
|
171
|
+
|
|
172
|
+
private
|
|
173
|
+
|
|
174
|
+
def analyze_with_ai(feedback_data)
|
|
175
|
+
Aidp.log_debug("feedback_analyzer", "analyze_with_ai")
|
|
176
|
+
|
|
177
|
+
prompt = build_analysis_prompt(feedback_data)
|
|
178
|
+
|
|
179
|
+
schema = {
|
|
180
|
+
type: "object",
|
|
181
|
+
properties: {
|
|
182
|
+
summary: {type: "string"},
|
|
183
|
+
findings: {
|
|
184
|
+
type: "array",
|
|
185
|
+
items: {
|
|
186
|
+
type: "object",
|
|
187
|
+
properties: {
|
|
188
|
+
title: {type: "string"},
|
|
189
|
+
description: {type: "string"},
|
|
190
|
+
evidence: {type: "array", items: {type: "string"}},
|
|
191
|
+
impact: {type: "string"}
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
},
|
|
195
|
+
trends: {
|
|
196
|
+
type: "array",
|
|
197
|
+
items: {
|
|
198
|
+
type: "object",
|
|
199
|
+
properties: {
|
|
200
|
+
title: {type: "string"},
|
|
201
|
+
description: {type: "string"},
|
|
202
|
+
frequency: {type: "string"},
|
|
203
|
+
implication: {type: "string"}
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
},
|
|
207
|
+
insights: {
|
|
208
|
+
type: "array",
|
|
209
|
+
items: {
|
|
210
|
+
type: "object",
|
|
211
|
+
properties: {
|
|
212
|
+
category: {type: "string"},
|
|
213
|
+
description: {type: "string"}
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
},
|
|
217
|
+
sentiment_breakdown: {
|
|
218
|
+
type: "array",
|
|
219
|
+
items: {
|
|
220
|
+
type: "object",
|
|
221
|
+
properties: {
|
|
222
|
+
type: {type: "string"},
|
|
223
|
+
count: {type: "integer"},
|
|
224
|
+
percentage: {type: "number"}
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
},
|
|
228
|
+
feature_feedback: {
|
|
229
|
+
type: "array",
|
|
230
|
+
items: {
|
|
231
|
+
type: "object",
|
|
232
|
+
properties: {
|
|
233
|
+
feature_name: {type: "string"},
|
|
234
|
+
sentiment: {type: "string"},
|
|
235
|
+
positive: {type: "array", items: {type: "string"}},
|
|
236
|
+
negative: {type: "array", items: {type: "string"}},
|
|
237
|
+
improvements: {type: "array", items: {type: "string"}}
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
},
|
|
241
|
+
recommendations: {
|
|
242
|
+
type: "array",
|
|
243
|
+
items: {
|
|
244
|
+
type: "object",
|
|
245
|
+
properties: {
|
|
246
|
+
title: {type: "string"},
|
|
247
|
+
description: {type: "string"},
|
|
248
|
+
rationale: {type: "string"},
|
|
249
|
+
effort: {type: "string"},
|
|
250
|
+
impact: {type: "string"}
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
},
|
|
254
|
+
priority_issues: {
|
|
255
|
+
type: "array",
|
|
256
|
+
items: {
|
|
257
|
+
type: "object",
|
|
258
|
+
properties: {
|
|
259
|
+
title: {type: "string"},
|
|
260
|
+
priority: {type: "string"},
|
|
261
|
+
impact: {type: "string"},
|
|
262
|
+
affected_users: {type: "string"},
|
|
263
|
+
action: {type: "string"}
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
},
|
|
267
|
+
positive_highlights: {
|
|
268
|
+
type: "array",
|
|
269
|
+
items: {type: "string"}
|
|
270
|
+
}
|
|
271
|
+
},
|
|
272
|
+
required: ["summary", "findings", "recommendations"]
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
decision = @ai_decision_engine.decide(
|
|
276
|
+
context: "feedback_analysis",
|
|
277
|
+
prompt: prompt,
|
|
278
|
+
data: feedback_data,
|
|
279
|
+
schema: schema
|
|
280
|
+
)
|
|
281
|
+
|
|
282
|
+
Aidp.log_debug("feedback_analyzer", "ai_analysis_complete",
|
|
283
|
+
findings: decision[:findings]&.size || 0,
|
|
284
|
+
recommendations: decision[:recommendations]&.size || 0)
|
|
285
|
+
|
|
286
|
+
decision
|
|
287
|
+
end
|
|
288
|
+
|
|
289
|
+
def build_analysis_prompt(feedback_data)
|
|
290
|
+
# Format response data for AI analysis
|
|
291
|
+
responses_text = feedback_data[:responses]&.map&.with_index { |r, i|
|
|
292
|
+
<<~RESPONSE
|
|
293
|
+
Response #{i + 1}:
|
|
294
|
+
- ID: #{r[:respondent_id]}
|
|
295
|
+
- Timestamp: #{r[:timestamp]}
|
|
296
|
+
- Rating: #{r[:rating]}
|
|
297
|
+
- Feature: #{r[:feature]}
|
|
298
|
+
- Feedback: #{r[:feedback_text]}
|
|
299
|
+
- Sentiment: #{r[:sentiment]}
|
|
300
|
+
- Tags: #{r[:tags]&.join(", ")}
|
|
301
|
+
RESPONSE
|
|
302
|
+
}&.join("\n") || "No responses"
|
|
303
|
+
|
|
304
|
+
<<~PROMPT
|
|
305
|
+
Analyze the following user feedback data and extract insights, trends, and recommendations.
|
|
306
|
+
|
|
307
|
+
FEEDBACK DATA:
|
|
308
|
+
Total Responses: #{feedback_data[:response_count]}
|
|
309
|
+
Source: #{feedback_data[:source_file]}
|
|
310
|
+
Format: #{feedback_data[:format]}
|
|
311
|
+
|
|
312
|
+
RESPONSES:
|
|
313
|
+
#{responses_text}
|
|
314
|
+
|
|
315
|
+
TASK:
|
|
316
|
+
Perform comprehensive feedback analysis:
|
|
317
|
+
|
|
318
|
+
1. SUMMARY
|
|
319
|
+
- High-level overview of feedback (2-3 paragraphs)
|
|
320
|
+
- Overall sentiment and key themes
|
|
321
|
+
|
|
322
|
+
2. KEY FINDINGS (3-5 findings)
|
|
323
|
+
- Important discoveries from the data
|
|
324
|
+
- Evidence supporting each finding
|
|
325
|
+
- Impact assessment (high/medium/low)
|
|
326
|
+
|
|
327
|
+
3. TRENDS AND PATTERNS
|
|
328
|
+
- Recurring themes
|
|
329
|
+
- Frequency of occurrence
|
|
330
|
+
- Implications for product development
|
|
331
|
+
|
|
332
|
+
4. INSIGHTS
|
|
333
|
+
- Categorized insights (usability, features, performance, etc.)
|
|
334
|
+
- Actionable observations
|
|
335
|
+
|
|
336
|
+
5. SENTIMENT BREAKDOWN
|
|
337
|
+
- Distribution of positive, negative, neutral sentiment
|
|
338
|
+
- Counts and percentages
|
|
339
|
+
|
|
340
|
+
6. FEATURE-SPECIFIC FEEDBACK
|
|
341
|
+
- For each mentioned feature: sentiment, positive/negative feedback, improvements
|
|
342
|
+
|
|
343
|
+
7. PRIORITY ISSUES
|
|
344
|
+
- Critical issues requiring immediate attention
|
|
345
|
+
- Priority level (critical/high/medium)
|
|
346
|
+
- Affected user count
|
|
347
|
+
- Recommended action
|
|
348
|
+
|
|
349
|
+
8. POSITIVE HIGHLIGHTS
|
|
350
|
+
- What users loved
|
|
351
|
+
- Strengths to maintain or amplify
|
|
352
|
+
|
|
353
|
+
9. RECOMMENDATIONS (4-6 recommendations)
|
|
354
|
+
- Specific, actionable recommendations
|
|
355
|
+
- Rationale based on feedback
|
|
356
|
+
- Effort estimate (low/medium/high)
|
|
357
|
+
- Expected impact
|
|
358
|
+
|
|
359
|
+
Use semantic analysis to understand context and meaning. Look beyond keywords to understand user intent and emotion.
|
|
360
|
+
PROMPT
|
|
361
|
+
end
|
|
362
|
+
end
|
|
363
|
+
end
|
|
364
|
+
end
|
|
365
|
+
end
|