Packages
execution_plane_process
0.1.0
Execution Plane process launch, stdio, PTY, and process-session runtime.
Current section
Files
Jump to
Current section
Files
lib/execution_plane/process/transport/subprocess/state.ex
# credo:disable-for-this-file Credo.Check.Warning.StructFieldAmount
defmodule ExecutionPlane.Process.Transport.Subprocess.State do
@moduledoc """
Internal state schema for the subprocess transport coordinator.
The GenServer is intentionally a coordinator. This module owns the state
shape and groups fields by responsibility:
* process identity and surface metadata;
* subscriber/event delivery;
* stdout/stderr framing and overflow recovery;
* pending request tasks;
* lifecycle timers and startup options;
* stdin/stdout/interrupt runtime configuration.
Phase 41 owns moving long-line spool file I/O behind its own boundary.
"""
alias ExecutionPlane.{Command, LineFraming}
alias ExecutionPlane.Process.OS
alias ExecutionPlane.Process.Transport.Options
defstruct subprocess: nil,
invocation: nil,
surface_kind: :local_subprocess,
target_id: nil,
lease_ref: nil,
surface_ref: nil,
boundary_class: nil,
observability: %{},
adapter_capabilities: nil,
effective_capabilities: nil,
bridge_profile: nil,
protocol_version: nil,
extensions: %{},
adapter_metadata: %{},
subscribers: %{},
buffered_events: :queue.new(),
buffered_event_count: 0,
stdout_framer: %LineFraming{},
pending_lines: :queue.new(),
drain_scheduled?: false,
status: :disconnected,
stderr_buffer: "",
stderr_framer: %LineFraming{},
max_buffer_size: nil,
oversize_line_chunk_bytes: nil,
max_recoverable_line_bytes: nil,
oversize_line_mode: :chunk_then_fail,
buffer_overflow_mode: :fatal,
long_line_spool: nil,
max_stderr_buffer_size: nil,
overflowed?: false,
fatal_stop_scheduled?: false,
pending_calls: %{},
finalize_timer_ref: nil,
headless_timeout_ms: nil,
headless_timer_ref: nil,
task_supervisor: nil,
event_tag: nil,
stdout_mode: :line,
stdin_mode: :line,
pty?: false,
interrupt_mode: :signal,
os: OS,
stderr_callback: nil,
replay_stderr_on_subscribe?: false,
buffer_events_until_subscribe?: false,
max_buffered_events: 128,
startup_options: nil
@doc false
def new(%Options{} = options) do
%__MODULE__{
invocation: options.invocation_override || build_invocation(options),
surface_kind: options.surface_kind,
target_id: options.target_id,
lease_ref: options.lease_ref,
surface_ref: options.surface_ref,
boundary_class: options.boundary_class,
observability: options.observability,
adapter_capabilities: options.adapter_capabilities,
effective_capabilities: options.effective_capabilities,
bridge_profile: options.bridge_profile,
protocol_version: options.protocol_version,
extensions: options.extensions,
adapter_metadata: options.adapter_metadata,
status: :disconnected,
buffered_events: :queue.new(),
buffered_event_count: 0,
max_buffer_size: options.max_buffer_size,
oversize_line_chunk_bytes: options.oversize_line_chunk_bytes,
max_recoverable_line_bytes: options.max_recoverable_line_bytes,
oversize_line_mode: options.oversize_line_mode,
buffer_overflow_mode: options.buffer_overflow_mode,
max_stderr_buffer_size: options.max_stderr_buffer_size,
max_buffered_events: options.max_buffered_events,
headless_timeout_ms: options.headless_timeout_ms,
task_supervisor: options.task_supervisor,
event_tag: options.event_tag,
stdout_mode: options.stdout_mode,
stdin_mode: options.stdin_mode,
pty?: options.pty?,
interrupt_mode: options.interrupt_mode,
os: options.os,
stderr_callback: options.stderr_callback,
replay_stderr_on_subscribe?: options.replay_stderr_on_subscribe?,
buffer_events_until_subscribe?: options.buffer_events_until_subscribe?,
startup_options: options
}
end
defp build_invocation(%Options{} = options) do
Command.new(options.command, options.args,
cwd: options.cwd,
env: options.env,
clear_env?: options.clear_env?,
user: options.user
)
end
end