Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 16 additions & 2 deletions crates/sharecli-session/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,6 @@ pub mod discovery;
pub mod events;
pub mod layout;
pub mod ledger;
pub mod migration;
pub mod recovery;
pub mod resolver;
pub mod rpc;
Expand Down Expand Up @@ -231,7 +230,22 @@ impl SessionStore {
}
fn init(conn: Connection) -> Result<Self> {
conn.pragma_update(None, "journal_mode", "WAL")?;
migration::run_migrations(&conn)?;
conn.execute_batch(
"CREATE TABLE IF NOT EXISTS sessions (id TEXT PRIMARY KEY, harness TEXT NOT NULL, session_id TEXT NOT NULL, cwd TEXT NOT NULL, resume_json TEXT NOT NULL, confidence TEXT NOT NULL, state TEXT NOT NULL);
CREATE TABLE IF NOT EXISTS session_observations (
seq INTEGER PRIMARY KEY AUTOINCREMENT,
observed_at TEXT NOT NULL,
surface_id TEXT NOT NULL,
surface_json TEXT NOT NULL,
session_json TEXT,
capabilities_json TEXT NOT NULL,
kind TEXT NOT NULL
);
CREATE INDEX IF NOT EXISTS session_observations_surface_seq
ON session_observations(surface_id, seq);
CREATE INDEX IF NOT EXISTS session_observations_time
ON session_observations(observed_at);",
)?;
Ok(Self { conn: Mutex::new(conn) })
}
pub fn upsert(&self, session: &AgentSession) -> Result<()> {
Expand Down
110 changes: 6 additions & 104 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -472,70 +472,6 @@ enum Commands {
#[arg(long)]
dry_run: bool,
},

/// Soft auto-update probe (C11 L111) — report current vs latest
/// advertised version without performing any install. Operators MUST
/// execute the printed `install_hint` themselves (e.g.
/// `cargo install sharecli --force`). Hard signed updates are
/// blocked on L112 secrets.
Upgrade {
/// Only report; never install. Always true (no `--apply` flag yet).
#[arg(long, default_value_t = true)]
check: bool,

/// Channel to advertise (crates-io | binstall | brew | gh-releases)
#[arg(long, default_value = "crates-io")]
channel: String,
},

/// Show recent CLI invocation history (C09 L81.12)
History {
/// Maximum number of entries to display
#[arg(long, default_value_t = 20)]
limit: usize,

/// Output as machine-readable JSON
#[arg(long)]
json: bool,

/// Clear all history entries
#[arg(long)]
clear: bool,
},
/// Harbor soak harness — long-running CLI stability evaluation
Soak {
/// Subcommand: run (default) or report
#[command(subcommand)]
cmd: SoakCmd,
},
}

#[derive(Subcommand, Debug)]
enum SoakCmd {
/// Run the soak harness (executes scenarios repeatedly)
Run {
/// Total duration in seconds (overrides config)
#[arg(short, long)]
duration: Option<u64>,

/// Interval between scenario runs in seconds (overrides config)
#[arg(short, long)]
interval: Option<u64>,

/// Path to soak.yaml config
#[arg(short, long, default_value = "soak.yaml")]
config: std::path::PathBuf,

/// Output path for the JSON report
#[arg(short, long)]
output: Option<std::path::PathBuf>,
},
/// Display an existing soak report
Report {
/// Path to the soak report JSON
#[arg(short, long, default_value = "soak-report.json")]
output: std::path::PathBuf,
},
}

