Skip to content

Commit e724ee8

Browse files
gmoonclaude
andcommitted
Add auto-update support, update README install docs
Auto-update: enabled via ~/.lattice/config.yaml (auto_update: true) or LATTICE_AUTO_UPDATE=1 env var. When enabled, silently updates instead of printing the notice. Disabled by default. Update notice now mentions auto-update option. README: added Updating section with auto-update docs, updated install description for ~/.local/bin default, updated status line. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent 4f09d79 commit e724ee8

2 files changed

Lines changed: 85 additions & 5 deletions

File tree

README.md

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -113,13 +113,29 @@ DRIFT DETECTED:
113113
curl -fsSL https://forkzero.ai/lattice/install.sh | sh
114114
```
115115

116+
Installs to `~/.local/bin` (no sudo required). Falls back to `/usr/local/bin` when writable (Docker, CI).
117+
116118
**Windows (PowerShell):**
117119
```powershell
118120
irm https://forkzero.ai/lattice/install.ps1 | iex
119121
```
120122

121123
Or download from [GitHub Releases](https://github.com/forkzero/lattice/releases).
122124

125+
### Updating
126+
127+
```bash
128+
lattice update # Update to latest
129+
lattice update --check # Check without installing
130+
```
131+
132+
Enable auto-update in `~/.lattice/config.yaml`:
133+
```yaml
134+
auto_update: true
135+
```
136+
137+
Or per-session: `LATTICE_AUTO_UPDATE=1`
138+
123139
<details>
124140
<summary>Platform-specific binaries</summary>
125141

@@ -248,7 +264,7 @@ lattice export --audience overview
248264

249265
## Status
250266

251-
**v0.2.1** — Adversarial debate (rebuts/concedes edges, contested status, confidence history), messages (persona-specific claims grounded in theses), unified health check, change pressure assessment, schema versioning.
267+
**v0.2.6** — Adversarial debate, persona messaging, unified health check with code impact tracking, auto-update, sudo-free installs.
252268

253269
See [docs/STRATEGIC_VISION.md](docs/STRATEGIC_VISION.md) for the full vision.
254270

src/update.rs

Lines changed: 68 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -374,6 +374,56 @@ fn write_check_state(path: &std::path::Path, state: &UpdateCheckState) {
374374
.and_then(|json| std::fs::write(path, json).ok());
375375
}
376376

377+
/// Check if auto-update is enabled via env var or user config.
378+
///
379+
/// Priority: LATTICE_AUTO_UPDATE env var > ~/.lattice/config.yaml > default (false)
380+
fn is_auto_update_enabled() -> bool {
381+
// Env var takes priority
382+
if let Ok(val) = std::env::var("LATTICE_AUTO_UPDATE") {
383+
return val == "1" || val.eq_ignore_ascii_case("true");
384+
}
385+
386+
// Check user config at ~/.lattice/config.yaml
387+
let home = std::env::var("HOME")
388+
.or_else(|_| std::env::var("USERPROFILE"))
389+
.ok();
390+
if let Some(home) = home {
391+
let config_path = std::path::PathBuf::from(home)
392+
.join(".lattice")
393+
.join("config.yaml");
394+
if let Ok(contents) = std::fs::read_to_string(&config_path)
395+
&& let Ok(config) = serde_yaml::from_str::<serde_yaml::Value>(&contents)
396+
&& let Some(auto) = config.get("auto_update")
397+
{
398+
return auto.as_bool().unwrap_or(false);
399+
}
400+
}
401+
402+
false
403+
}
404+
405+
/// Attempt a silent auto-update. Returns true if update succeeded.
406+
fn run_silent_auto_update() -> bool {
407+
let rt = match tokio::runtime::Runtime::new() {
408+
Ok(rt) => rt,
409+
Err(_) => return false,
410+
};
411+
412+
let options = UpdateOptions {
413+
check_only: false,
414+
force: false,
415+
target_version: None,
416+
};
417+
418+
match rt.block_on(run_update(options)) {
419+
Ok(UpdateResult::Updated { from, to }) => {
420+
eprintln!(" {} v{} → v{}", "Auto-updated:".green().bold(), from, to);
421+
true
422+
}
423+
_ => false,
424+
}
425+
}
426+
377427
fn print_update_notice(current: &Version, latest: &Version) {
378428
eprintln!();
379429
eprintln!(
@@ -382,7 +432,11 @@ fn print_update_notice(current: &Version, latest: &Version) {
382432
format!("v{}", current).dimmed(),
383433
format!("v{}", latest).green().bold()
384434
);
385-
eprintln!(" Run {} to install", "lattice update".cyan());
435+
eprintln!(
436+
" Run {} to install, or enable {} in ~/.lattice/config.yaml",
437+
"lattice update".cyan(),
438+
"auto_update: true".cyan()
439+
);
386440
eprintln!();
387441
}
388442

@@ -413,15 +467,21 @@ pub fn maybe_notify_update(command_name: Option<&str>) {
413467
let current = current_version();
414468
let now = chrono::Utc::now();
415469

470+
let auto_update = is_auto_update_enabled();
471+
416472
// Check cache first
417473
if let Some(state) = read_check_state(&cache_path) {
418474
let age = now.signed_duration_since(state.last_checked);
419475
if age < chrono::Duration::hours(24) {
420-
// Cache is fresh — show notice if newer version exists
476+
// Cache is fresh — auto-update or show notice if newer version exists
421477
if let Ok(latest) = Version::parse(&state.latest_version)
422478
&& latest > current
423479
{
424-
print_update_notice(&current, &latest);
480+
if auto_update {
481+
run_silent_auto_update();
482+
} else {
483+
print_update_notice(&current, &latest);
484+
}
425485
}
426486
return;
427487
}
@@ -450,7 +510,11 @@ pub fn maybe_notify_update(command_name: Option<&str>) {
450510
},
451511
);
452512
if latest > current {
453-
print_update_notice(&current, &latest);
513+
if auto_update {
514+
run_silent_auto_update();
515+
} else {
516+
print_update_notice(&current, &latest);
517+
}
454518
}
455519
}
456520
Err(_) => {

0 commit comments

Comments
 (0)