fix: hivectl choom enters as the agent user from the state dir so claude gets creds + session
This commit is contained in:
parent
d25f2779e8
commit
c59a0de01e
3 changed files with 62 additions and 17 deletions
|
|
@ -73,11 +73,19 @@ enum Cmd {
|
|||
},
|
||||
/// Open an interactive Claude session inside an agent container.
|
||||
///
|
||||
/// Replaces the current process with `machinectl shell h-<name>`
|
||||
/// running `claude --continue` — drops the operator straight into
|
||||
/// the agent's live Claude session with its full loaded context and
|
||||
/// persona. Requires root (same as all machinectl shell operations)
|
||||
/// and the container must be running.
|
||||
/// Replaces the current process with `machinectl shell
|
||||
/// <name>@h-<name>` running `claude --continue` from the agent's
|
||||
/// state dir — drops the operator straight into the agent's live
|
||||
/// Claude session with its full loaded context and persona. Requires
|
||||
/// root (same as all machinectl shell operations) and the container
|
||||
/// must be running.
|
||||
///
|
||||
/// The session is entered **as the agent user** (not root): claude
|
||||
/// reads its OAuth credentials + settings from the agent's
|
||||
/// `/home/<name>/.claude`, and the working directory is set to the
|
||||
/// agent's state dir (`/agents/<name>/state`) so `--continue`
|
||||
/// resumes the same per-project session the harness runs. Entering
|
||||
/// as root (the `machinectl shell` default) is what loses both.
|
||||
///
|
||||
/// Pass `--fresh` to start a new Claude session instead of continuing
|
||||
/// the most recent one.
|
||||
|
|
@ -357,10 +365,24 @@ fn is_agent(name: &str) -> bool {
|
|||
|
||||
/// Drop into an interactive Claude session in the agent container.
|
||||
///
|
||||
/// Replaces the current process (exec) with `machinectl shell h-<name>
|
||||
/// /run/current-system/sw/bin/claude [--continue]`. The `--continue`
|
||||
/// flag is passed by default so the operator joins the agent's active
|
||||
/// session; omit it via `--fresh` to start a blank session instead.
|
||||
/// Replaces the current process (exec) with `machinectl shell
|
||||
/// <name>@h-<name> /bin/sh -lc 'cd /agents/<name>/state && exec claude
|
||||
/// [--continue]'`. Two things matter here, both of which the naive
|
||||
/// `machinectl shell h-<name> claude` got wrong (issue: choom missing
|
||||
/// creds + settings):
|
||||
///
|
||||
/// 1. **Run as the agent user.** `machinectl shell` defaults to root in
|
||||
/// the container, so claude would read `/root/.claude` (empty)
|
||||
/// instead of the agent's `/home/<name>/.claude` where the OAuth
|
||||
/// credentials + settings live. Prefixing the machine with
|
||||
/// `<name>@` enters the session as the agent user (the meta-flake
|
||||
/// sets `hyperhive.user.name` to the agent label, so the unix user
|
||||
/// name matches the agent name).
|
||||
/// 2. **Start in the agent's state dir.** `claude --continue` resumes
|
||||
/// the most recent session *for the current project directory*. The
|
||||
/// harness runs claude from `/agents/<name>/state`, so choom has to
|
||||
/// `cd` there or `--continue` finds no session (it would look under
|
||||
/// the user's home instead).
|
||||
///
|
||||
/// `machinectl shell` inherits the caller's PTY, so the session is
|
||||
/// fully interactive. Requires root and a running container.
|
||||
|
|
@ -369,12 +391,25 @@ fn choom(name: &str, fresh: bool) -> Result<()> {
|
|||
bail!("no such agent: '{name}' (no state dir under /var/lib/hyperhive/agents/)");
|
||||
}
|
||||
let container = hive_c0re::lifecycle::container_name(name);
|
||||
// The agent's unix user name matches its agent name (meta-flake
|
||||
// sets `hyperhive.user.name = <label>`); enter the session as that
|
||||
// user so claude sees the right `$HOME/.claude`.
|
||||
let target = format!("{name}@{container}");
|
||||
let claude = "/run/current-system/sw/bin/claude";
|
||||
// In-container state dir (host `/var/lib/hyperhive/agents/<name>/state`
|
||||
// is bind-mounted here); matches `hive-ag3nt::paths::state_dir()`.
|
||||
let state_dir = format!("/agents/{name}/state");
|
||||
let continue_flag = if fresh { "" } else { " --continue" };
|
||||
// `cd` so `--continue` resolves the harness's per-project session;
|
||||
// `exec` replaces the shell with claude so it owns the PTY directly.
|
||||
// `name` is constrained to `[a-z0-9._-]` so there's nothing to quote.
|
||||
let inner = format!("cd {state_dir} && exec {claude}{continue_flag}");
|
||||
let mut cmd = std::process::Command::new("machinectl");
|
||||
cmd.arg("shell").arg(&container).arg(claude);
|
||||
if !fresh {
|
||||
cmd.arg("--continue");
|
||||
}
|
||||
cmd.arg("shell")
|
||||
.arg(&target)
|
||||
.arg("/bin/sh")
|
||||
.arg("-lc")
|
||||
.arg(&inner);
|
||||
// exec() replaces the current process — we inherit stdin/stdout/stderr
|
||||
// (the caller's PTY) so the Claude session is fully interactive.
|
||||
// This call only returns on error.
|
||||
|
|
|
|||
Loading…
Reference in a new issue