cctally 1.116.0 → 1.117.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 +36 -0
- package/README.md +4 -6
- package/bin/_cctally_account.py +57 -3
- package/bin/_cctally_cache.py +5720 -885
- package/bin/_cctally_claude_attribution.py +997 -0
- package/bin/_cctally_completion.py +101 -28
- package/bin/_cctally_core.py +235 -12
- package/bin/_cctally_dashboard.py +224 -7
- package/bin/_cctally_dashboard_conversation.py +107 -21
- package/bin/_cctally_dashboard_envelope.py +34 -0
- package/bin/_cctally_db.py +928 -80
- package/bin/_cctally_diagnosis_sources.py +78 -13
- package/bin/_cctally_doctor.py +211 -86
- package/bin/_cctally_five_hour.py +389 -18
- package/bin/_cctally_forecast.py +30 -6
- package/bin/_cctally_journal.py +2418 -158
- package/bin/_cctally_oauth_samples.py +185 -7
- package/bin/_cctally_parser.py +38 -0
- package/bin/_cctally_project.py +34 -8
- package/bin/_cctally_quarantine.py +821 -343
- package/bin/_cctally_quota.py +69 -4
- package/bin/_cctally_quota_calibration.py +677 -3
- package/bin/_cctally_quota_model.py +927 -127
- package/bin/_cctally_record.py +922 -445
- package/bin/_cctally_rederive.py +119 -15
- package/bin/_cctally_statusline.py +1048 -176
- package/bin/_cctally_store.py +544 -110
- package/bin/_cctally_tui.py +93 -9
- package/bin/_cctally_update.py +77 -14
- package/bin/_lib_account_protocol.py +227 -19
- package/bin/_lib_claude_attribution.py +421 -0
- package/bin/_lib_clone_copy.py +30 -0
- package/bin/_lib_codex_conversation_query.py +45 -9
- package/bin/_lib_codex_conversation_watch.py +72 -13
- package/bin/_lib_codex_rollout_container.py +234 -19
- package/bin/_lib_codex_worker_lifecycle.py +374 -0
- package/bin/_lib_credit.py +22 -13
- package/bin/_lib_dashboard_sources.py +163 -10
- package/bin/_lib_detector_access_registry.py +1335 -166
- package/bin/_lib_doctor.py +276 -92
- package/bin/_lib_ingest_frontier.py +269 -36
- package/bin/_lib_journal.py +273 -22
- package/bin/_lib_jsonl.py +12 -0
- package/bin/_lib_meter_rate_change.py +72 -0
- package/bin/_lib_outcome_quarantine.py +917 -554
- package/bin/_lib_provider_activity.py +24 -6
- package/bin/_lib_quota_calibration.py +57 -3
- package/bin/_lib_quota_copy.py +7 -2
- package/bin/_lib_quota_lineage.py +613 -0
- package/bin/_lib_quota_model.py +435 -22
- package/bin/_lib_rate_change_delivery.py +16 -0
- package/bin/_lib_reclaim_planner.py +6 -4
- package/bin/_lib_rederive.py +2046 -21
- package/bin/_lib_selector_state.py +131 -3
- package/bin/_lib_stale_proof.py +113 -4
- package/bin/_lib_statusline.py +72 -3
- package/bin/_lib_statusline_candidates.py +246 -42
- package/bin/_lib_write_io.py +418 -5
- package/bin/cctally +24 -11
- package/dashboard/static/assets/{ConversationsView-Dflb_myA.js → ConversationsView-Dcfn8T6f.js} +1 -1
- package/dashboard/static/assets/{DoctorModal-DFX5CfIs.js → DoctorModal-BqmXbnhn.js} +1 -1
- package/dashboard/static/assets/{ModalRoot-HlxoagIa.js → ModalRoot-Ck3WJK2V.js} +1 -1
- package/dashboard/static/assets/{ProjectsDrillPanel-C3PJy1xx.js → ProjectsDrillPanel-B-HZkDnT.js} +1 -1
- package/dashboard/static/assets/{SourceDetailModal-BczsWKhD.js → SourceDetailModal-QhJkHB7i.js} +1 -1
- package/dashboard/static/assets/{UpdateModal-Os-Lo5cs.js → UpdateModal-CkXEIQcK.js} +1 -1
- package/dashboard/static/assets/index-D34eYhAc.css +1 -0
- package/dashboard/static/assets/{index-CYZ3NLqF.js → index-HKS1s56o.js} +3 -3
- package/dashboard/static/assets/{outlineNavigation-k-zIif6W.js → outlineNavigation-BNGaNPCp.js} +1 -1
- package/dashboard/static/assets/{useKeymap-CW7Up0Ay.js → useKeymap-CUgEnnua.js} +1 -1
- package/dashboard/static/dashboard.html +3 -3
- package/package.json +5 -1
- package/dashboard/static/assets/index-BKITk1CT.css +0 -1
package/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,42 @@ based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
|
|
|
5
5
|
|
|
6
6
|
## [Unreleased]
|
|
7
7
|
|
|
8
|
+
## [1.117.0] - 2026-11-02
|
|
9
|
+
|
|
10
|
+
### Added
|
|
11
|
+
- `cctally doctor` adds `accounts.claude_cost_attribution`, reporting how recent Claude cost was attributed to accounts and the progress of the one-time upgrade step that records existing attribution.
|
|
12
|
+
|
|
13
|
+
### Changed
|
|
14
|
+
- `cctally quota` no longer withholds a forecast over a small Sonnet 5.5 share shift that meter evidence shows to be immaterial, and withheld lines name the family reason. Stored calibrations go stale until the next `cctally quota` run.
|
|
15
|
+
- When a reviewed `cctally db rederive` correction changes a calibration's inputs, `cctally forecast` and the dashboard withhold calibrated figures ("recalibration needed") until `cctally quota` refits. Stats rebuilds once on upgrade.
|
|
16
|
+
- A metering-rate change fitted from corrected inputs no longer shows its status-line marker or sends its notification; the dashboard's Recent Alerts keeps it, labelled "superseded by a correction".
|
|
17
|
+
- After a gap without a running `cctally dashboard`, its first transcript catch-up writes less to `conversations.db`, and `cctally dashboard-perf` and `cctally doctor` no longer judge that catch-up as steady-state disk writes.
|
|
18
|
+
- Automatic credit, early-reset and status-line drop detection paused by an older cctally process now resumes on its own, per account and per limit; `cctally doctor` shows what each limit waits for. Stats rebuilds once on upgrade.
|
|
19
|
+
|
|
20
|
+
### Fixed
|
|
21
|
+
- A `stats.db` upgrade rebuild or `cctally db rebuild --db stats` no longer reprices closed five-hour blocks and their milestones at the current rate card when it recovers missing records.
|
|
22
|
+
- Archived Codex threads now count in `codex-*` reports, quota history and the dashboard, and archiving no longer deletes history. Archived usage first seen with no recorded account stays unattributed unless quota windows assign it.
|
|
23
|
+
- On Python builds that link SQLite 3.54.1, a running `cctally dashboard` reclaims transcript space freed by retention again, so `conversations.db` shrinks instead of keeping the freed pages.
|
|
24
|
+
- An idle Claude Code session's stale `cctally statusline` reading no longer records a false weekly reset, five-hour credit or zero-cost milestone once a later usage check reads higher; the stats index rebuilds once after upgrading.
|
|
25
|
+
- Claude cost is attributed to the account active when Claude Code wrote it, not the one active when cctally read it. Upgrades and `cctally cache-sync --rebuild` keep each row's account.
|
|
26
|
+
- `cctally statusline` measures `🧠` context % against the session's real context window (1M for Opus, Sonnet and Haiku 5.5), so an Opus 5.5 session no longer shows a red percentage five times too high and Fable sessions no longer show `N/A`.
|
|
27
|
+
- A `stats.db` upgrade rebuild could exit early as busy when a status-line check for a running rebuild landed at the instant it started, delaying the rebuild; that check no longer interferes with a starting rebuild.
|
|
28
|
+
- `cctally explain` and the dashboard's Explain view measure Opus, Sonnet and Haiku 5.5 requests against their 1M context window and now evaluate Fable requests, so short conversations are no longer flagged for large context against 200K.
|
|
29
|
+
- `cctally five-hour-blocks`, `cctally five-hour-breakdown` and the dashboard keep each five-hour window's genuine peak, milestones and readings through a usage credit and through every stats.db rebuild, instead of dropping some.
|
|
30
|
+
- `cctally record-credit` records the exact `--at` time instead of the start of that hour, keeping readings taken earlier in that hour, and a `--force` replacement at the replaced credit's own second now takes effect.
|
|
31
|
+
- A weekly usage credit is no longer lost when recording is interrupted while it is being saved.
|
|
32
|
+
- After stats.db is rebuilt from a missing or corrupt file, the stats index keeps updating incrementally instead of falling back to rereading the whole recorded history.
|
|
33
|
+
- On an exFAT data folder, cctally now quarantines and rebuilds a corrupt `conversations.db` or `cache.db` and can run `db repair --db stats`, and a rebuild no longer fails after 20 s while another cctally process has the store open but idle.
|
|
34
|
+
- On macOS, `cctally cache-sync --rebuild` no longer writes a full copy of `conversations.db` on volumes without copy-on-write clones (HFS+, exFAT); there and on Linux ext4 its integrity check runs in place when no write-ahead log is pending.
|
|
35
|
+
- `cctally dashboard` no longer waits on a reverse-DNS lookup of its bind address before it prints its URL and serves, a wait that lasted the resolver's whole timeout where the network never answers that lookup.
|
|
36
|
+
- Codex hooks installed by `cctally setup` no longer stall Codex sessions for over 10 seconds on large histories or after upgrading, or for over a minute with Codex budget alerts on; leftover work runs in the background.
|
|
37
|
+
- `cctally db rederive` restores a five-hour milestone's cost when an earlier rederive repriced it under a closed block; one whose history is ambiguous keeps its cost and is listed in `withheldMilestoneRepairs`.
|
|
38
|
+
|
|
39
|
+
## [1.116.1] - 2026-10-28
|
|
40
|
+
|
|
41
|
+
### Maintenance
|
|
42
|
+
- Internal improvements only; no user-facing changes.
|
|
43
|
+
|
|
8
44
|
## [1.116.0] - 2026-10-28
|
|
9
45
|
|
|
10
46
|
### Added
|
package/README.md
CHANGED
|
@@ -30,13 +30,11 @@ Your Claude Code plan meters you with a percentage that creeps up all week. ccta
|
|
|
30
30
|
</p>
|
|
31
31
|
|
|
32
32
|
<!-- cctally:latest-stable:begin -->
|
|
33
|
-
**Latest stable: v1.
|
|
33
|
+
**Latest stable: v1.116.1** (2026-10-28)
|
|
34
34
|
|
|
35
|
-
Highlights from the `v1.
|
|
35
|
+
Highlights from the `v1.113.0` to `v1.116.1` stable upgrade:
|
|
36
36
|
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
[See every change in this stable upgrade](https://github.com/omrikais/cctally/releases/tag/v1.113.0)
|
|
37
|
+
[See every change in this stable upgrade](https://github.com/omrikais/cctally/releases/tag/v1.116.1)
|
|
40
38
|
<!-- cctally:latest-stable:end -->
|
|
41
39
|
|
|
42
40
|
## Quick start
|
|
@@ -135,7 +133,7 @@ See [docs/commands/blocks.md](docs/commands/blocks.md) and [docs/commands/five-h
|
|
|
135
133
|
|
|
136
134
|
## Codex
|
|
137
135
|
|
|
138
|
-
If you also use OpenAI's Codex CLI, cctally tracks it with the same depth. `cctally codex daily`, `monthly`, and `session` are drop-in replacements for the ccusage codex commands, reading from your local `~/.codex/sessions
|
|
136
|
+
If you also use OpenAI's Codex CLI, cctally tracks it with the same depth. `cctally codex daily`, `monthly`, and `session` are drop-in replacements for the ccusage codex commands, reading from your local `~/.codex/sessions/`, archived threads in `~/.codex/archived_sessions/` included. `cctally codex weekly` adds a subscription week rollup, and `cctally codex quota` shows your native Codex rate limit windows.
|
|
139
137
|
|
|
140
138
|
<p align="center">
|
|
141
139
|
<img src="docs/img/cli-codex-daily.svg" alt="cctally codex daily: Codex cost by day">
|
package/bin/_cctally_account.py
CHANGED
|
@@ -1295,9 +1295,34 @@ def _attribute_apply(planned, *, account_key, mode, since, until, at,
|
|
|
1295
1295
|
conn.execute("BEGIN IMMEDIATE")
|
|
1296
1296
|
_landed, skipped = _cache_mod.rehydrate_codex_window_attributions(
|
|
1297
1297
|
conn)
|
|
1298
|
+
# #980 F1: the reconciliation's adoption demotes Spark windows
|
|
1299
|
+
# through the RESOLVED `observed_model` (#373), so owed model
|
|
1300
|
+
# resolution runs first, on this transaction and under the
|
|
1301
|
+
# writer flocks this command holds. When it still cannot
|
|
1302
|
+
# resolve, nothing is reconciled over an unresolved model: the
|
|
1303
|
+
# apply aborts (`recordedPending` once records were appended)
|
|
1304
|
+
# and a rerun finishes it.
|
|
1305
|
+
if _cache_mod.codex_model_resolution_pending(conn):
|
|
1306
|
+
_cache_mod._codex_settle_finalization(
|
|
1307
|
+
conn, deadline=None, stages=("expand", "model"))
|
|
1308
|
+
if _cache_mod.codex_model_resolution_pending(conn):
|
|
1309
|
+
raise sqlite3.DatabaseError(
|
|
1310
|
+
_quota.PROJECTION_DEFERRED_MODEL)
|
|
1298
1311
|
restored, adopted = (
|
|
1299
1312
|
_cache_mod.reconcile_codex_window_attribution_spend(
|
|
1300
1313
|
conn, strict=True))
|
|
1314
|
+
# #980 R7: the rehydrate above armed `attribution` debt for
|
|
1315
|
+
# exactly the reconciliation that just succeeded, on this
|
|
1316
|
+
# transaction; settle it here, or every account-scoped hook
|
|
1317
|
+
# read defers until a later settlement repeats it. Kept while
|
|
1318
|
+
# adoption items remain: the reconcile runs after them (D4).
|
|
1319
|
+
# A later failure rolls this back with everything else.
|
|
1320
|
+
debt = _cache_mod.load_codex_finalization_debt(conn)
|
|
1321
|
+
if (debt.attribution and not debt.malformed
|
|
1322
|
+
and not debt.full and debt.first_item() is None):
|
|
1323
|
+
debt.attribution = False
|
|
1324
|
+
debt.strikes = 0
|
|
1325
|
+
_cache_mod._store_codex_finalization_debt(conn, debt)
|
|
1301
1326
|
# Verify the applied record set against the plan we locked,
|
|
1302
1327
|
# BEFORE the commit: a silent partial application must abort the
|
|
1303
1328
|
# transaction rather than be reported as success (spec §8.2).
|
|
@@ -1365,20 +1390,49 @@ def _attribute_apply(planned, *, account_key, mode, since, until, at,
|
|
|
1365
1390
|
# rerun completes it, because the certificate's attribution revision is
|
|
1366
1391
|
# still behind the derived table's (`_attribute_tail_pending`).
|
|
1367
1392
|
try:
|
|
1368
|
-
|
|
1393
|
+
deferred = _attribute_publish_projection()
|
|
1369
1394
|
except Exception as exc: # noqa: BLE001 - reported, never swallowed
|
|
1395
|
+
deferred = str(exc)
|
|
1396
|
+
if deferred is not None:
|
|
1370
1397
|
return ("recordedPending", actions, [{
|
|
1371
1398
|
"code": "recordedPending",
|
|
1372
1399
|
"message": (
|
|
1373
1400
|
f"the attribution was recorded and applied but the quota "
|
|
1374
|
-
f"projection did not finish ({
|
|
1375
|
-
f"to complete it"),
|
|
1401
|
+
f"projection did not finish ({deferred}); rerun the same "
|
|
1402
|
+
f"command to complete it"),
|
|
1376
1403
|
}], fresh)
|
|
1377
1404
|
status = ("recovered" if ((recovered or completion) and not appended)
|
|
1378
1405
|
else "applied")
|
|
1379
1406
|
return (status, actions, [], fresh)
|
|
1380
1407
|
|
|
1381
1408
|
|
|
1409
|
+
def _attribute_publish_projection() -> "str | None":
|
|
1410
|
+
"""Publish the quota projection; return None, or why it is still refused.
|
|
1411
|
+
|
|
1412
|
+
#980 D6: every projection publisher refuses while model resolution is
|
|
1413
|
+
owed, returning a ``deferred_model`` status rather than raising, so a bare
|
|
1414
|
+
reconcile here reported success over an unpublished projection. Owed
|
|
1415
|
+
resolution is therefore settled first, unbudgeted, through the cache
|
|
1416
|
+
writer flocks an unbudgeted sync takes; when the projection still refuses
|
|
1417
|
+
(those flocks were contended) the caller reports ``recordedPending``.
|
|
1418
|
+
"""
|
|
1419
|
+
import _cctally_cache as _cache_mod
|
|
1420
|
+
import _cctally_quota as _quota
|
|
1421
|
+
|
|
1422
|
+
settled = False
|
|
1423
|
+
if _cache_mod.codex_model_resolution_pending_now():
|
|
1424
|
+
_cache_mod.settle_codex_finalization_unbudgeted()
|
|
1425
|
+
settled = True
|
|
1426
|
+
result = _quota.reconcile_codex_quota_projection()
|
|
1427
|
+
if (getattr(result, "status", None) == _quota.PROJECTION_DEFERRED_MODEL
|
|
1428
|
+
and not settled):
|
|
1429
|
+
_cache_mod.settle_codex_finalization_unbudgeted()
|
|
1430
|
+
result = _quota.reconcile_codex_quota_projection()
|
|
1431
|
+
if getattr(result, "status", None) == _quota.PROJECTION_DEFERRED_MODEL:
|
|
1432
|
+
return _quota.PROJECTION_DEFERRED_MODEL
|
|
1433
|
+
return None
|
|
1434
|
+
|
|
1435
|
+
|
|
1382
1436
|
def _cmd_account_attribute(args: argparse.Namespace) -> int:
|
|
1383
1437
|
"""`cctally account attribute` — preview by default, `--yes` applies.
|
|
1384
1438
|
|