Class: Aidp::Watch::BuildProcessor

Inherits:
Object
  • Object
show all
Includes:
MessageDisplay
Defined in:
lib/aidp/watch/build_processor.rb

Overview

Handles the aidp-build trigger by running the autonomous work loop, creating a branch/PR, and posting completion status back to GitHub.

Constant Summary collapse

DEFAULT_BUILD_LABEL =
"aidp-build"
DEFAULT_NEEDS_INPUT_LABEL =
"aidp-needs-input"
IMPLEMENTATION_STEP =
"16_IMPLEMENTATION"

Constants included from MessageDisplay

MessageDisplay::COLOR_MAP

Instance Attribute Summary collapse

Instance Method Summary collapse

Methods included from MessageDisplay

#display_message, included, #message_display_prompt

Constructor Details

#initialize(repository_client:, state_store:, project_dir: Dir.pwd, use_workstreams: true, verbose: false, label_config: {}) ⇒ BuildProcessor

Returns a new instance of BuildProcessor.



29
30
31
32
33
34
35
36
37
38
39
40
41
# File 'lib/aidp/watch/build_processor.rb', line 29

def initialize(repository_client:, state_store:, project_dir: Dir.pwd, use_workstreams: true, verbose: false, label_config: {})
  @repository_client = repository_client
  @state_store = state_store
  @state_extractor = GitHubStateExtractor.new(repository_client: repository_client)
  @verifier = ImplementationVerifier.new(repository_client: repository_client, project_dir: project_dir)
  @project_dir = project_dir
  @use_workstreams = use_workstreams
  @verbose = verbose

  # Load label configuration
  @build_label = label_config[:build_trigger] || label_config["build_trigger"] || DEFAULT_BUILD_LABEL
  @needs_input_label = label_config[:needs_input] || label_config["needs_input"] || DEFAULT_NEEDS_INPUT_LABEL
end

Instance Attribute Details

#build_labelObject (readonly)

Returns the value of attribute build_label.



27
28
29
# File 'lib/aidp/watch/build_processor.rb', line 27

def build_label
  @build_label
end

#needs_input_labelObject (readonly)

Returns the value of attribute needs_input_label.



27
28
29
# File 'lib/aidp/watch/build_processor.rb', line 27

def needs_input_label
  @needs_input_label
end

Instance Method Details

#process(issue) ⇒ Object



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
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
# File 'lib/aidp/watch/build_processor.rb', line 43

def process(issue)
  number = issue[:number]
  display_message("🛠️  Starting implementation for issue ##{number}", type: :info)

  plan_data = ensure_plan_data(issue)
  return unless plan_data

  slug = workstream_slug_for(issue)
  branch_name = branch_name_for(issue)
  @state_store.record_build_status(number, status: "running", details: {branch: branch_name, workstream: slug, started_at: Time.now.utc.iso8601})

  ensure_git_repo!
  base_branch = detect_base_branch

  if @use_workstreams
    workstream_path = setup_workstream(slug: slug, branch_name: branch_name, base_branch: base_branch)
    working_dir = workstream_path
  else
    checkout_branch(base_branch, branch_name)
    working_dir = @project_dir
  end

  sync_local_aidp_config(working_dir)

  prompt_content = build_prompt(issue: issue, plan_data: plan_data)
  write_prompt(prompt_content, working_dir: working_dir)

  user_input = build_user_input(issue: issue, plan_data: plan_data)
  result = run_harness(user_input: user_input, working_dir: working_dir)

  if result[:status] == "completed"
    handle_success(issue: issue, slug: slug, branch_name: branch_name, base_branch: base_branch, plan_data: plan_data, working_dir: working_dir)
  elsif result[:status] == "needs_clarification"
    handle_clarification_request(issue: issue, slug: slug, result: result)
  elsif result[:reason] == :completion_criteria
    handle_incomplete_criteria(issue: issue, slug: slug, branch_name: branch_name, working_dir: working_dir, metadata: result[:failure_metadata])
  else
    handle_failure(issue: issue, slug: slug, result: result)
  end
rescue => e
  # Don't re-raise - handle gracefully for fix-forward pattern
  display_message("❌ Implementation failed with exception: #{e.message}", type: :error)
  Aidp.log_error(
    "build_processor",
    "Implementation failed with exception",
    issue: issue[:number],
    error: e.message,
    error_class: e.class.name,
    backtrace: e.backtrace&.first(10)
  )

  # Record failure state internally but DON'T post error to GitHub
  # (per issue #280 - error messages should never appear on issues)
  @state_store.record_build_status(
    issue[:number],
    status: "error",
    details: {
      error: e.message,
      error_class: e.class.name,
      workstream: slug,
      timestamp: Time.now.utc.iso8601
    }
  )

  # Note: We intentionally DON'T re-raise here to allow watch mode to continue
  # The error has been logged and recorded internally
end