agentop 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 (46) hide show
  1. agentop-0.2.0/LICENSE +21 -0
  2. agentop-0.2.0/PKG-INFO +136 -0
  3. agentop-0.2.0/README.md +99 -0
  4. agentop-0.2.0/agentop/__init__.py +5 -0
  5. agentop-0.2.0/agentop/__main__.py +13 -0
  6. agentop-0.2.0/agentop/core/__init__.py +23 -0
  7. agentop-0.2.0/agentop/core/constants.py +80 -0
  8. agentop-0.2.0/agentop/core/models.py +258 -0
  9. agentop-0.2.0/agentop/monitors/__init__.py +13 -0
  10. agentop-0.2.0/agentop/monitors/antigravity.py +132 -0
  11. agentop-0.2.0/agentop/monitors/claude_code.py +93 -0
  12. agentop-0.2.0/agentop/monitors/codex.py +95 -0
  13. agentop-0.2.0/agentop/monitors/opencode.py +97 -0
  14. agentop-0.2.0/agentop/monitors/process.py +201 -0
  15. agentop-0.2.0/agentop/parsers/__init__.py +15 -0
  16. agentop-0.2.0/agentop/parsers/antigravity_quota_api.py +162 -0
  17. agentop-0.2.0/agentop/parsers/claude_logs.py +220 -0
  18. agentop-0.2.0/agentop/parsers/claude_rate_limits.py +231 -0
  19. agentop-0.2.0/agentop/parsers/codex_rate_limits.py +246 -0
  20. agentop-0.2.0/agentop/parsers/codex_stats.py +445 -0
  21. agentop-0.2.0/agentop/parsers/google_auth.py +339 -0
  22. agentop-0.2.0/agentop/parsers/opencode_cache.py +97 -0
  23. agentop-0.2.0/agentop/parsers/opencode_stats.py +296 -0
  24. agentop-0.2.0/agentop/parsers/stats_parser.py +270 -0
  25. agentop-0.2.0/agentop/ui/__init__.py +5 -0
  26. agentop-0.2.0/agentop/ui/app.py +225 -0
  27. agentop-0.2.0/agentop/ui/widgets/__init__.py +7 -0
  28. agentop-0.2.0/agentop/ui/widgets/agent_panel.py +413 -0
  29. agentop-0.2.0/agentop/ui/widgets/antigravity_panel.py +207 -0
  30. agentop-0.2.0/agentop/ui/widgets/opencode_panel.py +344 -0
  31. agentop-0.2.0/agentop.egg-info/PKG-INFO +136 -0
  32. agentop-0.2.0/agentop.egg-info/SOURCES.txt +44 -0
  33. agentop-0.2.0/agentop.egg-info/dependency_links.txt +1 -0
  34. agentop-0.2.0/agentop.egg-info/entry_points.txt +2 -0
  35. agentop-0.2.0/agentop.egg-info/requires.txt +14 -0
  36. agentop-0.2.0/agentop.egg-info/top_level.txt +1 -0
  37. agentop-0.2.0/pyproject.toml +69 -0
  38. agentop-0.2.0/setup.cfg +4 -0
  39. agentop-0.2.0/tests/test_app_opencode_view.py +33 -0
  40. agentop-0.2.0/tests/test_opencode_aggregation.py +507 -0
  41. agentop-0.2.0/tests/test_opencode_cache.py +57 -0
  42. agentop-0.2.0/tests/test_opencode_models.py +14 -0
  43. agentop-0.2.0/tests/test_opencode_monitor.py +45 -0
  44. agentop-0.2.0/tests/test_opencode_panel.py +155 -0
  45. agentop-0.2.0/tests/test_opencode_stats_parser.py +306 -0
  46. agentop-0.2.0/tests/test_opencode_time_range.py +36 -0
