Repo cleanup: untrack CLAUDE.md / memory.md (agent-internal); fix README link

This commit is contained in:
megaproxy 2026-05-09 15:00:16 +01:00
parent dbf77a0cec
commit 5200caf21f
4 changed files with 6 additions and 111 deletions

5
.gitignore vendored
View file

@ -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

View file

@ -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$\<distro>\…` 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 `<sessionId>/subagents/<id>.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).

View file

@ -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.

View file

@ -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$\<distro>\home\<user>\.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