1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
//! The laboratory host's STDIN/STDOUT control channel — the dial-list
//! vocabulary between the daemon (the host's sole spawner, which owns
//! its pipes) and the host binary.
//!
//! The host is born with ZERO daemon connections: no `--address` argv
//! exists. The daemon writes one [`HostStdioRequest`] JSON object per
//! stdin line (seeding the config-derived list right after the
//! [`crate::process::ServerReady`] handshake, and again on every
//! `laboratories config` mutation), and the host answers each request
//! with one [`HostStdioAck`] line on stdout, echoing the request's
//! daemon-generated `id` — the correlation key.
//!
//! An ack confirms the DIAL-LIST mutation was applied (the dial task
//! spawned or cancelled), NOT connectivity: dialing retries forever,
//! and connection success is observed through the daemon's registry
//! exactly as before. Requests are idempotent — adding an address the
//! host already dials REPLACES that connection (the old one is torn
//! down first, then the new one dialed, so the host NEVER holds two
//! connections to one address — e.g. a changed signature re-dials
//! with the new preamble); removing an absent one still acks.
//!
//! This is a different transport from the `/laboratory` WebSocket
//! vocabulary in the sibling modules, and deliberately NAIVE to it.
//! Like [`crate::process::ServerReady`], these are internal pipe
//! types: plain serde, no schemas.
/// One dial-list request, daemon → host, one JSON object per stdin
/// line: a daemon-generated `id` (echoed back in the ack) wrapped
/// around the [`HostStdioCommand`], flattened — on the wire the line
/// is `{"id": …, "type": …, …}`.
/// The mutation a [`HostStdioRequest`] carries.
/// The host's answer to one [`HostStdioRequest`], host → daemon, one
/// JSON object per stdout line: the request's `id`, echoed.
/// Parse one stdin line as a dial-list request. `None` for anything
/// else (the host ignores unparseable lines; with nothing to
/// correlate, the daemon's ack wait times out and reports the error).
/// Parse one stdout line as an ack. `None` for anything else (the
/// ready line, stray output — the daemon's reader skips them).
/// Print one ack line to stdout and flush — the host side of the
/// channel, sharing stdout with the ready line under the same
/// lock-and-flush discipline as [`crate::process::print_ready`].