#[derive(Subcommand, Debug)]
Expand Down Expand Up @@ -974,12 +910,7 @@ async fn run() -> Result<()> {
.create(true)
.append(true)
.open(&log_path_for_writer)
.unwrap_or_else(|e| {
panic!(
"failed to reopen log file at {}: {e}",
log_path_for_writer.display()
)
}),
.expect("reopen log file"),
)
};
if json {
Expand Down Expand Up @@ -1102,35 +1033,6 @@ async fn run() -> Result<()> {
};
serve_run(bind, policy).await?
}
Commands::Upgrade { check: _, channel } => {
commands::upgrade::check(Some(channel.as_str()))?;
}
Commands::History { limit, json, clear } => {
let path = commands::history::history_path();
if *clear {
commands::history::clear(&path)?;
eprintln!("History cleared.");
} else {
let entries = commands::history::read_recent(&path, *limit)?;
if entries.is_empty() {
eprintln!("No history entries. CLI invocations are recorded automatically.");
} else if *json {
println!("{}", serde_json::to_string_pretty(&entries).unwrap_or_default());
} else {
for entry in &entries {
println!("{}", commands::history::format_entry(entry));
}
}
}
}
Commands::Soak { cmd } => match cmd {
SoakCmd::Run { duration, interval, config, output } => {
commands::soak::run(*duration, *interval, config, output.as_deref())?;
}
SoakCmd::Report { output } => {
commands::soak::report_cmd(output)?;
}
},
Commands::Thermal { cap } => {
let gov = sharecli_fleet::thermal::ThermalGovernor::new();
let poll_pool_status = move || {
Expand Down Expand Up @@ -1300,9 +1202,9 @@ fn session_cmd(cmd: &SessionCmd) -> Result<()> {
let service = SessionService::new(store);
let value = match cmd {
SessionCmd::List { .. } => serde_json::to_value(service.list()?)?,
SessionCmd::Inspect { .. } => serde_json::to_value(service.inspect(
operation.ok_or_else(|| anyhow::anyhow!("session inspect requires an operation id"))?,
)?)?,
SessionCmd::Inspect { .. } => {
serde_json::to_value(service.inspect(operation.expect("id"))?)?
}
SessionCmd::RecoveryPlan { max_age_seconds, .. } => serde_json::to_value(
service.recovery_plan(chrono::Duration::seconds(*max_age_seconds as i64))?,
)?,
Expand Down Expand Up @@ -1776,8 +1678,8 @@ async fn prune(idle_seconds: u64, force: bool) -> Result<()> {
let processes = pool.list().await;
let now = std::time::SystemTime::now()
.duration_since(std::time::UNIX_EPOCH)
.map(|d| d.as_secs())
.unwrap_or(0);
.expect("system clock before Unix epoch")
.as_secs();

let candidates: Vec<_> = processes
.into_iter()
Expand Down
27 changes: 7 additions & 20 deletions tests/c03_l30_agent_readiness_gate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -61,34 +61,21 @@ fn fr003_l303_fr_guardrail_coverage_and_pin() {
.find("## Measured coverage pin")
.expect("TEST_COVERAGE_MATRIX must have Measured coverage pin section");
let prior_start = matrix
.find("### Prior pin (superseded for current cycle)")
.find("### Prior pin (superseded)")
.expect("TEST_COVERAGE_MATRIX must have Prior pin section");
let measured_section = &matrix[measured_start..prior_start];
assert!(measured_section.contains("77.34%"), "Measured pin section must pin --lib 77.34%");
assert!(measured_section.contains("80.51%"), "Measured pin section must pin 80.51%");
assert!(
measured_section.contains("fa887e9"),
"Measured pin section must pin current source revision fa887e9"
measured_section.contains("e89755c"),
"Measured pin section must pin current source revision e89755c"
);
assert!(
measured_section.contains("fa887e9.coverage-snapshot.json"),
"Measured pin section must reference retained snapshot fa887e9"
);
assert!(
root.join("audit/coverage-snapshots/fa887e9.coverage-snapshot.json").is_file(),
"retained llvm-cov snapshot artifact must exist"
);
// Workspace-broad pin 80.51% @ 5d8dc08 retained as historical evidence.
assert!(
matrix.contains("80.51%"),
"TEST_COVERAGE_MATRIX must retain prior workspace-broad pin 80.51%"
);
assert!(
matrix.contains("5d8dc08"),
"TEST_COVERAGE_MATRIX must retain prior workspace-broad pin sha 5d8dc08"
measured_section.contains("5d8dc08"),
"Measured pin section must reference retained snapshot 5d8dc08"
);
assert!(
root.join("audit/coverage-snapshots/5d8dc08.coverage-snapshot.json").is_file(),
"prior workspace-broad llvm-cov snapshot artifact must exist"
"retained llvm-cov snapshot artifact must exist"
);
assert!(ci.contains("cargo nextest run"), "ci.yml must run nextest guardrail suite");
assert!(justfile.contains("test"), "justfile must expose test recipe");
Expand Down
Loading