feat: add background version check with local cache#247
Conversation
Non-blocking background version check that queries crates.io on every CLI invocation and displays a one-time update hint when a newer version is available. Runs on a detached background thread with 24h cache TTL. - Background thread spawned before CLI parsing, never blocks execution - Cache at ~/.cache/agentsync/update-check.json with 24h TTL - Hint printed to stderr only on TTY, once per new version - Opt-out via AGENTSYNC_NO_UPDATE_CHECK or CI environment variables - All network/parse errors are silent Closes #242
|
Important Review skippedReview was skipped due to path filters ⛔ Files ignored due to path filters (1)
CodeRabbit blocks several paths by default. You can override this behavior by explicitly including those paths in the path filters. For example, including ⚙️ Run configurationConfiguration used: Organization UI Review profile: ASSERTIVE Plan: Pro Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
📝 WalkthroughWalkthroughIntroduces a non-blocking background update-check feature that spawns a detached thread early in application startup to periodically query crates.io for newer versions of the agentsync crate, caches results for 24 hours, and displays a hint to stderr once per detected version. Changes
Sequence DiagramsequenceDiagram
participant Main as Main Thread
participant BG as Background Thread
participant Cache as File System Cache
participant API as crates.io API
participant Stderr as stderr/TTY
Main->>Main: Initialize logging
Main->>BG: spawn() called
activate BG
BG->>BG: Check AGENTSYNC_NO_UPDATE_CHECK, CI, stderr is TTY
alt Opt-out conditions met
BG->>BG: Return early (skip)
else Checks enabled
BG->>Cache: Load ~/.cache/agentsync/update-check.json
alt Cache missing/invalid
BG->>BG: Cache miss
else Cache valid
BG->>BG: Check 24h TTL + notified_version == latest_version
alt Cache fresh and already notified
BG->>BG: Skip HTTP fetch
end
end
BG->>API: GET /api/v1/crates/agentsync (3s timeout)
alt HTTP success
BG->>BG: Parse newest_version, skip pre-releases
BG->>BG: Compare against CARGO_PKG_VERSION
alt Newer stable version exists
BG->>Cache: Update cache (last_checked, latest_version, notified_version)
BG->>Stderr: Print yellow bold upgrade hint
end
else Network/HTTP error
BG->>BG: Silently drop error
end
end
deactivate BG
Main->>Main: Parse CLI arguments
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes
🚥 Pre-merge checks | ✅ 2 | ❌ 3❌ Failed checks (3 warnings)
✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 14
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@openspec/changes/archive/2026-03-22-background-version-check/design.md`:
- Line 21: Update the spawn-point reference that currently reads
`srC/main.rs:118` to the correct casing `src/main.rs:118` so links and
references point to the valid file; locate and replace the `srC/main.rs:118`
token in the design document (the spawn-point reference) with `src/main.rs:118`.
- Around line 7-12: Add explicit language identifiers to the fenced code blocks
in the design document: change the module tree fence (the block showing
update_check.rs, lib.rs, main.rs) to use a language tag such as ```text (or
```bash) and update any Rust code fences to use ```rust; apply the same fix to
the other fenced blocks mentioned (the additional code/design snippets later in
the file) so all triple-backtick fences include the appropriate language tag.
In `@openspec/changes/archive/2026-03-22-background-version-check/proposal.md`:
- Around line 26-27: The Markdown list item contains a missing space after the
dash: replace the token "-GUI/TTY progress indicators or interactive prompts"
with "- GUI/TTY progress indicators or interactive prompts" so the list
formatting is consistent; locate this string in the proposal.md content and add
the space after the hyphen.
In `@openspec/changes/archive/2026-03-22-background-version-check/tasks.md`:
- Line 108: Update the end-of-file line-count note string "End of file - total
106 lines" to reflect the actual current total lines (including that note line);
locate and replace that literal note in the file so the number matches the
file's true line count.
- Around line 16-19: The guidance incorrectly instructs deriving Copy for the
Cache struct; since Cache contains a PathBuf field (type PathBuf) which is not
Copy, remove Copy from the derive list for Cache (leave Debug and Clone) so the
derive on struct Cache compiles; update any references or documentation that
list Cache as implementing Copy to reflect it is only Clone (and Debug).
- Line 43: Remove the invalid `.daemon(true)` usage from the
std::thread::Builder instruction: update the note that currently reads "`Set
`.daemon(true)` and call `.spawn().ok()` — drop the handle immediately`" to
instead say "`Call `.spawn().ok()` — drop the handle immediately`", since
std::thread::Builder only supports `.name()` and `.stack_size()` and `.daemon()`
is not a valid API; locate references to std::thread::Builder or the exact
phrase containing `.daemon(true)` (e.g., the line with ".daemon(true) and call
.spawn().ok()") and delete the `.daemon(true)` part so the instruction points
only to calling `.spawn().ok()`.
In
`@openspec/changes/archive/2026-03-22-background-version-check/verify-report.md`:
- Around line 10-16: Update the fenced code block that shows the cargo build and
agentsync run (the triple-backtick block containing "$ cargo build --release"
and "$ ./target/release/agentsync --version") to include a language specifier
(e.g., change ``` to ```shell) so the snippet renders with shell/bash syntax
highlighting and improved accessibility in verify-report.md.
In `@openspec/specs/version-check/spec.md`:
- Line 382: The acceptance criteria use the wrong function name; replace
references to spawn_version_check() with the actual integration entrypoint
update_check::spawn() in the spec text so the documented call matches the
implemented function name (update_check::spawn) and any tooling/acceptance
checks will look for the correct symbol.
- Around line 23-27: The spec's cache schema must match the implemented struct:
change `last_checked` from integer to a datetime string (RFC3339/ISO8601) to
represent `DateTime<Utc>`, and rename `notified_version` to
`notified_for_version` to match the struct field; update all other occurrences
mentioned (lines referenced in the review) so the field names and types mirror
the implementation used in update_check.rs (e.g., the struct reading/writing
`last_checked: DateTime<Utc>` and `notified_for_version`).
- Line 130: The spec sentence "When stderr is not a TTY, the system SHALL still
perform the background check and cache updates, but SHALL NOT print output."
conflicts with the implementation that performs an early return when stderr is
not a TTY; reconcile by choosing one behavior and making both doc and code
match: either (A) update the implementation to remove the early return and
ensure the version-check function still performs background check/cache updates
while suppressing prints when stderr is not a TTY, or (B) update this spec
sentence to state that the system will early-return (skip background check/cache
updates) when stderr is not a TTY; apply the chosen change consistently (spec
text and implementation branch where the early return lives) and update any
related tests or documentation that reference "stderr is not a TTY" or the early
return behavior.
In `@src/lib.rs`:
- Line 14: The update_check module is exposed publicly but should be
crate-private; change its declaration from pub mod update_check to pub(crate)
mod update_check so external consumers cannot access internal implementation
details (e.g., update_check::spawn()); update any external usages within the
crate if needed to maintain access.
In `@src/update_check.rs`:
- Around line 14-22: The CheckedVersion struct has redundant serde rename
attributes for last_checked, latest_version, and notified_for_version because
the Rust field names already match the JSON keys; remove the three
#[serde(rename = "...")] attributes from the CheckedVersion definition so it
relies on default serde field name mapping (keep the struct, derives, and field
types intact) to simplify the code.
- Around line 45-52: The cache_path() function uses the Unix-only HOME env var
and should be made cross-platform; update cache_path to use a platform-aware
cache directory (e.g., dirs::cache_dir() or dirs_next::cache_dir()) and then
join "agentsync" and "update-check.json" (instead of directly reading HOME), and
if dirs::cache_dir() returns None fall back to using
std::env::var_os("USERPROFILE") or a safe default directory (not "."), and add
the chosen dirs crate to Cargo.toml; reference the cache_path function when
making these changes.
- Around line 94-105: The crates.io request is missing a User-Agent header;
update the reqwest blocking Client builder used around the client creation (the
builder chain that currently sets timeout in the code constructing client and
used to call client.get(CRATES_IO_URL)) to include a default header for
"User-Agent" (e.g. "agentsync/<version>" or "agentsync/<version>
(contact@example.com)"). Add the header via the builder (so all requests from
that client include it) before .build(), ensuring the client used for
client.get(CRATES_IO_URL) sends the User-Agent with the request.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: ASSERTIVE
Plan: Pro
Run ID: 3a6a6145-9c6e-4b4e-ba3b-71bea2bb1465
📒 Files selected for processing (12)
Cargo.tomlopenspec/changes/archive/2026-03-22-background-version-check/ARCHIVE.txtopenspec/changes/archive/2026-03-22-background-version-check/design.mdopenspec/changes/archive/2026-03-22-background-version-check/exploration.mdopenspec/changes/archive/2026-03-22-background-version-check/proposal.mdopenspec/changes/archive/2026-03-22-background-version-check/specs/version-check/spec.mdopenspec/changes/archive/2026-03-22-background-version-check/tasks.mdopenspec/changes/archive/2026-03-22-background-version-check/verify-report.mdopenspec/specs/version-check/spec.mdsrc/lib.rssrc/main.rssrc/update_check.rs
| ``` | ||
| src/ | ||
| update_check.rs # New module (pub(crate)) | ||
| lib.rs # Add: pub(crate) mod update_check | ||
| main.rs # Add: update_check::spawn() call | ||
| ``` |
There was a problem hiding this comment.
Add language identifiers to fenced code blocks.
These fences are missing language tags, which is currently triggering markdownlint MD040 warnings.
Also applies to: 76-103, 109-121, 205-207
🧰 Tools
🪛 markdownlint-cli2 (0.21.0)
[warning] 7-7: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@openspec/changes/archive/2026-03-22-background-version-check/design.md`
around lines 7 - 12, Add explicit language identifiers to the fenced code blocks
in the design document: change the module tree fence (the block showing
update_check.rs, lib.rs, main.rs) to use a language tag such as ```text (or
```bash) and update any Rust code fences to use ```rust; apply the same fix to
the other fenced blocks mentioned (the additional code/design snippets later in
the file) so all triple-backtick fences include the appropriate language tag.
|
|
||
| ### Spawn Point | ||
|
|
||
| `srC/main.rs:118` — after `tracing_subscriber::fmt::init()`, before `Cli::parse()`. |
There was a problem hiding this comment.
Fix incorrect file path casing in spawn-point reference.
srC/main.rs:118 should be src/main.rs:118; the current path is invalid and can misdirect readers.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@openspec/changes/archive/2026-03-22-background-version-check/design.md` at
line 21, Update the spawn-point reference that currently reads `srC/main.rs:118`
to the correct casing `src/main.rs:118` so links and references point to the
valid file; locate and replace the `srC/main.rs:118` token in the design
document (the spawn-point reference) with `src/main.rs:118`.
| -GUI/TTY progress indicators or interactive prompts | ||
| - Cross-crate version comparison (only checks agentsync) |
There was a problem hiding this comment.
Minor typo: missing space.
Line 26 has "-GUI/TTY" which should be "- GUI/TTY" (space after dash for consistent list formatting).
📝 Proposed fix
-- Automatic updates (no self-update mechanism)
--GUI/TTY progress indicators or interactive prompts
+- Automatic updates (no self-update mechanism)
+- GUI/TTY progress indicators or interactive prompts🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@openspec/changes/archive/2026-03-22-background-version-check/proposal.md`
around lines 26 - 27, The Markdown list item contains a missing space after the
dash: replace the token "-GUI/TTY progress indicators or interactive prompts"
with "- GUI/TTY progress indicators or interactive prompts" so the list
formatting is consistent; locate this string in the proposal.md content and add
the space after the hyphen.
| - Derive `Debug, Serialize, Deserialize]` on `CheckedVersion` | ||
| - Define `Cache` struct with `path: PathBuf` field | ||
| - Derive `Debug, Clone, Copy)]` on `Cache` | ||
| - Verify: `cargo check` shows no errors in the new file |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -euo pipefail
# 1) Find Cache struct definitions and fields.
rg -n --type=rust -C3 'struct\s+Cache\s*\{'
# 2) Find derive attributes attached to Cache.
rg -n --type=rust -C2 '#\[derive\([^\)]*\)\]\s*struct\s+Cache\b'Repository: dallay/agentsync
Length of output: 284
Remove Copy from the Cache derive guidance.
The task instructs to derive Debug, Clone, Copy on Cache, but Cache contains a PathBuf field, which does not implement Copy. This derive guidance is invalid and cannot compile.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@openspec/changes/archive/2026-03-22-background-version-check/tasks.md` around
lines 16 - 19, The guidance incorrectly instructs deriving Copy for the Cache
struct; since Cache contains a PathBuf field (type PathBuf) which is not Copy,
remove Copy from the derive list for Cache (leave Debug and Clone) so the derive
on struct Cache compiles; update any references or documentation that list Cache
as implementing Copy to reflect it is only Clone (and Debug).
| - Return early if `CI` env var equals `"true"` (case-insensitive) | ||
| - Return early if `stderr` is not a TTY | ||
| - Spawn a detached thread named `"agentsync-update-check"` using `thread::Builder` | ||
| - Set `.daemon(true)` and call `.spawn().ok()` — drop the handle immediately |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -euo pipefail
# 1) Verify whether repository code uses a non-existent daemon() thread API.
rg -n --type=rust '\.daemon\s*\('
# 2) Inspect thread spawn usage in update-check implementation.
rg -n --type=rust -C3 'thread::Builder::new\(\)|\.name\(|\.spawn\('Repository: dallay/agentsync
Length of output: 42
🏁 Script executed:
# Check if the file exists and read its content
find . -name "tasks.md" -path "*2026-03-22-background-version-check*" 2>/dev/nullRepository: dallay/agentsync
Length of output: 131
🌐 Web query:
Rust std::thread::Builder daemon method API
💡 Result:
The Rust standard library's std::thread::Builder does not have a daemon method or any equivalent API for creating daemon threads. Rust threads are not daemon threads by default; all non-main threads continue running until explicitly joined or the main thread exits, which terminates the entire process. The Builder only supports configuring name (Builder::name) and stack_size (Builder::stack_size), plus some unstable/experimental features like spawn hooks.
Citations:
- 1: https://doc.rust-lang.org/std/thread/struct.Builder.html
- 2: https://doc.rust-lang.org/src/std/thread/builder.rs.html
- 3: https://doc.rust-lang.org/nightly/std/thread/struct.Builder.html
- 4: https://doc.rust-lang.org/std/thread/
- 5: https://doc.rust-lang.org/stable/std/thread/struct.Builder.html
🏁 Script executed:
cat -n ./openspec/changes/archive/2026-03-22-background-version-check/tasks.md | sed -n '35,50p'Repository: dallay/agentsync
Length of output: 1474
Remove .daemon(true) from the thread-builder instruction on line 43.
std::thread::Builder does not provide a .daemon(true) API. The standard library only supports .name() and .stack_size() configuration methods. Following this documentation would result in a compilation error.
- Set `.daemon(true)` and call `.spawn().ok()` — drop the handle immediately
Should be:
- Call `.spawn().ok()` — drop the handle immediately
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@openspec/changes/archive/2026-03-22-background-version-check/tasks.md` at
line 43, Remove the invalid `.daemon(true)` usage from the std::thread::Builder
instruction: update the note that currently reads "`Set `.daemon(true)` and call
`.spawn().ok()` — drop the handle immediately`" to instead say "`Call
`.spawn().ok()` — drop the handle immediately`", since std::thread::Builder only
supports `.name()` and `.stack_size()` and `.daemon()` is not a valid API;
locate references to std::thread::Builder or the exact phrase containing
`.daemon(true)` (e.g., the line with ".daemon(true) and call .spawn().ok()") and
delete the `.daemon(true)` part so the instruction points only to calling
`.spawn().ok()`.
|
|
||
| ## Acceptance Criteria | ||
|
|
||
| 1. `spawn_version_check()` is called from `main()` before CLI parsing |
There was a problem hiding this comment.
Use the correct function name in acceptance criteria.
spawn_version_check() does not match the documented integration call (update_check::spawn()), which can cause incorrect acceptance verification.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@openspec/specs/version-check/spec.md` at line 382, The acceptance criteria
use the wrong function name; replace references to spawn_version_check() with
the actual integration entrypoint update_check::spawn() in the spec text so the
documented call matches the implemented function name (update_check::spawn) and
any tooling/acceptance checks will look for the correct symbol.
| pub mod linker; | ||
| pub mod mcp; | ||
| pub mod skills; | ||
| pub mod update_check; |
There was a problem hiding this comment.
🧹 Nitpick | 🔵 Trivial
Consider pub(crate) visibility for internal module.
The update_check module is declared as pub mod, making it part of the library's public API. However, the proposal specifies pub(crate) mod update_check since this is an internal implementation detail for the CLI binary. External library consumers shouldn't need to call update_check::spawn().
♻️ Proposed visibility fix
-pub mod update_check;
+pub(crate) mod update_check;📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| pub mod update_check; | |
| pub(crate) mod update_check; |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@src/lib.rs` at line 14, The update_check module is exposed publicly but
should be crate-private; change its declaration from pub mod update_check to
pub(crate) mod update_check so external consumers cannot access internal
implementation details (e.g., update_check::spawn()); update any external usages
within the crate if needed to maintain access.
| #[derive(Debug, Clone, Serialize, Deserialize)] | ||
| struct CheckedVersion { | ||
| #[serde(rename = "last_checked")] | ||
| last_checked: i64, | ||
| #[serde(rename = "latest_version")] | ||
| latest_version: String, | ||
| #[serde(rename = "notified_for_version")] | ||
| notified_for_version: Option<String>, | ||
| } |
There was a problem hiding this comment.
🧹 Nitpick | 🔵 Trivial
Redundant #[serde(rename = "...")] attributes.
The rename attributes are unnecessary since the field names already match the JSON keys exactly. Consider removing them for cleaner code.
♻️ Proposed simplification
#[derive(Debug, Clone, Serialize, Deserialize)]
struct CheckedVersion {
- #[serde(rename = "last_checked")]
last_checked: i64,
- #[serde(rename = "latest_version")]
latest_version: String,
- #[serde(rename = "notified_for_version")]
notified_for_version: Option<String>,
}📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| #[derive(Debug, Clone, Serialize, Deserialize)] | |
| struct CheckedVersion { | |
| #[serde(rename = "last_checked")] | |
| last_checked: i64, | |
| #[serde(rename = "latest_version")] | |
| latest_version: String, | |
| #[serde(rename = "notified_for_version")] | |
| notified_for_version: Option<String>, | |
| } | |
| #[derive(Debug, Clone, Serialize, Deserialize)] | |
| struct CheckedVersion { | |
| last_checked: i64, | |
| latest_version: String, | |
| notified_for_version: Option<String>, | |
| } |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@src/update_check.rs` around lines 14 - 22, The CheckedVersion struct has
redundant serde rename attributes for last_checked, latest_version, and
notified_for_version because the Rust field names already match the JSON keys;
remove the three #[serde(rename = "...")] attributes from the CheckedVersion
definition so it relies on default serde field name mapping (keep the struct,
derives, and field types intact) to simplify the code.
| fn cache_path() -> PathBuf { | ||
| let home = std::env::var_os("HOME") | ||
| .map(PathBuf::from) | ||
| .unwrap_or_else(|| PathBuf::from(".")); | ||
| home.join(".cache") | ||
| .join("agentsync") | ||
| .join("update-check.json") | ||
| } |
There was a problem hiding this comment.
Cross-platform compatibility: HOME is not set on Windows.
The cache_path() function relies on the HOME environment variable, which is Unix-specific. On Windows, USERPROFILE or LOCALAPPDATA should be used instead. Additionally, the fallback to "." (current directory) could lead to unexpected cache file locations.
Consider using the dirs or home crate for cross-platform home directory detection, or add USERPROFILE as a fallback.
🛠️ Proposed cross-platform fix
fn cache_path() -> PathBuf {
- let home = std::env::var_os("HOME")
- .map(PathBuf::from)
- .unwrap_or_else(|| PathBuf::from("."));
+ let home = std::env::var_os("HOME")
+ .or_else(|| std::env::var_os("USERPROFILE"))
+ .map(PathBuf::from)
+ .unwrap_or_else(|| PathBuf::from("."));
home.join(".cache")
.join("agentsync")
.join("update-check.json")
}🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@src/update_check.rs` around lines 45 - 52, The cache_path() function uses the
Unix-only HOME env var and should be made cross-platform; update cache_path to
use a platform-aware cache directory (e.g., dirs::cache_dir() or
dirs_next::cache_dir()) and then join "agentsync" and "update-check.json"
(instead of directly reading HOME), and if dirs::cache_dir() returns None fall
back to using std::env::var_os("USERPROFILE") or a safe default directory (not
"."), and add the chosen dirs crate to Cargo.toml; reference the cache_path
function when making these changes.
| let client = match reqwest::blocking::Client::builder() | ||
| .timeout(std::time::Duration::from_secs(3)) | ||
| .build() | ||
| { | ||
| Ok(c) => c, | ||
| Err(_) => return, | ||
| }; | ||
|
|
||
| let response = match client.get(CRATES_IO_URL).send() { | ||
| Ok(r) => r, | ||
| Err(_) => return, | ||
| }; |
There was a problem hiding this comment.
🧩 Analysis chain
🌐 Web query:
crates.io API User-Agent requirements
💡 Result:
crates.io requires all API requests to include a User-Agent header that identifies the application or bot making the requests. This requirement was implemented in 2019 via a code change to enforce the header on API endpoints (excluding cargo build for compatibility). The User-Agent should uniquely identify your application, preferably including contact information (e.g., "my-bot (help@mybot.com)") to allow the crates.io team to reach out if issues arise. Generic headers like "reqwest/0.9.1" are insufficient. Additionally, API usage is subject to rate limits: maximum 1 request per second. Exceeding this or causing service impact may result in blocking. Prefer using the crates.io index (https://github.com/rust-lang/crates.io-index) or database dumps for bulk data access when possible. Examples of compliant User-Agents from crates.io error messages and client libraries: - "my_crawler (my_crawler.com/info)" - "crates_io_api_client (github.com/theduke/crates-io-api)"
Citations:
- 1: Require a User-Agent header, take 2 rust-lang/crates.io#1696
- 2: Add required user-agent to crates-io lib api (breaking change) rust-lang/cargo#6969
- 3: https://crates.io/data-access
- 4: https://docs.rs/crates_io_api/latest/crates_io_api/
- 5: https://doc.rust-lang.org/cargo/reference/registry-web-api.html
- 6: Publish an official crawler policy rust-lang/crates.io#1535
- 7: https://rust-lang.github.io/rfcs/3463-crates-io-policy-update.html
🏁 Script executed:
cat -n src/update_check.rs | sed -n '90,110p'Repository: dallay/agentsync
Length of output: 846
🏁 Script executed:
grep -n "CRATES_IO_URL\|User-Agent\|user_agent" src/update_check.rsRepository: dallay/agentsync
Length of output: 207
🏁 Script executed:
rg "user_agent|User-Agent" src/Repository: dallay/agentsync
Length of output: 42
Add User-Agent header for crates.io API requests.
The crates.io API requires all requests to include a User-Agent header identifying the client. Without it, requests may be rate-limited or rejected. The current code lacks this header.
🛠️ Proposed fix to add User-Agent header
let client = match reqwest::blocking::Client::builder()
.timeout(std::time::Duration::from_secs(3))
+ .user_agent(concat!(env!("CARGO_PKG_NAME"), "/", env!("CARGO_PKG_VERSION")))
.build()
{
Ok(c) => c,
Err(_) => return,
};Alternatively, consider including contact information in the User-Agent for better support: "agentsync/version (contact@example.com)".
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| let client = match reqwest::blocking::Client::builder() | |
| .timeout(std::time::Duration::from_secs(3)) | |
| .build() | |
| { | |
| Ok(c) => c, | |
| Err(_) => return, | |
| }; | |
| let response = match client.get(CRATES_IO_URL).send() { | |
| Ok(r) => r, | |
| Err(_) => return, | |
| }; | |
| let client = match reqwest::blocking::Client::builder() | |
| .timeout(std::time::Duration::from_secs(3)) | |
| .user_agent(concat!(env!("CARGO_PKG_NAME"), "/", env!("CARGO_PKG_VERSION"))) | |
| .build() | |
| { | |
| Ok(c) => c, | |
| Err(_) => return, | |
| }; | |
| let response = match client.get(CRATES_IO_URL).send() { | |
| Ok(r) => r, | |
| Err(_) => return, | |
| }; |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@src/update_check.rs` around lines 94 - 105, The crates.io request is missing
a User-Agent header; update the reqwest blocking Client builder used around the
client creation (the builder chain that currently sets timeout in the code
constructing client and used to call client.get(CRATES_IO_URL)) to include a
default header for "User-Agent" (e.g. "agentsync/<version>" or
"agentsync/<version> (contact@example.com)"). Add the header via the builder (so
all requests from that client include it) before .build(), ensuring the client
used for client.get(CRATES_IO_URL) sends the User-Agent with the request.
|



Non-blocking background version check that queries crates.io on every CLI invocation and displays a one-time update hint when a newer version is available. Runs on a detached background thread with 24h cache TTL.
Closes #242