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
2 changes: 1 addition & 1 deletion .coderabbit.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ reviews:
path_instructions:
- path: "crates/**/*.rs"
instructions: >-
Rust, edition 2024 (MSRV 1.85). In runtime (non-test) paths, flag `unwrap`, `expect`,
Rust, edition 2024 (MSRV 1.88). In runtime (non-test) paths, flag `unwrap`, `expect`,
`panic!`, `todo!`, or `unreachable!` unless the condition is proven infallible in local
context; prefer typed errors, logging, or a structured browser error. Failures must be
visible at the right boundary: browser-action failures over HTTP/WebSocket, server/operator
Expand Down
2 changes: 1 addition & 1 deletion AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ Cargo workspace with 7 crates under `crates/`:
- `giskard-server` — Axum backend + the embedded vanilla static web UI (`static/`)

## Conventions
- Edition 2024, MSRV 1.85.
- Edition 2024, MSRV 1.88.
Comment thread
coderabbitai[bot] marked this conversation as resolved.
- All Codex-specific types confined to `giskard-harness-codex`.
- Atomic writes for all persistence (temp file + fsync + rename).
- IDs are ULIDs.
Expand Down
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ default-members = [
version = "0.1.0"
edition = "2024"
license = "MIT"
rust-version = "1.85"
rust-version = "1.88"

[workspace.dependencies]
giskard-core = { path = "crates/giskard-core" }
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ The agent harness is a replaceable component behind a neutral `AgentHarness` tra

## Prerequisites

- **Rust** — edition 2024, MSRV **1.85+** (`rustup` recommended).
- **Rust** — edition 2024, MSRV **1.88+** (`rustup` recommended).
- **Codex CLI**, already installed and authenticated on the machine. Giskard does **not** manage
Codex's credentials — it inherits `~/.codex` (ChatGPT login or an API key / custom provider) when
it spawns the app-server. If Codex isn't configured, turns will fail with an "unauthenticated"
Expand Down
10 changes: 5 additions & 5 deletions crates/giskard-harness-codex/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1270,11 +1270,11 @@ async fn handle_background_server_message(
remaining_active_turns = active_turns.len(),
"Codex turn completion observed"
);
} else if let Some((turn, message)) = fatal_completion {
if emit_fatal_turn_completion(senders, thread, turn, message).await {
active_turns.remove(&thread);
mapper.clear_active_turn(thread);
}
} else if let Some((turn, message)) = fatal_completion
&& emit_fatal_turn_completion(senders, thread, turn, message).await
{
active_turns.remove(&thread);
mapper.clear_active_turn(thread);
}
if let Some(elapsed_ms) = completed_compaction {
return StreamOutcome::CompactionCompleted { thread, elapsed_ms };
Expand Down
24 changes: 12 additions & 12 deletions crates/giskard-harness-codex/src/mapping.rs
Original file line number Diff line number Diff line change
Expand Up @@ -502,10 +502,10 @@ impl CodexMapper {
let thread = self.resolve_thread(&n.thread_id, fallback_thread)?;
let turn = self.resolve_turn(thread, &n.turn_id);
let mut lines = Vec::new();
if let Some(explanation) = &n.explanation {
if !explanation.trim().is_empty() {
lines.push(explanation.clone());
}
if let Some(explanation) = &n.explanation
&& !explanation.trim().is_empty()
{
lines.push(explanation.clone());
}
for step in &n.plan {
lines.push(format!("{}: {}", enum_string(&step.status), step.step));
Expand Down Expand Up @@ -1642,14 +1642,14 @@ fn add_permission_profile_metadata(
if let Some(file_system) = &permissions.file_system {
add_file_system_permissions_metadata(metadata, workspace_root, file_system);
}
if let Some(network) = &permissions.network {
if let Some(enabled) = network.enabled {
add_text_metadata(
metadata,
"Network access",
if enabled { "enabled" } else { "disabled" },
);
}
if let Some(network) = &permissions.network
&& let Some(enabled) = network.enabled
{
add_text_metadata(
metadata,
"Network access",
if enabled { "enabled" } else { "disabled" },
);
}
}

Expand Down
8 changes: 4 additions & 4 deletions crates/giskard-harness-replay/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -265,10 +265,10 @@ impl AgentHarness for ReplayHarness {
fn subscribe(&self, thread: &ThreadHandle) -> AgentEventStream {
// We need to get the sender synchronously. Use try_lock.
let threads = self.threads.try_lock();
if let Ok(threads) = threads {
if let Some((_, state)) = threads.iter().find(|(id, _)| *id == thread.thread) {
return AgentEventStream::new(state.sender.subscribe());
}
if let Ok(threads) = threads
&& let Some((_, state)) = threads.iter().find(|(id, _)| *id == thread.thread)
{
return AgentEventStream::new(state.sender.subscribe());
}
// Fallback: create a dummy channel.
let (_, rx) = broadcast::channel(1);
Expand Down
19 changes: 9 additions & 10 deletions crates/giskard-persist/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -159,17 +159,16 @@ impl ProviderConfig {
/// Resolve the discovery API key: the inline `api_key`, else the value of the env var named by
/// `api_key_env`. Empty values are treated as unset.
pub fn resolve_api_key(&self) -> Option<String> {
if let Some(key) = self.api_key.as_deref() {
if !key.is_empty() {
return Some(key.to_string());
}
if let Some(key) = self.api_key.as_deref()
&& !key.is_empty()
{
return Some(key.to_string());
}
if let Some(var) = self.api_key_env.as_deref() {
if let Ok(val) = std::env::var(var) {
if !val.is_empty() {
return Some(val);
}
}
if let Some(var) = self.api_key_env.as_deref()
&& let Ok(val) = std::env::var(var)
&& !val.is_empty()
{
return Some(val);
}
None
}
Expand Down
8 changes: 4 additions & 4 deletions crates/giskard-persist/src/store.rs
Original file line number Diff line number Diff line change
Expand Up @@ -717,10 +717,10 @@ impl PersistStore {
{
let name = entry.file_name();
let name = name.to_string_lossy();
if let Some(stem) = name.strip_suffix(".json") {
if let Ok(ulid) = stem.parse::<ulid::Ulid>() {
ids.push(ThreadId(ulid));
}
if let Some(stem) = name.strip_suffix(".json")
&& let Ok(ulid) = stem.parse::<ulid::Ulid>()
{
ids.push(ThreadId(ulid));
}
}
Ok(ids)
Expand Down
8 changes: 4 additions & 4 deletions crates/giskard-server/src/bin/giskard-server-replay.rs
Original file line number Diff line number Diff line change
Expand Up @@ -419,10 +419,10 @@ impl AgentHarness for ScriptedHarness {
}

fn subscribe(&self, thread: &ThreadHandle) -> AgentEventStream {
if let Ok(threads) = self.threads.try_lock() {
if let Some((_, tx)) = threads.iter().find(|(id, _)| *id == thread.thread) {
return AgentEventStream::new(tx.subscribe());
}
if let Ok(threads) = self.threads.try_lock()
&& let Some((_, tx)) = threads.iter().find(|(id, _)| *id == thread.thread)
{
return AgentEventStream::new(tx.subscribe());
}
let (_, rx) = broadcast::channel(1);
AgentEventStream::new(rx)
Expand Down
8 changes: 4 additions & 4 deletions crates/giskard-server/src/highlight.rs
Original file line number Diff line number Diff line change
Expand Up @@ -148,10 +148,10 @@ impl Highlighter {
let cache_key = path.to_path_buf();
{
let cache = self.cache.lock().await;
if let Some((_, entry)) = cache.iter().find(|(k, _)| *k == cache_key) {
if entry.mtime == mtime {
return Ok(apply_range(&entry.cached, start_line, end_line));
}
if let Some((_, entry)) = cache.iter().find(|(k, _)| *k == cache_key)
&& entry.mtime == mtime
{
return Ok(apply_range(&entry.cached, start_line, end_line));
}
}

Expand Down
8 changes: 4 additions & 4 deletions crates/giskard-server/src/ledger.rs
Original file line number Diff line number Diff line change
Expand Up @@ -90,10 +90,10 @@ async fn actor(store: Arc<PersistStore>, mut rx: mpsc::Receiver<Record>) {
warn!(%e, "failed to persist global token ledger");
}
for pid in dirty {
if let Some(ledger) = projects.get(&pid) {
if let Err(e) = store.save_project_tokens(pid, ledger).await {
warn!(%pid, %e, "failed to persist project token ledger");
}
if let Some(ledger) = projects.get(&pid)
&& let Err(e) = store.save_project_tokens(pid, ledger).await
{
warn!(%pid, %e, "failed to persist project token ledger");
}
}
}
Expand Down
37 changes: 19 additions & 18 deletions crates/giskard-server/src/linkify.rs
Original file line number Diff line number Diff line change
Expand Up @@ -88,20 +88,21 @@ pub fn linkify_text(text: &str, workspace_root: &Path) -> Vec<LinkSpan> {
}

let resolved = resolve_path(path_str, workspace_root);
if let Some(full_path) = resolved {
if full_path.exists() && full_path.is_file() {
let relative = full_path
.strip_prefix(workspace_root)
.map(|p| p.to_string_lossy().to_string())
.unwrap_or_else(|_| full_path.to_string_lossy().to_string());

spans.push(LinkSpan {
start: mat.start(),
end,
path: relative,
line,
});
}
if let Some(full_path) = resolved
&& full_path.exists()
&& full_path.is_file()
{
let relative = full_path
.strip_prefix(workspace_root)
.map(|p| p.to_string_lossy().to_string())
.unwrap_or_else(|_| full_path.to_string_lossy().to_string());

spans.push(LinkSpan {
start: mat.start(),
end,
path: relative,
line,
});
}
}
spans
Expand All @@ -127,10 +128,10 @@ fn split_line_fragment(candidate: &str) -> (&str, Option<usize>) {
return (candidate, None);
};

if let Some((path, maybe_line)) = before_last_colon.rsplit_once(':') {
if let Some(line) = parse_positive_usize(maybe_line) {
return (path, Some(line));
}
if let Some((path, maybe_line)) = before_last_colon.rsplit_once(':')
&& let Some(line) = parse_positive_usize(maybe_line)
{
return (path, Some(line));
}

(before_last_colon, Some(last_number))
Expand Down
8 changes: 4 additions & 4 deletions crates/giskard-server/src/live_buffer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -200,10 +200,10 @@ fn command_output_item_id(event: &AgentEvent) -> Option<ItemId> {
}

fn compact_completed_command_output(mut event: AgentEvent) -> AgentEvent {
if let AgentEvent::ItemCompleted { item, .. } = &mut event {
if let ItemPayload::CommandExecution { output, .. } = &mut item.payload {
*output = compact_command_output(output);
}
if let AgentEvent::ItemCompleted { item, .. } = &mut event
&& let ItemPayload::CommandExecution { output, .. } = &mut item.payload
{
*output = compact_command_output(output);
}
event
}
Expand Down
Loading
Loading