cctally 1.72.0 → 1.74.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.
Files changed (37) hide show
  1. package/CHANGELOG.md +22 -0
  2. package/bin/_cctally_cache.py +271 -55
  3. package/bin/_cctally_core.py +20 -40
  4. package/bin/_cctally_dashboard.py +35 -1
  5. package/bin/_cctally_dashboard_conversation.py +731 -94
  6. package/bin/_cctally_dashboard_share.py +38 -3
  7. package/bin/_cctally_dashboard_sources.py +812 -74
  8. package/bin/_cctally_db.py +104 -1
  9. package/bin/_cctally_doctor.py +86 -4
  10. package/bin/_cctally_parser.py +17 -4
  11. package/bin/_cctally_record.py +162 -33
  12. package/bin/_cctally_refresh.py +58 -36
  13. package/bin/_cctally_source_analytics.py +288 -3
  14. package/bin/_cctally_statusline.py +811 -82
  15. package/bin/_cctally_transcript.py +223 -7
  16. package/bin/_cctally_tui.py +17 -14
  17. package/bin/_lib_aggregators.py +48 -34
  18. package/bin/_lib_codex_conversation_export.py +124 -0
  19. package/bin/_lib_codex_conversation_query.py +500 -28
  20. package/bin/_lib_codex_conversation_watch.py +323 -0
  21. package/bin/_lib_conversation_dispatch.py +269 -7
  22. package/bin/_lib_conversation_query.py +88 -0
  23. package/bin/_lib_dashboard_sources.py +20 -7
  24. package/bin/_lib_doctor.py +106 -0
  25. package/bin/_lib_jsonl.py +11 -0
  26. package/bin/_lib_pricing.py +7 -4
  27. package/bin/_lib_pricing_check.py +7 -1
  28. package/bin/_lib_quota.py +12 -11
  29. package/bin/_lib_statusline_candidates.py +734 -0
  30. package/bin/_lib_view_models.py +50 -14
  31. package/bin/cctally +31 -2
  32. package/dashboard/static/assets/index-DeQjEMO6.js +80 -0
  33. package/dashboard/static/assets/index-ZiPO8veo.css +1 -0
  34. package/dashboard/static/dashboard.html +2 -2
  35. package/package.json +4 -1
  36. package/dashboard/static/assets/index-BWadAHxC.js +0 -80
  37. package/dashboard/static/assets/index-D2nwo_ln.css +0 -1
@@ -1884,20 +1884,8 @@ def build_codex_weekly_view(entries, *, now_utc, tz_name=None,
1884
1884
  )
1885
1885
 
1886
1886
 
1887
- def build_codex_session_view(entries, *, now_utc, tz_name=None, speed="standard"):
1888
- """Build a ``CodexSessionView`` from a list of ``CodexEntry`` (issue #58).
1889
-
1890
- ``rows`` order mirrors the aggregator: descending by
1891
- ``last_activity`` (upstream parity).
1892
- ``cmd_codex_session`` reverses to ASC when ``--order asc``.
1893
-
1894
- ``period_start`` is set to ``min(s.last_activity)`` across emitted
1895
- sessions when any exist — best-available approximation since
1896
- ``CodexSessionUsage`` doesn't carry a ``first_activity`` field (the
1897
- aggregator only tracks ``last`` per session). ``None`` on empty.
1898
- """
1899
- _agg = _load_lib("_lib_aggregators")
1900
- sessions = _agg._aggregate_codex_sessions(entries, speed=speed)
1887
+ def _build_codex_session_view_from_rows(sessions, *, now_utc, tz_name):
1888
+ """Wrap already-aggregated Codex sessions in the public view contract."""
1901
1889
  total_cost = 0.0
1902
1890
  total_tok = 0
1903
1891
  earliest = None
@@ -1915,3 +1903,51 @@ def build_codex_session_view(entries, *, now_utc, tz_name=None, speed="standard"
1915
1903
  period_end=now_utc,
1916
1904
  display_tz_label=_codex_tz_label(tz_name),
1917
1905
  )
