usage-cli 0.29.32__py3-none-any.whl
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.
- adapters/__init__.py +5 -0
- adapters/agy.py +68 -0
- adapters/claude.py +215 -0
- adapters/codex.py +209 -0
- adapters/rate_limits.py +76 -0
- adapters/registry.py +17 -0
- adapters/types.py +139 -0
- agy_disk_cache.py +135 -0
- agy_loader.py +416 -0
- agy_quota_probe.py +748 -0
- agy_window_keeper.py +185 -0
- analyzer/__init__.py +5 -0
- analyzer/aggregator.py +139 -0
- analyzer/blocks.py +80 -0
- analyzer/diagnoser.py +638 -0
- analyzer/insights.py +277 -0
- analyzer/persona_loader.py +199 -0
- analyzer/reporter.py +989 -0
- analyzer/subscription.py +108 -0
- burn_rate.py +75 -0
- cache_quarantine.py +50 -0
- codex_disk_cache.py +227 -0
- codex_events.py +136 -0
- codex_fork_replay.py +111 -0
- codex_loader.py +1426 -0
- codex_paths.py +20 -0
- critter_frames.py +26 -0
- discussion_bridge.py +1196 -0
- discussion_cli.py +844 -0
- discussion_session.py +622 -0
- discussion_usage.py +13 -0
- discussion_window.py +955 -0
- disk_cache_common.py +132 -0
- disk_cache_lifecycle.py +39 -0
- doctor.py +452 -0
- fsevents_watch.py +207 -0
- history_disk_cache.py +110 -0
- history_loader.py +416 -0
- i18n.py +88 -0
- jsonl_limits.py +17 -0
- jsonl_utils.py +40 -0
- login_item.py +154 -0
- main.py +387 -0
- menubar.py +1201 -0
- menubar_actions.py +204 -0
- menubar_agy.py +193 -0
- menubar_chrome.py +156 -0
- menubar_menu.py +169 -0
- menubar_notify.py +102 -0
- menubar_popover.py +233 -0
- menubar_prefs.py +118 -0
- menubar_refresh.py +285 -0
- menubar_state.py +1200 -0
- menubar_title.py +157 -0
- menubar_update.py +123 -0
- panel_window.py +78 -0
- panel_window_state.py +159 -0
- panels/__init__.py +186 -0
- panels/base.py +83 -0
- panels/dynamic_height.py +140 -0
- panels/payload.py +178 -0
- panels/web_panel.py +513 -0
- panels/window_drag.py +56 -0
- prefs.py +44 -0
- pricing.py +452 -0
- project_resolver.py +112 -0
- service_status.py +383 -0
- session_hooks.py +1154 -0
- setup_app.py +171 -0
- setup_hook.py +1011 -0
- statusline_settings.py +160 -0
- talent_market_bridge.py +243 -0
- time_utils.py +24 -0
- tui.py +288 -0
- tui_sprite.py +206 -0
- ui/__init__.py +5 -0
- ui/html_report.py +923 -0
- ui/report_scripts.py +251 -0
- ui/report_styles.py +370 -0
- ui/tables.py +888 -0
- update_checker.py +156 -0
- update_gate.py +66 -0
- update_release_notes.py +49 -0
- usage_cli-0.29.32.data/data/share/usage/i18n.json +2427 -0
- usage_cli-0.29.32.dist-info/METADATA +223 -0
- usage_cli-0.29.32.dist-info/RECORD +109 -0
- usage_cli-0.29.32.dist-info/WHEEL +5 -0
- usage_cli-0.29.32.dist-info/entry_points.txt +3 -0
- usage_cli-0.29.32.dist-info/licenses/LICENSE +663 -0
- usage_cli-0.29.32.dist-info/top_level.txt +80 -0
- usage_cli.py +827 -0
- usage_client.py +487 -0
- usage_diagnosis_snapshot.py +143 -0
- usage_dir_sweeper.py +100 -0
- usage_lang.py +79 -0
- usage_logging.py +75 -0
- usage_notifications.py +96 -0
- usage_rate.py +97 -0
- usage_session_resume.py +913 -0
- usage_statusline.py +810 -0
- usage_statusline_agy.py +397 -0
- usage_statusline_forwarder.py +88 -0
- usage_terse_mode.py +223 -0
- usage_terse_reminder.py +151 -0
- win_login_item.py +53 -0
- window_keeper.py +264 -0
- windows_watch.py +443 -0
- wintray.py +2014 -0
- wintray_menu.py +136 -0
codex_fork_replay.py
ADDED
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
# SPDX-License-Identifier: AGPL-3.0-only
|
|
2
|
+
# Copyright (C) 2026 lollapalooza <https://github.com/aqua5230>
|
|
3
|
+
#
|
|
4
|
+
# Part of "usage". Free software licensed under the GNU Affero General Public
|
|
5
|
+
# License v3.0 only; see the LICENSE file for full terms and the warranty disclaimer.
|
|
6
|
+
|
|
7
|
+
"""Stateless scanning for Codex fork-replay deduplication.
|
|
8
|
+
|
|
9
|
+
Fork logs rewrite replay timestamps but preserve the parent's cumulative token
|
|
10
|
+
sequence, so the boundary between replayed and new events is found by matching
|
|
11
|
+
token-usage prefixes against candidate parent logs. The LRU cache and its
|
|
12
|
+
orchestration (_fork_replay_boundary) stay in codex_loader; these helpers only
|
|
13
|
+
read the files they are handed.
|
|
14
|
+
"""
|
|
15
|
+
|
|
16
|
+
from __future__ import annotations
|
|
17
|
+
|
|
18
|
+
from pathlib import Path
|
|
19
|
+
from typing import Any
|
|
20
|
+
|
|
21
|
+
from codex_events import (
|
|
22
|
+
_as_dict,
|
|
23
|
+
_as_str,
|
|
24
|
+
_load_json_line,
|
|
25
|
+
_token_usage_from_payload,
|
|
26
|
+
_TokenUsage,
|
|
27
|
+
)
|
|
28
|
+
|
|
29
|
+
_ReplayCacheKey = tuple[str, float, int, int] | None
|
|
30
|
+
_ReplayLookupKey = tuple[float, int, tuple[tuple[str, float, int], ...]]
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
def _fork_replay_lookup_key(
|
|
34
|
+
path: Path,
|
|
35
|
+
parent_paths: list[Path],
|
|
36
|
+
) -> _ReplayLookupKey | None:
|
|
37
|
+
try:
|
|
38
|
+
child_stat = path.stat()
|
|
39
|
+
except OSError:
|
|
40
|
+
return None
|
|
41
|
+
parent_stats: list[tuple[str, float, int]] = []
|
|
42
|
+
for parent_path in parent_paths:
|
|
43
|
+
try:
|
|
44
|
+
parent_stat = parent_path.stat()
|
|
45
|
+
except OSError:
|
|
46
|
+
continue
|
|
47
|
+
parent_stats.append((str(parent_path), parent_stat.st_mtime, parent_stat.st_size))
|
|
48
|
+
return child_stat.st_mtime, child_stat.st_size, tuple(sorted(parent_stats))
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
def _token_usage_events_after_embedded_parent(
|
|
52
|
+
path: Path,
|
|
53
|
+
parent_session_id: str,
|
|
54
|
+
) -> list[tuple[int, _TokenUsage]] | None:
|
|
55
|
+
embedded_parent = False
|
|
56
|
+
root_seen = False
|
|
57
|
+
events: list[tuple[int, _TokenUsage]] = []
|
|
58
|
+
try:
|
|
59
|
+
with path.open(encoding="utf-8") as file:
|
|
60
|
+
for line_number, line in enumerate(file, start=1):
|
|
61
|
+
data = _load_json_line(line)
|
|
62
|
+
if data is None:
|
|
63
|
+
continue
|
|
64
|
+
if data.get("type") == "session_meta":
|
|
65
|
+
session_id = _as_str(_as_dict(data.get("payload")).get("id"))
|
|
66
|
+
if not root_seen:
|
|
67
|
+
root_seen = True
|
|
68
|
+
elif session_id == parent_session_id:
|
|
69
|
+
embedded_parent = True
|
|
70
|
+
continue
|
|
71
|
+
usage = _token_usage_from_event(data)
|
|
72
|
+
if embedded_parent and usage is not None:
|
|
73
|
+
events.append((line_number, usage))
|
|
74
|
+
except (OSError, UnicodeDecodeError):
|
|
75
|
+
return None
|
|
76
|
+
return events if embedded_parent else None
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
def _raw_token_usage_sequence(path: Path) -> list[_TokenUsage]:
|
|
80
|
+
usage_events: list[_TokenUsage] = []
|
|
81
|
+
try:
|
|
82
|
+
with path.open(encoding="utf-8") as file:
|
|
83
|
+
for line in file:
|
|
84
|
+
data = _load_json_line(line)
|
|
85
|
+
if data is None:
|
|
86
|
+
continue
|
|
87
|
+
usage = _token_usage_from_event(data)
|
|
88
|
+
if usage is not None:
|
|
89
|
+
usage_events.append(usage)
|
|
90
|
+
except (OSError, UnicodeDecodeError):
|
|
91
|
+
return []
|
|
92
|
+
return usage_events
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
def _token_usage_from_event(data: dict[str, Any]) -> _TokenUsage | None:
|
|
96
|
+
if data.get("type") != "event_msg":
|
|
97
|
+
return None
|
|
98
|
+
payload = _as_dict(data.get("payload"))
|
|
99
|
+
if payload.get("type") != "token_count":
|
|
100
|
+
return None
|
|
101
|
+
usage = _as_dict(_as_dict(payload.get("info")).get("total_token_usage"))
|
|
102
|
+
return _token_usage_from_payload(usage) if usage else None
|
|
103
|
+
|
|
104
|
+
|
|
105
|
+
def _common_prefix_length(left: list[_TokenUsage], right: list[_TokenUsage]) -> int:
|
|
106
|
+
matched = 0
|
|
107
|
+
for left_usage, right_usage in zip(left, right, strict=False):
|
|
108
|
+
if left_usage != right_usage:
|
|
109
|
+
break
|
|
110
|
+
matched += 1
|
|
111
|
+
return matched
|