Class: Ace::Overseer::Organisms::WorkOnOrchestrator

Inherits:
Object
  • Object
show all
Defined in:
lib/ace/overseer/organisms/work_on_orchestrator.rb

Constant Summary collapse

SUBTASK_PATTERN =

B36TS subtask pattern: “8pp.t.q7w.a” (parent 9-char ID + dot + single char)

/^[0-9a-z]{3}\.[a-z]\.[0-9a-z]{3}\.[a-z0-9]$/

Instance Method Summary collapse

Constructor Details

#initialize(worktree_provisioner: nil, tmux_window_opener: nil, assignment_launcher: nil, task_loader: nil, config: nil, assignment_detector: nil) ⇒ WorkOnOrchestrator

Returns a new instance of WorkOnOrchestrator.



10
11
12
13
14
15
16
17
18
# File 'lib/ace/overseer/organisms/work_on_orchestrator.rb', line 10

def initialize(worktree_provisioner: nil, tmux_window_opener: nil, assignment_launcher: nil,
  task_loader: nil, config: nil, assignment_detector: nil)
  @worktree_provisioner = worktree_provisioner || Molecules::WorktreeProvisioner.new
  @tmux_window_opener = tmux_window_opener || Molecules::TmuxWindowOpener.new
  @task_manager = task_loader || Ace::Task::Organisms::TaskManager.new
  @assignment_launcher = assignment_launcher || Molecules::AssignmentLauncher.new(task_manager: @task_manager)
  @config = config || Ace::Overseer.config
  @assignment_detector = assignment_detector
end

Instance Method Details

#call(task_ref:, task_refs: nil, cli_preset: nil, on_progress: nil) ⇒ Object

Raises:



20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
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
89
90
91
92
93
94
95
96
97
98
99
100
101
# File 'lib/ace/overseer/organisms/work_on_orchestrator.rb', line 20

def call(task_ref:, task_refs: nil, cli_preset: nil, on_progress: nil)
  progress = on_progress || ->(_msg) {}

  requested_refs = normalize_requested_refs(task_ref, task_refs)
  raise Error, "No valid task references provided" if requested_refs.empty?

  progress.call("Loading task #{requested_refs.join(", ")}...")
  resolved_refs, skipped_terminal = resolve_requested_refs(requested_refs)

  if resolved_refs.empty?
    raise Error, "All requested tasks are already terminal (done/skipped/cancelled): #{skipped_terminal.join(", ")}. No assignment created."
  end

  if skipped_terminal.any?
    progress.call("Skipped terminal tasks (done/skipped/cancelled): #{skipped_terminal.join(", ")}")
  end

  primary_ref = resolved_refs.first[:ref]
  primary_task = resolved_refs.first[:task]

  preset_name = Atoms::PresetResolver.resolve(
    task_frontmatter: primary_task.respond_to?(:metadata) ? (primary_task. || {}) : {},
    cli_preset: cli_preset,
    default: @config["default_assign_preset"] || "work-on-task"
  )
  guard_multi_task_preset!(preset_name, resolved_refs.length)

  expanded_taskrefs = expand_task_refs_in_order(resolved_refs)
  primary_subtask_refs = extract_subtask_refs(primary_task)
  tmux_preset = @config.dig("tmux_window_presets", preset_name)

  progress.call("Provisioning worktree...")
  worktree = @worktree_provisioner.provision(primary_ref)
  if worktree[:created]
    progress.call("Worktree created at #{worktree[:worktree_path]}")
  else
    progress.call("Worktree exists at #{worktree[:worktree_path]}")
  end

  progress.call("Opening tmux window...")
  @tmux_window_opener.open(
    worktree_path: worktree[:worktree_path],
    preset: tmux_preset
  )

  progress.call("Checking assignment status...")
  existing = if @assignment_detector
    @assignment_detector.call(worktree[:worktree_path])
  else
    existing_assignment(worktree[:worktree_path])
  end
  assignment_result = if existing
    progress.call("Assignment already active: #{existing.dig("assignment", "id")}")
    {
      assignment_id: existing.dig("assignment", "id"),
      first_step: existing.dig("current_step", "number"),
      created: false
    }
  else
    progress.call("Launching assignment (preset: #{preset_name})...")
    launched = @assignment_launcher.launch(
      worktree_path: worktree[:worktree_path],
      preset_name: preset_name,
      task_ref: primary_ref.to_s,
      subtask_refs: primary_subtask_refs,
      task_refs: expanded_taskrefs
    )
    launched.merge(created: true)
  end

  {
    task_ref: primary_ref.to_s,
    task_refs: expanded_taskrefs,
    preset: preset_name,
    worktree_path: worktree[:worktree_path],
    branch: worktree[:branch],
    worktree_created: worktree[:created],
    assignment_id: assignment_result[:assignment_id],
    first_step: assignment_result[:first_step],
    assignment_created: assignment_result[:created]
  }
end