Class: Aidp::Watch::PlanProcessor

Inherits:
Object
  • Object
show all
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

DEFAULT_PLAN_LABEL =

Default label names

"aidp-plan"
DEFAULT_NEEDS_INPUT_LABEL =
"aidp-needs-input"
DEFAULT_READY_LABEL =
"aidp-ready"
DEFAULT_BUILD_LABEL =
"aidp-build"
COMMENT_HEADER =
"## 🤖 AIDP Plan Proposal"

Constants included from MessageDisplay

MessageDisplay::COLOR_MAP

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Methods included from MessageDisplay

#display_message, #in_test_environment?, included, #message_display_prompt, #suppress_display_message?

Constructor Details

#initialize(repository_client:, state_store:, plan_generator:, label_config: {}) ⇒ PlanProcessor

Returns a new instance of PlanProcessor.



24
25
26
27
28
29
30
31
32
33
34
# File 'lib/aidp/watch/plan_processor.rb', line 24

def initialize(repository_client:, state_store:, plan_generator:, label_config: {})
  @repository_client = repository_client
  @state_store = state_store
  @plan_generator = plan_generator

  # Load label configuration with defaults
  @plan_label = label_config[:plan_trigger] || label_config["plan_trigger"] || DEFAULT_PLAN_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
end

Instance Attribute Details

#build_labelObject (readonly)

Returns the value of attribute build_label.



22
23
24
# File 'lib/aidp/watch/plan_processor.rb', line 22

def build_label
  @build_label
end

#needs_input_labelObject (readonly)

Returns the value of attribute needs_input_label.



22
23
24
# File 'lib/aidp/watch/plan_processor.rb', line 22

def needs_input_label
  @needs_input_label
end

#plan_labelObject (readonly)

Returns the value of attribute plan_label.



22
23
24
# File 'lib/aidp/watch/plan_processor.rb', line 22

def plan_label
  @plan_label
end

#ready_labelObject (readonly)

Returns the value of attribute ready_label.



22
23
24
# File 'lib/aidp/watch/plan_processor.rb', line 22

def ready_label
  @ready_label
end

Class Method Details

.plan_label_from_config(config) ⇒ Object

For backward compatibility



37
38
39
40
# File 'lib/aidp/watch/plan_processor.rb', line 37

def self.plan_label_from_config(config)
  labels = config[:labels] || config["labels"] || {}
  labels[:plan_trigger] || labels["plan_trigger"] || DEFAULT_PLAN_LABEL
end

Instance Method Details

#process(issue) ⇒ Object



42
43
44
45
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
# File 'lib/aidp/watch/plan_processor.rb', line 42

def process(issue)
  number = issue[:number]
  existing_plan = @state_store.plan_data(number)

  if existing_plan
    display_message("🔄 Re-planning for issue ##{number} (iteration #{@state_store.plan_iteration_count(number) + 1})", type: :info)
  else
    display_message("🧠 Generating plan for issue ##{number} (#{issue[:title]})", type: :info)
  end

  plan_data = @plan_generator.generate(issue)

  # 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, label_actor: label_actor, archived_content: archived_content)

  if existing_plan && existing_plan["comment_id"]
    # Update existing comment
    @repository_client.update_comment(existing_plan["comment_id"], comment_body)
    display_message("📝 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)
      display_message("📝 Updated plan comment for issue ##{number}", type: :success)
      plan_data = plan_data.merge(comment_id: existing_comment[:id])
    else
      # Fallback to posting new comment if we can't find the old one
      @repository_client.post_comment(number, comment_body)
      display_message("💬 Posted new plan comment for issue ##{number}", type: :success)
    end
  else
    # First time planning - post new comment
    @repository_client.post_comment(number, comment_body)
    display_message("💬 Posted plan comment for issue ##{number}", type: :success)
  end

  @state_store.record_plan(number, plan_data.merge(comment_body: comment_body, comment_hint: COMMENT_HEADER))

  # Update labels: remove plan trigger, add appropriate status label
  update_labels_after_plan(number, plan_data)
end