Commit Graph
5 Commits
Author SHA1 Message Date
glm-5.2 0ff0ceeac3 feat(tty-local): implement LocalTtyBackend (TtyBackend) branching on terminal Some/None
Implements the wiring task: LocalTtyBackend::allocate() dispatches to
pty::allocate_pty when TtyParams.terminal is Some (PTY mode, stderr None)
and pipe::allocate_pipe when None (runner mode, stderr Some). Validates
non-empty cmd, ignores backend_params (local backend has no backend-
specific selector fields), and resource_id() returns None (local backend
creates its own resource — process). Adds async-trait dependency.
2026-07-07 23:03:05 +00:00
glm-5.2 6dce987ed4 Merge feat/tty-local/pipe-mode: resolve Cargo.toml/Cargo.lock conflicts with pty-mode (both tokio-stream and tokio-util needed) 2026-07-07 22:58:40 +00:00
glm-5.2 c76b6aab7a feat(tty-local): implement pipe mode — tokio::process spawn, PipeControl, ADR-056 kill guard
Implements the runner case (terminal: None, no PTY) in pipe.rs:
- allocate_pipe spawns via tokio::process::Command with Stdio::piped(),
  returning a TtyHandle with separate stdout/stderr (stderr=Some).
- stdin: ChildStdin boxed as Box<dyn AsyncWrite + Send + Unpin>.
- stdout/stderr: ChildStdout/ChildStderr wrapped via tokio_util::io::ReaderStream
  into Pin<Box<dyn Stream<Item = Bytes> + Send>> (errors map to stream EOF).
- exit_code: PipeExitFuture holding the Child; poll drives Child::wait() and
  disarms the guard on resolve; Drop calls Child::start_kill() on cancel
  (ADR-056 spec-compliant kill-on-Drop, not kill_on_drop(true) alone).
- control: PipeControl (no-op resize, libc::kill(pid, sig) signal on Unix,
  SIGKILL fallback for unknown names; non-Unix logs and relies on Drop guard).
  Doc comment documents the no-process-group limitation of pipe mode.

Adds tokio-util (io) and tokio-stream (dev) deps. 9 unit tests cover the
happy path, stdin round-trip, separate stderr, SIGTERM signal, cancel
cleanup (asserts child killed via kill(pid,0)), resize no-op, unknown
signal SIGKILL fallback, pid recording, and empty-command error.
2026-07-07 15:04:30 +00:00
glm-5.2 9f8d07fc25 feat(tty-local): implement PTY mode — three-thread bridge, PtyControl, REQ-TTY-02, ADR-056 kill guard
Implement allocate_pty in src/pty.rs: portable_pty openpty + spawn as
session leader (set_controlling_tty(true)), with the three-thread
blocking→async bridge (REQ-TTY-01): reader → mpsc<Bytes> with
zero-length EOF sentinel, writer draining mpsc<StdinCmd> (Bytes/Eof),
waiter → oneshot<i32>. TtyHandle.stdout is ReceiverStream<Bytes>,
stdin is a StdinSink AsyncWrite wrapper over mpsc::Sender<StdinCmd>
(parks a reserve+send future when the channel is full), stderr is None
(PTY merges), exit_code is LocalExitFuture.

PtyControl implements TtyControl: resize via MasterPty::resize; signal
via libc::kill(-pgid, sig) with kill(pid, sig) fallback (Unix, REQ-TTY-02)
using alknet_tty::signal_from_name; unknown names and non-Unix fall back
to ChildKiller::kill (SIGHUP).

LocalExitFuture wraps the oneshot::Receiver<i32> + a ChildKiller kill
guard (ADR-056). poll delegates to the receiver and disarms the guard
on Ready (no-op Drop on happy path); Drop on cancel calls
ChildKiller::kill (SIGHUP) — best-effort; the waiter thread reaps.

Bump portable-pty 0.8 → 0.9 to match the POC API (MasterPty: Send).
Add tokio-stream, serde_json (dev), tempfile (dev) deps.

Tests: happy path (echo), stdin round-trip (cat), resize, signal INT
kills child, signal reaches process group (bash -c "sleep 60"),
cancel cleanup on drop, unknown signal falls back to ChildKiller.
2026-07-07 14:56:35 +00:00
glm-5.2 2022a5496a feat(tty-local): initialize alknet-tty-local sibling crate (ADR-054)
Create crates/alknet-tty-local with Cargo.toml (alknet-tty workspace dep,
portable-pty, libc unix-only, tokio, bytes, futures-core, tracing,
thiserror), src/lib.rs with module declarations and LocalTtyBackend
re-export, and skeleton module files (pty, pipe, backend) with doc
comments and TODO markers. Add the crate to the workspace members list.
2026-07-07 14:16:10 +00:00