1906
+
1907
+
1908
+ def build_codex_session_view(entries, *, now_utc, tz_name=None, speed="standard"):
1909
+ """Build a ``CodexSessionView`` from CLI ``CodexEntry`` rows (issue #58)."""
1910
+ _agg = _load_lib("_lib_aggregators")
1911
+ return _build_codex_session_view_from_rows(
1912
+ _agg._aggregate_codex_sessions(entries, speed=speed),
1913
+ now_utc=now_utc,
1914
+ tz_name=tz_name,
1915
+ )
1916
+
1917
+
1918
+ def build_rooted_codex_session_view(entries, *, now_utc, tz_name=None, speed="standard"):
1919
+ """Build dashboard sessions from cache-rooted accounting without I/O.
1920
+
1921
+ The file identity is lexical: ``(source_root_key, source_path)``. It
1922
+ deliberately does not inspect configured roots or touch the filesystem,
1923
+ and a native session id remains payload rather than a grouping key.
1924
+ """
1925
+ _agg = _load_lib("_lib_aggregators")
1926
+ keyed = []
1927
+ for entry in entries:
1928
+ source_path = str(getattr(entry, "source_path"))
1929
+ source_root_key = str(getattr(entry, "source_root_key"))
1930
+ path = pathlib.PurePosixPath(source_path)
1931
+ codex_entry = _agg.CodexEntry(
1932
+ timestamp=getattr(entry, "timestamp"),
1933
+ session_id=str(getattr(entry, "session_id") or ""),
1934
+ model=str(getattr(entry, "model")),
1935
+ input_tokens=int(getattr(entry, "input_tokens")),
1936
+ cached_input_tokens=int(getattr(entry, "cached_input_tokens")),
1937
+ output_tokens=int(getattr(entry, "output_tokens")),
1938
+ reasoning_output_tokens=int(getattr(entry, "reasoning_output_tokens")),
1939
+ total_tokens=int(getattr(entry, "total_tokens")),
1940
+ source_path=source_path,
1941
+ )
1942
+ keyed.append((codex_entry, _agg.CodexSessionIdentity(
1943
+ group_key=(source_root_key, source_path),
1944
+ session_id_path=source_path,
1945
+ session_file=path.stem,
1946
+ directory=str(path.parent),
1947
+ codex_root=source_root_key,
1948
+ )))
1949
+ return _build_codex_session_view_from_rows(
1950
+ _agg._aggregate_codex_sessions_keyed(keyed, speed=speed),
1951
+ now_utc=now_utc,
1952
+ tz_name=tz_name,
1953
+ )
package/bin/cctally CHANGED
@@ -312,11 +312,17 @@ HOOK_TICK_LOG_ROTATED_PATH = _cctally_core.HOOK_TICK_LOG_ROTATED_PATH
312
312
  HOOK_TICK_THROTTLE_PATH = _cctally_core.HOOK_TICK_THROTTLE_PATH
313
313
  HOOK_TICK_THROTTLE_LOCK_PATH = _cctally_core.HOOK_TICK_THROTTLE_LOCK_PATH
314
314
 
315
- # Statusline usage-persistence markers + tunables (spec 2026-07-17).
315
+ # Statusline candidate-arbitration paths + tunables (#318).
316
316
  STATUSLINE_OBSERVE_MARKER_PATH = _cctally_core.STATUSLINE_OBSERVE_MARKER_PATH
317
317
  STATUSLINE_PERSIST_LOCK_PATH = _cctally_core.STATUSLINE_PERSIST_LOCK_PATH
318
+ STATUSLINE_CANDIDATE_DIR = _cctally_core.STATUSLINE_CANDIDATE_DIR
319
+ STATUSLINE_SELECTED_PATH = _cctally_core.STATUSLINE_SELECTED_PATH
320
+ STATUSLINE_TRANSPORT_MARKER_PATH = _cctally_core.STATUSLINE_TRANSPORT_MARKER_PATH
321
+ STATUSLINE_AUTHORITATIVE_7D_PATH = _cctally_core.STATUSLINE_AUTHORITATIVE_7D_PATH
322
+ STATUSLINE_AUTHORITATIVE_5H_PATH = _cctally_core.STATUSLINE_AUTHORITATIVE_5H_PATH
318
323
  OAUTH_BACKOFF_MARKER_PATH = _cctally_core.OAUTH_BACKOFF_MARKER_PATH
319
- STATUSLINE_PERSIST_THROTTLE_SECONDS = _cctally_core.STATUSLINE_PERSIST_THROTTLE_SECONDS
324
+ STATUSLINE_CANDIDATE_TTL_SECONDS = _cctally_core.STATUSLINE_CANDIDATE_TTL_SECONDS
325
+ STATUSLINE_CANDIDATE_FUTURE_SKEW_SECONDS = _cctally_core.STATUSLINE_CANDIDATE_FUTURE_SKEW_SECONDS
320
326
  OAUTH_BACKFILL_STALE_SECONDS = _cctally_core.OAUTH_BACKFILL_STALE_SECONDS
