Status LEDs, image model selection, backup restore, provider test, monthly versions

- Sidebar: three status LEDs (server, models, MCP) with an overview popover (/api/status)
- Images: preview stage, purpose-based model choice and reference images
  (Nano Banana Pro edit refines the chosen preview)
- Settings: restore a stored or uploaded backup (staged, applied on restart)
- Provider form: test connection; saving or reloading re-checks the status at once
- opencode Zen/Go: send x-opencode-session with a stable id per conversation
- Releases are named vYYYYMM-NNNNN; scripts/release.sh numbers, tags, builds and publishes
- Fix: backups made in the same second no longer overwrite each other

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Richard ZinkandClaude Opus 5.5 committed 2026-11-09 09:31:24 +01:00
1 parent 49d404eec7
commit 1f69d63b09
35 files changed
+1156 -88

No files matched your search

+43
View File
@@ -0,0 +1,43 @@
//! Release version. Releases are named vYYYYMM-NNNNN (a counter per month, from 00001);
//! the release build sets CODECRAFT_VERSION (without the leading "v"). Builds without it
//! (development) fall back to the crate version.
pub const VERSION: &str = match option_env!("CODECRAFT_VERSION") {
Some(v) if !v.is_empty() => v,
_ => env!("CARGO_PKG_VERSION"),
};
/// Sort key: monthly releases (YYYYMM-NNNNN) come after the old semantic versions.
fn key(v: &str) -> (u8, Vec<u64>) {
let v = v.trim().trim_start_matches('v');
if let Some((month, n)) = v.split_once('-')
&& month.len() == 6
&& month.chars().all(|c| c.is_ascii_digit())
&& !n.is_empty()
&& n.chars().all(|c| c.is_ascii_digit())
{
return (1, vec![month.parse().unwrap_or(0), n.parse().unwrap_or(0)]);
}
(0, v.split(['.', '-']).take(3).map(|x| x.parse::<u64>().unwrap_or(0)).collect())
}
/// Is version `a` newer than `b`? Accepts both schemes, with or without "v".
pub fn newer(a: &str, b: &str) -> bool {
key(a) > key(b)
}
#[cfg(test)]
mod tests {
use super::newer;
#[test]
fn compares_monthly_and_semver() {
assert!(newer("v202611-00002", "202611-00001"));
assert!(newer("v202612-00001", "v202611-00042"));
assert!(!newer("v202611-00001", "202611-00001"));
assert!(newer("v202611-00001", "0.1.0"));
assert!(!newer("0.9.9", "v202611-00001"));
assert!(newer("v0.2.0", "0.1.9"));
assert!(newer("1.0.0", "0.9.9"));
}
}