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
//! Resolution of `tmux` and agent-command binaries on `PATH` (and cron's minimal `PATH`), split
//! out of `command.rs` to keep that file under the line-count gate.
/// Return the first directory on the daemon's `PATH` that contains an executable named `bin`.
pub
/// Return the first directory in the `:`-separated `path` list that contains a file named `bin`.
///
/// Split out from [`bin_dir`] so the resolution logic is injectable in tests: callers can point
/// `path` at a temp dir with or without a fake binary without mutating the process-global `PATH`.
pub
/// Whether `tmux` resolves to a file on the given `:`-separated `path` list.
///
/// `tmux` is a hard runtime dependency: routine launches run `tmux new-session … \; pipe-pane …`
/// and a missing `tmux` would be silently ignored (the statement is one of several `;`-joined
/// steps), making the run a no-op. This helper surfaces its presence so startup can warn and
/// `GET /health` can report it.
/// Injectable for tests via the `path` argument; see [`tmux_available`] for the live-`PATH` variant.
pub
/// Whether `tmux` resolves on the daemon's live `PATH`. Returns `false` when `PATH` is unset.
pub
/// Whether `command` resolves to a file on the given `:`-separated `path` list.
///
/// Generalizes [`tmux_available_in`] to an arbitrary executable name: a routine's agent `command`
/// (e.g. `claude`, `codex`) is launched the same way `tmux` is — unresolved, it makes the cron
/// firing a silent no-op. Used to distinguish "agent config present" from "agent binary actually
/// runnable" in [`crate::routines::model::RoutineResponse`]. Injectable for tests via the `path` argument;
/// see [`agent_command_available`] for the live-`PATH` variant.
pub
/// Whether `command` resolves on the daemon's live `PATH`. Returns `false` when `PATH` is unset.
pub
/// The first whitespace-delimited token of an agent's `setup` step — the interpreter or binary it
/// shells out to (e.g. `python3` for the built-in `claude` agent's workspace-trust seeding). `None`
/// for an empty/all-whitespace `setup` string.
///
/// `setup` is inserted verbatim into the launch command (see
/// [`super::build_routine_command`]), so this is a best-effort probe, not a shell parse:
/// it only catches the common "the step shells out to an interpreter that isn't installed" case
/// (issue #404), not every way a `setup` step can fail.
pub
/// Whether an agent's `setup` step (if any) is safe to run: either there is no `setup` step, or
/// its [`setup_step_interpreter`] resolves on the daemon's live `PATH`. Mirrors
/// [`agent_command_available`] so a routine whose `setup` step would fail before the agent ever
/// launches (e.g. the built-in `claude` agent's `setup` shelling out to a missing `python3`) is
/// distinguishable from one that would actually run — see [`crate::routines::model::RoutineResponse`].
pub
/// Common install locations to probe for `tmux` when it is not on `path` at all.
///
/// Split out so [`resolve_tmux_bin_from`] can be exercised in tests against fake, temp-dir-anchored
/// fallback lists instead of these real absolute paths (which may or may not hold a real `tmux` on
/// the machine running the tests).
pub
/// Best-effort absolute path to `tmux`: first dir on `path` holding it, else the first of
/// `fallback_dirs` holding it, else the bare `"tmux"` name.
///
/// Injectable variant of [`resolve_tmux_bin`] for tests. Mirrors the fallback list [`cron_path`]
/// bakes into crontab lines: launchd/systemd start the daemon with a minimal `PATH`
/// (`/usr/bin:/bin:/usr/sbin:/sbin`) that hides a Homebrew- or npm-installed `tmux`, so the
/// daemon's own tmux probes (`routines::cleanup::session`) would otherwise always fail to find it
/// — every liveness check then reads as "not running", so a hung run's workbench gets TTL-reaped
/// while the real tmux session and agent process are never killed and become permanently
/// untracked. Returning the bare `"tmux"` name when it cannot be found anywhere leaves the
/// caller's `Command::new` failing exactly as before.
pub
/// Live-`PATH`/`HOME` variant of [`resolve_tmux_bin_from`]; see its docs for why this exists.
pub
/// A short `PATH` for cron, since cron's default (`/usr/bin:/bin`) hides homebrew/npm-installed
/// tools like `tmux` and the agent binary.
///
/// Baking the daemon's full inherited `PATH` is not viable: it can exceed cron's per-line length
/// limit (~1000 chars) and silently disable the job. Instead this resolves just the dirs holding
/// `tmux` and the agent `command`, then appends common tool locations and the cron defaults,
/// deduplicated and order-preserving — short enough to stay well under the limit.
pub