321
327
  OAUTH_BACKOFF_BASE_SECONDS = _cctally_core.OAUTH_BACKOFF_BASE_SECONDS
322
328
  OAUTH_BACKOFF_CAP_SECONDS = _cctally_core.OAUTH_BACKOFF_CAP_SECONDS
@@ -1037,12 +1043,14 @@ _build_credit_plan = _cctally_record._build_credit_plan
1037
1043
  _resolve_reset_aware_hwm = _cctally_record._resolve_reset_aware_hwm
1038
1044
  _insert_credit_snapshot = _cctally_record._insert_credit_snapshot
1039
1045
  _resolve_prior_5h = _cctally_record._resolve_prior_5h
1046
+ _resolve_active_five_hour_reset_event_id = _cctally_record._resolve_active_five_hour_reset_event_id
1040
1047
  _apply_credit = _cctally_record._apply_credit
1041
1048
  _fire_in_place_credit = _cctally_record._fire_in_place_credit
1042
1049
  _force_clear_credit = _cctally_record._force_clear_credit
1043
1050
  _count_stale_replays = _cctally_record._count_stale_replays
1044
1051
  _credit_preview_text = _cctally_record._credit_preview_text
1045
1052
  _credit_json = _cctally_record._credit_json
1053
+ _revalidate_credit_plan = _cctally_record._revalidate_credit_plan
1046
1054
  _arm_reset_zero_marker = _cctally_record._arm_reset_zero_marker
1047
1055
  _read_reset_zero_marker = _cctally_record._read_reset_zero_marker
1048
1056
  _clear_reset_zero_marker = _cctally_record._clear_reset_zero_marker
@@ -1055,6 +1063,8 @@ _hook_tick_throttle_touch = _cctally_record._hook_tick_throttle_touch
1055
1063
  # `cctally.X` (the `_cctally()` accessor + test monkeypatch surface) resolves.
1056
1064
  _statusline_observe_age_seconds = _cctally_record._statusline_observe_age_seconds
1057
1065
  _statusline_observe_touch = _cctally_record._statusline_observe_touch
1066
+ _statusline_transport_age_seconds = _cctally_record._statusline_transport_age_seconds
1067
+ _statusline_transport_touch = _cctally_record._statusline_transport_touch
1058
1068
  _oauth_backoff_remaining_seconds = _cctally_record._oauth_backoff_remaining_seconds
1059
1069
  _oauth_backoff_set = _cctally_record._oauth_backoff_set
1060
1070
  _oauth_backoff_clear = _cctally_record._oauth_backoff_clear
@@ -1322,6 +1332,25 @@ _fork_persist = _cctally_statusline._fork_persist
1322
1332
  _record_args = _cctally_statusline._record_args
1323
1333
  _try_acquire_persist_lock = _cctally_statusline._try_acquire_persist_lock
1324
1334
  _release_persist_lock = _cctally_statusline._release_persist_lock
1335
+ _atomic_write_json = _cctally_statusline._atomic_write_json
1336
+ _load_candidate_spool = _cctally_statusline._load_candidate_spool
1337
+ _scan_active_candidate_spool = _cctally_statusline._scan_active_candidate_spool
1338
+ _read_db_projection_stable = _cctally_statusline._read_db_projection_stable
1339
+ _read_db_projection_once = _cctally_statusline._read_db_projection_once
1340
+ _read_control_state = _cctally_statusline._read_control_state
1341
+ _statusline_control_db_agreement = _cctally_statusline._statusline_control_db_agreement
1342
+ _write_control_state = _cctally_statusline._write_control_state
1343
+ _reconcile_selected_control = _cctally_statusline._reconcile_selected_control
1344
+ _read_tombstone = _cctally_statusline._read_tombstone
1345
+ _write_tombstone = _cctally_statusline._write_tombstone
1346
+ _selected_state_lock = _cctally_statusline._selected_state_lock
1347
+ _authoritative_begin = _cctally_statusline._authoritative_begin
1348
+ _authoritative_commit = _cctally_statusline._authoritative_commit
1349
+ _authoritative_record_usage = _cctally_statusline._authoritative_record_usage
1350
+ _authoritative_repair_required = _cctally_statusline._authoritative_repair_required
1351
+ _after_authoritative_record = _cctally_statusline._after_authoritative_record
1352
+ _statusline_reduce_and_publish = _cctally_statusline._statusline_reduce_and_publish
1353
+ _build_publication_plan = _cctally_statusline._build_publication_plan
1325
1354
 
1326
1355
 
1327
1356
  # Eager re-export of bin/_cctally_codex.py — the four cmd_codex_* are the