Skip to content

Commit d4be7fa

Browse files
committed
0.5.0
1 parent 76061a1 commit d4be7fa

10 files changed

Lines changed: 175 additions & 77 deletions

File tree

package-lock.json

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "headroom-desktop",
3-
"version": "0.4.6",
3+
"version": "0.5.0-rc.1",
44
"private": true,
55
"type": "module",
66
"scripts": {

src-tauri/Cargo.lock

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src-tauri/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "headroom-desktop"
3-
version = "0.4.6"
3+
version = "0.5.0-rc.1"
44
description = "Headroom v1 local-first LLM optimization tray app"
55
authors = ["Codex"]
66
license = "MIT"

src-tauri/src/lib.rs

Lines changed: 38 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -1922,7 +1922,7 @@ fn debug_force_proxy_bypass(state: State<'_, AppState>, on: bool) -> Result<bool
19221922
}
19231923

19241924
#[tauri::command]
1925-
fn get_headroom_logs(
1925+
async fn get_headroom_logs(
19261926
state: State<'_, AppState>,
19271927
max_lines: Option<usize>,
19281928
) -> Result<Vec<String>, String> {
@@ -1946,7 +1946,7 @@ fn get_headroom_logs(
19461946
/// a transient unreachable → reachable transition would look like a counter
19471947
/// jump from 0 → N and falsely flip the badge to healthy.
19481948
#[tauri::command]
1949-
fn get_headroom_request_count() -> Option<u64> {
1949+
async fn get_headroom_request_count() -> Option<u64> {
19501950
fetch_proxy_request_count_stats()
19511951
}
19521952

@@ -1978,7 +1978,7 @@ fn fetch_proxy_stats_body() -> Option<String> {
19781978
/// proxy's agent id (`claude-code`, `codex`, ...). Used by setup verification
19791979
/// so a prompt sent to one client only flips that client's row, not all rows.
19801980
#[tauri::command]
1981-
fn get_headroom_request_counts_by_agent() -> Option<std::collections::HashMap<String, u64>> {
1981+
async fn get_headroom_request_counts_by_agent() -> Option<std::collections::HashMap<String, u64>> {
19821982
parse_request_counts_by_agent(&fetch_proxy_stats_body()?)
19831983
}
19841984

@@ -2050,7 +2050,7 @@ fn find_u64_key_recursive_local(value: &serde_json::Value, key: &str) -> Option<
20502050
}
20512051

20522052
#[tauri::command]
2053-
fn get_rtk_activity(
2053+
async fn get_rtk_activity(
20542054
state: State<'_, AppState>,
20552055
max_lines: Option<usize>,
20562056
) -> Result<Vec<String>, String> {
@@ -2062,7 +2062,7 @@ fn get_rtk_activity(
20622062
}
20632063

20642064
#[tauri::command]
2065-
fn get_tool_logs(
2065+
async fn get_tool_logs(
20662066
state: State<'_, AppState>,
20672067
tool_id: String,
20682068
max_lines: Option<usize>,
@@ -2075,14 +2075,14 @@ fn get_tool_logs(
20752075
}
20762076

20772077
#[tauri::command]
2078-
fn get_claude_code_projects(state: State<'_, AppState>) -> Result<Vec<ClaudeCodeProject>, String> {
2078+
async fn get_claude_code_projects(state: State<'_, AppState>) -> Result<Vec<ClaudeCodeProject>, String> {
20792079
state
20802080
.list_claude_code_projects()
20812081
.map_err(|err| err.to_string())
20822082
}
20832083

20842084
#[tauri::command]
2085-
fn get_claude_usage(state: State<'_, AppState>) -> Result<ClaudeUsage, String> {
2085+
async fn get_claude_usage(state: State<'_, AppState>) -> Result<ClaudeUsage, String> {
20862086
pricing::fetch_claude_usage(&state)
20872087
}
20882088

@@ -2092,7 +2092,7 @@ fn get_claude_profile(state: State<'_, AppState>) -> ClaudeAccountProfile {
20922092
}
20932093

20942094
#[tauri::command]
2095-
fn get_headroom_pricing_status(
2095+
async fn get_headroom_pricing_status(
20962096
state: State<'_, AppState>,
20972097
) -> Result<HeadroomPricingStatus, String> {
20982098
let status = pricing::get_pricing_status(&state)?;
@@ -2107,7 +2107,7 @@ fn get_headroom_pricing_status(
21072107
}
21082108

21092109
#[tauri::command]
2110-
fn request_headroom_auth_code(
2110+
async fn request_headroom_auth_code(
21112111
app: AppHandle,
21122112
state: State<'_, AppState>,
21132113
email: String,
@@ -2118,7 +2118,7 @@ fn request_headroom_auth_code(
21182118
}
21192119

21202120
#[tauri::command]
2121-
fn verify_headroom_auth_code(
2121+
async fn verify_headroom_auth_code(
21222122
app: AppHandle,
21232123
state: State<'_, AppState>,
21242124
email: String,
@@ -2144,12 +2144,12 @@ fn verify_headroom_auth_code(
21442144
}
21452145

21462146
#[tauri::command]
2147-
fn sign_out_headroom_account() -> Result<(), String> {
2147+
async fn sign_out_headroom_account() -> Result<(), String> {
21482148
pricing::sign_out()
21492149
}
21502150

21512151
#[tauri::command]
2152-
fn activate_headroom_account(
2152+
async fn activate_headroom_account(
21532153
app: AppHandle,
21542154
state: State<'_, AppState>,
21552155
) -> Result<HeadroomPricingStatus, String> {
@@ -2160,7 +2160,7 @@ fn activate_headroom_account(
21602160
}
21612161

21622162
#[tauri::command]
2163-
fn create_headroom_checkout_session(
2163+
async fn create_headroom_checkout_session(
21642164
app: AppHandle,
21652165
subscription_tier: HeadroomSubscriptionTier,
21662166
billing_period: BillingPeriod,
@@ -2177,7 +2177,7 @@ fn create_headroom_checkout_session(
21772177
}
21782178

21792179
#[tauri::command]
2180-
fn change_headroom_subscription_plan(
2180+
async fn change_headroom_subscription_plan(
21812181
app: AppHandle,
21822182
subscription_tier: HeadroomSubscriptionTier,
21832183
billing_period: BillingPeriod,
@@ -2194,14 +2194,14 @@ fn change_headroom_subscription_plan(
21942194
}
21952195

21962196
#[tauri::command]
2197-
fn reactivate_headroom_subscription(app: AppHandle) -> Result<(), String> {
2197+
async fn reactivate_headroom_subscription(app: AppHandle) -> Result<(), String> {
21982198
pricing::reactivate_subscription()?;
21992199
analytics::track_event(&app, "subscription_reactivated", None);
22002200
Ok(())
22012201
}
22022202

22032203
#[tauri::command]
2204-
fn get_headroom_billing_portal_url(target: Option<String>) -> Result<String, String> {
2204+
async fn get_headroom_billing_portal_url(target: Option<String>) -> Result<String, String> {
22052205
pricing::get_billing_portal_url(target)
22062206
}
22072207

@@ -2225,7 +2225,7 @@ fn get_headroom_learn_prereq_status(
22252225
}
22262226

22272227
#[tauri::command]
2228-
fn get_transformations_feed(limit: Option<u32>) -> TransformationFeedResponse {
2228+
async fn get_transformations_feed(limit: Option<u32>) -> TransformationFeedResponse {
22292229
let limit = limit.unwrap_or(50).min(100);
22302230
fetch_transformations_feed(limit).unwrap_or_else(|_| TransformationFeedResponse {
22312231
log_full_messages: false,
@@ -2363,7 +2363,7 @@ fn flatten_applied_bullets(sections: &[crate::models::AppliedSection]) -> Vec<St
23632363
}
23642364

23652365
#[tauri::command]
2366-
fn list_live_learnings(
2366+
async fn list_live_learnings(
23672367
state: State<'_, AppState>,
23682368
project_path: String,
23692369
) -> Result<Vec<crate::models::LiveLearning>, String> {
@@ -2376,7 +2376,7 @@ fn list_live_learnings(
23762376
}
23772377

23782378
#[tauri::command]
2379-
fn list_live_learnings_for_projects(
2379+
async fn list_live_learnings_for_projects(
23802380
state: State<'_, AppState>,
23812381
project_paths: Vec<String>,
23822382
) -> Result<std::collections::HashMap<String, Vec<crate::models::LiveLearning>>, String> {
@@ -2421,7 +2421,7 @@ fn memory_export_cached(state: &State<'_, AppState>, memory_path: &Path) -> Resu
24212421
}
24222422

24232423
#[tauri::command]
2424-
fn delete_live_learning(state: State<'_, AppState>, memory_id: String) -> Result<(), String> {
2424+
async fn delete_live_learning(state: State<'_, AppState>, memory_id: String) -> Result<(), String> {
24252425
let memory_path = headroom_memory_db_path();
24262426
if !memory_path.exists() {
24272427
return Err("Memory database does not exist.".into());
@@ -2450,12 +2450,12 @@ fn delete_live_learning(state: State<'_, AppState>, memory_id: String) -> Result
24502450
}
24512451

24522452
#[tauri::command]
2453-
fn list_applied_patterns(project_path: String) -> Result<crate::models::AppliedPatterns, String> {
2453+
async fn list_applied_patterns(project_path: String) -> Result<crate::models::AppliedPatterns, String> {
24542454
Ok(read_applied_patterns_for_project(&project_path))
24552455
}
24562456

24572457
#[tauri::command]
2458-
fn list_applied_patterns_for_projects(
2458+
async fn list_applied_patterns_for_projects(
24592459
project_paths: Vec<String>,
24602460
) -> Result<std::collections::HashMap<String, crate::models::AppliedPatterns>, String> {
24612461
let mut out = std::collections::HashMap::with_capacity(project_paths.len());
@@ -2477,7 +2477,7 @@ fn read_applied_patterns_for_project(project_path: &str) -> crate::models::Appli
24772477
}
24782478

24792479
#[tauri::command]
2480-
fn delete_applied_pattern(
2480+
async fn delete_applied_pattern(
24812481
project_path: String,
24822482
file_kind: String,
24832483
section_title: String,
@@ -2607,7 +2607,7 @@ fn pattern_matches_project(content: &str, entity_refs: &[String], project_path:
26072607
}
26082608

26092609
#[tauri::command]
2610-
fn start_headroom_learn(
2610+
async fn start_headroom_learn(
26112611
app: AppHandle,
26122612
agent: String,
26132613
project_path: Option<String>,
@@ -2655,7 +2655,7 @@ fn show_dashboard_window(app: AppHandle) -> Result<(), String> {
26552655
}
26562656

26572657
#[tauri::command]
2658-
fn open_headroom_dashboard() -> Result<(), String> {
2658+
async fn open_headroom_dashboard() -> Result<(), String> {
26592659
open_external_link_impl(HEADROOM_DASHBOARD_URL)
26602660
.map_err(|err| format!("Failed to open Headroom dashboard: {err}"))
26612661
}
@@ -2723,7 +2723,7 @@ fn open_external_link_impl(url: &str) -> Result<(), String> {
27232723
}
27242724

27252725
#[tauri::command]
2726-
fn open_external_link(url: String) -> Result<(), String> {
2726+
async fn open_external_link(url: String) -> Result<(), String> {
27272727
open_external_link_impl(&url)
27282728
}
27292729

@@ -2792,7 +2792,7 @@ fn validate_contact_request_url(raw: &str) -> Option<reqwest::Url> {
27922792
}
27932793

27942794
#[tauri::command]
2795-
fn apply_client_setup(app: AppHandle, client_id: String) -> Result<ClientSetupResult, String> {
2795+
async fn apply_client_setup(app: AppHandle, client_id: String) -> Result<ClientSetupResult, String> {
27962796
// Two recovery paths land on the tray-banner "Re-enable" button:
27972797
// 1. Watchdog give-up — pauses the runtime and clears client setups.
27982798
// 2. Pricing gate (grace expiry, weekly cap) — sets `proxy_bypass` and
@@ -2864,17 +2864,17 @@ fn apply_client_setup(app: AppHandle, client_id: String) -> Result<ClientSetupRe
28642864
}
28652865

28662866
#[tauri::command]
2867-
fn verify_client_setup(client_id: String) -> Result<ClientSetupVerification, String> {
2867+
async fn verify_client_setup(client_id: String) -> Result<ClientSetupVerification, String> {
28682868
client_adapters::verify_client_setup(&client_id).map_err(|err| err.to_string())
28692869
}
28702870

28712871
#[tauri::command]
2872-
fn get_client_connectors(state: State<'_, AppState>) -> Result<Vec<ClientConnectorStatus>, String> {
2872+
async fn get_client_connectors(state: State<'_, AppState>) -> Result<Vec<ClientConnectorStatus>, String> {
28732873
client_adapters::list_client_connectors(&state.cached_clients()).map_err(|err| err.to_string())
28742874
}
28752875

28762876
#[tauri::command]
2877-
fn disable_client_setup(app: AppHandle, client_id: String) -> Result<(), String> {
2877+
async fn disable_client_setup(app: AppHandle, client_id: String) -> Result<(), String> {
28782878
client_adapters::disable_client_setup(&client_id).map_err(|err| err.to_string())?;
28792879
analytics::track_event(
28802880
&app,
@@ -2885,12 +2885,12 @@ fn disable_client_setup(app: AppHandle, client_id: String) -> Result<(), String>
28852885
}
28862886

28872887
#[tauri::command]
2888-
fn clear_client_setups() -> Result<(), String> {
2888+
async fn clear_client_setups() -> Result<(), String> {
28892889
client_adapters::clear_client_setups().map_err(|err| err.to_string())
28902890
}
28912891

28922892
#[tauri::command]
2893-
fn pause_headroom(app: AppHandle) -> Result<(), String> {
2893+
async fn pause_headroom(app: AppHandle) -> Result<(), String> {
28942894
let state: tauri::State<'_, AppState> = app.state();
28952895
state.set_runtime_paused(true);
28962896
// A deliberate user pause is not an auto-pause; clear the flag so the
@@ -2903,7 +2903,7 @@ fn pause_headroom(app: AppHandle) -> Result<(), String> {
29032903
}
29042904

29052905
#[tauri::command]
2906-
fn start_headroom(app: AppHandle) -> Result<(), String> {
2906+
async fn start_headroom(app: AppHandle) -> Result<(), String> {
29072907
let state: tauri::State<'_, AppState> = app.state();
29082908
state.resume_runtime().map_err(|err| err.to_string())?;
29092909
std::thread::spawn(|| {
@@ -2920,7 +2920,7 @@ fn start_headroom(app: AppHandle) -> Result<(), String> {
29202920
/// wedged process is actually replaced by a fresh one. This is the one-click
29212921
/// equivalent of the manual quit-and-relaunch users do today.
29222922
#[tauri::command]
2923-
fn force_restart_headroom(app: AppHandle) -> Result<(), String> {
2923+
async fn force_restart_headroom(app: AppHandle) -> Result<(), String> {
29242924
let state: tauri::State<'_, AppState> = app.state();
29252925
state.stop_headroom();
29262926
state.set_runtime_auto_paused(false);
@@ -2941,12 +2941,12 @@ fn hide_launcher_animated(app: AppHandle) {
29412941
}
29422942

29432943
#[tauri::command]
2944-
fn get_autostart_enabled(app: AppHandle) -> Result<bool, String> {
2944+
async fn get_autostart_enabled(app: AppHandle) -> Result<bool, String> {
29452945
app.autolaunch().is_enabled().map_err(|err| err.to_string())
29462946
}
29472947

29482948
#[tauri::command]
2949-
fn set_autostart_enabled(app: AppHandle, enabled: bool) -> Result<bool, String> {
2949+
async fn set_autostart_enabled(app: AppHandle, enabled: bool) -> Result<bool, String> {
29502950
let manager = app.autolaunch();
29512951
if enabled {
29522952
manager.enable().map_err(|err| err.to_string())?;
@@ -2957,7 +2957,7 @@ fn set_autostart_enabled(app: AppHandle, enabled: bool) -> Result<bool, String>
29572957
}
29582958

29592959
#[tauri::command]
2960-
fn set_rtk_enabled(app: AppHandle, enabled: bool) -> Result<bool, String> {
2960+
async fn set_rtk_enabled(app: AppHandle, enabled: bool) -> Result<bool, String> {
29612961
let state: tauri::State<'_, AppState> = app.state();
29622962
client_adapters::set_rtk_enabled(
29632963
enabled,
@@ -5003,7 +5003,7 @@ fn complete_setup_wizard(state: tauri::State<'_, AppState>) {
50035003
}
50045004

50055005
#[tauri::command]
5006-
fn accept_terms(app: AppHandle, version: u32) {
5006+
async fn accept_terms(app: AppHandle, version: u32) {
50075007
// Local acceptance is the authoritative gate (works offline / pre-signin).
50085008
{
50095009
let state: tauri::State<'_, AppState> = app.state();

src-tauri/tauri.conf.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"$schema": "https://schema.tauri.app/config/2",
33
"productName": "Headroom",
4-
"version": "0.4.6",
4+
"version": "0.5.0-rc.1",
55
"identifier": "com.extraheadroom.headroom",
66
"build": {
77
"beforeDevCommand": "npm run dev",

src/App.tsx

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2135,7 +2135,7 @@ export default function App() {
21352135
);
21362136
const learnBlurb =
21372137
claudeLearnEnabled && codexLearnEnabled
2138-
? "Headroom learns from your Claude Code and Codex sessions. When an agent repeats a mistake, Headroom updates that agent's memory — CLAUDE.md / MEMORY.md for Claude Code, AGENTS.md / instructions.md for Codex — so it doesn't happen again."
2138+
? "Headroom learns from your Claude Code and Codex sessions. When an agent repeats a mistake, Headroom updates that agent's memory so it doesn't happen again."
21392139
: codexLearnEnabled
21402140
? "Headroom learns from your Codex sessions. When Codex repeats a mistake, Headroom updates your ~/.codex/AGENTS.md and instructions.md so it doesn't happen again."
21412141
: "Headroom helps Claude Code learn from experience. When Claude makes mistakes, Headroom automatically updates the project's MEMORY.md so they don't happen again. You can also ask Headroom to scan past sessions & add token-saving learnings to CLAUDE.md.";
@@ -5868,8 +5868,9 @@ export default function App() {
58685868
</div>
58695869
</div>
58705870
<p>
5871-
Reverses every change Headroom made: removes the managed Python runtime, the Claude Code
5872-
hook, and restores <code>~/.claude/settings.json</code> changes. Headroom will quit when done.
5871+
Reverses every change Headroom made: removes the managed Python runtime and the shell
5872+
hooks, and restores <code>~/.claude/settings.json</code> and{" "}
5873+
<code>~/.codex/config.toml</code> changes. Headroom will quit when done.
58735874
</p>
58745875
<button
58755876
className="secondary-button secondary-button--small"

0 commit comments

Comments
 (0)