From 5200caf21f827387815ba00f4edabfb6c9fd745a Mon Sep 17 00:00:00 2001 From: megaproxy Date: Sat, 9 May 2026 15:00:16 +0100 Subject: [PATCH] Repo cleanup: untrack CLAUDE.md / memory.md (agent-internal); fix README link --- .gitignore | 5 ++++ CLAUDE.md | 30 --------------------- README.md | 3 +-- memory.md | 79 ------------------------------------------------------ 4 files changed, 6 insertions(+), 111 deletions(-) delete mode 100644 CLAUDE.md delete mode 100644 memory.md diff --git a/.gitignore b/.gitignore index 40bad81..d370359 100644 --- a/.gitignore +++ b/.gitignore @@ -47,3 +47,8 @@ src-tauri/target/ src-tauri/Cargo.lock *.tsbuildinfo .vite/ + +# Agent working files — meaningful to local Claude Code sessions, noise for +# anyone else. Kept out of the public repo (they still live on disk). +CLAUDE.md +memory.md diff --git a/CLAUDE.md b/CLAUDE.md deleted file mode 100644 index a633e3e..0000000 --- a/CLAUDE.md +++ /dev/null @@ -1,30 +0,0 @@ -# Project: claude-usage-widget - -A small always-on-top Windows desktop widget that visualizes local Claude Code usage — current 5-hour session block, 7-day rolling weekly window, and per-model token breakdown. Reads `~/.claude/projects/**/*.jsonl` directly (via `\\wsl$\\…` from Windows). No Anthropic API. No auth. - -## Working agreement - -- This is a git repo. Commit after each logical change with a one-line imperative message. -- Read `memory.md` at session start. Update it before ending the session. -- Never commit secrets — see `.gitignore` and the rules in `~/claude/CLAUDE.md`. - -## Project-specific notes - -- **Stack:** Tauri 2 (Rust + Svelte 5 + Vite + TS). Inline SVG for charts, no chart library. -- **Build target:** Windows `.exe` only. Develop the Rust + frontend code in WSL; do `pnpm tauri dev` / `pnpm tauri build` on the Windows host (it needs MSVC toolchain + WebView2). -- **Data source:** `~/.claude/projects/**/*.jsonl` — assistant lines have `message.usage.{input_tokens, output_tokens, cache_creation_input_tokens, cache_read_input_tokens}` and a `requestId` / `uuid` for dedupe (subagent transcripts in `/subagents/.jsonl` overlap the parent). -- **Aggregation algorithm:** ccusage-equivalent. 5-hour blocks are `floor_to_hour(first_ts) → +5h`; new block on ≥5h gap or when previous block ends. Weekly is rolling 7 days. -- **Plan reference:** `~/.claude/plans/snug-mapping-milner.md` (the approved plan that drove this scaffold). - -## Run - -```powershell -# On the Windows host, from this directory: -pnpm install -pnpm tauri dev # iterate -pnpm tauri build # NSIS installer in src-tauri/target/release/bundle/nsis/ -``` - -## Verify - -See `memory.md` and the plan file for the 10-step verification checklist (parse correctness, block boundary, dedupe, live tail, watcher fallback, autostart, etc). diff --git a/README.md b/README.md index 058ac7c..67a6a38 100644 --- a/README.md +++ b/README.md @@ -104,5 +104,4 @@ pnpm tauri dev # iterate pnpm tauri build # produces NSIS installer in src-tauri\target\release\bundle\nsis\ ``` -Project layout, architecture decisions, and known follow-ups live in -[`memory.md`](./memory.md). +Filing issues / pull requests on the Forgejo repo is welcome. diff --git a/memory.md b/memory.md deleted file mode 100644 index cd04e59..0000000 --- a/memory.md +++ /dev/null @@ -1,79 +0,0 @@ -# memory — claude-usage-widget - -Durable memory for this project. Read at session start, update before session end. Date format: `YYYY-MM-DD`. - -## Decisions & rationale - -- **Tauri 2 (Rust + Svelte 5 + Vite + TS)** over Electron — smaller binary (~10 MB vs ~150 MB), native Windows transparency, real always-on-top z-order. Chose Svelte over React because the widget has only three SVG primitives; React boilerplate isn't worth it. -- **Inline SVG, no chart library** — `BlockRing` is one ring, `WeeklyBar` is two stacked progress bars, `ModelStack` is a single segmented bar. Adding Chart.js / ECharts / uPlot for ~80 lines of SVG would balloon the bundle for nothing. -- **Subscription %s come from PTY-driving `claude /usage`** (NOT JSONL estimates, NOT the Anthropic API). The widget spawns `claude` via `portable-pty`, sends `/usage`, parses the three rendered bars (Current session / Current week all / Current week Sonnet), and shows those exact numbers. This is the same data Anthropic shows you in the CLI — no API key, no admin scope, no reverse-engineering of their backend. The trade-off is ~3-5 s per refresh and brittleness if Anthropic changes the rendered output format. Refresh every 5 min by default; manual refresh button on the title bar. -- **Per-model breakdown still comes from local JSONL** — the CLI's `/usage` doesn't break out Opus/Sonnet/Haiku, but our token-summing does. ModelStack remains. -- **Widget runs on Windows host, not in WSLg** — needs to pin to the Windows desktop, autostart on login, and share the always-on-top z-order with native Windows apps. WSLg windows can't do that. JSONL transcripts read via `\\wsl$\\home\\.claude\projects\` UNC mount; the PTY-driven `claude` is invoked via `wsl.exe -d Ubuntu bash -lc claude` (default on Windows when wsl.exe is on PATH). -- **`notify` watcher + 60s tokio poll fallback** — `ReadDirectoryChangesW` on the WSL 9P mount is unreliable; the poll backstops it. -- **All filesystem reads happen Rust-side** — the JS `capabilities/default.json` does NOT grant `tauri-plugin-fs`. Keeps the webview sandbox tight. -- **Block algorithm (still in code, used for ModelStack only)** — `block_start = floor_to_hour(first_ts_of_block)`, `block_end = block_start + 5h`, new block on ≥5h gap OR when previous block ends. ccusage-equivalent. -- **DROPPED: caps + tier-detection UI.** Replaced by real CLI percentages. Caps struct still exists in code as a deprecated fallback but the Settings panel no longer exposes it. - -## Open questions / TODOs - -- [ ] **Watcher does not re-bind on settings change.** If user changes WSL distro override in Settings, `set_settings` calls `refresh_and_emit` and updates `state.roots`, but the `notify` watcher is still pinned to the *old* roots. v0 workaround: restart the widget after changing distro. -- [ ] **`/usage` parser is fragile to output format changes.** If Anthropic changes the rendered text (relabels sections, adds new ones, changes "X% used" pattern), the bars stop parsing silently. Settings panel exposes the raw output for debugging when this happens. -- [ ] **`/usage` spawn cost is ~3-5s on Windows.** That's per refresh; default refresh is 300s so net overhead is fine. Title-bar refresh button gives user control. Consider caching to disk so cold start has *something* before the first PTY drive completes. -- [ ] **Autostart toggle fails in dev builds** (target\debug\ exe path is unstable). Currently swallowed as a warning; needs proper testing once we ship the NSIS bundle. -- [ ] **The default WSL-on-Windows command assumes Ubuntu.** Auto-detect could iterate `wsl.exe -l -q` for any distro that has `claude` on its login PATH, instead of hardcoding `-d Ubuntu`. -- [ ] Decide whether to expose a tray icon for relaunch after `quit_app` (currently the widget can only be reopened via Start Menu / autostart). -- [ ] Window background is too transparent — files behind it bleed through visibly. Bump `--bg` opacity from 0.78 to ~0.92. -- [ ] Replace placeholder Tauri icons in `src-tauri/icons/` before release (`pnpm tauri icon source.png`). -- [ ] Caps struct + Caps::default() are dead code now — delete after a few releases of stability. - -## Session log - -### 2026-05-08 / 2026-05-09 -- Planned the project (approved plan at `~/.claude/plans/snug-mapping-milner.md`) and built the full scaffold in one session that crossed midnight UTC. -- Authored Tauri config (frameless, transparent, alwaysOnTop, skipTaskbar, 280×360), Cargo.toml, capabilities/default.json. -- Authored Rust modules: `state.rs`, `settings.rs`, `paths.rs`, `jsonl.rs`, `usage.rs` (with unit tests for block boundaries), `watch.rs`, `commands.rs`, `lib.rs`, `main.rs`. -- Authored Svelte 5 frontend: `App`, `TitleBar`, `BlockRing`, `WeeklyBar`, `ModelStack`, `Settings` components plus `ipc.ts`, `types.ts`, `format.ts`, `styles.css`. -- Wrote `scripts/seed-fake-jsonl.ps1` verification helper and `README.md` build instructions. -- Pushed to Forgejo at `https://git.rdx4.com/megaproxy/claude-usage-widget`. (Note: had to rename local `master` → `main` after the fact — `git init` ran before the global `init.defaultBranch=main` was set.) -- **First successful run on Windows host (Doug's machine).** Took 4 incremental fixes to get there: - 1. pnpm 11 default-deny on postinstall scripts → declared `pnpm.onlyBuiltDependencies: ["esbuild"]` in `package.json`. - 2. Missing icons → user generated placeholder via PowerShell `System.Drawing` + `pnpm tauri icon`. - 3. `notify::Watcher` trait not in scope (E0599) and `tokio::JoinHandle` ≠ `tauri::async_runtime::JoinHandle` (E0308 ×2) in `watch.rs` — fixed in commit `ab75ca9`. - 4. `tauri-plugin-autostart` doesn't accept a `{"args":[…]}` block in `tauri.conf.json` — args go through the Rust `init()` call only. Removed the JSON entry in commit `8c25b01`. -- **Pivoted from cap estimation to real `/usage` data.** First version showed 999% red ring because the placeholder caps (200k/2M) were wildly under what a Max user actually does. Tier-detection from `.claude.json` improved defaults but still wasn't right; user pointed out they'd previously had an app showing real subscription %. Investigated and found: - - `/usage` slash command output isn't reachable via `claude --print` (LLM intercepts the literal string). - - The data isn't cached anywhere on disk between invocations. - - The OAuth credentials at `~/.claude/.credentials.json` work, but reusing them to call an undocumented endpoint felt fragile. - - **Solution: PTY-drive `claude` itself.** New `src-tauri/src/cli_usage.rs` spawns claude via `portable-pty`, sends `/usage`, parses the three rendered bars (Current session / Current week all / Current week Sonnet). 5-min refresh + manual button. ~3-5s per fetch. (commit `db9a10a`) -- **Bring-up gotchas while wiring the PTY drive on Windows:** - 1. Settings UI was non-interactive earlier because of two compounding bugs — a) Save was silently failing because the autostart plugin threw "OS error 2" in dev builds (target\debug exe path is unstable) and we let it abort the save; b) my PowerShell `mouse_event` clicks weren't reaching WebView2 (legacy API on a transparent borderless host), making me think the user's clicks were broken too. Real-mouse clicks worked once Save stopped getting blocked. Fix: best-effort autostart toggle (commit `9786437`). - 2. `paths::resolve_roots` was canonicalizing UNC paths to `\\?\UNC\…` form, which broke `Path::parent()` and made tier detection silently fail. Stopped canonicalizing (commit `c5c38d1`). - 3. Default `wsl.exe -- claude` invokes a non-interactive non-login shell with no PATH; resolved by defaulting to `wsl.exe -d Ubuntu bash -lc claude` on Windows when wsl.exe is detected (commit `7504990`). The `-d Ubuntu` matters because user's default WSL distro was `docker-desktop` (Alpine; no claude, no bash). - 4. Title bar buttons were inside `data-tauri-drag-region`; needed explicit `data-tauri-drag-region="false"` per button so clicks don't get interpreted as drag-start. -- **Final UX polish (this session):** widget made resizable (220×240 min, 300×320 default), inline-SVG ring scales via viewBox, background opacity bumped to 93% so files behind don't bleed through, scrollbar bug from `border + width: 100vw` overflow killed via `box-sizing: border-box` reset + `body { overflow: hidden }` (commits `f90bb3b`, `c38d895`). -- **Status:** widget is live on Windows showing real subscription percentages (72% session at end of session). 18 commits on `main`, all pushed. User is happy. - -### 2026-05-09 — v0.1.0 release - -- Polish pass for shipping to friends: - - Robust claude command auto-detect: tries native `claude`, then enumerates WSL distros via `wsl.exe -l -q` and probes each via `bash -lc 'command -v claude'`. No more hardcoded `-d Ubuntu`. - - Clear empty-state UI when no claude is reachable (Anthropic install link). - - Real icon: `scripts/make-icon.py` produces a 1024×1024 ring-on-dark monogram. Pillow's multi-res ICO writer was flaky so user re-ran `pnpm tauri icon` to regenerate proper multi-resolution icons. - - System tray icon (left-click = restore window, right-click menu Show/Hide/Refresh/Quit). Solves "lost off-screen" recovery. - - End-user-focused README; build instructions moved to bottom. -- `pnpm tauri build` produced `Claude Usage Widget_0.1.0_x64-setup.exe` (1.7 MB NSIS user-scope installer). -- Created Forgejo release v0.1.0 with the .exe attached. -- Repo flipped to public (per user's explicit request via AskUserQuestion + by trying to do it themselves) so anonymous downloads work. -- Public download URL: https://git.rdx4.com/megaproxy/claude-usage-widget/releases/tag/v0.1.0 -- Toolchain (rust/node/pnpm) NOT installed in this WSL environment — that's expected; the build runs on the Windows host. `cargo check` / `pnpm install` not run from here. - -## External references - -- Forgejo repo: https://git.rdx4.com/megaproxy/claude-usage-widget -- Approved plan: `/home/megaproxy/.claude/plans/snug-mapping-milner.md` -- Tauri 2 prerequisites: https://v2.tauri.app/start/prerequisites/ -- Tauri 2 window customization: https://v2.tauri.app/learn/window-customization/ -- Tauri 2 autostart plugin: https://v2.tauri.app/plugin/autostart/ -- Tauri 2 capabilities: https://v2.tauri.app/security/capabilities/ -- ccusage (algorithm reference): https://github.com/ryoppippi/ccusage -- Claude Max weekly reset issues (context for "rolling 7d" choice): https://github.com/anthropics/claude-code/issues/54974 · https://github.com/anthropics/claude-code/issues/52921