feat: clean-room rewrite — replace ported modules with original implementations

Every Rust module under src/ that previously contained upstream-derivative
code has been replaced by a from-scratch implementation:

  diag/    log + simplelog file appender (was: diagnose.rs)
  os/      color, dpi, registry, string, theme (was: theme.rs, native_interop.rs)
  net/     WinHTTP-based HTTP client (was: ureq + native-tls)
  i18n/    TOML-embedded locale tables (was: localization/*.rs)
  usage/   trait UsageProvider + ClaudeProvider + ChatGptProvider + refresh
           orchestrator + registry (was: poller.rs, models.rs)
  creds/   trait CredentialSource + local/WSL/Codex impls (was: poller.rs)
  tray/    stateless tray manager + tiny-skia anti-aliased badge renderer
           (was: tray_icon.rs)
  update/  release fetch + inline cmd /c handoff installer
           (was: updater.rs's helper-exe pattern)

Application files (app.rs, bubble.rs, panel.rs, settings.rs) migrated to
the new modules. main.rs declares only the new modules.

NOTICE deleted; LICENSE is plain Apache-2.0; README updated to credit
inspiration rather than claim derivation. Cargo.toml drops ureq + native-tls
+ winres in favour of log + simplelog + thiserror + toml + tiny-skia +
embed-resource. Build script swapped to embed-resource via res/icon.rc.

External contracts preserved unchanged: Anthropic + ChatGPT endpoints and
headers, ~/.claude/.credentials.json + Codex auth.json paths, WSL bridging
via wsl.exe, CLI-driven token refresh, GitHub Releases JSON shape, Windows
registry path for startup, single-instance mutex name.

Phase docs: plans/260516-0707-cleanroom-rewrite/.
This commit is contained in:
2026-05-16 10:09:43 +07:00
parent c0f3e3f860
commit aa6217d2cf
72 changed files with 6265 additions and 3788 deletions
+9 -7
View File
@@ -18,9 +18,11 @@ use windows::Win32::UI::HiDpi::*;
use windows::Win32::UI::Shell::ExtractIconExW;
use windows::Win32::UI::WindowsAndMessaging::*;
use crate::diagnose;
use crate::native_interop::{wide_str, Color, TIMER_FULLSCREEN_CHECK};
use crate::tray_icon::TrayIconKind;
use crate::os::{to_utf16_nul as wide_str, Rgb as Color};
const TIMER_FULLSCREEN_CHECK: usize = 5;
use crate::usage::ProviderId;
type TrayIconKind = ProviderId;
// ---------- Public types & API ----------
@@ -58,7 +60,7 @@ pub fn register_class() {
..Default::default()
};
if RegisterClassExW(&wc) == 0 {
diagnose::log("bubble RegisterClassExW returned 0");
log::error!("bubble RegisterClassExW returned 0");
}
});
}
@@ -98,7 +100,7 @@ pub fn create(config: BubbleConfig) -> HWND {
};
if hwnd == HWND::default() {
diagnose::log("bubble CreateWindowExW failed");
log::error!("bubble CreateWindowExW failed");
return hwnd;
}
@@ -807,8 +809,8 @@ fn default_position(size_px: i32, model: TrayIconKind) -> (i32, i32) {
};
let gap = 24;
let stagger = match model {
TrayIconKind::Claude => 0,
TrayIconKind::Codex => size_px + gap,
ProviderId::Claude => 0,
ProviderId::ChatGpt => size_px + gap,
};
let x = wa.right - size_px - gap;
let y = wa.bottom - size_px - gap - stagger;