agentop-0.2.0/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026
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.
agentop-0.2.0/PKG-INFO ADDED
@@ -0,0 +1,136 @@
1
+ Metadata-Version: 2.4
2
+ Name: agentop
3
+ Version: 0.2.0
4
+ Summary: A terminal UI tool for monitoring local AI coding agents (Claude Code, etc.)
5
+ Author: Yuanhong Yu
6
+ License-Expression: MIT
7
+ Project-URL: Homepage, https://github.com/dadwadw233/agentop
8
+ Project-URL: Repository, https://github.com/dadwadw233/agentop
9
+ Project-URL: Issues, https://github.com/dadwadw233/agentop/issues
10
+ Keywords: ai,monitoring,tui,claude,agent
11
+ Classifier: Development Status :: 3 - Alpha
12
+ Classifier: Environment :: Console
13
+ Classifier: Intended Audience :: Developers
14
+ Classifier: Programming Language :: Python :: 3
15
+ Classifier: Programming Language :: Python :: 3.9
16
+ Classifier: Programming Language :: Python :: 3.10
17
+ Classifier: Programming Language :: Python :: 3.11
18
+ Classifier: Programming Language :: Python :: 3.12
19
+ Classifier: Topic :: System :: Monitoring
20
+ Requires-Python: >=3.9
21
+ Description-Content-Type: text/markdown
22
+ License-File: LICENSE
23
+ Requires-Dist: textual>=0.88.0
24
+ Requires-Dist: rich>=13.9.0
25
+ Requires-Dist: psutil>=6.1.0
26
+ Requires-Dist: pydantic>=2.10.0
27
+ Requires-Dist: aiofiles>=24.1.0
28
+ Requires-Dist: httpx>=0.28.0
29
+ Requires-Dist: pyyaml>=6.0.2
30
+ Requires-Dist: platformdirs>=4.3.0
31
+ Provides-Extra: dev
32
+ Requires-Dist: pytest>=8.0.0; extra == "dev"
33
+ Requires-Dist: pytest-asyncio>=0.23.0; extra == "dev"
34
+ Requires-Dist: black>=24.0.0; extra == "dev"
35
+ Requires-Dist: ruff>=0.6.0; extra == "dev"
36
+ Dynamic: license-file
37
+
38
+ # Agentop
39
+
40
+ A terminal UI tool for monitoring local AI coding agents — like `nvtop`/`htop`, but for Claude/Codex.
41
+
42
+ ## Features
43
+
44
+ - Real-time process monitoring (CPU, memory, uptime)
45
+ - Claude Code usage + cost from local stats
46
+ - Quota panels (beta) for Codex + Antigravity
47
+ - Lightweight Textual TUI
48
+
49
+ ## Supported Agents
50
+
51
+ | Agent | Process Monitor | Usage Stats | Quota | Status |
52
+ |-------|----------------|-------------|-------|--------|
53
+ | **Claude Code** | ✅ | ✅ | ✅ | Stable |
54
+ | **Antigravity** | ⏳ | ⏳ | ✅ | Beta |
55
+ | **OpenAI Codex** | ✅ | ✅ | ✅ | Beta |
56
+ | **OpenCode** | ✅ | ✅ | ⏳ | Beta |
57
+
58
+ ## Supported Platforms (has been tested)
59
+
60
+ - macOS
61
+ - Linux
62
+
63
+ ## Installation (macOS / Linux)
64
+
65
+ ### PyPI
66
+ ```bash
67
+ pip install agentop
68
+ ```
69
+
70
+ ### From source
71
+ ```bash
72
+ pip install git+https://github.com/dadwadw233/agentop.git
73
+ ```
74
+
75
+ ## Quick Start
76
+
77
+ ```bash
78
+ # TUI
79
+ agentop
80
+
81
+ # Or
82
+ python3 -m agentop
83
+ ```
84
+
85
+ Detailed stats:
86
+ ```bash
87
+ python3 show_stats.py
88
+ ```
89
+
90
+ ## Data Sources
91
+
92
+ - Claude stats: `~/.claude/stats-cache.json`
93
+ - Codex usage/quota: `/usage` API via Codex auth (`~/.codex/auth.json`)
94
+ - Antigravity quota: Google Cloud Code API via Antigravity auth (local state db)
95
+ - OpenCode stats: `~/.local/share/opencode/storage/` (message + session directories)
96
+
97
+ ## Changelog
98
+
99
+ ### 0.2.0 (2026-01-25)
100
+
101
+ **OpenCode Features:**
102
+ - Fixed time filtering bug - now shows all historical data (not just today)
103
+ - Added time range support (Today/Week/Month/All) for all views
104
+ - Implemented lazy loading - only computes aggregates needed for current view
105
+ - Added index cache for faster incremental parsing
106
+ - Performance optimizations for large datasets
107
+
108
+ **TUI Improvements:**
109
+ - Redesigned overview dashboard with structured layout (Process Status, Session Stats, Token Usage)
110
+ - Added progress bars for visual token usage comparison
111
+ - Implemented pagination for handling large datasets
112
+ - Dynamic page sizing based on available screen height
113
+ - Enhanced table formatting with better alignment and smart truncation
114
+ - Color gradients for usage intensity (cyan/magenta/blue)
115
+ - Visual status indicators (🟢/⚪) with colored borders
116
+ - Improved hint text with time range display and update timestamps
117
+ - Consistent styling across all sub-views (Sessions, Projects, Models, Agents, Timeline)
118
+
119
+ ## Roadmap
120
+
121
+ - More agents (TBD)
122
+ - Config file (YAML)
123
+ - History + export (CSV/JSON)
124
+ - UI polish
125
+
126
+ ## Known Limitations
127
+
128
+ - Claude stats can lag behind real time
129
+ - Codex usage is fetched from the API (not local files)
130
+ - Antigravity quota depends on account access
131
+ - Antigravity refresh requires `ANTIGRAVITY_OAUTH_CLIENT_SECRET` or a fresh login
132
+ - Proxy users: if you see “unknown scheme for proxy URL”, set `AGENTOP_DISABLE_PROXY=1` or install `httpx[socks]`
133
+
134
+ ## License
135
+
136
+ MIT (see `LICENSE`)
@@ -0,0 +1,99 @@
1
+ # Agentop
2
+
3
+ A terminal UI tool for monitoring local AI coding agents — like `nvtop`/`htop`, but for Claude/Codex.
4
+
5
+ ## Features
6
+
7
+ - Real-time process monitoring (CPU, memory, uptime)
8
+ - Claude Code usage + cost from local stats
9
+ - Quota panels (beta) for Codex + Antigravity
10
+ - Lightweight Textual TUI
11
+
12
+ ## Supported Agents
13
+
14
+ | Agent | Process Monitor | Usage Stats | Quota | Status |
15
+ |-------|----------------|-------------|-------|--------|
16
+ | **Claude Code** | ✅ | ✅ | ✅ | Stable |
17
+ | **Antigravity** | ⏳ | ⏳ | ✅ | Beta |
18
+ | **OpenAI Codex** | ✅ | ✅ | ✅ | Beta |
19
+ | **OpenCode** | ✅ | ✅ | ⏳ | Beta |
20
+
21
+ ## Supported Platforms (has been tested)
22
+
23
+ - macOS
24
+ - Linux
25
+
26
+ ## Installation (macOS / Linux)
27
+
28
+ ### PyPI
29
+ ```bash
30
+ pip install agentop
31
+ ```
32
+
33
+ ### From source
34
+ ```bash
35
+ pip install git+https://github.com/dadwadw233/agentop.git
36
+ ```
37
+
38
+ ## Quick Start
39
+
40
+ ```bash
41
+ # TUI
42
+ agentop
43
+
44
+ # Or
45
+ python3 -m agentop
46
+ ```
47
+
48
+ Detailed stats:
49
+ ```bash
50
+ python3 show_stats.py
51
+ ```
52
+
53
+ ## Data Sources
54
+
55
+ - Claude stats: `~/.claude/stats-cache.json`
56
+ - Codex usage/quota: `/usage` API via Codex auth (`~/.codex/auth.json`)
57
+ - Antigravity quota: Google Cloud Code API via Antigravity auth (local state db)
58
+ - OpenCode stats: `~/.local/share/opencode/storage/` (message + session directories)
59
+
60
+ ## Changelog
61
+
62
+ ### 0.2.0 (2026-01-25)
63
+
64
+ **OpenCode Features:**
65
+ - Fixed time filtering bug - now shows all historical data (not just today)
66
+ - Added time range support (Today/Week/Month/All) for all views
67
+ - Implemented lazy loading - only computes aggregates needed for current view
68
+ - Added index cache for faster incremental parsing
69
+ - Performance optimizations for large datasets
70
+
71
+ **TUI Improvements:**
72
+ - Redesigned overview dashboard with structured layout (Process Status, Session Stats, Token Usage)
73
+ - Added progress bars for visual token usage comparison
74
+ - Implemented pagination for handling large datasets
75
+ - Dynamic page sizing based on available screen height
76
+ - Enhanced table formatting with better alignment and smart truncation
77
+ - Color gradients for usage intensity (cyan/magenta/blue)
78
+ - Visual status indicators (🟢/⚪) with colored borders
79
+ - Improved hint text with time range display and update timestamps
80
+ - Consistent styling across all sub-views (Sessions, Projects, Models, Agents, Timeline)
81
+
82
+ ## Roadmap
83
+
84
+ - More agents (TBD)
85
+ - Config file (YAML)
86
+ - History + export (CSV/JSON)
87
+ - UI polish
88
+
89
+ ## Known Limitations
90
+
91
+ - Claude stats can lag behind real time
92
+ - Codex usage is fetched from the API (not local files)
93
+ - Antigravity quota depends on account access
94
+ - Antigravity refresh requires `ANTIGRAVITY_OAUTH_CLIENT_SECRET` or a fresh login
95
+ - Proxy users: if you see “unknown scheme for proxy URL”, set `AGENTOP_DISABLE_PROXY=1` or install `httpx[socks]`
96
+
97
+ ## License
98
+
99
+ MIT (see `LICENSE`)
@@ -0,0 +1,5 @@
1
+ """Agentop - Terminal UI for monitoring AI coding agents."""
2
+
3
+ __version__ = "0.1.2"
4
+ __author__ = "Yuanhong Yu"
5
+ __license__ = "MIT"
@@ -0,0 +1,13 @@
1
+ """Main entry point for Agentop."""
2
+
3
+ from .ui.app import AgentopApp
4
+
5
+
6
+ def main():
7
+ """Main entry point."""
8
+ app = AgentopApp()
9
+ app.run()
10
+
11
+
12
+ if __name__ == "__main__":
13
+ main()
@@ -0,0 +1,23 @@
1
+ """Core modules for Agentop."""
2
+
3
+ from .models import (
4
+ ProcessMetrics,
5
+ AgentMetrics,
6
+ ClaudeCodeMetrics,
7
+ OpenCodeTokenUsage,
8
+ OpenCodeMessage,
9
+ OpenCodeSession,
10
+ OpenCodeMetrics,
11
+ )
12
+ from .constants import AgentType
13
+
14
+ __all__ = [
15
+ "ProcessMetrics",
16
+ "AgentMetrics",
17
+ "ClaudeCodeMetrics",
18
+ "OpenCodeTokenUsage",
19
+ "OpenCodeMessage",
20
+ "OpenCodeSession",
21
+ "OpenCodeMetrics",
22
+ "AgentType",
23
+ ]
@@ -0,0 +1,80 @@
1
+ """Constants and enumerations."""
2
+
3
+ from enum import Enum
4
+
5
+
6
+ class AgentType(str, Enum):
7
+ """Supported agent types."""
8
+
9
+ CLAUDE_CODE = "claude_code"
10
+ COPILOT = "copilot"
11
+ CODEX = "codex"
12
+ OPENCODE = "opencode"
13
+
14
+
15
+ # Process detection patterns
16
+ AGENT_PATTERNS = {
17
+ AgentType.CLAUDE_CODE: {
18
+ "process_names": ["claude"],
19
+ "cmdline_patterns": [
20
+ r"\.local/bin/claude",
21
+ r"--model\s+claude-",
22
+ ],
23
+ "min_memory_mb": 50,
24
+ },
25
+ AgentType.CODEX: {
26
+ "process_names": ["codex"],
27
+ "cmdline_patterns": [
28
+ r"(?:^|/)codex(?:\s|$)",
29
+ r"\bopenai[-_ ]?codex\b",
30
+ ],
31
+ "min_memory_mb": 40,
32
+ },
33
+ AgentType.OPENCODE: {
34
+ "process_names": ["node"],
35
+ "cmdline_patterns": [
36
+ r"(?:^|/)node(?:\s+|$)",
37
+ r"\bopencode\b",
38
+ ],
39
+ "min_memory_mb": 100,
40
+ },
41
+ }
42
+
43
+ # Claude pricing (per 1M tokens)
44
+ CLAUDE_PRICING = {
45
+ "claude-opus-4": {"input": 15.0, "output": 75.0},
46
+ "claude-sonnet-4": {"input": 3.0, "output": 15.0},
47
+ "claude-sonnet-3.5": {"input": 3.0, "output": 15.0},
48
+ "claude-haiku-4": {"input": 0.25, "output": 1.25},
49
+ }
50
+
51
+ # Default paths
52
+ DEFAULT_CLAUDE_LOGS_DIR = "~/.claude-code/sessions/"
53
+ DEFAULT_CODEX_STATS_FILES = [
54
+ "~/.codex/stats.json",
55
+ "~/.codex/usage.json",
56
+ "~/.codex/usage.jsonl",
57
+ "~/.openai/codex/stats.json",
58
+ "~/.openai/codex/usage.json",
59
+ "~/.openai/codex/usage.jsonl",
60
+ "~/.config/codex/stats.json",
61
+ "~/.config/codex/usage.json",
62
+ "~/.config/codex/usage.jsonl",
63
+ "~/.config/openai/codex/stats.json",
64
+ "~/.config/openai/codex/usage.json",
65
+ "~/.config/openai/codex/usage.jsonl",
66
+ "~/Library/Application Support/Codex/stats.json",
67
+ "~/Library/Application Support/OpenAI/Codex/stats.json",
68
+ ]
69
+ DEFAULT_CODEX_LOGS_DIRS = [
70
+ "~/.codex/logs/",
71
+ "~/.codex/sessions/",
72
+ "~/.openai/codex/logs/",
73
+ "~/.openai/codex/sessions/",
74
+ "~/.config/codex/logs/",
75
+ "~/.config/codex/sessions/",
76
+ "~/Library/Application Support/Codex/logs/",
77
+ "~/Library/Application Support/Codex/sessions/",
78
+ "~/Library/Application Support/OpenAI/Codex/logs/",
79
+ "~/Library/Application Support/OpenAI/Codex/sessions/",
80
+ ]
@@ -0,0 +1,258 @@
1
+ """Data models for Agentop."""
2
+
3
+ from dataclasses import dataclass, field
4
+ from datetime import datetime
5
+ from typing import Optional, List
6
+ from enum import Enum
7
+
8
+
9
+ class ProcessStatus(str, Enum):
10
+ """Process status."""
11
+
12
+ RUNNING = "running"
13
+ SLEEPING = "sleeping"
14
+ IDLE = "idle"
15
+ ZOMBIE = "zombie"
16
+ STOPPED = "stopped"
17
+
18
+
19
+ @dataclass
20
+ class ProcessMetrics:
21
+ """Metrics for a single process."""
22
+
23
+ pid: int
24
+ name: str
25
+ cmdline: str
26
+ cpu_percent: float
27
+ memory_mb: float
28
+ memory_percent: float
29
+ num_threads: int
30
+ create_time: datetime
31
+ status: ProcessStatus
32
+
33
+ @property
34
+ def uptime(self) -> float:
35
+ """Return uptime in seconds."""
36
+ return (datetime.now() - self.create_time).total_seconds()
37
+
38
+
39
+ @dataclass
40
+ class TokenUsage:
41
+ """Token usage statistics."""
42
+
43
+ input_tokens: int = 0
44
+ output_tokens: int = 0
45
+
46
+ @property
47
+ def total_tokens(self) -> int:
48
+ """Total tokens used."""
49
+ return self.input_tokens + self.output_tokens
50
+
51
+
52
+ @dataclass
53
+ class OpenCodeTokenUsage:
54
+ """OpenCode-specific token usage statistics with cache and reasoning tokens."""
55
+
56
+ input_tokens: int = 0
57
+ output_tokens: int = 0
58
+ reasoning_tokens: int = 0
59
+ cache_read_tokens: int = 0
60
+ cache_write_tokens: int = 0
61
+
62
+ @property
63
+ def total_tokens(self) -> int:
64
+ """Total tokens used including reasoning and cache."""
65
+ return (
66
+ self.input_tokens
67
+ + self.output_tokens
68
+ + self.reasoning_tokens
69
+ + self.cache_read_tokens
70
+ + self.cache_write_tokens
71
+ )
72
+
73
+
74
+ @dataclass
75
+ class CostEstimate:
76
+ """Cost estimation."""
77
+
78
+ amount: float # in USD
79
+ currency: str = "USD"
80
+
81
+
82
+ @dataclass
83
+ class RateLimitWindow:
84
+ """Rate limit window snapshot."""
85
+
86
+ used_percent: float
87
+ window_minutes: Optional[int] = None
88
+ resets_at: Optional[datetime] = None
89
+
90
+ @property
91
+ def remaining_percent(self) -> float:
92
+ """Percent remaining in this window."""
93
+ return max(0.0, 100.0 - self.used_percent)
94
+
95
+
96
+ @dataclass
97
+ class CreditsSnapshot:
98
+ """Credits snapshot."""
99
+
100
+ has_credits: bool
101
+ unlimited: bool
102
+ balance: Optional[str] = None
103
+
104
+
105
+ @dataclass
106
+ class RateLimitSnapshot:
107
+ """Rate limit snapshot with primary/secondary windows."""
108
+
109
+ primary: Optional[RateLimitWindow] = None
110
+ secondary: Optional[RateLimitWindow] = None
111
+ credits: Optional[CreditsSnapshot] = None
112
+ plan_type: Optional[str] = None
113
+ captured_at: Optional[datetime] = None
114
+
115
+
116
+ @dataclass
117
+ class AgentMetrics:
118
+ """Base metrics for any agent."""
119
+
120
+ agent_type: str
121
+ processes: List[ProcessMetrics] = field(default_factory=list)
122
+ is_active: bool = False
123
+ last_active: Optional[datetime] = None
124
+
125
+ @property
126
+ def total_cpu(self) -> float:
127
+ """Total CPU usage across all processes."""
128
+ return sum(p.cpu_percent for p in self.processes)
129
+
130
+ @property
131
+ def total_memory_mb(self) -> float:
132
+ """Total memory usage in MB."""
133
+ return sum(p.memory_mb for p in self.processes)
134
+
135
+ @property
136
+ def process_count(self) -> int:
137
+ """Number of processes."""
138
+ return len(self.processes)
139
+
140
+
141
+ @dataclass
142
+ class ClaudeCodeMetrics(AgentMetrics):
143
+ """Metrics specific to Claude Code."""
144
+
145
+ agent_type: str = "claude_code"
146
+
147
+ # Session info
148
+ active_sessions: int = 0
149
+ total_sessions_today: int = 0
150
+
151
+ # Token usage
152
+ tokens_today: TokenUsage = field(default_factory=TokenUsage)
153
+ tokens_this_month: TokenUsage = field(default_factory=TokenUsage)
154
+
155
+ # Cost
156
+ cost_today: CostEstimate = field(default_factory=lambda: CostEstimate(0.0))
157
+ cost_this_month: CostEstimate = field(default_factory=lambda: CostEstimate(0.0))
158
+
159
+ # Stats metadata
160
+ stats_last_updated: Optional[datetime] = None
161
+
162
+ # Rate limits (quota)
163
+ rate_limits: Optional[RateLimitSnapshot] = None
164
+ rate_limits_source: Optional[str] = None
165
+ rate_limits_error: Optional[str] = None
166
+
167
+
168
+ @dataclass
169
+ class CodexMetrics(AgentMetrics):
170
+ """Metrics specific to OpenAI Codex."""
171
+
172
+ agent_type: str = "codex"
173
+
174
+ # Session info
175
+ active_sessions: int = 0
176
+ total_sessions_today: int = 0
177
+
178
+ # Token usage
179
+ tokens_today: TokenUsage = field(default_factory=TokenUsage)
180
+ tokens_this_month: TokenUsage = field(default_factory=TokenUsage)
181
+
182
+ # Cost (optional if logs don't include pricing)
183
+ cost_today: Optional[CostEstimate] = None
184
+ cost_this_month: Optional[CostEstimate] = None
185
+
186
+ # Usage metadata
187
+ usage_source: Optional[str] = None
188
+
189
+ # Rate limits
190
+ rate_limits: Optional[RateLimitSnapshot] = None
191
+ rate_limits_source: Optional[str] = None
192
+ rate_limits_error: Optional[str] = None
193
+
194
+
195
+ @dataclass
196
+ class SessionData:
197
+ """Data from a single Claude Code session."""
198
+
199
+ session_id: str
200
+ start_time: datetime
201
+ end_time: Optional[datetime] = None
202
+ model: Optional[str] = None
203
+ tokens: TokenUsage = field(default_factory=TokenUsage)
204
+ cost: CostEstimate = field(default_factory=lambda: CostEstimate(0.0))
205
+ message_count: int = 0
206
+
207
+
208
+ @dataclass
209
+ class OpenCodeMessage:
210
+ """Data from a single OpenCode message."""
211
+
212
+ message_id: str
213
+ session_id: str
214
+ role: str
215
+ model_id: str
216
+ provider_id: str
217
+ agent: Optional[str] = None
218
+ project_path: Optional[str] = None
219
+ created_at: datetime = field(default_factory=datetime.now)
220
+ completed_at: Optional[datetime] = None
221
+ tokens: OpenCodeTokenUsage = field(default_factory=OpenCodeTokenUsage)
222
+
223
+
224
+ @dataclass
225
+ class OpenCodeSession:
226
+ """Data from a single OpenCode session."""
227
+
228
+ session_id: str
229
+ start_time: datetime
230
+ end_time: Optional[datetime] = None
231
+ model_id: Optional[str] = None
232
+ provider_id: Optional[str] = None
233
+ agent: Optional[str] = None
234
+ project_path: Optional[str] = None
235
+ tokens: OpenCodeTokenUsage = field(default_factory=OpenCodeTokenUsage)
236
+ message_count: int = 0
237
+
238
+
239
+ @dataclass
240
+ class OpenCodeMetrics(AgentMetrics):
241
+ """Metrics specific to OpenCode."""
242
+
243
+ agent_type: str = "opencode"
244
+
245
+ active_sessions: int = 0
246
+ total_sessions_today: int = 0
247
+
248
+ total_tokens: OpenCodeTokenUsage = field(default_factory=OpenCodeTokenUsage)
249
+ tokens_today: OpenCodeTokenUsage = field(default_factory=OpenCodeTokenUsage)
250
+
251
+ by_session: dict = field(default_factory=dict)
252
+ by_agent: dict = field(default_factory=dict)
253
+ by_model: dict = field(default_factory=dict)
254
+ by_provider: dict = field(default_factory=dict)
255
+ by_project: dict = field(default_factory=dict)
256
+ by_date: dict = field(default_factory=dict)
257
+
258
+ stats_last_updated: Optional[datetime] = None
@@ -0,0 +1,13 @@
1
+ """Process and agent monitoring modules."""
2
+
3
+ from .process import ProcessMonitor
4
+ from .claude_code import ClaudeCodeMonitor
5
+ from .codex import CodexMonitor
6
+ from .antigravity import AntigravityMonitor
7
+
8
+ __all__ = [
9
+ "ProcessMonitor",
10
+ "ClaudeCodeMonitor",
11
+ "CodexMonitor",
12
+ "AntigravityMonitor",
13
+ ]