Module: OmnifocusMcp::Tools::Operations::BatchAddItems::BulkExecutor

Defined in:
lib/omnifocus_mcp/tools/operations/batch_add_items/bulk_executor.rb

Overview

Runs eligible batch adds in a single osascript invocation instead of one process per item. Large MCP batches (20+ tasks) were timing out when each item spawned its own osascript call.

Constant Summary collapse

BULK_MIN_ITEMS =

Independent task batches at or above this size use one osascript call.

2

Class Method Summary collapse

Class Method Details

.eligible?(batch_items) ⇒ Boolean

Returns:

  • (Boolean)


42
43
44
45
46
47
# File 'lib/omnifocus_mcp/tools/operations/batch_add_items/bulk_executor.rb', line 42

def eligible?(batch_items)
  return false if batch_items.length < BULK_MIN_ITEMS

  batch_items.all? { |bi| bi.payload.type.to_s == "task" } &&
    batch_items.none? { |bi| needs_sequential_resolution?(bi.payload) }
end

.needs_sequential_resolution?(payload) ⇒ Boolean

Returns:

  • (Boolean)


49
50
51
52
53
54
55
# File 'lib/omnifocus_mcp/tools/operations/batch_add_items/bulk_executor.rb', line 49

def needs_sequential_resolution?(payload)
  [
    payload.parent_temp_id,
    payload.parent_task_id,
    payload.parent_task_name
  ].any? { !Utils::Blank.blank?(it) }
end

.run(batch_items, execute_applescript: Infrastructure::ScriptRunner.method(:execute_applescript)) ⇒ Array<OmnifocusMcp::Result>?

Returns per-item results in pending order, or nil when bulk is not eligible or the script fails.

Parameters:

  • batch_items (Array<BatchItem>)

    only pending items are executed

Returns:

  • (Array<OmnifocusMcp::Result>, nil)

    per-item results in pending order, or nil when bulk is not eligible or the script fails



25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
# File 'lib/omnifocus_mcp/tools/operations/batch_add_items/bulk_executor.rb', line 25

def run(batch_items, execute_applescript: Infrastructure::ScriptRunner.method(:execute_applescript))
  pending = batch_items.select(&:pending?)
  return nil unless eligible?(pending)

  params_list = pending.map do |bi|
    ParamBuilder.task(bi.payload, parent_task_id: nil, project_name: bi.payload.project_name)
  end
  script = Generators::AddOmniFocusTask.generate_bulk_apple_script(params_list)

  stdout, stderr, status = execute_applescript.call(script)
  log_stderr(stderr)

  return nil unless status.success?

  parse_bulk_results(stdout, expected_count: pending.length)
end