feat(#1298): add hivectl choom verb — interactive claude session in agent container
This commit is contained in:
parent
70832fcbf1
commit
ab65245619
1 changed files with 51 additions and 0 deletions
|
|
@ -15,6 +15,8 @@
|
||||||
//! `hive-c0re` lib — single source of truth, no duplication.
|
//! `hive-c0re` lib — single source of truth, no duplication.
|
||||||
|
|
||||||
use std::path::{Path, PathBuf};
|
use std::path::{Path, PathBuf};
|
||||||
|
#[cfg(unix)]
|
||||||
|
use std::os::unix::process::CommandExt as _;
|
||||||
|
|
||||||
use anyhow::{Context as _, Result, bail};
|
use anyhow::{Context as _, Result, bail};
|
||||||
use clap::{Parser, Subcommand};
|
use clap::{Parser, Subcommand};
|
||||||
|
|
@ -69,6 +71,25 @@ enum Cmd {
|
||||||
#[command(subcommand)]
|
#[command(subcommand)]
|
||||||
cmd: AgentsCmd,
|
cmd: AgentsCmd,
|
||||||
},
|
},
|
||||||
|
/// 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.
|
||||||
|
///
|
||||||
|
/// Pass `--fresh` to start a new Claude session instead of continuing
|
||||||
|
/// the most recent one.
|
||||||
|
Choom {
|
||||||
|
/// Agent name (e.g. `damocles`, `iris`).
|
||||||
|
name: String,
|
||||||
|
/// Start a fresh Claude session instead of continuing the most
|
||||||
|
/// recent one. Without this flag `--continue` is passed to Claude
|
||||||
|
/// so the operator joins the agent's ongoing session context.
|
||||||
|
#[arg(long)]
|
||||||
|
fresh: bool,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Subcommand)]
|
#[derive(Subcommand)]
|
||||||
|
|
@ -292,6 +313,7 @@ async fn main() -> Result<()> {
|
||||||
AgentsCmd::Restart { name, socket } => agents_restart(&socket, &name).await,
|
AgentsCmd::Restart { name, socket } => agents_restart(&socket, &name).await,
|
||||||
AgentsCmd::RestartAll { socket } => agents_restart_all(&socket).await,
|
AgentsCmd::RestartAll { socket } => agents_restart_all(&socket).await,
|
||||||
},
|
},
|
||||||
|
Cmd::Choom { name, fresh } => choom(&name, fresh),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -304,6 +326,35 @@ fn is_agent(name: &str) -> bool {
|
||||||
Coordinator::agent_state_root(name).exists()
|
Coordinator::agent_state_root(name).exists()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// 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.
|
||||||
|
///
|
||||||
|
/// `machinectl shell` inherits the caller's PTY, so the session is
|
||||||
|
/// fully interactive. Requires root and a running container.
|
||||||
|
fn choom(name: &str, fresh: bool) -> Result<()> {
|
||||||
|
if !is_agent(name) {
|
||||||
|
bail!(
|
||||||
|
"no such agent: '{name}' (no state dir under /var/lib/hyperhive/agents/)"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
let container = hive_c0re::lifecycle::container_name(name);
|
||||||
|
let claude = "/run/current-system/sw/bin/claude";
|
||||||
|
let mut cmd = std::process::Command::new("machinectl");
|
||||||
|
cmd.arg("shell").arg(&container).arg(claude);
|
||||||
|
if !fresh {
|
||||||
|
cmd.arg("--continue");
|
||||||
|
}
|
||||||
|
// 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.
|
||||||
|
let err = cmd.exec();
|
||||||
|
Err(anyhow::anyhow!("exec machinectl: {err}"))
|
||||||
|
}
|
||||||
|
|
||||||
async fn forge_create_user(name: &str, password: Option<&str>, password_stdin: bool) -> Result<()> {
|
async fn forge_create_user(name: &str, password: Option<&str>, password_stdin: bool) -> Result<()> {
|
||||||
if !hive_c0re::forge::is_present().await {
|
if !hive_c0re::forge::is_present().await {
|
||||||
bail!(
|
bail!(
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue