mirror of
https://github.com/0xrsydn/idx-cli.git
synced 2026-11-07 09:45:36 +00:00
fix(cli): close small JSON-contract gaps for agent consumers
- --offline now warns when it serves a cache entry past its TTL; before, arbitrarily old data was returned with no signal at all - version, cache info and cache clear honour -o json - ownership resolve map/merge honour -o json - stocks quote/compare require at least one symbol instead of printing [] - cache schema-mismatch notice goes through runtime::info so --quiet silences it, instead of a raw debug eprintln Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013Q2PufCUdvVZoVW1Dy53js
This commit is contained in:
parent
793d765e5a
commit
277273bc78
6 changed files with 130 additions and 18 deletions
37
src/cache.rs
37
src/cache.rs
|
|
@ -52,11 +52,7 @@ impl Cache {
|
|||
let Some(entry): Option<CacheEntry<T>> = self.read_entry(data_type, symbol)? else {
|
||||
return Ok(None);
|
||||
};
|
||||
let age = Utc::now().signed_duration_since(entry.fetched_at);
|
||||
if age
|
||||
>= chrono::Duration::from_std(Duration::from_secs(entry.ttl_secs))
|
||||
.map_err(|e| IdxError::CacheMiss(e.to_string()))?
|
||||
{
|
||||
if is_expired(entry.fetched_at, entry.ttl_secs) {
|
||||
return Ok(None);
|
||||
}
|
||||
Ok(Some(entry.data))
|
||||
|
|
@ -70,6 +66,25 @@ impl Cache {
|
|||
Ok(self.read_entry::<T>(data_type, symbol)?.map(|e| e.data))
|
||||
}
|
||||
|
||||
/// Like [`Cache::get_stale`], but warns when the entry served is past its TTL.
|
||||
/// Used by `--offline`, which otherwise serves arbitrarily old data silently.
|
||||
pub fn get_offline<T: DeserializeOwned>(
|
||||
&self,
|
||||
data_type: &str,
|
||||
symbol: &str,
|
||||
) -> Result<Option<T>, IdxError> {
|
||||
let Some(entry) = self.read_entry::<T>(data_type, symbol)? else {
|
||||
return Ok(None);
|
||||
};
|
||||
if is_expired(entry.fetched_at, entry.ttl_secs) {
|
||||
runtime::warn(format!(
|
||||
"offline: serving expired cache for {symbol} (fetched {})",
|
||||
entry.fetched_at.to_rfc3339()
|
||||
));
|
||||
}
|
||||
Ok(Some(entry.data))
|
||||
}
|
||||
|
||||
pub fn put<T: Serialize>(
|
||||
&self,
|
||||
data_type: &str,
|
||||
|
|
@ -184,12 +199,12 @@ impl Cache {
|
|||
}
|
||||
};
|
||||
if entry.schema_version != CURRENT_SCHEMA_VERSION {
|
||||
eprintln!(
|
||||
"debug: cache schema mismatch for {} (got {}, expected {})",
|
||||
runtime::info(format!(
|
||||
"cache schema mismatch for {} (got {}, expected {}), treating as miss",
|
||||
path.display(),
|
||||
entry.schema_version,
|
||||
CURRENT_SCHEMA_VERSION
|
||||
);
|
||||
));
|
||||
let _ = fs::remove_file(&path);
|
||||
return Ok(None);
|
||||
}
|
||||
|
|
@ -201,6 +216,12 @@ impl Cache {
|
|||
}
|
||||
}
|
||||
|
||||
fn is_expired(fetched_at: DateTime<Utc>, ttl_secs: u64) -> bool {
|
||||
let ttl =
|
||||
chrono::Duration::from_std(Duration::from_secs(ttl_secs)).unwrap_or(chrono::Duration::MAX);
|
||||
Utc::now().signed_duration_since(fetched_at) >= ttl
|
||||
}
|
||||
|
||||
pub fn cache_dir() -> Result<PathBuf, IdxError> {
|
||||
if let Ok(dir) = std::env::var("XDG_CACHE_HOME")
|
||||
&& !dir.is_empty()
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue