Skip to content

Commit b32489a

Browse files
authored
Source Code for Ver 1.1.0
Refactoring the App with webview UI.
1 parent e0cb7e9 commit b32489a

50 files changed

Lines changed: 8904 additions & 956 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

AGENTS.md

Lines changed: 76 additions & 207 deletions
Original file line numberDiff line numberDiff line change
@@ -1,207 +1,76 @@
1-
AGENTS.md
2-
3-
Agent Guidelines for OpenCode Token Meter
4-
=======================================
5-
6-
Purpose
7-
-------
8-
This document orients agents and contributors to the OpenCode Token Meter repository.
9-
It summarizes build/run/test commands, coding style expectations, database safety rules,
10-
and the exact deduplication behavior implemented in the agent.
11-
12-
Workdir
13-
-------
14-
Repository root: the working directory where AGENTS.md lives (example):
15-
`/Users/<you>/Desktop/OpenCode Token Meter`
16-
17-
Quick commands
18-
--------------
19-
- Build (production):
20-
- From repo root: `./build.sh` — builds both agent and menubar with PyInstaller
21-
- Development build (agent):
22-
- `cd App/agent` then:
23-
- `python3 -m PyInstaller --onefile --name opencode-agent agent/__main__.py`
24-
- Development build (menubar):
25-
- `cd App/menubar` then:
26-
- `python3 -m PyInstaller -y --clean opencode-menubar.spec`
27-
- Clean build artifacts:
28-
- `rm -rf build/ App/menubar/dist/ App/menubar/build/`
29-
- `rm -rf App/agent/dist/ App/agent/build/`
30-
- `rm -f opencode-agent.spec`
31-
32-
Run (development)
33-
-----------------
34-
- Run agent (development):
35-
- `cd App/agent` then `python3 -m agent`
36-
- Run menubar (development):
37-
- `cd App/menubar` then `python3 -m menubar`
38-
39-
Syntax / quick checks
40-
---------------------
41-
- Quick syntax check for a file:
42-
- `python3 -m py_compile <path>` e.g. `python3 -m py_compile App/agent/agent/db.py`
43-
- Run a small import test for menubar:
44-
- `cd App/menubar && python3 -c "from menubar.app import OpenCodeTokenMeter, SettingsDialog; print('Import successful')"`
45-
46-
Database paths and inspection
47-
-----------------------------
48-
- Default DB path used by code: `~/Library/Application Support/OpenCode Token Meter/index.db`
49-
- Socket path: `~/Library/Application Support/OpenCode Token Meter/agent.sock`
50-
- Inspect DB with sqlite3 CLI:
51-
- `sqlite3 "~/Library/Application Support/OpenCode Token Meter/index.db" ".tables"`
52-
- Run queries with: `sqlite3 "<path>" "SELECT ...;"`
53-
54-
Testing
55-
-------
56-
- Currently there are no unit tests in the repository by default. Recommended patterns:
57-
- Use pytest for unit tests.
58-
- Example single-test run:
59-
- `python -m pytest tests/test_db_dedup.py::test_deduped_counts -q`
60-
- Suggested test files to add:
61-
1. `tests/test_db_dedup.py` — exercises dedup SQL on a temporary SQLite DB.
62-
2. `tests/test_settings_dialog.py` — basic tests for SettingsDialog behavior (preset vs custom).
63-
3. `tests/test_uds_client.py` — socket/client integration checks against a running agent (optional).
64-
65-
Linting and formatting
66-
----------------------
67-
- Recommended tools and commands:
68-
- Black: `black .` (88 char line length by default)
69-
- isort: `isort .` (use to keep imports grouped)
70-
- flake8: `flake8 .` (project specific ignores can be added)
71-
- mypy: `mypy .` (optional — gradually adopt for public APIs)
72-
73-
Code style guidelines (for agents)
74-
---------------------------------
75-
Follow these rules to keep changes consistent and predictable for automated agents.
76-
77-
1) Imports
78-
- Group imports: stdlib → third-party → local
79-
- Use absolute imports inside packages (e.g. `from agent.config import DB_PATH`)
80-
- Keep import statements at top of file except for guarded imports (platform/bundled checks)
81-
82-
2) Formatting
83-
- Use Black formatting (88 char width). Keep simple, machine-enforced style.
84-
- Use isort for import ordering.
85-
86-
3) Naming
87-
- Files/modules: `snake_case.py`
88-
- Classes: `PascalCase`
89-
- Functions/Methods: `snake_case()`
90-
- Constants: `UPPER_SNAKE_CASE`
91-
92-
4) Type hints
93-
- Prefer lightweight type hints on public APIs. Be pragmatic — gradual typing is fine.
94-
- Annotate return types for functions that are part of the public package surface.
95-
96-
5) SQL and DB safety
97-
- Always use parameterized queries for user-supplied values: `?` placeholders in sqlite3.
98-
- Avoid f-strings or string concatenation to build SQL with external inputs.
99-
- Use `get_conn()` helper patterns and close connections (use context managers).
100-
- Enable WAL mode: `conn.execute("PRAGMA journal_mode=WAL;")` near connection initialization.
101-
- Keep long-running transactions off the UI thread (menubar). Do DB work in a worker thread or the agent.
102-
103-
6) Error handling
104-
- Catch specific exceptions where possible (e.g. `sqlite3.OperationalError`).
105-
- Log errors to stderr: `print(f"Error: {e}", file=sys.stderr)`.
106-
- Fail gracefully in the UI: return empty data structures rather than raising uncaught exceptions.
107-
108-
7) Tests
109-
- Write unit tests for DB logic (dedup, aggregates) and small integration tests for UDS client/server.
110-
- Keep tests isolated: create temporary files/DBs and remove them after tests.
111-
112-
8) Git / PR expectations
113-
- Create small focused PRs with a single logical change.
114-
- Commit messages: present-tense, short summary + optional body. Example: `docs: add AGENTS.md with build/lint/test commands`
115-
- Run `python -m py_compile` and `black .` before pushing.
116-
117-
Deduplication details (exact behavior)
118-
-------------------------------------
119-
Deduplication is implemented entirely at the database query level to avoid double counting messages
120-
that OpenCode sometimes duplicates across sessions.
121-
122-
- Implementation location: `App/agent/agent/db.py`
123-
- Function: `_get_deduplicated_messages_subquery(where_clause="")`
124-
- Other aggregates updated to use deduped subquery: `aggregate()`, `aggregate_range()`,
125-
`aggregate_by_provider()`, `aggregate_by_model()`, `get_message_count*`, `get_request_count*`.
126-
127-
- Dedup rule (precise):
128-
- Group messages by the following stable fields:
129-
- `ts, role, input, output, reasoning, cache_read, cache_write, provider_id, model_id`
130-
- For each group keep the row whose `msg_id` is lexicographically smallest (SQL: `HAVING msg_id = MIN(msg_id)`).
131-
- The aggregates and exports operate over this deduplicated derived table (subquery).
132-
133-
Why this approach
134-
------------------
135-
- OpenCode can copy the same message into multiple sessions — these duplicates are identical for all token/usage
136-
relevant fields but differ in `msg_id` and sometimes `session_id`.
137-
- Grouping by token-relevant fields and selecting a deterministic canonical `msg_id` prevents double counting
138-
while preserving one representative record for exports.
139-
140-
Performance & optional DB improvements
141-
-------------------------------------
142-
- Consider adding a composite index to speed the dedup query:
143-
- `CREATE INDEX IF NOT EXISTS idx_dedup ON messages(ts, role, input, output, reasoning, cache_read, cache_write, provider_id, model_id);`
144-
- Optionally create a view for debugging:
145-
- `CREATE VIEW IF NOT EXISTS dedup_messages AS SELECT * FROM (<dedup subquery>);`
146-
147-
Files of interest (where to look first)
148-
--------------------------------------
149-
- Agent DB + dedup: `App/agent/agent/db.py`
150-
- Agent config: `App/agent/agent/config.py`
151-
- Menubar app & SettingsDialog: `App/menubar/menubar/app.py`
152-
- Menubar settings helpers: `App/menubar/menubar/settings.py`
153-
154-
Recommended unit tests to add (starter outlines)
155-
----------------------------------------------
156-
1) tests/test_db_dedup.py
157-
- Create a temporary sqlite DB file and a `messages` table with the same schema.
158-
- Insert multiple duplicate rows (same ts, role, inputs/outputs, provider/model, different msg_id and session_id).
159-
- Run the aggregate function(s) or run the dedup subquery and assert duplicates collapse.
160-
161-
2) tests/test_settings_dialog.py (UI-level, minimal)
162-
- Instantiate `SettingsDialog` in a headless Qt test harness (or mock UI state).
163-
- Assert selecting a preset model fills and disables provider/model inputs.
164-
- Assert selecting `Custom model` clears and enables provider/model inputs.
165-
166-
3) tests/test_agent_socket.py (integration)
167-
- Start the agent in subprocess mode (dev binary), connect with `menubar/uds_client.AgentClient`, verify `is_online()`.
168-
169-
How to run a single test file
170-
-----------------------------
171-
- With pytest installed:
172-
- `python -m pytest tests/test_db_dedup.py -q`
173-
- Or a single test function: `python -m pytest tests/test_db_dedup.py::test_deduped_counts -q`
174-
175-
Cursor/Copilot hints
176-
--------------------
177-
- Check for workspace-specific AI/cursor rules in these locations (if present, include or adapt):
178-
- `.cursor/`, `.cursorrules`, `.github/copilot-instructions.md`
179-
180-
Agent checklist for changes
181-
---------------------------
182-
When making code changes, follow this checklist:
183-
1. Run `python -m py_compile` on modified files.
184-
2. Run `black .` and `isort .`.
185-
3. Add or update unit tests; run them locally with `pytest`.
186-
4. Ensure SQL uses parameterized placeholders for external inputs.
187-
5. Update AGENTS.md if workflows or build commands change.
188-
189-
Suggested next steps (pick one)
190-
1) Add `AGENTS.md` (done) and run the quick syntax checks:
191-
- `python3 -m py_compile App/agent/agent/db.py`
192-
- `python3 -m py_compile App/menubar/menubar/app.py`
193-
2) Add unit tests for the dedup SQL (suggested path: `tests/test_db_dedup.py`).
194-
3) Add the composite index and/or the `dedup_messages` view to speed debugging.
195-
196-
Notes & caveats
197-
---------------
198-
- The dedup approach uses `ts` (integer seconds). If messages have sub-second precision, consider
199-
adjusting the grouping key.
200-
- The canonicalization uses `MIN(msg_id)`. If `msg_id` ordering is non-deterministic in some environments,
201-
consider switching to `MIN(rowid)` or a deterministic tiebreaker.
202-
203-
Contact
204-
-------
205-
If anything in this document is unclear, open an issue or ask in the repository's primary communication channel.
206-
207-
End of AGENTS.md
1+
# AGENTS.md — Developer Guidance
2+
3+
This document codifies how to work with the **OpenCode Token Meter** codebase. It covers development, testing, and build requirements for both macOS and Windows.
4+
5+
---
6+
7+
## 1) Execution & Development Workflow
8+
9+
### Running in Development Mode
10+
11+
To run the application directly from source:
12+
13+
```bash
14+
# macOS/Windows
15+
python App/webview_ui/main_tray.py --debug
16+
```
17+
18+
*Note: The tray application will automatically start the background agent and stats worker as threads.*
19+
20+
### Environment Requirements
21+
22+
- **Python**: 3.9+
23+
- **Conda Environment**: Recommended to use the `opencode` environment.
24+
- **Dependencies**:
25+
- `pip install pyinstaller pywebview pystray pillow pyperclip`
26+
- macOS specific: `pip install rumps pyobjc-framework-Cocoa`
27+
- Windows specific: `pip install win10toast`
28+
29+
---
30+
31+
## 2) Component Architecture
32+
33+
- **Agent**: Monitors `~/.local/share/opencode/storage/message/` (all platforms) for new JSON messages.
34+
- **Stats Worker**: Periodically aggregates database data for the tray display.
35+
- **Webview UI**: Frontend built with HTML/CSS/JS (Tailwind, Chart.js, Lato font), communicating with Python via a `JsApi` bridge.
36+
- **Database**: Local SQLite database stored at:
37+
- macOS: `~/Library/Application Support/OpenCode Token Meter/index.db`
38+
- Windows: `%APPDATA%\OpenCode Token Meter\index.db`
39+
40+
---
41+
42+
## 3) Testing & Verification
43+
44+
### Manual GUI Checklist
45+
46+
Before releasing, verify the following:
47+
48+
1. **Startup**: App launches into the system tray/menubar.
49+
2. **Webview**: Selecting "Show Dashboard" opens the UI window.
50+
3. **Data**: Counters (In/Out/Cost) update correctly after message activity.
51+
4. **Theme**: Verify dark mode aesthetics and high-weight (900) typography for headers/charts.
52+
5. **Export**: Verify CSV/JSON export functionality from the Details page.
53+
54+
### Code Integrity
55+
56+
- **Syntax Check**: `python -m py_compile <path>`
57+
- **Formatting**: Adhere to PEP 8. Headers and specific UI text use **Lato** with a font-weight of **900** for a premium look.
58+
59+
---
60+
61+
## 4) Build & Packaging
62+
63+
This repository uses a **unified spec file** (`OpenCodeTokenMeter.spec`) for all platforms.
64+
65+
- **Build Commands**:
66+
- macOS: `./build.sh` (produces `.app` and `.dmg`)
67+
- Windows: `.\build_windows.bat` (produces `.exe`)
68+
- **Cleanup**: `rm -rf build/ dist/`
69+
70+
---
71+
72+
## 5) Contributor Guidelines
73+
74+
1. **SQL Safety**: Always use parameterized queries (`?`). Never use f-strings for SQL inputs.
75+
2. **Deduplication**: Message counting must use the deduplication logic in `App/agent/agent/db.py`.
76+
3. **Version Control**: Follow Semantic Versioning. Update `CHANGELOG.md` for every release.

App/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
# App package

0 commit comments

Comments
 (0)