mirror of
https://github.com/l0ng-ai/tty7.git
synced 2026-09-22 00:02:23 +00:00
fix(doctor): say when the server is running panes nothing holds
An interrupted `tty7 run` strands a pane. So does a window reconciling its layout while something else edits the tree — measured at 17 from 160 operations, every one a live `zsh` holding a pty and its descriptors, and `tty7 pane close --orphans` ended all 17. None of that was news to tty7: `pane ls --all` names them, the switcher lists them, and the reaper works. What was missing is that nothing volunteered they existed. `doctor` printed `status pid …, up 6s, 2 panes` and counted the stray among them, so the one verb somebody runs when something feels wrong had the number and did not say what it meant. A row and a `server.orphans` count. Deliberately not an exit code: one stray after an interrupted `run` is ordinary and the reference documents it as such, so `tty7 doctor || alert` firing on it would cry wolf. What was missing was the sentence, not an alarm. Counted inside the arm that already has the machine tree in hand for the dangling-context row, so it costs no extra round trip, and under `server` because it takes a server to have panes at all. The first draft put the count at the top level of the JSON, and `the_doctor_json_sections_are_the_ones_the_reference_names` — added earlier today for exactly this — caught it as an undocumented section before it went anywhere.
This commit is contained in:
@@ -166,6 +166,16 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
this account's open-file limit is the ceiling on how many panes can run at
|
||||
once; raise it (`ulimit -n`, …)", keeping the original error in parentheses.
|
||||
|
||||
- **`doctor` now says when the server is running panes nothing holds.** An
|
||||
interrupted `tty7 run` leaves one behind, and a window reconciling its layout
|
||||
against concurrent edits leaves more — each a live shell holding a pty and
|
||||
its descriptors. They were findable (`tty7 pane ls --all`, the switcher) and
|
||||
recoverable (`tty7 pane close --orphans`), but nothing volunteered that they
|
||||
were there: doctor's status row counted them among the panes without saying
|
||||
any were stray. It is a row and a `server.orphans` count, not an exit code —
|
||||
one stray after an interrupted `run` is ordinary, and failing on it would cry
|
||||
wolf.
|
||||
|
||||
- **`doctor` now checks the configured shell.** A `shell` naming something
|
||||
that is not there — missing, a directory, not executable — makes every new
|
||||
tab and every `tty7 new` fail, while `doctor` reported `config ok`, because
|
||||
|
||||
@@ -2000,13 +2000,51 @@ fn doctor(ctx: &Context, backend: &mut dyn Backend) -> Result<Outcome> {
|
||||
// an id the reader has no reason to doubt, which is the state
|
||||
// `doctor` is run in. Only checked when the server answered —
|
||||
// there is nothing to check against otherwise.
|
||||
// Shells the server runs that no workspace holds. An interrupted
|
||||
// `tty7 run` leaves one; a window reconciling its layout against
|
||||
// concurrent edits leaves more — measured at 17 from 160
|
||||
// operations, every one a live shell holding a pty and its
|
||||
// descriptors. They are recoverable and findable, but nothing
|
||||
// volunteered that they were there: the `status` row counts them
|
||||
// among the panes without saying any are stray.
|
||||
//
|
||||
// A row, not an exit code. One orphan after an interrupted `run`
|
||||
// is ordinary and documented as such, and `tty7 doctor || alert`
|
||||
// firing on it would cry wolf. What was missing is the sentence.
|
||||
//
|
||||
// Counted here because the tree is already in hand for the row
|
||||
// below, and because it takes a server to have panes at all.
|
||||
let mut strays = 0usize;
|
||||
if let Ok(machine) = fetch_machine(backend) {
|
||||
dangling = Some(note_dangling_context(&mut rows, ctx, &machine));
|
||||
if let Ok(running) = backend.list_panes() {
|
||||
let held: std::collections::HashSet<u64> = machine
|
||||
.workspaces
|
||||
.iter()
|
||||
.flat_map(|ws| ws.tabs.iter())
|
||||
.flat_map(|tab| tab.root.pane_ids())
|
||||
.collect();
|
||||
strays = running
|
||||
.iter()
|
||||
.filter(|info| !held.contains(&info.pane_id))
|
||||
.count();
|
||||
}
|
||||
if strays > 0 {
|
||||
rows.push(vec![
|
||||
"stray panes".to_string(),
|
||||
format!(
|
||||
"{} running that no workspace holds — `tty7 pane ls --all` \
|
||||
names them, `tty7 pane close --orphans` ends them",
|
||||
panes_count(strays)
|
||||
),
|
||||
]);
|
||||
}
|
||||
}
|
||||
server = json!({
|
||||
"reachable": true,
|
||||
"dialect_ok": dialect_ok,
|
||||
"build": hello.build,
|
||||
"orphans": strays,
|
||||
"status": serde_json::to_value(&status)?,
|
||||
"routes": serde_json::to_value(&routes)?,
|
||||
});
|
||||
|
||||
@@ -320,7 +320,7 @@ nothing, so `tty7 agents` shows it standing still and `tty7 wait` sits there
|
||||
until it times out. Outdated hooks fail the same quiet way. Hooks are a local
|
||||
install, so under `-m` the row reads `unknown`.
|
||||
|
||||
JSON: `{"context":{"config_dir","workspace","pane"},"server":{"reachable","dialect_ok","build","status","routes"},"config":{"ok","state","dir_writable","shell_problem"},"hooks":{"installed","outdated","not_installed"}}`
|
||||
JSON: `{"context":{"config_dir","workspace","pane"},"server":{"reachable","dialect_ok","build","orphans","status","routes"},"config":{"ok","state","dir_writable","shell_problem"},"hooks":{"installed","outdated","not_installed"}}`
|
||||
— the context fields are booleans, not values, and each `hooks` field is a list
|
||||
of agent slugs. `context` also carries `workspace_gone` and `pane_gone` when a
|
||||
server answered and could be asked; both are absent when none did, so that "it
|
||||
@@ -329,7 +329,11 @@ false only when the file failed to parse and tty7 is running on defaults;
|
||||
`config.state` is the same sentence the table prints. `config.dir_writable` is
|
||||
probed by writing, not read off the mode bits, because a read-only mount or an
|
||||
ACL leaves a `0700` directory that refuses every write — false means settings
|
||||
cannot be saved and `tty7 new` cannot file a workspace. `config.shell_problem` is null unless the
|
||||
cannot be saved and `tty7 new` cannot file a workspace. `server.orphans` counts the panes the
|
||||
server is running that no workspace holds — an interrupted `run` leaves one,
|
||||
and each is a live shell holding a pty. It is a row and a number, not an exit
|
||||
code: one stray is ordinary, and `tty7 pane close --orphans` ends them.
|
||||
`config.shell_problem` is null unless the
|
||||
configured `shell` names something that cannot be launched — missing, a
|
||||
directory, not executable — in which case every new tab and every `tty7 new`
|
||||
fails; a shell given as a bare name is left to `PATH` and never reported here,
|
||||
|
||||
Reference in New Issue
Block a user