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
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
//! Git-tree view-model (ARCH §7.1 live view, §3.5 agent-state contract).
//!
//! [`GitTree::from_repo`] inspects the workspace's on-disk state and
//! produces a view-model suitable for rendering. The view-model is a pure
//! function of the workspace's refs and tree content; it holds no egui
//! dependency, so a future `lernie-ui-web` crate can render the same
//! structure from the web.
//!
//! Git access is via the `git` CLI (a hard dep of lernie itself, per ARCH
//! §2.2) — no libgit2 native build step is required.
//!
//! # Workspace layout (ARCH §2.2–§2.3)
//!
//! A workspace holds one bare repository at `<workspace>/repo.git`: config
//! branches (`config/<name>`) and agent refs (`agents/<agent-id>`) — no
//! `main`. Callers pass the workspace path; this module resolves the git
//! dir to `<workspace>/repo.git` before issuing any git command, and reads
//! step records, inboxes, and marks directly from the workspace root.
//!
//! The trunk section is the config lineage (`HEAD`, which the workspace
//! repository points at `config/default`); the agent section enumerates
//! every `agents/*` ref and renders it as a **tree** by hyphenated descent
//! (§2.3) — agents never merge anywhere (§2.6), so every agent persists on
//! its own ref. Each agent carries its §3.5 state ([`AgentState`]), its four
//! ref-derived mark oids (conflicted, budget-exhausted, abandoned, notify —
//! §6/§4.1; two render as tree labels, the rest drive attention), a
//! pending-message count from its inbox, and its branch commits with their
//! subjects (delivery / work-product-transfer commits surface by subject).
// The Linux `/proc` probe backends (§10). Compiled only where they have a
// consumer — always on Linux (production + test), and under `cfg(test)` on
// macOS (their own unit tests) — since macOS drives liveness through `lsof`.
// The macOS `lsof` backend (§10): a pure parser + spawn shim + TTL cache. Its
// core is platform-independent, but Linux never *uses* it (its `/proc` probes
// are cheaper and always definite), so it is compiled only where it has a
// consumer — under `cfg(test)` for its coverage, and on macOS in production.
pub use ;
// Config-branch browse plumbing (§9.3 / §5.1 #17–#18), consumed by
// [`crate::config_edit::branch`]. Every config-ref git call routes through
// the env-scrubbed `cmd` wrapper; these re-exports are the only doorway.
pub use ;
pub use Probe;
pub use ProbeStack;
pub use AgentState;
// The live-tail fold, shared with the transcript view-model (Y12) so the
// JSONL text-delta parser is never duplicated (§15 Y12: "reuse the
// streaming fold — do NOT duplicate the JSONL parser").
pub use streaming_text_from_disk;
// The §4.4 terminal classifier, shared with the Y13 steps inspector so the
// segment-boundary parser is never duplicated (§15 Y13: "reuse
// git_tree::terminal's segment classification — do NOT duplicate the
// parser"). The live view reads it as `AgentState`; the steps inspector
// reads the raw framing (a public classification it surfaces per step) plus
// the completed-segment count. The two folds stay crate-internal.
pub use Framing;
pub use ;
use ;
/// The bare workspace repository dir (ARCH §2.2). Mirrors
/// `src/workspace::REPO_DIR` in the harness; the duplicate constant keeps
/// the UI crate free of a dep on the harness binary. `pub(crate)` so the
/// config-branch browse surface ([`crate::config_edit::branch`]) resolves
/// `<workspace>/repo.git` through the one authoritative name.
pub const REPO_DIR: &str = "repo.git";
/// Top-level directory under the workspace root holding per-agent step
/// records (ARCH §2.2 / §2.3). Mirrors `src/prompt/step::STEPS_DIR`.
const STEPS_DIR: &str = "steps";
/// Top-level directory under the workspace root holding per-agent inboxes
/// (ARCH §2.11). Mirrors the harness's `inbox/<agent-id>/` layout; the
/// pending-message count and the executor-lock probe both key off it.
const INBOX_DIR: &str = "inbox";
/// Top-level directory under the workspace root holding the per-agent worktrees
/// (`agents/<agent-id>/`, ARCH §2.2): where `goal.md` and the rest of the
/// dispatch control files live on disk (§7.1 watch roots).
const AGENTS_DIR: &str = "agents";
/// One agent branch (`agents/<agent-id>`, §2.3). Named `Agent` — every
/// row is an agent, not an "unmerged conversation branch"; nothing merges
/// (§2.6), so the merged/unmerged framing is gone.
/// A single tool call surfaced to the renderer. The disk records carry
/// more metadata (timing, exit code, raw stdout) but the view-model only
/// needs identity + state to drive the indicator.
// `pub(crate)` (not private) so Y6's milestone-proof test in `crate::app`
// reuses the workspace [`tests::fixture`] builder — the one place a real
// on-disk workspace is spun up (§15 Y6: "use the existing fixture builders").
pub