cctrack 0.1.0__tar.gz → 0.2.0__tar.gz

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.
@@ -1,10 +1,10 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: cctrack
3
- Version: 0.1.0
3
+ Version: 0.2.0
4
4
  Summary: Claude Code cost tracker — scans JSONL logs and reports token usage + estimated cost
5
- Project-URL: Homepage, https://github.com/ksred/cctrack
6
- Project-URL: Repository, https://github.com/ksred/cctrack
7
- Project-URL: Issues, https://github.com/ksred/cctrack/issues
5
+ Project-URL: Homepage, https://github.com/rappdw/cctrack
6
+ Project-URL: Repository, https://github.com/rappdw/cctrack
7
+ Project-URL: Issues, https://github.com/rappdw/cctrack/issues
8
8
  Author: Dan Rapp
9
9
  License-Expression: MIT
10
10
  License-File: LICENSE
@@ -99,11 +99,12 @@ Prices per million tokens, from [Anthropic's pricing page](https://www.anthropic
99
99
 
100
100
  | Model | Input | Output | Cache Read | Cache Write |
101
101
  |---|---|---|---|---|
102
- | Opus 4.6 / 4.5 | $5.00 | $25.00 | $0.50 | $6.25 |
102
+ | Opus 4.7 / 4.6 / 4.5 | $5.00 | $25.00 | $0.50 | $6.25 |
103
103
  | Opus 4 / 4.1 | $15.00 | $75.00 | $1.50 | $18.75 |
104
- | Sonnet 4.x | $3.00 | $15.00 | $0.30 | $3.75 |
105
- | Haiku 4.5 | $1.00 | $5.00 | $0.10 | $1.25 |
106
- | Haiku 3.x | $0.80 | $4.00 | $0.08 | $1.00 |
104
+ | Sonnet 4.x / 3.7 | $3.00 | $15.00 | $0.30 | $3.75 |
105
+ | Haiku 4.x | $1.00 | $5.00 | $0.10 | $1.25 |
106
+ | Haiku 3.5 | $0.80 | $4.00 | $0.08 | $1.00 |
107
+ | Haiku 3 | $0.25 | $1.25 | $0.03 | $0.30 |
107
108
 
108
109
  Unknown models fall back to Sonnet rates.
109
110
 
@@ -74,11 +74,12 @@ Prices per million tokens, from [Anthropic's pricing page](https://www.anthropic
74
74
 
75
75
  | Model | Input | Output | Cache Read | Cache Write |
76
76
  |---|---|---|---|---|
77
- | Opus 4.6 / 4.5 | $5.00 | $25.00 | $0.50 | $6.25 |
77
+ | Opus 4.7 / 4.6 / 4.5 | $5.00 | $25.00 | $0.50 | $6.25 |
78
78
  | Opus 4 / 4.1 | $15.00 | $75.00 | $1.50 | $18.75 |
79
- | Sonnet 4.x | $3.00 | $15.00 | $0.30 | $3.75 |
80
- | Haiku 4.5 | $1.00 | $5.00 | $0.10 | $1.25 |
81
- | Haiku 3.x | $0.80 | $4.00 | $0.08 | $1.00 |
79
+ | Sonnet 4.x / 3.7 | $3.00 | $15.00 | $0.30 | $3.75 |
80
+ | Haiku 4.x | $1.00 | $5.00 | $0.10 | $1.25 |
81
+ | Haiku 3.5 | $0.80 | $4.00 | $0.08 | $1.00 |
82
+ | Haiku 3 | $0.25 | $1.25 | $0.03 | $0.30 |
82
83
 
83
84
  Unknown models fall back to Sonnet rates.
84
85
 
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "cctrack"
7
- version = "0.1.0"
7
+ version = "0.2.0"
8
8
  description = "Claude Code cost tracker — scans JSONL logs and reports token usage + estimated cost"
9
9
  readme = "README.md"
10
10
  license = "MIT"
@@ -31,6 +31,6 @@ classifiers = [
31
31
  cctrack = "cctrack:main"
32
32
 
33
33
  [project.urls]
34
- Homepage = "https://github.com/ksred/cctrack"
35
- Repository = "https://github.com/ksred/cctrack"
36
- Issues = "https://github.com/ksred/cctrack/issues"
34
+ Homepage = "https://github.com/rappdw/cctrack"
35
+ Repository = "https://github.com/rappdw/cctrack"
36
+ Issues = "https://github.com/rappdw/cctrack/issues"
@@ -25,15 +25,18 @@ from pathlib import Path
25
25
  # Longer/more-specific prefixes MUST come first — "claude-opus-4-6" would
26
26
  # otherwise match "claude-opus-4" and get the wrong rate.
27
27
  RATES = [
28
+ {"family": "claude-opus-4-7", "input": 5.0, "output": 25.0, "cache_read": 0.50, "cache_write": 6.25},
28
29
  {"family": "claude-opus-4-6", "input": 5.0, "output": 25.0, "cache_read": 0.50, "cache_write": 6.25},
29
30
  {"family": "claude-opus-4-5", "input": 5.0, "output": 25.0, "cache_read": 0.50, "cache_write": 6.25},
30
31
  {"family": "claude-opus-4", "input": 15.0, "output": 75.0, "cache_read": 1.50, "cache_write": 18.75},
31
32
  {"family": "claude-sonnet-4", "input": 3.0, "output": 15.0, "cache_read": 0.30, "cache_write": 3.75},
32
- {"family": "claude-haiku-4-5", "input": 1.0, "output": 5.0, "cache_read": 0.10, "cache_write": 1.25},
33
- {"family": "claude-haiku-3", "input": 0.80, "output": 4.0, "cache_read": 0.08, "cache_write": 1.00},
33
+ {"family": "claude-sonnet-3", "input": 3.0, "output": 15.0, "cache_read": 0.30, "cache_write": 3.75},
34
+ {"family": "claude-haiku-4", "input": 1.0, "output": 5.0, "cache_read": 0.10, "cache_write": 1.25},
35
+ {"family": "claude-haiku-3-5", "input": 0.80, "output": 4.0, "cache_read": 0.08, "cache_write": 1.00},
36
+ {"family": "claude-haiku-3", "input": 0.25, "output": 1.25, "cache_read": 0.03, "cache_write": 0.30},
34
37
  ]
35
38
 
36
- SONNET_RATES = RATES[3] # fallback
39
+ SONNET_RATES = RATES[4] # fallback
37
40
 
38
41
 
39
42
  def get_rates(model: str) -> dict:
@@ -52,13 +52,20 @@ def write_jsonl(dir_path: str, filename: str, events: list[dict]) -> str:
52
52
 
53
53
  # ── Rate card tests ─────────────────────────────────────────────────────
54
54
 
55
+ def test_get_rates_opus_4_7():
56
+ r = cctrack.get_rates("claude-opus-4-7-20260416")
57
+ assert r["family"] == "claude-opus-4-7"
58
+ assert r["input"] == 5.0
59
+ assert r["output"] == 25.0
60
+ assert r["cache_read"] == 0.50
61
+ assert r["cache_write"] == 6.25
62
+
63
+
55
64
  def test_get_rates_opus_4_6():
56
65
  r = cctrack.get_rates("claude-opus-4-6")
57
66
  assert r["family"] == "claude-opus-4-6"
58
67
  assert r["input"] == 5.0
59
68
  assert r["output"] == 25.0
60
- assert r["cache_read"] == 0.50
61
- assert r["cache_write"] == 6.25
62
69
 
63
70
 
64
71
  def test_get_rates_opus_4_5():
@@ -95,20 +102,34 @@ def test_get_rates_sonnet_4_6():
95
102
  assert r["input"] == 3.0
96
103
 
97
104
 
105
+ def test_get_rates_sonnet_3_7():
106
+ """Deprecated Sonnet 3.7 matches claude-sonnet-3 prefix."""
107
+ r = cctrack.get_rates("claude-sonnet-3-7-20250219")
108
+ assert r["family"] == "claude-sonnet-3"
109
+ assert r["input"] == 3.0
110
+
111
+
98
112
  def test_get_rates_haiku_4_5():
99
113
  r = cctrack.get_rates("claude-haiku-4-5-20251001")
100
- assert r["family"] == "claude-haiku-4-5"
114
+ assert r["family"] == "claude-haiku-4"
101
115
  assert r["input"] == 1.0
102
116
  assert r["output"] == 5.0
103
117
 
104
118
 
105
119
  def test_get_rates_haiku_3_5():
106
120
  r = cctrack.get_rates("claude-haiku-3-5-20241022")
107
- assert r["family"] == "claude-haiku-3"
121
+ assert r["family"] == "claude-haiku-3-5"
108
122
  assert r["input"] == 0.80
109
123
  assert r["output"] == 4.0
110
124
 
111
125
 
126
+ def test_get_rates_haiku_3():
127
+ r = cctrack.get_rates("claude-haiku-3-20240307")
128
+ assert r["family"] == "claude-haiku-3"
129
+ assert r["input"] == 0.25
130
+ assert r["output"] == 1.25
131
+
132
+
112
133
  def test_get_rates_unknown_falls_back_to_sonnet():
113
134
  r = cctrack.get_rates("claude-mystery-99")
114
135
  assert r["family"] == "claude-sonnet-4"
File without changes
File without changes
File without changes
File without changes