From c6d8e902f6511f00df06023604d95eb402dfe489 Mon Sep 17 00:00:00 2001 From: megaproxy Date: Sat, 9 May 2026 00:00:26 +0100 Subject: [PATCH] Initial scaffold --- .gitignore | 49 +++++++++++++++++++++++++++++++++++++++++++++++++ CLAUDE.md | 30 ++++++++++++++++++++++++++++++ memory.md | 43 +++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 122 insertions(+) create mode 100644 .gitignore create mode 100644 CLAUDE.md create mode 100644 memory.md diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..40bad81 --- /dev/null +++ b/.gitignore @@ -0,0 +1,49 @@ +# Secrets — never commit +.env +.env.* +!.env.example +*.pem +*.key +*.p12 +*.pfx +secrets/ +credentials/ +.aws/ +.ssh/ + +# Dependencies / build artifacts +node_modules/ +__pycache__/ +*.py[cod] +.venv/ +venv/ +env/ +dist/ +build/ +target/ +*.egg-info/ + +# Editor / OS noise +.DS_Store +Thumbs.db +.vscode/ +.idea/ +*.swp +*.swo + +# Logs / caches +*.log +.cache/ +.pytest_cache/ +.mypy_cache/ +.ruff_cache/ +coverage/ +.coverage +.nyc_output/ + +# Tauri / Vite +src-tauri/gen/ +src-tauri/target/ +src-tauri/Cargo.lock +*.tsbuildinfo +.vite/ diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 0000000..a633e3e --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,30 @@ +# 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/memory.md b/memory.md new file mode 100644 index 0000000..fe0420f --- /dev/null +++ b/memory.md @@ -0,0 +1,43 @@ +# 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 circle, `WeeklyBar` is seven ``s, `ModelStack` is a stacked single-row bar. Adding Chart.js / ECharts / uPlot for ~80 lines of SVG would balloon the bundle for nothing. +- **JSONL-only data source, no Anthropic API** — Anthropic doesn't expose a local cap-state file, but the JSONL transcripts contain everything we need to derive usage (this is what `ccusage` does). Avoids needing an admin key and keeps the widget fully offline. +- **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. The widget reads WSL transcripts via the `\\wsl$\\home\\.claude\projects\` UNC mount. +- **`notify` watcher + 60s tokio poll fallback** — `ReadDirectoryChangesW` on the WSL 9P mount is unreliable; the poll backstops it. 60 s is a pragmatic balance vs CPU. +- **All filesystem reads happen Rust-side** — the JS `capabilities/default.json` does NOT grant `tauri-plugin-fs`. Keeps the webview sandbox tight. +- **Block algorithm** — `block_start = floor_to_hour(first_ts_of_block)`, `block_end = block_start + 5h`, new block on ≥5h gap OR when previous block ends. This matches ccusage and the way Anthropic's docs describe the rolling window. +- **Weekly = rolling 7 days, no calendar anchoring** — Anthropic's reported Max-plan weekly reset day is buggy and shifts (see GH issues #54974, #52921). The honest thing is "past 7 days from now." +- **Caps are user-configurable in Settings** with placeholder defaults (200k tokens / 5h block, 2M tokens / week). No authoritative local source for the real caps. + +## Open questions / TODOs + +- [ ] Tune cap defaults once we have a few weeks of real data — current 200k / 2M values are guesses. +- [ ] Decide whether to expose a tray icon for relaunch after `quit_app` (currently the widget can only be reopened via Start Menu / autostart). +- [ ] Consider whether to fold in the pricing / `$ estimate` view later — out of scope for v0 per user. +- [ ] Verify subagent dedupe assumption: do subagent JSONLs ever contain assistant lines that aren't also in the parent transcript? If yes, we MUST count them; if always duplicate, we MUST skip them. Plan currently uses `requestId || uuid` set, which is safe either way. +- [ ] Replace placeholder Tauri icons in `src-tauri/icons/` before release. + +## Session log + +### 2026-05-08 +- Created project scaffold per the approved plan at `~/.claude/plans/snug-mapping-milner.md`. +- 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`, `watch.rs`, `commands.rs`, `lib.rs`, `main.rs`. +- Authored Svelte frontend: `App`, `TitleBar`, `BlockRing`, `WeeklyBar`, `ModelStack`, `Settings` components plus `ipc.ts`, `types.ts`, `format.ts`. +- Wrote `scripts/seed-fake-jsonl.ps1` verification helper and `README.md` build instructions. +- 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 yet run. + +## External references + +- 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