Class: Space::Architect::Harness::OpenCodeHarness

Inherits:
Object
  • Object
show all
Defined in:
lib/space_architect/harness.rb

Instance Method Summary collapse

Constructor Details

#initialize(model:, max_turns:, bin: nil, config_dir:, effort: nil) ⇒ OpenCodeHarness

Returns a new instance of OpenCodeHarness.



240
241
242
243
244
245
246
# File 'lib/space_architect/harness.rb', line 240

def initialize(model:, max_turns:, bin: nil, config_dir:, effort: nil)
  @model      = model
  @max_turns  = max_turns
  @bin        = bin || ENV.fetch("ARCHITECT_OPENCODE_BIN", "opencode")
  @config_dir = Pathname.new(config_dir)
  @effort     = effort
end

Instance Method Details

#builder_configObject

Returns the agent config hash (deterministic, unit-testable).



249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
# File 'lib/space_architect/harness.rb', line 249

def builder_config
  cfg = {
    "agent" => {
      "builder" => {
        "steps" => @max_turns,
        "permission" => {
          "bash" => {
            "git commit *"   => "deny",
            "git push *"     => "deny",
            "git reset *"    => "deny",
            "git rebase *"   => "deny",
            "git checkout *" => "deny",
            "*"              => "allow"
          }
        }
      }
    }
  }
  cfg.merge!(reasoning_provider_config) if @effort
  cfg
end

#run(prompt_path:, run_log_path:, chdir:, timeout: nil) ⇒ Object

timeout: deferred — opencode kill path is out of scope



271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
# File 'lib/space_architect/harness.rb', line 271

def run(prompt_path:, run_log_path:, chdir:, timeout: nil) # timeout: deferred — opencode kill path is out of scope
  prompt_path  = Pathname.new(prompt_path)
  run_log_path = Pathname.new(run_log_path)
  config_path  = write_config

  env = {
    "OPENCODE_CONFIG"                 => config_path.to_s,
    "OPENCODE_DISABLE_PROJECT_CONFIG" => "1"
  }

  File.open(prompt_path, "r") do |prompt_io|
    File.open(run_log_path, "w") do |log|
      status = Sync do
        Async::Process.spawn(env, *argv(chdir),
                             chdir: chdir.to_s, in: prompt_io, out: log, err: log)
      end
      status.exitstatus
    end
  end
end

#run_detached(prompt_path:, run_log_path:, chdir:) ⇒ Object



292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
# File 'lib/space_architect/harness.rb', line 292

def run_detached(prompt_path:, run_log_path:, chdir:)
  prompt_path  = Pathname.new(prompt_path)
  run_log_path = Pathname.new(run_log_path)
  config_path  = write_config

  env = {
    "OPENCODE_CONFIG"                 => config_path.to_s,
    "OPENCODE_DISABLE_PROJECT_CONFIG" => "1"
  }

  prompt_io = File.open(prompt_path, "r")
  log       = File.open(run_log_path, "w")
  begin
    pid = Process.spawn(env, *argv(chdir), chdir: chdir.to_s, pgroup: true,
                        in: prompt_io, out: log, err: log)
    Process.detach(pid)
  ensure
    prompt_io.close
    log.close
  end
  pid
end