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
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
//! Process-wide CLI principal.
//!
//! The `astrid` CLI acts as exactly one principal for its whole
//! lifetime. The uplink proxy pins the first principal it sees on a
//! connection: it auto-attributes unstamped messages to that principal
//! and DROPS any message stamped with a different one. A mixed stream
//! therefore loses messages silently, so the CLI must present one
//! consistent principal on every IPC message it sends.
//!
//! The principal is resolved ONCE at startup ([`resolve_process`]) with
//! precedence explicit `--principal` flag > `ASTRID_PRINCIPAL` env >
//! the operator's active-agent context (`cli-context.toml`, set by
//! `astrid agent use`) > `default`. clap folds the env var into the
//! flag value, so the explicit-source resolver ([`resolve`]) sees a
//! single `Option<&str>`; the active-agent fallback only applies when
//! neither flag nor env is set, preserving the pre-flag admin-command
//! attribution. The resolved principal is validated through
//! [`PrincipalId::new`] before any socket connection, then stored in a
//! [`OnceLock`] read by every transport ([`crate::socket_client`],
//! [`crate::admin_client`]) so each outbound message stamps the same
//! identity without threading it through every handler signature.
use OnceLock;
use ;
use PrincipalId;
/// Process-wide resolved principal, set once in `main` after argument
/// parsing and read by the transport constructors.
static PRINCIPAL: = new;
/// Validate an explicit principal source. `value` is the flag-or-env
/// value clap produced (`Some` when `--principal` or `ASTRID_PRINCIPAL`
/// was set, `None` otherwise). `None` resolves to `None` here so the
/// caller can apply the lower-precedence active-agent fallback;
/// `Some(s)` is validated through [`PrincipalId::new`].
///
/// Pure over its input so precedence and validation can be unit-tested
/// without touching the environment (`clippy.toml` bans
/// `std::env::set_var`).
///
/// # Errors
/// Returns an error naming the constraint if `value` is present but is
/// not a valid [`PrincipalId`] (1-64 chars of `[a-zA-Z0-9_-]`).
pub
/// Resolve the process principal with full precedence: explicit
/// flag/env ([`resolve`]) > active-agent context > [`PrincipalId::default`].
///
/// The active-agent fallback preserves the pre-flag attribution for
/// admin commands (`astrid agent use X` then `astrid caps list` acts as
/// `X`); a malformed `cli-context.toml` surfaces as an error rather
/// than silently downgrading to `default`.
///
/// # Errors
/// Returns an error if the explicit value is invalid, or if the
/// active-agent context file exists but is malformed.
pub
/// Store the resolved principal for the process. Called once from
/// `main` immediately after [`resolve`]. Idempotent: a second call is a
/// no-op (the first value wins), which keeps the contract simple even
/// though the binary only sets it once.
pub
/// The process principal. Falls back to [`PrincipalId::default`] if
/// [`set`] was never called (e.g. a code path that builds a transport
/// before `main` resolved the flag — there is none today, but the
/// fallback keeps callers total and matches the no-flag default).
pub