cctally 1.98.0 → 1.99.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +31 -0
- package/README.md +4 -4
- package/bin/_cctally_account.py +925 -0
- package/bin/_cctally_cache.py +829 -31
- package/bin/_cctally_core.py +52 -0
- package/bin/_cctally_dashboard.py +375 -19
- package/bin/_cctally_dashboard_share.py +50 -1
- package/bin/_cctally_dashboard_sources.py +1510 -120
- package/bin/_cctally_db.py +810 -34
- package/bin/_cctally_doctor.py +184 -1
- package/bin/_cctally_journal.py +732 -76
- package/bin/_cctally_parser.py +81 -0
- package/bin/_cctally_quota.py +896 -17
- package/bin/_cctally_rederive.py +157 -5
- package/bin/_cctally_source_analytics.py +60 -6
- package/bin/_cctally_tui.py +513 -47
- package/bin/_lib_aggregators.py +117 -11
- package/bin/_lib_budget.py +60 -0
- package/bin/_lib_codex_window_attribution.py +259 -0
- package/bin/_lib_dashboard_sources.py +26 -1
- package/bin/_lib_doctor.py +71 -0
- package/bin/_lib_journal.py +212 -0
- package/bin/_lib_jsonl.py +6 -0
- package/bin/_lib_rederive.py +8 -0
- package/bin/_lib_snapshot_cache.py +236 -7
- package/bin/_lib_source_analytics.py +20 -2
- package/bin/cctally +12 -0
- package/dashboard/static/assets/index-C5NBB2w9.js +97 -0
- package/dashboard/static/assets/index-hJP4wlIO.css +1 -0
- package/dashboard/static/dashboard.html +2 -2
- package/package.json +2 -1
- package/dashboard/static/assets/index-CC8TTZUC.css +0 -1
- package/dashboard/static/assets/index-CChXFhs_.js +0 -97
package/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,37 @@ based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
|
|
|
5
5
|
|
|
6
6
|
## [Unreleased]
|
|
7
7
|
|
|
8
|
+
## [1.99.1] - 2026-08-15
|
|
9
|
+
|
|
10
|
+
### Fixed
|
|
11
|
+
- The dashboard now recognizes the previous calendar day as `Yesterday` across a fall-back daylight-saving transition instead of falling through to the absolute timestamp (#584).
|
|
12
|
+
- Budget figures no longer depend on which Python version is running cctally. The dashboard's Claude and Codex budget blocks added their spend with the built-in `sum()`, which CPython changed in 3.12 to use compensated summation, so the same spend over the same entries produced `$49.20424485` on Python 3.12 and later and `$49.204244850000016` on Python 3.11. The rendered figure is rounded to cents and never differed to the eye, but the published payload did, which is why the repository's own byte-comparison of that payload failed on 3.11. These four sums now use the exactly-rounded helper the rest of the cost surfaces already use, so every supported interpreter publishes the same number.
|
|
13
|
+
- `cctally account attribute --help` no longer prints `(default: None)` beneath `--since`, which is a required argument and therefore has no default. Python 3.13 already suppressed it and 3.11 and 3.12 did not, so the same command printed two different help texts depending on the interpreter. cctally now applies the 3.13 rule on every supported version, and this covers every required option on every subcommand, not only this one.
|
|
14
|
+
|
|
15
|
+
## [1.99.0] - 2026-08-15
|
|
16
|
+
|
|
17
|
+
### Added
|
|
18
|
+
- The dashboard's Forecast panel and modal now show your configured budget beside the quota forecast, on `All` and on both provider tabs. It is a different quantity from the forecast next to it: the forecast projects quota usage toward the 100% cap, while this measures spend against the amount you set with `cctally budget set` over the period you configured. The block states the provider, the period, spend against the budget, a consumption bar with its percent, the verdict and the daily pace; the modal adds remaining, the projection band, the trailing-24h rate, the alert thresholds and the resolved period bounds. Under `All` the two provider cards sit side by side at desktop widths and stack in order, Claude first, on a phone. Nothing is composed across providers: two budgets over two different periods against two independently configured amounts do not add, so there is no combined budget figure anywhere (#556).
|
|
19
|
+
- The dashboard states which budget state you are actually in, rather than collapsing four of them into one. A provider with no budget reads `No budget set.` with the command that sets one, correct per provider. A provider that has only per-account budgets reads `No provider-wide budget set.` and points at the account cards, because telling you that you have no budget when you have several would be false. A configured budget whose window cannot be resolved yet, or whose computation failed, states the amount and the period you configured with the window named as unresolved, and says why — never a fabricated percentage or verdict (#556).
|
|
20
|
+
- You can focus an account on the `All` view. There is one chip row per provider that has more than one account, and each row states on screen what it actually does: the Codex row filters every panel, and the Claude row changes the hero and the alert list only. That difference is real rather than cosmetic — only Codex publishes per-account data, so only a Codex focus can narrow a panel. `a` cycles the Codex row under `All`, or the Claude row when Codex has a single account. A focus set on `All` and a focus set on a provider's own tab are stored separately and never affect each other, so neither view can silently narrow the other. Each provider's alerts are filtered by that provider's own focus and vendor-wide crossings stay visible under any focus, and where a panel is narrowed for one provider while the other is not, its badge names the provider it filtered rather than claiming the whole panel (#556).
|
|
21
|
+
- A share taken while an account is focused now carries that account under `All` too. Opening a share flow there used to capture no account at all, so a focused chip could read as one account on screen while the artifact it produced contained every account's data. A shared Forecast artifact also states the configured budget beside its quota projections, on Claude as well as Codex, so it says what the panel it was taken from says (#556).
|
|
22
|
+
- `cctally account attribute <ref> --since <iso> [--until <iso>]` attributes already-recorded Codex quota windows and spend to a known Codex account. cctally began recording which account each sample belongs to partway through its life, so on a multi-account Codex install every earlier record is stuck in the `unattributed` bucket with nothing able to move it; this command lets the operator state the fact they already know. It previews by default and writes nothing until `--yes`, asserts whole physical quota windows rather than individual observations (a window the range covers only partially is refused rather than split), and moves the quota-percentage and spend attributions together in one step. Applying is all or nothing over the windows the range could have meant, with one exception worth knowing before the first run: a window that is not account-level weekly quota — a five-hour window, or a separate model pool such as Codex Spark — is listed as refused and left alone rather than stopping the rest of the range from applying. On any real range these are the majority, so the preview normally reports far more refused windows than attributed ones. `--retract` withdraws an assertion and recomputes as if it had never been recorded, so a provider-identified account or a second valid assertion still stands. Recorded provider evidence always wins: if the provider later identifies a different account for an attributed window, the assertion stops applying and both axes move to the account the provider named, with no operator action. The assertion lives in the append-only journal, so the result survives both `cctally db rebuild --db stats` and `cctally cache-sync --rebuild --source codex`. `cctally doctor` reports assertions that match no current window, match more than one, or conflict with recorded evidence under a new `accounts.codex_window_attribution` check at WARN (#500).
|
|
23
|
+
|
|
24
|
+
### Changed
|
|
25
|
+
- Complete the Claude/Codex parity certification with current source-aware dashboard, analytics, sharing, conversation, privacy, and scale evidence; the TUI remains explicitly Claude-only under its bugfix-only maintenance policy (#322).
|
|
26
|
+
|
|
27
|
+
### Fixed
|
|
28
|
+
- Failed authoritative test-gate records now retain the exact `test-remote` case function and source line even when private assertion detail is redacted, and the local record survives the next passing invocation (#579).
|
|
29
|
+
- Schema tables, views, triggers and indexes in both cache stores now have a structural delivery guard, so a definition added without a migration cannot silently reach only fresh installations (#580).
|
|
30
|
+
- Claude-active dashboard refreshes now incrementally update the `All` view's shared-range project and daily aggregates instead of rescanning and repricing the full thirty-day Claude history on every new entry. On the 60,000-entry benchmark with one live append before each warm run, the median added source-build time fell from about 404 ms to 2.5 ms while project and daily totals remained byte-identical to a cold rebuild (#567).
|
|
31
|
+
- A Codex-active dashboard refresh now updates only changed rollout paths, accounts, and day/period/session/project aggregates instead of re-reading and re-aggregating the complete retained Codex history. On a copied production store with 154,600 Codex entries, a caught-up live dirty iteration including ingest completed in 4.77 seconds (9.77-second cooldown-adjusted publish period) while preserving the exact prior dashboard payload (#582).
|
|
32
|
+
- Focusing a Claude account no longer prints the whole provider's weekly percentage as that account's own. When the focused account has no weekly percentage of its own — the common case, because Claude's per-account quota evidence is much sparser than its per-account spend — the dashboard's largest figure fell back to the merged all-accounts number, so every account showed the identical percentage while the line beside it correctly said `no data` and the account's own card correctly said `Weekly —`. The headline now states that it has no figure for that account, matching what the rest of the hero already said. This affected the Claude tab as shipped and the `All` view's new account focus (#556).
|
|
33
|
+
- A valid Codex budget configured only per account no longer destroys the whole Codex view. Setting per-account Codex budgets without a vendor-wide amount is a supported configuration, and the dashboard read it as a computation error for the entire provider — every Codex panel went unavailable at once. A budget problem now degrades the budget and nothing else, on both providers (#556).
|
|
34
|
+
- An old alert in Recent alerts now shows the time it fired, not just the day. Once an alert was no longer today's or yesterday's, both the panel and the modal printed a bare calendar day such as `Apr 16`, so every alert that fired on one day rendered as the same string and there was no way to tell them apart or confirm the order they are listed in. That cell now reads the full instant — `Apr 16 14:32 PDT` — in the dashboard's display timezone. Every alert row also carries the instant, with its calendar year, as a hover title on desktop; a row whose recorded instant is missing or unreadable carries no title rather than an em dash. On a narrow screen the longer timestamp no longer competes with the chips beside it for a single line — it takes a line of its own beneath them, as the alerts modal already did, which makes each row in the panel one line taller (#574).
|
|
35
|
+
- On a Codex install with more than one account, the dashboard's spend headline now covers the seven days it is labelled with. That figure is the sum of the per-account cards beneath it, and two of those cards were totalled over the dashboard's whole accounting range — roughly thirty days — while the headline said "spent this week": an account whose weekly cycle had expired or was never observed, and the unattributed bucket that holds spend recorded before per-file attribution existed. Both are now counted over the last seven days, so the headline reconciles against the cards again. Any account counted that way says so: its card is captioned with the period, the headline notes that it includes accounts with no live cycle, focusing that account labels its figure with the period instead of "this week", and the Current Cycle modal marks the same rows and qualifies the same focused figure. The unattributed bucket keeps its card even when all of its spend is older than seven days, showing $0.00 for the period rather than disappearing, and each account's own daily, session and project views still cover the wider range under their own labels. An install with a single Codex account is unaffected (#564).
|
|
36
|
+
- The dashboard index fix described in the 1.97.0 notes never reached an existing installation, and now does. The composite index was added to the schema body, which the cache only re-applies when its recorded schema version changes; because no migration accompanied it, only a freshly created cache gained the index, and every install that upgraded to 1.97.0 kept the slow lookup. A real install running 1.97.0 was measured with the index absent. It is now delivered by a migration, so every store picks it up once on the next open, and a new structural check fails the test suite if another re-derivable index is ever added to the schema body without a delivery path (#566).
|
|
37
|
+
- The dashboard now refreshes in seconds rather than minutes on a large store. Publishing waits for the previous rebuild to finish, so a slow rebuild doubles into a much longer gap between updates: on a store holding about 574,000 usage rows the gap between pushes was measured at 167 to 184 seconds. Alongside the index delivery above, four pieces of repeated work were removed from the rebuild. Codex session files are now parsed once per file per refresh instead of once per usage row, the health check summarizes each quota window in the database instead of loading every retained observation into memory, project labels are no longer re-derived while adding up token totals that carry no label, and each visible row is adapted once for the combined view and every per-account view rather than once per view. On the same store the rebuild dropped from about 17.9 seconds to about 10.7 seconds, on top of the roughly 90 seconds the index delivery removes. Every published payload was verified byte-for-byte identical before and after under a frozen clock, so nothing on screen changes except how often it is current (#566).
|
|
38
|
+
|
|
8
39
|
## [1.98.0] - 2026-08-14
|
|
9
40
|
|
|
10
41
|
### Changed
|
package/README.md
CHANGED
|
@@ -37,7 +37,7 @@ Your Claude Code plan meters you with a percentage that creeps up all week. ccta
|
|
|
37
37
|
|
|
38
38
|
## Quick start
|
|
39
39
|
|
|
40
|
-
Requirements: Python 3.11+, macOS or Linux, Claude Code installed and run at least once.
|
|
40
|
+
Requirements: Python 3.11+, macOS or Linux, and Claude Code and/or OpenAI's Codex CLI installed and run at least once.
|
|
41
41
|
|
|
42
42
|
```bash
|
|
43
43
|
# Homebrew (macOS / Linux)
|
|
@@ -50,7 +50,7 @@ npm install -g cctally && cctally setup
|
|
|
50
50
|
git clone https://github.com/omrikais/cctally && cd cctally && ./bin/cctally setup
|
|
51
51
|
```
|
|
52
52
|
|
|
53
|
-
The reporting commands work immediately on your existing logs, before any setup. Running `cctally setup` once adds the hooks that
|
|
53
|
+
The reporting commands work immediately on your existing logs, before any setup. Running `cctally setup` once adds the Claude hooks and native Codex handlers that keep each provider's local quota observations current as you work.
|
|
54
54
|
|
|
55
55
|
```bash
|
|
56
56
|
cctally daily # cost by day: your first table
|
|
@@ -87,7 +87,7 @@ See [docs/commands/dashboard.md](docs/commands/dashboard.md).
|
|
|
87
87
|
|
|
88
88
|
## Conversation viewer
|
|
89
89
|
|
|
90
|
-
The dashboard's Conversations tab is a read-only reader for your Claude Code transcripts. A searchable rail lists every conversation with its project, branch, models, and cost; the reader shows the full turn-by-turn flow with
|
|
90
|
+
The dashboard's Conversations tab is a read-only reader for your Claude Code and Codex transcripts. A searchable rail lists every conversation with its source, project, branch, models, and cost; the reader shows the full turn-by-turn flow with reasoning, tool calls, and per-turn cost. Subagent runs render as nested threads, and the open conversation live-tails as you work. It never modifies your transcripts, and it never leaves your machine.
|
|
91
91
|
|
|
92
92
|
<p align="center">
|
|
93
93
|
<img src="docs/img/conversation-reader.png" alt="Conversation viewer: rail, threaded reader, and outline" width="900">
|
|
@@ -141,7 +141,7 @@ See [docs/commands/codex.md](docs/commands/codex.md) and [docs/commands/codex-qu
|
|
|
141
141
|
|
|
142
142
|
## Terminal UI
|
|
143
143
|
|
|
144
|
-
Prefer to stay in the terminal, or working over SSH? `cctally tui`
|
|
144
|
+
Prefer to stay in the terminal, or working over SSH? `cctally tui` is the Claude-only, bugfix-only terminal dashboard. It remains supported, but it does not track newer web-dashboard capabilities and is not part of cross-provider parity. It is the one feature that needs the optional `rich` library; everything else runs on a plain Python install.
|
|
145
145
|
|
|
146
146
|
<p align="center">
|
|
147
147
|
<img src="docs/img/cli-tui.svg" alt="cctally tui: live terminal dashboard">
|