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.
- agentop-0.2.0/LICENSE +21 -0
- agentop-0.2.0/PKG-INFO +136 -0
- agentop-0.2.0/README.md +99 -0
- agentop-0.2.0/agentop/__init__.py +5 -0
- agentop-0.2.0/agentop/__main__.py +13 -0
- agentop-0.2.0/agentop/core/__init__.py +23 -0
- agentop-0.2.0/agentop/core/constants.py +80 -0
- agentop-0.2.0/agentop/core/models.py +258 -0
- agentop-0.2.0/agentop/monitors/__init__.py +13 -0
- agentop-0.2.0/agentop/monitors/antigravity.py +132 -0
- agentop-0.2.0/agentop/monitors/claude_code.py +93 -0
- agentop-0.2.0/agentop/monitors/codex.py +95 -0
- agentop-0.2.0/agentop/monitors/opencode.py +97 -0
- agentop-0.2.0/agentop/monitors/process.py +201 -0
- agentop-0.2.0/agentop/parsers/__init__.py +15 -0
- agentop-0.2.0/agentop/parsers/antigravity_quota_api.py +162 -0
- agentop-0.2.0/agentop/parsers/claude_logs.py +220 -0
- agentop-0.2.0/agentop/parsers/claude_rate_limits.py +231 -0
- agentop-0.2.0/agentop/parsers/codex_rate_limits.py +246 -0
- agentop-0.2.0/agentop/parsers/codex_stats.py +445 -0
- agentop-0.2.0/agentop/parsers/google_auth.py +339 -0
- agentop-0.2.0/agentop/parsers/opencode_cache.py +97 -0
- agentop-0.2.0/agentop/parsers/opencode_stats.py +296 -0
- agentop-0.2.0/agentop/parsers/stats_parser.py +270 -0
- agentop-0.2.0/agentop/ui/__init__.py +5 -0
- agentop-0.2.0/agentop/ui/app.py +225 -0
- agentop-0.2.0/agentop/ui/widgets/__init__.py +7 -0
- agentop-0.2.0/agentop/ui/widgets/agent_panel.py +413 -0
- agentop-0.2.0/agentop/ui/widgets/antigravity_panel.py +207 -0
- agentop-0.2.0/agentop/ui/widgets/opencode_panel.py +344 -0
- agentop-0.2.0/agentop.egg-info/PKG-INFO +136 -0
- agentop-0.2.0/agentop.egg-info/SOURCES.txt +44 -0
- agentop-0.2.0/agentop.egg-info/dependency_links.txt +1 -0
- agentop-0.2.0/agentop.egg-info/entry_points.txt +2 -0
- agentop-0.2.0/agentop.egg-info/requires.txt +14 -0
- agentop-0.2.0/agentop.egg-info/top_level.txt +1 -0
- agentop-0.2.0/pyproject.toml +69 -0
- agentop-0.2.0/setup.cfg +4 -0
- agentop-0.2.0/tests/test_app_opencode_view.py +33 -0
- agentop-0.2.0/tests/test_opencode_aggregation.py +507 -0
- agentop-0.2.0/tests/test_opencode_cache.py +57 -0
- agentop-0.2.0/tests/test_opencode_models.py +14 -0
- agentop-0.2.0/tests/test_opencode_monitor.py +45 -0
- agentop-0.2.0/tests/test_opencode_panel.py +155 -0
- agentop-0.2.0/tests/test_opencode_stats_parser.py +306 -0
- 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`)
|
agentop-0.2.0/README.md
ADDED
|
@@ -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,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
|
+
]
|