Class: Aidp::Watch::PlanProcessor
- Inherits:
-
Object
- Object
- Aidp::Watch::PlanProcessor
- Includes:
- MessageDisplay
- Defined in:
- lib/aidp/watch/plan_processor.rb
Overview
Handles the aidp-plan label trigger by generating an implementation plan and posting it back to the originating GitHub issue.
Constant Summary collapse
- TrackedSubIssuesRetirementError =
Class.new(StandardError)
- DEFAULT_PLAN_LABEL =
Default label names
"aidp-plan"- DEFAULT_PROJECT_LABEL =
"aidp-project"- DEFAULT_NEEDS_INPUT_LABEL =
"aidp-needs-input"- DEFAULT_READY_LABEL =
"aidp-ready"- DEFAULT_BUILD_LABEL =
"aidp-build"- DEFAULT_BLOCKED_LABEL =
"aidp-blocked"- COMMENT_HEADER =
"## 🤖 AIDP Plan Proposal"
Constants included from MessageDisplay
MessageDisplay::COLOR_MAP, MessageDisplay::CRITICAL_TYPES
Instance Attribute Summary collapse
-
#blocked_label ⇒ Object
readonly
Returns the value of attribute blocked_label.
-
#build_label ⇒ Object
readonly
Returns the value of attribute build_label.
-
#needs_input_label ⇒ Object
readonly
Returns the value of attribute needs_input_label.
-
#plan_label ⇒ Object
readonly
Returns the value of attribute plan_label.
-
#project_label ⇒ Object
readonly
Returns the value of attribute project_label.
-
#ready_label ⇒ Object
readonly
Returns the value of attribute ready_label.
Instance Method Summary collapse
-
#initialize(repository_client:, state_store:, plan_generator:, label_config: {}, project_config: {}) ⇒ PlanProcessor
constructor
A new instance of PlanProcessor.
- #process(issue, trigger_label: @plan_label) ⇒ Object
Methods included from MessageDisplay
#display_message, included, #message_display_prompt, #quiet_mode?
Constructor Details
#initialize(repository_client:, state_store:, plan_generator:, label_config: {}, project_config: {}) ⇒ PlanProcessor
Returns a new instance of PlanProcessor.
31 32 33 34 35 36 37 38 39 40 41 42 43 44 |
# File 'lib/aidp/watch/plan_processor.rb', line 31 def initialize(repository_client:, state_store:, plan_generator:, label_config: {}, project_config: {}) @repository_client = repository_client @state_store = state_store @plan_generator = plan_generator @project_config = project_config # Load label configuration with defaults @plan_label = label_config[:plan_trigger] || label_config["plan_trigger"] || DEFAULT_PLAN_LABEL @project_label = label_config[:project_trigger] || label_config["project_trigger"] || DEFAULT_PROJECT_LABEL @needs_input_label = label_config[:needs_input] || label_config["needs_input"] || DEFAULT_NEEDS_INPUT_LABEL @ready_label = label_config[:ready_to_build] || label_config["ready_to_build"] || DEFAULT_READY_LABEL @build_label = label_config[:build_trigger] || label_config["build_trigger"] || DEFAULT_BUILD_LABEL @blocked_label = label_config[:blocked_trigger] || label_config["blocked_trigger"] || DEFAULT_BLOCKED_LABEL end |
Instance Attribute Details
#blocked_label ⇒ Object (readonly)
Returns the value of attribute blocked_label.
29 30 31 |
# File 'lib/aidp/watch/plan_processor.rb', line 29 def blocked_label @blocked_label end |
#build_label ⇒ Object (readonly)
Returns the value of attribute build_label.
29 30 31 |
# File 'lib/aidp/watch/plan_processor.rb', line 29 def build_label @build_label end |
#needs_input_label ⇒ Object (readonly)
Returns the value of attribute needs_input_label.
29 30 31 |
# File 'lib/aidp/watch/plan_processor.rb', line 29 def needs_input_label @needs_input_label end |
#plan_label ⇒ Object (readonly)
Returns the value of attribute plan_label.
29 30 31 |
# File 'lib/aidp/watch/plan_processor.rb', line 29 def plan_label @plan_label end |
#project_label ⇒ Object (readonly)
Returns the value of attribute project_label.
29 30 31 |
# File 'lib/aidp/watch/plan_processor.rb', line 29 def project_label @project_label end |
#ready_label ⇒ Object (readonly)
Returns the value of attribute ready_label.
29 30 31 |
# File 'lib/aidp/watch/plan_processor.rb', line 29 def ready_label @ready_label end |
Instance Method Details
#process(issue, trigger_label: @plan_label) ⇒ Object
46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 |
# File 'lib/aidp/watch/plan_processor.rb', line 46 def process(issue, trigger_label: @plan_label) number = issue[:number] existing_plan = @state_store.plan_data(number) project_mode = trigger_label.to_s.casecmp(@project_label).zero? if existing_plan ("🔄 Re-planning for issue ##{number} (iteration #{@state_store.plan_iteration_count(number) + 1})", type: :info) else prefix = project_mode ? "🗂️ Generating project plan" : "🧠 Generating plan" ("#{prefix} for issue ##{number} (#{issue[:title]})", type: :info) end plan_data = @plan_generator.generate(issue, hierarchical: project_mode) # If plan generation failed (all providers unavailable), silently skip unless plan_data Aidp.log_warn("plan_processor", "plan_generation_failed", issue: number, reason: "no plan data returned") ("⚠️ Unable to generate plan for issue ##{number} - all providers failed", type: :warn) return end # Fetch the user who added the most recent label label_actor = @repository_client.most_recent_label_actor(number) # If updating existing plan, archive the previous content archived_content = existing_plan ? archive_previous_plan(number, existing_plan) : nil comment_body = build_comment( issue: issue, plan: plan_data, project_mode: project_mode, label_actor: label_actor, archived_content: archived_content ) comment_body_with_feedback = FeedbackCollector.append_feedback_prompt(comment_body) comment_id = nil if existing_plan && existing_plan["comment_id"] # Update existing comment @repository_client.update_comment(existing_plan["comment_id"], comment_body_with_feedback) comment_id = existing_plan["comment_id"] ("📝 Updated plan comment for issue ##{number}", type: :success) elsif existing_plan # Try to find existing comment by header existing_comment = @repository_client.find_comment(number, COMMENT_HEADER) if existing_comment @repository_client.update_comment(existing_comment[:id], comment_body_with_feedback) comment_id = existing_comment[:id] ("📝 Updated plan comment for issue ##{number}", type: :success) else # Fallback to posting new comment if we can't find the old one result = @repository_client.post_comment(number, comment_body_with_feedback) comment_id = result[:id] if result.is_a?(Hash) ("💬 Posted new plan comment for issue ##{number}", type: :success) end else # First time planning - post new comment result = @repository_client.post_comment(number, comment_body_with_feedback) comment_id = result[:id] if result.is_a?(Hash) ("💬 Posted plan comment for issue ##{number}", type: :success) end plan_data = plan_data.merge(comment_id: comment_id) if comment_id @state_store.record_plan(number, plan_data.merge(comment_body: comment_body, comment_hint: COMMENT_HEADER)) project_setup = project_mode ? process_project_plan(issue, plan_data) : {status: :not_applicable} # Update labels: remove plan trigger, add appropriate status label update_labels_after_plan( number, plan_data, trigger_label: trigger_label, project_mode: project_mode, project_setup: project_setup ) end |