# frozen_string_literal: true module Dispatch module Adapter class Claude < Base class TokenStore DEFAULT_PATH = File.join(Dir.home, ".config", "dispatch", "claude_oauth.json") def initialize(path: DEFAULT_PATH) @path = path end attr_reader :path def load return nil unless File.exist?(@path) File.open(@path, "r") do |f| f.flock(File::LOCK_SH) JSON.parse(f.read) end rescue JSON::ParserError nil end def save(creds) FileUtils.mkdir_p(File.dirname(@path)) tmp = "#{@path}.#{Process.pid}.#{Thread.current.object_id}.#{SecureRandom.hex(4)}.tmp" File.open(tmp, File::RDWR | File::CREAT, 0o600) do |f| f.flock(File::LOCK_EX) f.truncate(0) f.write(JSON.pretty_generate(creds)) f.flush end File.rename(tmp, @path) File.chmod(0o600, @path) ensure File.delete(tmp) if tmp && File.exist?(tmp) end def delete FileUtils.rm_f(@path) end end end end end