ai-spend-tracker 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.
Files changed (26) hide show
  1. ai_spend_tracker-0.2.0/LICENSE +21 -0
  2. ai_spend_tracker-0.2.0/PKG-INFO +132 -0
  3. ai_spend_tracker-0.2.0/README.md +107 -0
  4. ai_spend_tracker-0.2.0/ai_spend_tracker/__init__.py +0 -0
  5. ai_spend_tracker-0.2.0/ai_spend_tracker/collectors/__init__.py +104 -0
  6. ai_spend_tracker-0.2.0/ai_spend_tracker/collectors/base.py +104 -0
  7. ai_spend_tracker-0.2.0/ai_spend_tracker/collectors/claude_code.py +273 -0
  8. ai_spend_tracker-0.2.0/ai_spend_tracker/collectors/codex.py +128 -0
  9. ai_spend_tracker-0.2.0/ai_spend_tracker/collectors/copilot.py +225 -0
  10. ai_spend_tracker-0.2.0/ai_spend_tracker/collectors/hermes.py +124 -0
  11. ai_spend_tracker-0.2.0/ai_spend_tracker/collectors/kimi.py +233 -0
  12. ai_spend_tracker-0.2.0/ai_spend_tracker/collectors/openclaw.py +255 -0
  13. ai_spend_tracker-0.2.0/ai_spend_tracker/collectors/opencode.py +252 -0
  14. ai_spend_tracker-0.2.0/ai_spend_tracker/config.py +259 -0
  15. ai_spend_tracker-0.2.0/ai_spend_tracker/demo.py +119 -0
  16. ai_spend_tracker-0.2.0/ai_spend_tracker/display.py +186 -0
  17. ai_spend_tracker-0.2.0/ai_spend_tracker/main.py +255 -0
  18. ai_spend_tracker-0.2.0/ai_spend_tracker/models.py +65 -0
  19. ai_spend_tracker-0.2.0/ai_spend_tracker.egg-info/PKG-INFO +132 -0
  20. ai_spend_tracker-0.2.0/ai_spend_tracker.egg-info/SOURCES.txt +24 -0
  21. ai_spend_tracker-0.2.0/ai_spend_tracker.egg-info/dependency_links.txt +1 -0
  22. ai_spend_tracker-0.2.0/ai_spend_tracker.egg-info/entry_points.txt +2 -0
  23. ai_spend_tracker-0.2.0/ai_spend_tracker.egg-info/requires.txt +1 -0
  24. ai_spend_tracker-0.2.0/ai_spend_tracker.egg-info/top_level.txt +1 -0
  25. ai_spend_tracker-0.2.0/pyproject.toml +45 -0
  26. ai_spend_tracker-0.2.0/setup.cfg +4 -0
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 vick
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.
@@ -0,0 +1,132 @@
1
+ Metadata-Version: 2.4
2
+ Name: ai-spend-tracker
3
+ Version: 0.2.0
4
+ Summary: Aggregate token usage & cost across all your AI coding agents (Hermes, Codex, Claude Code, Copilot, OpenCode, OpenClaw, Kimi)
5
+ Author: vick
6
+ License: MIT
7
+ Project-URL: Homepage, https://github.com/vick/ai-spend-tracker
8
+ Project-URL: Repository, https://github.com/vick/ai-spend-tracker
9
+ Project-URL: Bug Tracker, https://github.com/vick/ai-spend-tracker/issues
10
+ Keywords: token-usage,cost-tracking,ai-coding-agent,claude-code,opencode
11
+ Classifier: Development Status :: 3 - Alpha
12
+ Classifier: Environment :: Console
13
+ Classifier: Intended Audience :: Developers
14
+ Classifier: License :: OSI Approved :: MIT License
15
+ Classifier: Operating System :: OS Independent
16
+ Classifier: Programming Language :: Python :: 3
17
+ Classifier: Programming Language :: Python :: 3.10
18
+ Classifier: Programming Language :: Python :: 3.11
19
+ Classifier: Programming Language :: Python :: 3.12
20
+ Classifier: Programming Language :: Python :: 3.13
21
+ Classifier: Topic :: Utilities
22
+ Requires-Python: >=3.10
23
+ Description-Content-Type: text/markdown
24
+ Requires-Dist: rich>=13.0.0
25
+
26
+ # AI Spend Tracker
27
+
28
+ **Aggregate token usage & cost across all your AI coding agents in one CLI.**
29
+
30
+ If you run multiple AI coding tools (Claude Code, Codex, Hermes, OpenClaw, OpenCode, GitHub Copilot, Kimi), you're probably flying blind on how much you're actually spending. AI Spend Tracker reads session data from every agent's local storage and shows you the big picture.
31
+
32
+ ## Features
33
+
34
+ - **7 built-in collectors** — Hermes Agent, Codex CLI, GitHub Copilot CLI, OpenCode, Claude Code, OpenClaw, Kimi Code CLI
35
+ - **Cross-platform** — Windows (native + WSL), Linux, macOS
36
+ - **Multi-agent aggregation** — all agents in one report
37
+ - **Extensible** — drop a custom collector in `~/.ai-spend/collectors/`
38
+ - **Path override** — manual data source path via `~/.ai-spend/config.json`
39
+ - **Rich terminal output** — agent summary, model breakdown, daily trends
40
+ - **JSON output** — pipe data into your own dashboards
41
+
42
+ ## Supported Agents
43
+
44
+ | Collector | Agent | Data Source |
45
+ |-----------|-------|-------------|
46
+ | `hermes` | Hermes Agent (Nous Research) | `~/.hermes/state.db` |
47
+ | `codex` | OpenAI Codex CLI | `~/.codex/state_*.sqlite` |
48
+ | `copilot` | GitHub Copilot CLI | `~/.copilot/session-store.db` |
49
+ | `opencode` | OpenCode CLI | `~/.local/share/opencode/opencode.db` |
50
+ | `claude-code` | Claude Code (Anthropic) | `~/.claude/projects/*.jsonl` |
51
+ | `openclaw` | OpenClaw | `~/.openclaw/agents/*/sessions/*.jsonl` |
52
+ | `kimi` | Kimi Code CLI (Moonshot AI) | `~/.kimi/sessions/*/*/wire.jsonl` |
53
+
54
+ > Note: Claude Code v2.1.140+ may not persist session logs to disk. See [anthropics/claude-code#25941](https://github.com/anthropics/claude-code/issues/25941).
55
+
56
+ ## Quick Start
57
+
58
+ ```bash
59
+ # Install
60
+ pip install ai-spend-tracker
61
+
62
+ # See your usage for the last 7 days
63
+ ai-spend
64
+
65
+ # List available data sources
66
+ ai-spend --list-agents
67
+
68
+ # See only Hermes data
69
+ ai-spend --agent hermes
70
+
71
+ # All historical data (no time limit)
72
+ ai-spend --days 0
73
+
74
+ # JSON output
75
+ ai-spend --format json
76
+ ```
77
+
78
+ ## Usage
79
+
80
+ ```
81
+ ai-spend [options]
82
+
83
+ Options:
84
+ --list-agents List all available data collectors
85
+ --init [name] Initialize ~/.ai-spend/ directory
86
+ --agent AGENT Filter by agent name (comma-separated)
87
+ --days DAYS Days to look back (default: 7, 0 = all time)
88
+ --since YYYY-MM-DD Start date
89
+ --until YYYY-MM-DD End date
90
+ --format {table,json} Output format (default: table)
91
+ --demo Show sample data (no real agents needed)
92
+ ```
93
+
94
+ ## Path Override
95
+
96
+ If auto-detection fails, manually specify data source paths:
97
+
98
+ ```json
99
+ // ~/.ai-spend/config.json
100
+ {"paths": {
101
+ "hermes": "D:/custom/hermes/state.db",
102
+ "codex": "C:/Users/me/.codex/state_1.sqlite",
103
+ "copilot": "D:/copilot/session-store.db",
104
+ "opencode": "D:/opencode/opencode.db",
105
+ "claude-code": "D:/claude/projects",
106
+ "openclaw": "D:/.openclaw",
107
+ "kimi": "D:/.kimi"
108
+ }}
109
+ ```
110
+
111
+ ## Custom Collectors
112
+
113
+ Create your own collector in `~/.ai-spend/collectors/`:
114
+
115
+ ```bash
116
+ ai-spend init my-agent
117
+ # Edit ~/.ai-spend/collectors/my-agent.py
118
+ # Implement BaseCollector.name(), display_name(), collect()
119
+ ```
120
+
121
+ ## Platform Support
122
+
123
+ | Platform | Status |
124
+ |----------|--------|
125
+ | Linux | ✅ Full |
126
+ | macOS | ✅ Full |
127
+ | Windows (native) | ✅ Full |
128
+ | Windows (WSL) | ✅ Full |
129
+
130
+ ## License
131
+
132
+ MIT
@@ -0,0 +1,107 @@
1
+ # AI Spend Tracker
2
+
3
+ **Aggregate token usage & cost across all your AI coding agents in one CLI.**
4
+
5
+ If you run multiple AI coding tools (Claude Code, Codex, Hermes, OpenClaw, OpenCode, GitHub Copilot, Kimi), you're probably flying blind on how much you're actually spending. AI Spend Tracker reads session data from every agent's local storage and shows you the big picture.
6
+
7
+ ## Features
8
+
9
+ - **7 built-in collectors** — Hermes Agent, Codex CLI, GitHub Copilot CLI, OpenCode, Claude Code, OpenClaw, Kimi Code CLI
10
+ - **Cross-platform** — Windows (native + WSL), Linux, macOS
11
+ - **Multi-agent aggregation** — all agents in one report
12
+ - **Extensible** — drop a custom collector in `~/.ai-spend/collectors/`
13
+ - **Path override** — manual data source path via `~/.ai-spend/config.json`
14
+ - **Rich terminal output** — agent summary, model breakdown, daily trends
15
+ - **JSON output** — pipe data into your own dashboards
16
+
17
+ ## Supported Agents
18
+
19
+ | Collector | Agent | Data Source |
20
+ |-----------|-------|-------------|
21
+ | `hermes` | Hermes Agent (Nous Research) | `~/.hermes/state.db` |
22
+ | `codex` | OpenAI Codex CLI | `~/.codex/state_*.sqlite` |
23
+ | `copilot` | GitHub Copilot CLI | `~/.copilot/session-store.db` |
24
+ | `opencode` | OpenCode CLI | `~/.local/share/opencode/opencode.db` |
25
+ | `claude-code` | Claude Code (Anthropic) | `~/.claude/projects/*.jsonl` |
26
+ | `openclaw` | OpenClaw | `~/.openclaw/agents/*/sessions/*.jsonl` |
27
+ | `kimi` | Kimi Code CLI (Moonshot AI) | `~/.kimi/sessions/*/*/wire.jsonl` |
28
+
29
+ > Note: Claude Code v2.1.140+ may not persist session logs to disk. See [anthropics/claude-code#25941](https://github.com/anthropics/claude-code/issues/25941).
30
+
31
+ ## Quick Start
32
+
33
+ ```bash
34
+ # Install
35
+ pip install ai-spend-tracker
36
+
37
+ # See your usage for the last 7 days
38
+ ai-spend
39
+
40
+ # List available data sources
41
+ ai-spend --list-agents
42
+
43
+ # See only Hermes data
44
+ ai-spend --agent hermes
45
+
46
+ # All historical data (no time limit)
47
+ ai-spend --days 0
48
+
49
+ # JSON output
50
+ ai-spend --format json
51
+ ```
52
+
53
+ ## Usage
54
+
55
+ ```
56
+ ai-spend [options]
57
+
58
+ Options:
59
+ --list-agents List all available data collectors
60
+ --init [name] Initialize ~/.ai-spend/ directory
61
+ --agent AGENT Filter by agent name (comma-separated)
62
+ --days DAYS Days to look back (default: 7, 0 = all time)
63
+ --since YYYY-MM-DD Start date
64
+ --until YYYY-MM-DD End date
65
+ --format {table,json} Output format (default: table)
66
+ --demo Show sample data (no real agents needed)
67
+ ```
68
+
69
+ ## Path Override
70
+
71
+ If auto-detection fails, manually specify data source paths:
72
+
73
+ ```json
74
+ // ~/.ai-spend/config.json
75
+ {"paths": {
76
+ "hermes": "D:/custom/hermes/state.db",
77
+ "codex": "C:/Users/me/.codex/state_1.sqlite",
78
+ "copilot": "D:/copilot/session-store.db",
79
+ "opencode": "D:/opencode/opencode.db",
80
+ "claude-code": "D:/claude/projects",
81
+ "openclaw": "D:/.openclaw",
82
+ "kimi": "D:/.kimi"
83
+ }}
84
+ ```
85
+
86
+ ## Custom Collectors
87
+
88
+ Create your own collector in `~/.ai-spend/collectors/`:
89
+
90
+ ```bash
91
+ ai-spend init my-agent
92
+ # Edit ~/.ai-spend/collectors/my-agent.py
93
+ # Implement BaseCollector.name(), display_name(), collect()
94
+ ```
95
+
96
+ ## Platform Support
97
+
98
+ | Platform | Status |
99
+ |----------|--------|
100
+ | Linux | ✅ Full |
101
+ | macOS | ✅ Full |
102
+ | Windows (native) | ✅ Full |
103
+ | Windows (WSL) | ✅ Full |
104
+
105
+ ## License
106
+
107
+ MIT
File without changes
@@ -0,0 +1,104 @@
1
+ """
2
+ CollectorRegistry — 自动发现并注册所有可用的数据采集器。
3
+
4
+ 发现路径:
5
+ 1. ai_spend_tracker/collectors/ 下的 .py 文件 → 内置 collector(正常 import)
6
+ 2. ~/.ai-spend/collectors/ 下的 .py 文件 → 用户自定义 collector(file import)
7
+ """
8
+
9
+ from __future__ import annotations
10
+
11
+ import importlib
12
+ import importlib.util
13
+ import inspect
14
+ import sys
15
+ from pathlib import Path
16
+ from types import ModuleType
17
+ from typing import Optional
18
+
19
+ from ai_spend_tracker.collectors.base import BaseCollector
20
+
21
+
22
+ def _builtin_dir() -> Path:
23
+ return Path(__file__).parent.resolve()
24
+
25
+
26
+ def _user_dir() -> Path:
27
+ return Path.home() / ".ai-spend" / "collectors"
28
+
29
+
30
+ def _import_user_module(file_path: Path) -> Optional[ModuleType]:
31
+ """从文件路径导入用户自定义模块。"""
32
+ try:
33
+ module_name = f"_custom_collector_{file_path.stem}"
34
+ spec = importlib.util.spec_from_file_location(module_name, file_path)
35
+ if spec is None or spec.loader is None:
36
+ return None
37
+ module = importlib.util.module_from_spec(spec)
38
+ sys.modules[module_name] = module
39
+ spec.loader.exec_module(module)
40
+ return module
41
+ except Exception:
42
+ return None
43
+
44
+
45
+ def _find_collectors_in_module(
46
+ module: ModuleType, base_module: str = ""
47
+ ) -> list[BaseCollector]:
48
+ """在模块中找出所有 BaseCollector 的非抽象子类实例。"""
49
+ collectors: list[BaseCollector] = []
50
+ for _name, obj in inspect.getmembers(module, inspect.isclass):
51
+ if (
52
+ issubclass(obj, BaseCollector)
53
+ and obj is not BaseCollector
54
+ and not inspect.isabstract(obj)
55
+ ):
56
+ try:
57
+ collectors.append(obj())
58
+ except Exception:
59
+ continue
60
+ return collectors
61
+
62
+
63
+ def get_all_collectors() -> list[BaseCollector]:
64
+ """返回所有可用的采集器(内置 + 用户自定义)。"""
65
+ collectors: list[BaseCollector] = []
66
+
67
+ # 1. 内置 collector — 通过正常 import 发现
68
+ builtin_dir = _builtin_dir()
69
+ if builtin_dir.exists():
70
+ for file_path in sorted(builtin_dir.iterdir()):
71
+ if (
72
+ not file_path.name.endswith(".py")
73
+ or file_path.name == "__init__.py"
74
+ or file_path.name == "base.py"
75
+ ):
76
+ continue
77
+ module_name = f"ai_spend_tracker.collectors.{file_path.stem}"
78
+ try:
79
+ module = importlib.import_module(module_name)
80
+ collectors.extend(_find_collectors_in_module(module))
81
+ except Exception:
82
+ continue
83
+
84
+ # 2. 用户自定义 collector — 通过文件路径导入
85
+ user_dir = _user_dir()
86
+ if user_dir.exists():
87
+ for file_path in sorted(user_dir.iterdir()):
88
+ if (
89
+ not file_path.name.endswith(".py")
90
+ or file_path.name == "__init__.py"
91
+ ):
92
+ continue
93
+ module = _import_user_module(file_path)
94
+ if module:
95
+ collectors.extend(_find_collectors_in_module(module))
96
+
97
+ return collectors
98
+
99
+
100
+ def get_collector(name: str) -> Optional[BaseCollector]:
101
+ for c in get_all_collectors():
102
+ if c.name() == name:
103
+ return c
104
+ return None
@@ -0,0 +1,104 @@
1
+ """
2
+ BaseCollector — 所有数据采集器的抽象基类。
3
+
4
+ 内置 collector 放在 ai_spend_tracker/collectors/ 下,
5
+ 用户自定义 collector 放在 ~/.ai-spend/collectors/ 下,
6
+ 两者都继承此类即可自动被 CollectorRegistry 发现。
7
+ """
8
+
9
+ from __future__ import annotations
10
+
11
+ from abc import ABC, abstractmethod
12
+ from datetime import datetime
13
+ from typing import Optional
14
+
15
+ from ai_spend_tracker.models import SessionRecord
16
+
17
+
18
+ # 常用模型定价表(USD per 1M input tokens)
19
+ # 用户自定义 collector 可以复用,也可以覆盖
20
+ DEFAULT_PRICING: dict[str, float] = {
21
+ # DeepSeek
22
+ "deepseek-v4-pro": 3.0,
23
+ "deepseek-v4-flash": 0.5,
24
+ "deepseek-v3.2": 2.0,
25
+ "deepseek-v3.1": 2.0,
26
+ "deepseek-v3": 2.0,
27
+ "deepseek-r1": 4.0,
28
+ # Qwen
29
+ "qwen3.7-max": 4.0,
30
+ "qwen3.6-max": 3.5,
31
+ "qwen3.5-plus": 2.0,
32
+ "qwen3.5-flash": 0.5,
33
+ "qwen-max": 4.0,
34
+ "qwen-plus": 2.0,
35
+ "qwen-turbo": 0.5,
36
+ "qwen3.5-omni-plus": 3.0,
37
+ # MiniMax
38
+ "MiniMax-M2.7": 3.0,
39
+ "MiniMax-M2.5": 2.0,
40
+ "MiniMax-M2.1": 1.0,
41
+ # Claude
42
+ "claude-sonnet-4-6": 15.0,
43
+ "claude-sonnet-4": 15.0,
44
+ "claude-opus-4": 15.0,
45
+ "claude-opus-4-8": 15.0,
46
+ "claude-sonnet-4.5": 15.0,
47
+ "claude-haiku-3.5": 1.0,
48
+ # Claude Code 内部模型别名
49
+ "claude-sonnet-4-8": 15.0,
50
+ "claude-opus-4-5": 15.0,
51
+ # GitHub Copilot(常见模型)
52
+ "gpt-5.4": 10.0,
53
+ "gpt-5.5": 15.0,
54
+ "gpt-5.1": 5.0,
55
+ "claude-sonnet-4.5": 15.0,
56
+ # Kimi (Moonshot AI)
57
+ "kimi-for-coding": 4.0,
58
+ "moonshot-k2.5": 4.0,
59
+ "moonshot-k2.6": 4.0,
60
+ }
61
+
62
+
63
+ def estimate_cost(
64
+ input_tokens: int,
65
+ output_tokens: int,
66
+ model: str,
67
+ pricing: dict[str, float] | None = None,
68
+ output_multiplier: float = 4.0,
69
+ ) -> float:
70
+ """根据 token 用量和模型估算费用。"""
71
+ table = pricing if pricing is not None else DEFAULT_PRICING
72
+ price_per_1m_input = table.get(model, 2.0)
73
+ cost_input = input_tokens / 1_000_000 * price_per_1m_input
74
+ cost_output = output_tokens / 1_000_000 * price_per_1m_input * output_multiplier
75
+ return round(cost_input + cost_output, 6)
76
+
77
+
78
+ class BaseCollector(ABC):
79
+ """所有数据采集器必须实现此接口。"""
80
+
81
+ @abstractmethod
82
+ def name(self) -> str:
83
+ """采集器名称,如 'hermes'、'codex'、'my-agent'。"""
84
+ ...
85
+
86
+ @abstractmethod
87
+ def display_name(self) -> str:
88
+ """用户友好的显示名称,如 'Hermes Agent'、'Codex CLI'。"""
89
+ ...
90
+
91
+ @abstractmethod
92
+ def collect(
93
+ self,
94
+ since: Optional[datetime] = None,
95
+ until: Optional[datetime] = None,
96
+ ) -> list[SessionRecord]:
97
+ """从数据源读取会话记录。"""
98
+ ...
99
+
100
+ def description(self) -> str:
101
+ return self.display_name()
102
+
103
+ def pricing_table(self) -> dict[str, float]:
104
+ return DEFAULT_PRICING