Class: Aidp::Watch::WorktreeReconciler

Inherits:
Object
  • Object
show all
Defined in:
lib/aidp/watch/worktree_reconciler.rb

Overview

Handles reconciliation of dirty worktrees (those with uncommitted changes). Determines appropriate action based on linked issue/PR state:

  • Open issue/PR: Resume work by triggering build processor
  • Merged PR: Reconcile changes and create follow-up PR if meaningful diff remains
  • Closed without merge: Log and optionally clean up

This runs as part of the watch mode poll cycle, after cleanup but before sleep.

Constant Summary collapse

ISSUE_SLUG_PATTERN =

Pattern to extract issue number from worktree slug e.g., "issue-375-thinking-tiers-escalate" -> 375

/^issue-(\d+)-/
PR_SLUG_PATTERN =

Pattern to extract PR number from worktree slug e.g., "pr-456-ci-fix" -> 456

/^pr-(\d+)-/

Instance Method Summary collapse

Constructor Details

#initialize(project_dir:, repository_client:, build_processor:, state_store:, config: {}) ⇒ WorktreeReconciler

Returns a new instance of WorktreeReconciler.

Parameters:

  • project_dir (String)

    Project root directory

  • repository_client (RepositoryClient)

    GitHub API client

  • build_processor (BuildProcessor)

    Processor for resuming builds

  • state_store (StateStore)

    For tracking build state

  • config (Hash) (defaults to: {})

    Configuration options



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

def initialize(project_dir:, repository_client:, build_processor:, state_store:, config: {})
  @project_dir = project_dir
  @repository_client = repository_client
  @build_processor = build_processor
  @state_store = state_store
  @config = normalize_config(config)

  Aidp.log_debug("worktree_reconciler", "initialized",
    project_dir: project_dir,
    config: @config)
end

Instance Method Details

#enabled?Boolean

Check if reconciliation is enabled

Returns:

  • (Boolean)


95
96
97
# File 'lib/aidp/watch/worktree_reconciler.rb', line 95

def enabled?
  @config[:enabled]
end

#executeHash

Execute reconciliation of dirty worktrees

Returns:

  • (Hash)

    Result containing resumed, reconciled, skipped counts and errors



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
# File 'lib/aidp/watch/worktree_reconciler.rb', line 56

def execute
  Aidp.log_info("worktree_reconciler", "reconciliation_started")

  return {resumed: 0, reconciled: 0, cleaned: 0, skipped: 0, errors: []} unless enabled?

  worktrees = list_dirty_worktrees
  Aidp.log_debug("worktree_reconciler", "dirty_worktrees_found", count: worktrees.size)

  results = {resumed: 0, reconciled: 0, cleaned: 0, skipped: 0, errors: []}

  worktrees.each do |worktree|
    result = process_dirty_worktree(worktree)
    case result[:action]
    when :resumed
      results[:resumed] += 1
    when :reconciled
      results[:reconciled] += 1
    when :cleaned
      results[:cleaned] += 1
    when :skipped
      results[:skipped] += 1
    when :error
      results[:errors] << {slug: worktree[:slug], error: result[:error]}
    end
  end

  Aidp.log_info("worktree_reconciler", "reconciliation_completed",
    resumed: results[:resumed],
    reconciled: results[:reconciled],
    cleaned: results[:cleaned],
    skipped: results[:skipped],
    errors_count: results[:errors].size)

  results
end

#reconciliation_due?(last_reconcile_at) ⇒ Boolean

Check if reconciliation is due based on last run time

Parameters:

  • last_reconcile_at (Time, nil)

    Time of last reconciliation run

Returns:

  • (Boolean)

    True if reconciliation should run



45
46
47
48
49
50
51
# File 'lib/aidp/watch/worktree_reconciler.rb', line 45

def reconciliation_due?(last_reconcile_at)
  return false unless enabled?
  return true if last_reconcile_at.nil?

  elapsed = Time.now - last_reconcile_at
  elapsed >= reconciliation_interval_seconds
end

#reconciliation_interval_secondsInteger

Get the configured reconciliation interval in seconds

Returns:

  • (Integer)


102
103
104
# File 'lib/aidp/watch/worktree_reconciler.rb', line 102

def reconciliation_interval_seconds
  @config[:interval_seconds]
end