feat(#2554): add hivectl forge reconcile-config to reconcile local applied config against forge main
This commit is contained in:
parent
11df4a1bf5
commit
d124dd205a
9 changed files with 335 additions and 1 deletions
|
|
@ -2,10 +2,13 @@
|
|||
//! daemon (which owns the forge admin token + account-token persistence);
|
||||
//! hivectl just resolves the password client-side and relays the request.
|
||||
|
||||
use std::io::{self, Write};
|
||||
use std::path::Path;
|
||||
|
||||
use anyhow::Result;
|
||||
use hive_host_sock::{HostRequest, ReconcileDirection};
|
||||
|
||||
use crate::cli::ReconcileFrom;
|
||||
use crate::util::{daemon_request, resolve_password};
|
||||
|
||||
pub(crate) async fn forge_create_user(
|
||||
|
|
@ -29,3 +32,58 @@ pub(crate) async fn forge_create_user(
|
|||
)
|
||||
.await
|
||||
}
|
||||
|
||||
/// `hivectl forge reconcile-config <agent> [--from <forge|local>] [--verbose]`.
|
||||
/// Always shows the divergence first (daemon computes it read-only), then
|
||||
/// applies the chosen direction — from `--from` or an interactive prompt.
|
||||
pub(crate) async fn forge_reconcile_config(
|
||||
socket: &Path,
|
||||
agent: &str,
|
||||
from: Option<ReconcileFrom>,
|
||||
verbose: bool,
|
||||
) -> Result<()> {
|
||||
daemon_request(
|
||||
socket,
|
||||
HostRequest::ReconcileConfigStatus {
|
||||
agent: agent.to_owned(),
|
||||
verbose,
|
||||
},
|
||||
"forge",
|
||||
)
|
||||
.await?;
|
||||
let direction = match from {
|
||||
Some(f) => Some(f.into()),
|
||||
None => prompt_direction()?,
|
||||
};
|
||||
let Some(direction) = direction else {
|
||||
println!("forge: aborted — no changes made");
|
||||
return Ok(());
|
||||
};
|
||||
daemon_request(
|
||||
socket,
|
||||
HostRequest::ReconcileConfigApply {
|
||||
agent: agent.to_owned(),
|
||||
direction,
|
||||
},
|
||||
"forge",
|
||||
)
|
||||
.await
|
||||
}
|
||||
|
||||
/// Prompt the operator for the reconcile direction after showing the diff.
|
||||
/// Returns `None` to abort (empty / `q` / unrecognized input).
|
||||
fn prompt_direction() -> Result<Option<ReconcileDirection>> {
|
||||
print!("reconcile from [forge/local] (or q to abort): ");
|
||||
io::stdout().flush()?;
|
||||
let mut line = String::new();
|
||||
io::stdin().read_line(&mut line)?;
|
||||
match line.trim().to_ascii_lowercase().as_str() {
|
||||
"forge" | "f" => Ok(Some(ReconcileDirection::Forge)),
|
||||
"local" | "l" => Ok(Some(ReconcileDirection::Local)),
|
||||
"" | "q" | "quit" => Ok(None),
|
||||
other => {
|
||||
println!("forge: unrecognized direction {other:?} — aborting");
|
||||
Ok(None)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue