codex-meter 0.3.0__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.
- codex_meter/__init__.py +12 -0
- codex_meter/__main__.py +4 -0
- codex_meter/aggregation.py +127 -0
- codex_meter/budgets.py +133 -0
- codex_meter/cli.py +2455 -0
- codex_meter/config.py +164 -0
- codex_meter/exporters.py +339 -0
- codex_meter/forecasts.py +92 -0
- codex_meter/humanize.py +38 -0
- codex_meter/insights.py +132 -0
- codex_meter/intervals.py +129 -0
- codex_meter/live.py +286 -0
- codex_meter/models.py +282 -0
- codex_meter/parse_cache.py +189 -0
- codex_meter/parser.py +498 -0
- codex_meter/pricing.py +311 -0
- codex_meter/prom_export.py +116 -0
- codex_meter/py.typed +0 -0
- codex_meter/render.py +545 -0
- codex_meter/timeutil.py +75 -0
- codex_meter/windows.py +153 -0
- codex_meter-0.3.0.dist-info/METADATA +304 -0
- codex_meter-0.3.0.dist-info/RECORD +26 -0
- codex_meter-0.3.0.dist-info/WHEEL +4 -0
- codex_meter-0.3.0.dist-info/entry_points.txt +2 -0
- codex_meter-0.3.0.dist-info/licenses/LICENSE +21 -0
codex_meter/windows.py
ADDED
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
"""Rate-limit window math. Pure functions, no I/O."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import datetime as dt
|
|
6
|
+
from dataclasses import dataclass
|
|
7
|
+
|
|
8
|
+
from codex_meter.models import RateLimitSample
|
|
9
|
+
|
|
10
|
+
BURN_RATE_LOOKBACK_HOURS = 6
|
|
11
|
+
MIN_BURN_RATE_SAMPLES = 3
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
@dataclass(frozen=True)
|
|
15
|
+
class WindowState:
|
|
16
|
+
"""Decoded state of a single rate-limit window at a moment in time."""
|
|
17
|
+
|
|
18
|
+
window: str # "primary" or "secondary"
|
|
19
|
+
used_percent: float | None
|
|
20
|
+
window_minutes: int | None
|
|
21
|
+
reset_at: dt.datetime | None
|
|
22
|
+
seconds_remaining: int | None
|
|
23
|
+
burn_rate_per_hour: float | None # percent points per hour
|
|
24
|
+
eta_to_100: dt.datetime | None
|
|
25
|
+
samples: int
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
def _coerce_float(value: object) -> float | None:
|
|
29
|
+
try:
|
|
30
|
+
return float(value) if value is not None else None
|
|
31
|
+
except (TypeError, ValueError):
|
|
32
|
+
return None
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
def _coerce_int(value: object) -> int | None:
|
|
36
|
+
try:
|
|
37
|
+
return int(value) if value is not None else None
|
|
38
|
+
except (TypeError, ValueError):
|
|
39
|
+
return None
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
def _epoch_to_datetime(value: object) -> dt.datetime | None:
|
|
43
|
+
seconds = _coerce_int(value)
|
|
44
|
+
if seconds is None:
|
|
45
|
+
return None
|
|
46
|
+
try:
|
|
47
|
+
return dt.datetime.fromtimestamp(seconds, tz=dt.UTC)
|
|
48
|
+
except (OverflowError, OSError, ValueError):
|
|
49
|
+
return None
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
def _percent(sample: RateLimitSample, which: str) -> float | None:
|
|
53
|
+
return _coerce_float(getattr(sample, f"{which}_used_percent", None))
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
def _window_minutes(sample: RateLimitSample, which: str) -> int | None:
|
|
57
|
+
return _coerce_int(getattr(sample, f"{which}_window_minutes", None))
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
def _reset_at(sample: RateLimitSample, which: str) -> dt.datetime | None:
|
|
61
|
+
return _epoch_to_datetime(getattr(sample, f"{which}_resets_at", None))
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
def compute_window_state(
|
|
65
|
+
samples: list[RateLimitSample], now: dt.datetime, which: str
|
|
66
|
+
) -> WindowState:
|
|
67
|
+
"""Compute a WindowState from raw RateLimitSamples. `which` is 'primary' or 'secondary'."""
|
|
68
|
+
if which not in {"primary", "secondary"}:
|
|
69
|
+
raise ValueError(f"window must be 'primary' or 'secondary', got {which!r}")
|
|
70
|
+
if not samples:
|
|
71
|
+
return WindowState(
|
|
72
|
+
window=which,
|
|
73
|
+
used_percent=None,
|
|
74
|
+
window_minutes=None,
|
|
75
|
+
reset_at=None,
|
|
76
|
+
seconds_remaining=None,
|
|
77
|
+
burn_rate_per_hour=None,
|
|
78
|
+
eta_to_100=None,
|
|
79
|
+
samples=0,
|
|
80
|
+
)
|
|
81
|
+
|
|
82
|
+
ordered = sorted(samples, key=lambda sample: sample.timestamp)
|
|
83
|
+
latest = ordered[-1]
|
|
84
|
+
used = _percent(latest, which)
|
|
85
|
+
window_minutes = _window_minutes(latest, which)
|
|
86
|
+
reset_at = _reset_at(latest, which)
|
|
87
|
+
|
|
88
|
+
seconds_remaining: int | None = None
|
|
89
|
+
if reset_at is not None:
|
|
90
|
+
seconds_remaining = max(0, int((reset_at - now).total_seconds()))
|
|
91
|
+
|
|
92
|
+
burn_rate = _compute_burn_rate(ordered, latest, which)
|
|
93
|
+
eta_to_100 = _project_to_full(used, burn_rate, now)
|
|
94
|
+
|
|
95
|
+
return WindowState(
|
|
96
|
+
window=which,
|
|
97
|
+
used_percent=used,
|
|
98
|
+
window_minutes=window_minutes,
|
|
99
|
+
reset_at=reset_at,
|
|
100
|
+
seconds_remaining=seconds_remaining,
|
|
101
|
+
burn_rate_per_hour=burn_rate,
|
|
102
|
+
eta_to_100=eta_to_100,
|
|
103
|
+
samples=len(ordered),
|
|
104
|
+
)
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
def _compute_burn_rate(
|
|
108
|
+
ordered: list[RateLimitSample], latest: RateLimitSample, which: str
|
|
109
|
+
) -> float | None:
|
|
110
|
+
"""Burn rate in percent-points per hour, derived from samples within the lookback window."""
|
|
111
|
+
cutoff = latest.timestamp - dt.timedelta(hours=BURN_RATE_LOOKBACK_HOURS)
|
|
112
|
+
recent = [sample for sample in ordered if sample.timestamp >= cutoff]
|
|
113
|
+
if len(recent) < MIN_BURN_RATE_SAMPLES:
|
|
114
|
+
return None
|
|
115
|
+
first = recent[0]
|
|
116
|
+
first_pct = _percent(first, which)
|
|
117
|
+
last_pct = _percent(latest, which)
|
|
118
|
+
if first_pct is None or last_pct is None:
|
|
119
|
+
return None
|
|
120
|
+
elapsed_hours = (latest.timestamp - first.timestamp).total_seconds() / 3600.0
|
|
121
|
+
if elapsed_hours <= 0:
|
|
122
|
+
return None
|
|
123
|
+
return (last_pct - first_pct) / elapsed_hours
|
|
124
|
+
|
|
125
|
+
|
|
126
|
+
def _project_to_full(
|
|
127
|
+
used: float | None, burn_rate: float | None, now: dt.datetime
|
|
128
|
+
) -> dt.datetime | None:
|
|
129
|
+
if used is None or burn_rate is None or burn_rate <= 0 or used >= 100:
|
|
130
|
+
return None
|
|
131
|
+
hours_to_full = (100.0 - used) / burn_rate
|
|
132
|
+
return now + dt.timedelta(hours=hours_to_full)
|
|
133
|
+
|
|
134
|
+
|
|
135
|
+
def format_seconds_remaining(seconds: int | None) -> str:
|
|
136
|
+
"""Render seconds as `Xh YYm ZZs`, `Ym Ss`, or `—`."""
|
|
137
|
+
if seconds is None:
|
|
138
|
+
return "—"
|
|
139
|
+
seconds = max(0, int(seconds))
|
|
140
|
+
hours, rem = divmod(seconds, 3600)
|
|
141
|
+
minutes, secs = divmod(rem, 60)
|
|
142
|
+
if hours:
|
|
143
|
+
return f"{hours}h {minutes:02d}m {secs:02d}s"
|
|
144
|
+
if minutes:
|
|
145
|
+
return f"{minutes}m {secs:02d}s"
|
|
146
|
+
return f"{secs}s"
|
|
147
|
+
|
|
148
|
+
|
|
149
|
+
def format_burn_rate(rate: float | None) -> str:
|
|
150
|
+
if rate is None:
|
|
151
|
+
return "—"
|
|
152
|
+
sign = "+" if rate >= 0 else ""
|
|
153
|
+
return f"{sign}{rate:.2f}%/h"
|
|
@@ -0,0 +1,304 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: codex-meter
|
|
3
|
+
Version: 0.3.0
|
|
4
|
+
Summary: Local Codex usage intelligence for sessions, projects, models, cache, and rate-limit windows.
|
|
5
|
+
Project-URL: Homepage, https://github.com/rajdeepmondaldotcom/codex-meter
|
|
6
|
+
Project-URL: Repository, https://github.com/rajdeepmondaldotcom/codex-meter
|
|
7
|
+
Project-URL: Issues, https://github.com/rajdeepmondaldotcom/codex-meter/issues
|
|
8
|
+
Project-URL: Changelog, https://github.com/rajdeepmondaldotcom/codex-meter/blob/main/CHANGELOG.md
|
|
9
|
+
Author: Rajdeep Mondal
|
|
10
|
+
License-Expression: MIT
|
|
11
|
+
License-File: LICENSE
|
|
12
|
+
Keywords: cli,codex,credits,openai,tokens,usage
|
|
13
|
+
Classifier: Development Status :: 4 - Beta
|
|
14
|
+
Classifier: Environment :: Console
|
|
15
|
+
Classifier: Intended Audience :: Developers
|
|
16
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
17
|
+
Classifier: Operating System :: OS Independent
|
|
18
|
+
Classifier: Programming Language :: Python :: 3
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
21
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
22
|
+
Classifier: Topic :: Software Development
|
|
23
|
+
Classifier: Topic :: Utilities
|
|
24
|
+
Classifier: Typing :: Typed
|
|
25
|
+
Requires-Python: >=3.11
|
|
26
|
+
Requires-Dist: rich>=13.7
|
|
27
|
+
Requires-Dist: typer>=0.12
|
|
28
|
+
Provides-Extra: prom
|
|
29
|
+
Requires-Dist: prometheus-client>=0.20; extra == 'prom'
|
|
30
|
+
Description-Content-Type: text/markdown
|
|
31
|
+
|
|
32
|
+
# codex-meter
|
|
33
|
+
|
|
34
|
+
[](https://github.com/rajdeepmondaldotcom/codex-meter/actions/workflows/ci.yml)
|
|
35
|
+
[](https://pypi.org/project/codex-meter/)
|
|
36
|
+
[](pyproject.toml)
|
|
37
|
+
[](LICENSE)
|
|
38
|
+
|
|
39
|
+
Understand your Codex work locally.
|
|
40
|
+
|
|
41
|
+
`codex-meter` turns local Codex logs into a clear record of how your coding work
|
|
42
|
+
happened: sessions, projects, models, tiers, cache reuse, tokens, credits,
|
|
43
|
+
API-equivalent dollars, and rate-limit windows.
|
|
44
|
+
|
|
45
|
+
No cloud sync. No account login. No billing scrape. Just local evidence you can
|
|
46
|
+
inspect, export, and trust.
|
|
47
|
+
|
|
48
|
+
## Install
|
|
49
|
+
|
|
50
|
+
Requires Python 3.11+.
|
|
51
|
+
|
|
52
|
+
```bash
|
|
53
|
+
uvx codex-meter
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
Persistent install:
|
|
57
|
+
|
|
58
|
+
```bash
|
|
59
|
+
uv tool install codex-meter
|
|
60
|
+
codex-meter
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
With `pipx`:
|
|
64
|
+
|
|
65
|
+
```bash
|
|
66
|
+
pipx install codex-meter
|
|
67
|
+
codex-meter
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
With `pip`:
|
|
71
|
+
|
|
72
|
+
```bash
|
|
73
|
+
python -m pip install codex-meter
|
|
74
|
+
codex-meter
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
Prometheus exporter:
|
|
78
|
+
|
|
79
|
+
```bash
|
|
80
|
+
uv tool install 'codex-meter[prom]'
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
Homebrew:
|
|
84
|
+
|
|
85
|
+
```bash
|
|
86
|
+
brew install rajdeepmondaldotcom/tap/codex-meter
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
## Start Here
|
|
90
|
+
|
|
91
|
+
```bash
|
|
92
|
+
codex-meter # 7 / 30 / 90 day overview
|
|
93
|
+
codex-meter doctor # check local data and assumptions
|
|
94
|
+
codex-meter live # watch usage while you work
|
|
95
|
+
codex-meter project --days 30 # see project activity
|
|
96
|
+
codex-meter models --days 30 # inspect model and tier mix
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
The first run parses local session files. Later runs use a sidecar parse cache.
|
|
100
|
+
Use `--no-parse-cache` when debugging parser behavior.
|
|
101
|
+
|
|
102
|
+
## Why It Exists
|
|
103
|
+
|
|
104
|
+
Codex already leaves a detailed trail on your machine. The problem is that the
|
|
105
|
+
trail is split across JSONL sessions, SQLite metadata, config, rate-limit
|
|
106
|
+
samples, and pricing assumptions. `codex-meter` turns that trail into one local
|
|
107
|
+
view.
|
|
108
|
+
|
|
109
|
+
It answers:
|
|
110
|
+
|
|
111
|
+
- What did I use?
|
|
112
|
+
- Where did it go?
|
|
113
|
+
- Which model and tier drove it?
|
|
114
|
+
- How much input was cached?
|
|
115
|
+
- What changed across sessions, projects, and days?
|
|
116
|
+
|
|
117
|
+
This is not an OpenAI billing ledger. It is local usage intelligence.
|
|
118
|
+
|
|
119
|
+
## Commands
|
|
120
|
+
|
|
121
|
+
| Need | Command |
|
|
122
|
+
| --- | --- |
|
|
123
|
+
| Overview | `codex-meter` |
|
|
124
|
+
| Daily / weekly / monthly | `codex-meter daily`, `weekly`, `monthly` |
|
|
125
|
+
| Sessions | `codex-meter session --top 20` |
|
|
126
|
+
| Projects | `codex-meter project --days 30` |
|
|
127
|
+
| Models and tiers | `codex-meter models --days 30` |
|
|
128
|
+
| Recent events | `codex-meter tail --n 20` |
|
|
129
|
+
| Rate limits | `codex-meter limits` |
|
|
130
|
+
| Insights | `codex-meter insights` |
|
|
131
|
+
| Forecast | `codex-meter forecast --days 14` |
|
|
132
|
+
| Compare windows | `codex-meter compare --a "last 7 days" --b "previous 7 days"` |
|
|
133
|
+
| What-if pricing | `codex-meter whatif --tier standard` |
|
|
134
|
+
| Optional budgets | `codex-meter budgets check` |
|
|
135
|
+
| Receipt | `codex-meter export receipt --month 2026-05 --format html` |
|
|
136
|
+
| Prometheus | `codex-meter export prometheus --port 9090` |
|
|
137
|
+
| Grafana | `codex-meter export grafana > dashboard.json` |
|
|
138
|
+
|
|
139
|
+
Most report commands support:
|
|
140
|
+
|
|
141
|
+
```bash
|
|
142
|
+
--format table|json|csv|markdown
|
|
143
|
+
--output report.json
|
|
144
|
+
--since 2026-05-01
|
|
145
|
+
--days 30
|
|
146
|
+
--top 20
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
## Live View
|
|
150
|
+
|
|
151
|
+
```bash
|
|
152
|
+
codex-meter live
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
Shows today's usage, trailing 7-day usage, 5-hour and weekly windows, burn rate,
|
|
156
|
+
and ETA to 100% when enough samples exist.
|
|
157
|
+
|
|
158
|
+
Hotkeys:
|
|
159
|
+
|
|
160
|
+
| Key | Action |
|
|
161
|
+
| --- | --- |
|
|
162
|
+
| `q` | Quit |
|
|
163
|
+
| `?` | Help |
|
|
164
|
+
| `r` | Refresh |
|
|
165
|
+
| `p` | Pause |
|
|
166
|
+
|
|
167
|
+
## Budgets
|
|
168
|
+
|
|
169
|
+
Create a config:
|
|
170
|
+
|
|
171
|
+
```bash
|
|
172
|
+
codex-meter init
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
Add limits:
|
|
176
|
+
|
|
177
|
+
```toml
|
|
178
|
+
[budgets]
|
|
179
|
+
daily_credits = 25000
|
|
180
|
+
weekly_credits = 100000
|
|
181
|
+
monthly_credits = 400000
|
|
182
|
+
weekly_api_dollars = 50.0
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
Check them:
|
|
186
|
+
|
|
187
|
+
```bash
|
|
188
|
+
codex-meter budgets check
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
Exit codes are built for automation:
|
|
192
|
+
|
|
193
|
+
| Exit | Meaning |
|
|
194
|
+
| ---: | --- |
|
|
195
|
+
| `0` | ok |
|
|
196
|
+
| `1` | warning |
|
|
197
|
+
| `2` | breached or failed |
|
|
198
|
+
|
|
199
|
+
## Exports
|
|
200
|
+
|
|
201
|
+
```bash
|
|
202
|
+
codex-meter export receipt --month 2026-05 --format markdown
|
|
203
|
+
codex-meter export receipt --month 2026-05 --format html > receipt.html
|
|
204
|
+
codex-meter export prometheus --host 127.0.0.1 --port 9090
|
|
205
|
+
codex-meter export grafana > dashboard.json
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
Receipts redact local session and project labels by default. Use
|
|
209
|
+
`--show-sensitive` only for private artifacts.
|
|
210
|
+
|
|
211
|
+
Prometheus exposes credits, burn rate, rate-limit window percent, event count,
|
|
212
|
+
long-context event count, and tokens by model/tier/kind.
|
|
213
|
+
|
|
214
|
+
## Data Sources
|
|
215
|
+
|
|
216
|
+
`codex-meter` reads:
|
|
217
|
+
|
|
218
|
+
- `~/.codex/sessions/**/*.jsonl`
|
|
219
|
+
- `~/.codex/state_5.sqlite`
|
|
220
|
+
- `~/.codex/config.toml`
|
|
221
|
+
|
|
222
|
+
Normal reports do not touch the network. The only networked command is explicit:
|
|
223
|
+
|
|
224
|
+
```bash
|
|
225
|
+
codex-meter rates refresh --allow-network
|
|
226
|
+
```
|
|
227
|
+
|
|
228
|
+
That writes a local pricing-source audit snapshot, including observed token
|
|
229
|
+
rates, fast multipliers, long-context rules, and discrepancies. It does not
|
|
230
|
+
rewrite the embedded rate card.
|
|
231
|
+
|
|
232
|
+
## Accuracy
|
|
233
|
+
|
|
234
|
+
The hard part is not adding tokens. It is making assumptions visible.
|
|
235
|
+
|
|
236
|
+
`codex-meter` tracks cached input separately, applies per-model long-context
|
|
237
|
+
rules, uses exact decimal math internally, and reports whether service tiers
|
|
238
|
+
came from logs, config, overrides, or assumptions. If a model or credit rate is
|
|
239
|
+
not source-verified, reports mark pricing as partial instead of silently using a
|
|
240
|
+
fallback as exact.
|
|
241
|
+
|
|
242
|
+
Reasoning tokens are only billed separately when the Codex token log shows they
|
|
243
|
+
are not already included in output tokens. This prevents double-counting on
|
|
244
|
+
current local Codex logs.
|
|
245
|
+
|
|
246
|
+
Service-tier precedence:
|
|
247
|
+
|
|
248
|
+
1. `--service-tier standard|fast`
|
|
249
|
+
2. `--tier-overrides overrides.json`
|
|
250
|
+
3. logged tier
|
|
251
|
+
4. current `~/.codex/config.toml`
|
|
252
|
+
5. `--unknown-service-tier`
|
|
253
|
+
|
|
254
|
+
Inspect pricing:
|
|
255
|
+
|
|
256
|
+
```bash
|
|
257
|
+
codex-meter rates show
|
|
258
|
+
codex-meter rates show --format json
|
|
259
|
+
```
|
|
260
|
+
|
|
261
|
+
Use local overrides when needed:
|
|
262
|
+
|
|
263
|
+
```bash
|
|
264
|
+
codex-meter daily --rates-file ./rates.json
|
|
265
|
+
```
|
|
266
|
+
|
|
267
|
+
Schemas:
|
|
268
|
+
|
|
269
|
+
- [`schemas/rates.schema.json`](schemas/rates.schema.json)
|
|
270
|
+
- [`schemas/tier-overrides.schema.json`](schemas/tier-overrides.schema.json)
|
|
271
|
+
|
|
272
|
+
## Privacy
|
|
273
|
+
|
|
274
|
+
The default posture is local and conservative.
|
|
275
|
+
|
|
276
|
+
- Reports read local files.
|
|
277
|
+
- Prompt and session labels are redacted unless requested.
|
|
278
|
+
- Receipts hide full session IDs and project paths by default.
|
|
279
|
+
- JSON, CSV, Markdown, and HTML exports may still contain local metadata.
|
|
280
|
+
|
|
281
|
+
Treat exports as sensitive unless you made them for sharing.
|
|
282
|
+
|
|
283
|
+
## Development
|
|
284
|
+
|
|
285
|
+
```bash
|
|
286
|
+
uv sync --dev
|
|
287
|
+
uv run ruff check .
|
|
288
|
+
uv run ruff format --check .
|
|
289
|
+
PYTHONWARNINGS=error::ResourceWarning uv run pytest
|
|
290
|
+
uv run pytest --cov=src/codex_meter --cov-report=term
|
|
291
|
+
uv run python -m build
|
|
292
|
+
```
|
|
293
|
+
|
|
294
|
+
Smoke test against your own logs:
|
|
295
|
+
|
|
296
|
+
```bash
|
|
297
|
+
uv run codex-meter doctor
|
|
298
|
+
uv run codex-meter overview
|
|
299
|
+
uv run codex-meter rates show
|
|
300
|
+
```
|
|
301
|
+
|
|
302
|
+
## License
|
|
303
|
+
|
|
304
|
+
MIT
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
codex_meter/__init__.py,sha256=IwovSXgnigRH64qIbBoBdQHsLUqa43qhK2tSTsmLUuA,292
|
|
2
|
+
codex_meter/__main__.py,sha256=Il5u5iA1jLBTRWK1Moy2K30VdDdN5Lld6zk2DDpQqUE,70
|
|
3
|
+
codex_meter/aggregation.py,sha256=ZyM0t2vz8Ceu1Jadmt6aJI30N4ju_j1QrmuQbN7eVBk,4330
|
|
4
|
+
codex_meter/budgets.py,sha256=OBBIEznlb5skrSyB494zhMw8fj_rAaSIp8Xfuk11t58,4278
|
|
5
|
+
codex_meter/cli.py,sha256=r9kAweIrKTsyKa_nTQqVmMNsLx1QYCLHYPA0YsrSqRk,87046
|
|
6
|
+
codex_meter/config.py,sha256=E-KcV9eXafzAMHT8Rnu4e4zeE-aPwHmEcvOPj9HRorY,6164
|
|
7
|
+
codex_meter/exporters.py,sha256=holZtgJPGnlNNYOT7egqUbdbYwVr8Ezoo1K9cgNho7A,12420
|
|
8
|
+
codex_meter/forecasts.py,sha256=XflsG2e2JI-8eZWeZbZ3-i-oP955sg-sKHEkB0OAiJQ,2686
|
|
9
|
+
codex_meter/humanize.py,sha256=h4KPo0zdugB7EjVml6_ooOyCyEg7bE3j9mG9MSfYFMs,1177
|
|
10
|
+
codex_meter/insights.py,sha256=8fkzO9GyrcQp2JMakb7Drxew-F9leNWAvgfPuA0gy-4,4768
|
|
11
|
+
codex_meter/intervals.py,sha256=GWtUkPftEEwUmRwTJzGIEGVLZjvkhZC8gf0qS52fqkM,4590
|
|
12
|
+
codex_meter/live.py,sha256=shtXCRGm4fn4GwinDMXKv3-g77qyHocgg4291f3VBao,10184
|
|
13
|
+
codex_meter/models.py,sha256=8Idl9gN0keOSho2xZdKoz6yFoi2fBNyjZKp3Qp2RxjI,8238
|
|
14
|
+
codex_meter/parse_cache.py,sha256=gwHC0rqZic3KGmfc2g-I7lKLg387YFeS-gbvhE6I6ws,6143
|
|
15
|
+
codex_meter/parser.py,sha256=70hLQwNBviKJcETKe2lpGU6AIIS35MWiu898zzaYvS4,18645
|
|
16
|
+
codex_meter/pricing.py,sha256=OxcA3ETBZ5caHbHN2XC7MEzseuJG_3TgxZQbbm1o1YU,11547
|
|
17
|
+
codex_meter/prom_export.py,sha256=jPFPplmr9AICp805wv4YhlcgiSQ4Nrp5z_4soIU0sz0,3920
|
|
18
|
+
codex_meter/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
19
|
+
codex_meter/render.py,sha256=67IyiXH-ciY347M9qhvGu6hcGWd5LoM93oYIQTgpiDY,19685
|
|
20
|
+
codex_meter/timeutil.py,sha256=0Vth-CWRwCmBh0oiGA_LkP9fsjk-Nts6SaNJI2LqiR0,2266
|
|
21
|
+
codex_meter/windows.py,sha256=Z2Ryst68Zu0usj3S_uvVuy_JiUFeB9vARwuryKeJq8k,4802
|
|
22
|
+
codex_meter-0.3.0.dist-info/METADATA,sha256=052G0GDMGwQPCJozZfcWMPResE8YZB9MgnrYu363MnQ,7934
|
|
23
|
+
codex_meter-0.3.0.dist-info/WHEEL,sha256=QccIxa26bgl1E6uMy58deGWi-0aeIkkangHcxk2kWfw,87
|
|
24
|
+
codex_meter-0.3.0.dist-info/entry_points.txt,sha256=3i4pFl39F6QW_OJQ2Ds5wM40eqArMNkFeuLftAdB_wM,52
|
|
25
|
+
codex_meter-0.3.0.dist-info/licenses/LICENSE,sha256=o5_prA7Ia_-1E726qg4ApoZOsGLloxBTq-Z6CCXMc9Y,1071
|
|
26
|
+
codex_meter-0.3.0.dist-info/RECORD,,
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Rajdeep Mondal
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|