cctally 1.97.0 → 1.99.0
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 +47 -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 +960 -55
- package/bin/_cctally_dashboard_envelope.py +43 -23
- package/bin/_cctally_dashboard_share.py +50 -1
- package/bin/_cctally_dashboard_sources.py +1580 -131
- 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 +65 -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 +811 -67
- package/bin/_lib_aggregators.py +117 -11
- package/bin/_lib_alert_axes.py +8 -3
- package/bin/_lib_budget.py +60 -0
- package/bin/_lib_codex_window_attribution.py +259 -0
- package/bin/_lib_dashboard_sources.py +488 -19
- 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 +248 -7
- package/bin/_lib_source_analytics.py +20 -2
- package/bin/cctally +25 -0
- package/dashboard/static/assets/index-Bcbm-DNP.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-BSESoPIK.css +0 -1
- package/dashboard/static/assets/index-DgsMz5hA.js +0 -97
package/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,53 @@ based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
|
|
|
5
5
|
|
|
6
6
|
## [Unreleased]
|
|
7
7
|
|
|
8
|
+
## [1.99.0] - 2026-08-15
|
|
9
|
+
|
|
10
|
+
### Added
|
|
11
|
+
- 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).
|
|
12
|
+
- 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).
|
|
13
|
+
- 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).
|
|
14
|
+
- 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).
|
|
15
|
+
- `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).
|
|
16
|
+
|
|
17
|
+
### Changed
|
|
18
|
+
- 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).
|
|
19
|
+
|
|
20
|
+
### Fixed
|
|
21
|
+
- 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).
|
|
22
|
+
- 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).
|
|
23
|
+
- 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).
|
|
24
|
+
- 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).
|
|
25
|
+
- 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).
|
|
26
|
+
- 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).
|
|
27
|
+
- 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).
|
|
28
|
+
- 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).
|
|
29
|
+
- 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).
|
|
30
|
+
|
|
31
|
+
## [1.98.0] - 2026-08-14
|
|
32
|
+
|
|
33
|
+
### Changed
|
|
34
|
+
- The stats-rebuild memory gate now rejects compact per-observation projections, not only full decoded-record retention. Its 512-byte overhead ceiling is derived from repeated production-shaped measurements on both remote runners, and a controlled coordinate-projection mutant freezes the regression class (#508).
|
|
35
|
+
- Every cross-provider aggregate on the dashboard's `All` view now states the range it covers and carries its provider attribution. The Projects leaderboard used to concatenate a Claude ranking bounded by the subscription week with a Codex ranking bounded by roughly thirty days, sort the union by cost, and print "(N this week)" over the result — so a Codex project could outrank a Claude project because of the window rather than the cost. Both providers are now folded over one shared absolute range, and the panel names its resolved dates in the header and in its empty state. The percentage beside each row is named in a legend on every tab: a share of the week's quota under Claude, a share of the ranked cost under Codex and All. Each row's accessible name carries its cost and that named percentage, which the decorative cost bar had been credited with conveying and did not (#556).
|
|
36
|
+
- A ranked project row that the drill-down cannot reach no longer offers one. A project active between a week's rollover and the projects envelope re-anchoring is in the ranking and in no route-visible collection, so clicking it opened a detail view reporting nothing. The row keeps its rank, its label and its cost, and simply has no detail affordance. When a Claude project drill does open from `All`, it now states the span it actually reported in resolved dates, because that window is anchored to whole weeks and is wider than the thirty-day ranking the row was priced over (#556).
|
|
37
|
+
- Monthly is no longer merged across providers under `All`. Two providers' calendar months were joined into one row per label, which nulled the Claude row's `Used %` and `$/1%` only when Codex happened to have that month, and recomputed one model split across two vendors' model families. Each provider now keeps its own months in its own section, and the modal's table and navigator name the provider so two rows sharing a label are tellable apart (#556).
|
|
38
|
+
- Weekly and Monthly now foot their combined cost with the span it covers and each provider's share. Weekly states exact dates, which its rows carry; Monthly states a month-label span, because monthly rows carry no bounds and the current month's read ends at the current instant rather than at the month's end (#556).
|
|
39
|
+
- A combined daily row no longer publishes a cache-hit percentage or a model split. Claude counts cache reads outside its input total and Codex counts them inside, so no ratio over their sum describes anything, and one model stack over two vendors' families shares a denominator that means nothing. The day's detail now breaks the combined figure back down per provider instead (#556).
|
|
40
|
+
- Five-hour blocks under `All` interleave both providers in time order rather than listing every Claude window above every Codex one, so a block from this morning can no longer render below one from last week. The footer keeps its total and states the interval the shown windows span plus each provider's count and cost — never a shared reset cycle, because the two providers' five-hour clocks are independent (#556).
|
|
41
|
+
- Weekly and Monthly table sorting is now per table. One shared preference meant a sort chosen on the weekly table applied to the monthly table, which does not have the `Used %` or `$/1%` columns at all. Under `All` the ordering applies inside each provider section rather than interleaving two providers' independent histories into one ranked list. An existing shared preference is reset rather than guessed at, because nothing recorded which table it came from (#556).
|
|
42
|
+
- When a cross-provider aggregate cannot be computed, the dashboard says so and names the missing fact, instead of rendering an empty table that reads as "no activity yet" or an error that reads as a broken instance. A version of the server the page has not seen before is handled the same way rather than rendering nothing (#556).
|
|
43
|
+
- A cross-provider span never names a day that has not happened yet. The Claude project drill and the `Weekly` footer both state calendar windows rather than data extents — the drill window runs to the current week's Sunday and the current weekly row ends at its reset — so on six days in seven they named future dates beside a cost figure. The stated end is now clamped to the instant the page was generated. The Codex project detail also states the window its totals cover, which is wider than the shared range the ranked row beside it is priced over, so the two figures no longer read as contradicting each other (#556).
|
|
44
|
+
- Recent alerts under `All` now lists both providers in one true chronological order. The union was ordered by a timestamp only the Codex side ever wrote, so every Claude row sank below every Codex row and a Claude alert from a minute ago rendered beneath a Codex alert from six days ago in a panel titled "Recent alerts". Alerts are now ordered — and truncated — by the instant each one fired, which is also the instant each row prints. Codex alert rows published the moment a threshold was crossed rather than the moment the alert fired, which are different moments, and now publish the firing instant (#556).
|
|
45
|
+
- The Codex budget alert chip now reads `BUDGET` rather than `CODEX`. It sat immediately beside a source chip already reading `Codex`, so the row said the same thing twice and named neither the metric nor anything the source chip did not already say. The chip names the metric; the source chip names the provider; the two budget chips stay distinguishable by colour (#556).
|
|
46
|
+
- The Recent Sessions panel now states its composition under `All`, on the same wrapping sub-line the Weekly, Monthly, Daily, Projects and Blocks panels already use. It was the last panel whose content changed under `All` without saying so, leaving the row-level provider chips as the only disclosure that two providers' sessions share one table. The note claims no ordering, because the table is recency-ordered only until a column header is clicked. The Claude and Codex tabs are unchanged (#572).
|
|
47
|
+
- Nothing under `All` is rendered but unreachable any more. At a 1440x900 desktop the Current Usage and Trend modals showed their content clipped with no scrollbar anywhere in the card: six of sixty Claude milestone rows were visible, the five-hour milestone table could not be reached at all, and Claude's Older-block and Newer-block controls sat entirely below the cut, although the identical controls work on the Claude tab. Both modals now scroll as one scrollport. The Weekly and Monthly modals are unchanged and keep their pinned left pane with a scrolling table (#556).
|
|
48
|
+
- The `All` Forecast panel now shows each provider's own detail. It rendered neither of Claude's two per-day budget figures nor Codex's confidence and budget pace, although both were already computed, so the combined panel showed strictly less than either provider tab. On an install with more than one Codex account the confidence line stays withheld, because it describes one arbitrarily chosen account's history and would reconcile against no account card and no tab (#556).
|
|
49
|
+
- A provider with no forecast is no longer reported as `unavailable` in the `All` Forecast panel. It now renders the same labelled dash structure its own tab renders, and keeps the sentence naming why it contributed nothing (#556).
|
|
50
|
+
- The Projects window pills now look disabled when they are. Under Codex and `All` the 1w / 4w / 8w / 12w buttons are inert, because provider-native project history has no week window, but they rendered pixel-identical to the working buttons beside them and still showed a pointer cursor on hover (#556).
|
|
51
|
+
- On an install with a single Codex account, the Codex cycle navigator in the Current Usage modal is announced in cycle vocabulary. Its two buttons were named "Older week" and "Newer week" for both providers, so a screen reader heard a Claude concept everywhere the visible labels said cycle (#556).
|
|
52
|
+
- Every provider section under `All` is now announced by a heading naming it, so the view can be navigated by heading instead of reading as one flat block beneath its panel or modal title. Nothing changes visually (#556).
|
|
53
|
+
- The Help overlay now says how to open the Current Usage modal, which no digit shortcut can reach, and no longer carries a "the current source doesn't show" block that could never list anything. The dashboard documentation's four false statements about `All` are corrected: which panels each source shows, how the persisted card order works, what the digit keys open, and how the side-by-side provider sections are navigated (#556).
|
|
54
|
+
|
|
8
55
|
## [1.97.0] - 2026-08-13
|
|
9
56
|
|
|
10
57
|
### 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">
|