code-meter 0.1.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.
@@ -0,0 +1,195 @@
1
+ """Rich table renderers for CLI commands including prompts and diff history."""
2
+
3
+ from typing import Any, Dict, List, Optional
4
+ from rich.console import Console
5
+ from rich.panel import Panel
6
+ from rich.table import Table
7
+
8
+ from code_meter.models.project import DailyStats, ModelStats, ProjectStats, SessionStats
9
+ from code_meter.models.usage import SessionCodeChange, SessionPrompt
10
+
11
+
12
+ def format_tokens(n: int) -> str:
13
+ """Format token count into readable human notation (e.g., 1.2M, 812K, 500)."""
14
+ if n >= 1_000_000:
15
+ return f"{n / 1_000_000:.2f}M"
16
+ if n >= 1_000:
17
+ return f"{n / 1_000:.1f}K"
18
+ return str(n)
19
+
20
+
21
+ def format_cost(cost: Optional[float]) -> str:
22
+ """Format cost as USD currency or N/A."""
23
+ if cost is None:
24
+ return "[dim]N/A[/dim]"
25
+ return f"${cost:.2f}"
26
+
27
+
28
+ def render_models_table(models: List[ModelStats], console: Optional[Console] = None) -> None:
29
+ c = console or Console()
30
+ table = Table(title="Usage by Model", header_style="bold magenta")
31
+ table.add_column("Model", style="cyan")
32
+ table.add_column("Requests", justify="right")
33
+ table.add_column("Input", justify="right")
34
+ table.add_column("Output", justify="right")
35
+ table.add_column("Cache Read", justify="right")
36
+ table.add_column("Cache Write", justify="right")
37
+ table.add_column("Total Tokens", justify="right", style="bold")
38
+ table.add_column("Estimated Cost", justify="right", style="bold green")
39
+
40
+ for m in models:
41
+ table.add_row(
42
+ m.model,
43
+ f"{m.request_count:,}",
44
+ format_tokens(m.input_tokens),
45
+ format_tokens(m.output_tokens),
46
+ format_tokens(m.cache_read_tokens),
47
+ format_tokens(m.cache_write_tokens),
48
+ format_tokens(m.total_tokens),
49
+ format_cost(m.estimated_cost_usd),
50
+ )
51
+ c.print(table)
52
+
53
+
54
+ def render_projects_table(projects: List[ProjectStats], console: Optional[Console] = None) -> None:
55
+ c = console or Console()
56
+ table = Table(title="Usage by Project", header_style="bold blue")
57
+ table.add_column("Project", style="cyan")
58
+ table.add_column("Requests", justify="right")
59
+ table.add_column("Input", justify="right")
60
+ table.add_column("Output", justify="right")
61
+ table.add_column("Cache Read", justify="right")
62
+ table.add_column("Cache Write", justify="right")
63
+ table.add_column("Total Tokens", justify="right", style="bold")
64
+ table.add_column("Estimated Cost", justify="right", style="bold green")
65
+
66
+ for p in projects:
67
+ table.add_row(
68
+ p.project_name,
69
+ f"{p.request_count:,}",
70
+ format_tokens(p.input_tokens),
71
+ format_tokens(p.output_tokens),
72
+ format_tokens(p.cache_read_tokens),
73
+ format_tokens(p.cache_write_tokens),
74
+ format_tokens(p.total_tokens),
75
+ format_cost(p.estimated_cost_usd),
76
+ )
77
+ c.print(table)
78
+
79
+
80
+ def render_sessions_table(sessions: List[SessionStats], console: Optional[Console] = None) -> None:
81
+ c = console or Console()
82
+ table = Table(title="Recent Sessions", header_style="bold yellow")
83
+ table.add_column("Session ID", style="dim")
84
+ table.add_column("Project", style="cyan")
85
+ table.add_column("Primary Model", style="magenta")
86
+ table.add_column("Requests", justify="right")
87
+ table.add_column("Total Tokens", justify="right", style="bold")
88
+ table.add_column("Estimated Cost", justify="right", style="bold green")
89
+
90
+ for s in sessions[:30]:
91
+ short_id = s.session_id[:8] if len(s.session_id) > 8 else s.session_id
92
+ table.add_row(
93
+ short_id,
94
+ s.project_name,
95
+ s.primary_model,
96
+ f"{s.request_count:,}",
97
+ format_tokens(s.total_tokens),
98
+ format_cost(s.estimated_cost_usd),
99
+ )
100
+ c.print(table)
101
+
102
+
103
+ def render_daily_table(daily_stats: List[DailyStats], console: Optional[Console] = None) -> None:
104
+ c = console or Console()
105
+ table = Table(title="Daily Aggregation", header_style="bold green")
106
+ table.add_column("Date", style="cyan")
107
+ table.add_column("Requests", justify="right")
108
+ table.add_column("Input", justify="right")
109
+ table.add_column("Output", justify="right")
110
+ table.add_column("Cache Read", justify="right")
111
+ table.add_column("Cache Write", justify="right")
112
+ table.add_column("Total Tokens", justify="right", style="bold")
113
+ table.add_column("Estimated Cost", justify="right", style="bold green")
114
+
115
+ for d in daily_stats:
116
+ table.add_row(
117
+ d.date_str,
118
+ f"{d.request_count:,}",
119
+ format_tokens(d.input_tokens),
120
+ format_tokens(d.output_tokens),
121
+ format_tokens(d.cache_read_tokens),
122
+ format_tokens(d.cache_write_tokens),
123
+ format_tokens(d.total_tokens),
124
+ format_cost(d.estimated_cost_usd),
125
+ )
126
+ c.print(table)
127
+
128
+
129
+ def render_prompts_table(prompts: List[SessionPrompt], console: Optional[Console] = None) -> None:
130
+ """Render list of user prompts asked per session."""
131
+ c = console or Console()
132
+ table = Table(title="Session Prompts History", header_style="bold cyan")
133
+ table.add_column("Timestamp", style="dim")
134
+ table.add_column("Session ID", style="yellow")
135
+ table.add_column("Project", style="blue")
136
+ table.add_column("User Prompt", style="white")
137
+
138
+ for p in prompts:
139
+ short_session = p.session_id[:8] if len(p.session_id) > 8 else p.session_id
140
+ short_prompt = p.prompt_text.replace("\n", " ")
141
+ if len(short_prompt) > 80:
142
+ short_prompt = short_prompt[:77] + "..."
143
+ ts_str = p.timestamp.strftime("%Y-%m-%d %H:%M")
144
+
145
+ table.add_row(
146
+ ts_str,
147
+ short_session,
148
+ p.project_id or "Unknown",
149
+ short_prompt,
150
+ )
151
+ c.print(table)
152
+
153
+
154
+ def render_code_changes_table(changes: List[SessionCodeChange], console: Optional[Console] = None) -> None:
155
+ """Render code change / git diff history per session."""
156
+ c = console or Console()
157
+ table = Table(title="Code Changes & Diff Log", header_style="bold green")
158
+ table.add_column("Timestamp", style="dim")
159
+ table.add_column("Session ID", style="yellow")
160
+ table.add_column("Type", style="magenta")
161
+ table.add_column("File Path", style="cyan")
162
+ table.add_column("Diff / Change Summary", style="white")
163
+
164
+ for ch in changes:
165
+ short_session = ch.session_id[:8] if len(ch.session_id) > 8 else ch.session_id
166
+ short_diff = ch.diff_summary.replace("\n", " | ")
167
+ if len(short_diff) > 80:
168
+ short_diff = short_diff[:77] + "..."
169
+ ts_str = ch.timestamp.strftime("%Y-%m-%d %H:%M")
170
+
171
+ table.add_row(
172
+ ts_str,
173
+ short_session,
174
+ ch.change_type.upper(),
175
+ ch.file_path,
176
+ short_diff,
177
+ )
178
+ c.print(table)
179
+
180
+
181
+ def render_status_panel(summary: Dict[str, Any], console: Optional[Console] = None) -> None:
182
+ c = console or Console()
183
+ db_size_mb = summary["db_size_bytes"] / (1024.0 * 1024.0)
184
+
185
+ content = f"""
186
+ [bold cyan]Database Location:[/bold cyan] {summary['db_path']}
187
+ [bold cyan]Database Size:[/bold cyan] {db_size_mb:.2f} MB
188
+ [bold cyan]Scanned Files:[/bold cyan] {summary['scanned_files']:,}
189
+ [bold cyan]Usage Events:[/bold cyan] {summary['total_records']:,}
190
+ [bold cyan]Saved Prompts:[/bold cyan] {summary['total_prompts']:,}
191
+ [bold cyan]Saved Code Edits:[/bold cyan] {summary['total_code_changes']:,}
192
+ [bold cyan]Unique Sessions:[/bold cyan] {summary['unique_sessions']:,}
193
+ [bold cyan]Unique Projects:[/bold cyan] {summary['unique_projects']:,}
194
+ """
195
+ c.print(Panel(content.strip(), title="[bold green]Code Meter Status[/bold green]", expand=False))
code_meter/watcher.py ADDED
@@ -0,0 +1,56 @@
1
+ """File watcher for watch mode (`code-meter watch`)."""
2
+
3
+ import logging
4
+ import time
5
+ from pathlib import Path
6
+ from typing import Callable, Optional
7
+
8
+ from rich.console import Console
9
+
10
+ try:
11
+ from watchdog.events import FileSystemEventHandler
12
+ from watchdog.observers import Observer
13
+ HAS_WATCHDOG = True
14
+ except ImportError:
15
+ HAS_WATCHDOG = False
16
+
17
+ logger = logging.getLogger(__name__)
18
+
19
+
20
+ def run_watch_loop(
21
+ target_dir: Path,
22
+ on_change_callback: Callable[[], None],
23
+ refresh_seconds: int = 2,
24
+ console: Optional[Console] = None,
25
+ ) -> None:
26
+ """Monitor target_dir and trigger on_change_callback whenever session jsonl files update."""
27
+ c = console or Console()
28
+ c.print(f"[bold green]Watching directory:[/bold green] {target_dir}")
29
+ c.print("[dim]Press Ctrl+C to stop watch mode.[/dim]\n")
30
+
31
+ on_change_callback()
32
+
33
+ if HAS_WATCHDOG and target_dir.exists():
34
+ class JSONLHandler(FileSystemEventHandler):
35
+ def on_any_event(self, event):
36
+ if not event.is_directory and event.src_path.endswith(".jsonl"):
37
+ on_change_callback()
38
+
39
+ observer = Observer()
40
+ observer.schedule(JSONLHandler(), str(target_dir), recursive=True)
41
+ observer.start()
42
+ try:
43
+ while True:
44
+ time.sleep(refresh_seconds)
45
+ except KeyboardInterrupt:
46
+ observer.stop()
47
+ c.print("\n[yellow]Watch mode stopped.[/yellow]")
48
+ observer.join()
49
+ else:
50
+ c.print("[yellow]Using fallback polling mode...[/yellow]")
51
+ try:
52
+ while True:
53
+ time.sleep(refresh_seconds)
54
+ on_change_callback()
55
+ except KeyboardInterrupt:
56
+ c.print("\n[yellow]Watch mode stopped.[/yellow]")
@@ -0,0 +1,207 @@
1
+ Metadata-Version: 2.4
2
+ Name: code-meter
3
+ Version: 0.1.0
4
+ Summary: Local AI coding token usage tracker and cost estimator for Claude Code and future agents.
5
+ Author-email: Dhanush Nayak <dhanushnayak.ram@mail.com>
6
+ License: MIT
7
+ Project-URL: Homepage, https://github.com/dhanushnayak/code-meter
8
+ Project-URL: Repository, https://github.com/dhanushnayak/code-meter
9
+ Project-URL: Bug Tracker, https://github.com/dhanushnayak/code-meter/issues
10
+ Requires-Python: >=3.11
11
+ Description-Content-Type: text/markdown
12
+ License-File: LICENSE
13
+ Requires-Dist: typer[all]>=0.9.0
14
+ Requires-Dist: rich>=13.0.0
15
+ Requires-Dist: pydantic>=2.0.0
16
+ Requires-Dist: tomli-w>=1.0.0
17
+ Requires-Dist: watchdog>=3.0.0
18
+ Provides-Extra: dev
19
+ Requires-Dist: pytest>=7.0.0; extra == "dev"
20
+ Requires-Dist: pytest-cov>=4.0.0; extra == "dev"
21
+ Requires-Dist: mypy>=1.0.0; extra == "dev"
22
+ Requires-Dist: ruff>=0.1.0; extra == "dev"
23
+ Dynamic: license-file
24
+
25
+ # code-meter
26
+
27
+ > **Local AI Coding Token Usage Tracker, Prompt Log & Cost Estimator**
28
+
29
+ `code-meter` (also available via `claude-meter`, `codex-meter`, `antigravity-meter`, and `agy-meter` aliases) is a production-quality local CLI application designed to track local usage for **Claude Code**, **OpenAI Codex**, and **Google Antigravity**, including tokens (input, output, cache-read, cache-write), session prompts, and code change history over time.
30
+
31
+ It features an extensible multi-provider architecture so all AI coding agents operate seamlessly within unified analytics and SQLite storage.
32
+
33
+ ---
34
+
35
+ ## ๐Ÿ”’ Privacy First
36
+
37
+ * **100% Local**: Operates completely offline using your local filesystem.
38
+ * **No Gateway / Telemetry**: `code-meter` is NOT an API gateway, proxy, or interceptor.
39
+ * **Zero Uploads**: No prompts, assistant responses, source code files, or conversation texts are uploaded anywhere. Only local token metrics, session prompts, and diff logs are saved to SQLite.
40
+ * **No API Key Required**: Analyzes existing local session logs generated by Claude Code (`~/.claude`), OpenAI Codex (`~/.codex`), and Google Antigravity (`~/.gemini/antigravity-ide`).
41
+
42
+ ---
43
+
44
+ ## ๐Ÿ“ฆ Installation
45
+
46
+ ### From PyPI (Standard Installation)
47
+
48
+ ```bash
49
+ pip install code-meter
50
+ ```
51
+
52
+ ### Local / Development (Editable Mode)
53
+
54
+ ```bash
55
+ git clone https://github.com/dhanushnayak/code-meter.git
56
+ cd code-meter
57
+ pip install -e .
58
+ ```
59
+
60
+ ---
61
+
62
+ ## ๐Ÿš€ Basic Usage
63
+
64
+ Simply run:
65
+
66
+ ```bash
67
+ code-meter
68
+ ```
69
+
70
+ Or use one of the provider aliases (`claude-meter`, `codex-meter`, `antigravity-meter`, `agy-meter`).
71
+
72
+ This launches the interactive Rich terminal dashboard displaying key metrics, model breakdowns, project breakdowns, today's usage, and token burn rates.
73
+
74
+ ---
75
+
76
+ ## ๐Ÿ› ๏ธ CLI Commands
77
+
78
+ | Command | Description |
79
+ | :--- | :--- |
80
+ | `code-meter` | Open interactive Rich terminal dashboard |
81
+ | `code-meter scan` | Force an incremental scan of local usage directories |
82
+ | `code-meter today` | Summary of token usage and cost for today |
83
+ | `code-meter week` | Summary of token usage and cost for the past 7 days |
84
+ | `code-meter month` | Summary of token usage and cost for the past 30 days |
85
+ | `code-meter status` | View system status (scanned files, records, prompts, code edits, DB size) |
86
+ | `code-meter prompts` | View log of user prompts asked per session over time |
87
+ | `code-meter history` | View log of code edits, file writes, and snapshots recorded per session |
88
+ | `code-meter diffs` | View formatted code diff summaries saved in SQLite |
89
+ | `code-meter report` | Detailed aggregated report with optional filters |
90
+ | `code-meter models` | Usage and cost breakdown by model |
91
+ | `code-meter projects` | Usage and cost breakdown by working project directory |
92
+ | `code-meter sessions` | Usage and cost breakdown by session ID |
93
+ | `code-meter export` | Export usage records to CSV or JSON format |
94
+ | `code-meter config` | Display active configuration settings and file paths |
95
+ | `code-meter watch` | Live file watcher mode for real-time dashboard updates |
96
+
97
+ ---
98
+
99
+ ## ๐Ÿ” Filters & Examples
100
+
101
+ Combine filters on reporting, prompts, and history commands:
102
+
103
+ ```bash
104
+ # Filter report by provider, project, model, and timeframe
105
+ code-meter report --provider codex --model gpt-4o --days 30
106
+ code-meter report --provider antigravity --model gemini-2.5-flash
107
+
108
+ # View prompts for a specific session or project
109
+ code-meter prompts --project rag-agent --limit 20
110
+
111
+ # View code changes and diffs for a file or session
112
+ code-meter history --file src/main.py
113
+ code-meter diffs --session abc12345
114
+
115
+ # Export usage stats to CSV or JSON
116
+ code-meter export --format csv --days 7 --output usage_report.csv
117
+ ```
118
+
119
+ ---
120
+
121
+ ## โš™๏ธ Configuration
122
+
123
+ Configuration is stored in `~/.config/code-meter/config.toml` (or Windows `%APPDATA%/code-meter/config.toml`).
124
+
125
+ ```toml
126
+ [general]
127
+ database = "~/.local/share/code-meter/usage.db"
128
+
129
+ [claude_code]
130
+ directory = "~/.claude"
131
+
132
+ [codex]
133
+ directory = "~/.codex"
134
+
135
+ [antigravity]
136
+ directory = "~/.gemini/antigravity-ide"
137
+
138
+ [ui]
139
+ refresh_seconds = 2
140
+
141
+ [pricing]
142
+ currency = "USD"
143
+ ```
144
+
145
+ Environment variables take precedence:
146
+ * `CODE_METER_DB`
147
+ * `CODE_METER_CLAUDE_DIR`
148
+ * `CODE_METER_CODEX_DIR`
149
+ * `CODE_METER_ANTIGRAVITY_DIR`
150
+ * `CODE_METER_REFRESH`
151
+
152
+ ---
153
+
154
+ ## ๐Ÿงฉ Architecture
155
+
156
+ ```text
157
+ Claude Code (~/.claude) Codex (~/.codex) Antigravity (~/.gemini/antigravity-ide)
158
+ โ”‚ โ”‚ โ”‚
159
+ โ–ผ โ–ผ โ–ผ
160
+ ClaudeCodeProvider CodexProvider AntigravityProvider
161
+ โ”‚ โ”‚ โ”‚
162
+ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
163
+ โ–ผ
164
+ UsageRecord / SessionPrompt / SessionCodeChange (Pydantic models)
165
+ โ”‚
166
+ โ–ผ
167
+ Database Repository & Incremental Scanner (SQLite)
168
+ โ”‚
169
+ โ–ผ
170
+ Pricing Engine (Multi-Provider Model Pricing Tables)
171
+ โ”‚
172
+ โ–ผ
173
+ Analytics Engine (Token counts, Costs, Aggregations)
174
+ โ”‚
175
+ โ–ผ
176
+ Terminal UI & Typer CLI Commands
177
+ ```
178
+ โ”‚
179
+ โ–ผ
180
+ UsageRecord / SessionPrompt / SessionCodeChange (Pydantic models)
181
+ โ”‚
182
+ โ–ผ
183
+ Database Repository & Incremental Scanner (SQLite)
184
+ โ”‚
185
+ โ–ผ
186
+ Pricing Engine (Model Pricing Tables)
187
+ โ”‚
188
+ โ–ผ
189
+ Analytics Engine (Token counts, Costs, Aggregations)
190
+ โ”‚
191
+ โ–ผ
192
+ Terminal UI & Typer CLI Commands
193
+ ```
194
+
195
+ ---
196
+
197
+ ## ๐Ÿงช Running Tests
198
+
199
+ ```bash
200
+ pytest -v
201
+ ```
202
+
203
+ ---
204
+
205
+ ## ๐Ÿ“œ License
206
+
207
+ Distributed under the **MIT License**. See [LICENSE](LICENSE) for details.
@@ -0,0 +1,33 @@
1
+ code_meter/__init__.py,sha256=Bq3a_GNZ6q8KNm5Dxqai_J_vyRZIIYwPKgqyqMXS_3Q,97
2
+ code_meter/cli.py,sha256=W2Y5syNWzZHPfO0SqjPKe6sew3q2iK7S95MaT9zJ5Yc,12042
3
+ code_meter/config.py,sha256=wAYZzq4Jdhu6m9U7cH4jrOFBL31sF9OHIuCRfrlu9QI,3516
4
+ code_meter/watcher.py,sha256=Jw5-8VE_zZS3XM55Insoqp0xhTrMLrwxq_oYGYbTk94,1762
5
+ code_meter/analytics/__init__.py,sha256=gEEZzoGa-EPLHa3ILScj6Rhs4pxHQNYhd_dDdRTjToo,264
6
+ code_meter/analytics/costs.py,sha256=LIvsr77h9PMO6n2rrhfwXzU23mkTMuxVCKw03S0vQC8,1408
7
+ code_meter/analytics/reports.py,sha256=9rD1-Kj5doTmVa0PpDnq-q7PX0VYMZ5p3Q2ZGV_AbAQ,13547
8
+ code_meter/analytics/tokens.py,sha256=KFU44DglTZcQ_cmzPwB12m03nu7FcONQml8aypJvXRU,2100
9
+ code_meter/models/__init__.py,sha256=GMuYr3LD4uPdP7qfA_GQDgLeNj1WpgjFyi-Ng8MeA5w,324
10
+ code_meter/models/project.py,sha256=WSa0hfRfdx6KmXc5_JWxr6CEpsP7DYzjhfOpiDMy8Tw,2346
11
+ code_meter/models/usage.py,sha256=z2oDLfgLHvQYKNVjxlfT6nYujxusqJc-YndMCemHchc,1563
12
+ code_meter/pricing/__init__.py,sha256=bCTHtuP-Zn8uYIY_zkF8bjxSGsMBBfS4pUrNklQzG6I,441
13
+ code_meter/pricing/anthropic.py,sha256=AZPSIbE4LCrQ2oahHSBh3YOQ80eXyMqoSPso4J9rcr0,2676
14
+ code_meter/pricing/engine.py,sha256=8UihgLSSTd3Jo3KLDDCt97HIne7DklMewGaFJRYrt1M,3987
15
+ code_meter/pricing/google.py,sha256=3oqnhi1fZNPuGNNqpo0JA5Pl2iHB7uEbBZjOrLUO3Gg,2033
16
+ code_meter/pricing/openai.py,sha256=1PTuBGJTGJ-SN4zCpuvtvkOQuV_x7RiqZeY-zJDxVr8,2237
17
+ code_meter/providers/__init__.py,sha256=McVVgaiQkP6uZ7iocC8jXTvWF3IiKiE2GNNimEkJTPs,461
18
+ code_meter/providers/antigravity.py,sha256=JaKFfzoqQv6WHyzoSBey0_8l3hdvKySwPgMwSakh-kA,14250
19
+ code_meter/providers/base.py,sha256=Z8DpDdqjgIDak4yQyv23EGt5o0FcmH74r_fDPo8t9Tg,1413
20
+ code_meter/providers/claude_code.py,sha256=cZ42yPpGgq0JRxErz7QWk-YCu4QiRBzKTiiXpYWJGTw,15106
21
+ code_meter/providers/codex.py,sha256=3OWCtnCGCF_5U2yYJAKtzTci3rm1nXJbPsMCreCBIMs,14298
22
+ code_meter/storage/__init__.py,sha256=hL5t8YA7FDUtVhTSVkkjSlKD1Vf3GXJQuIyCwlW-THg,222
23
+ code_meter/storage/database.py,sha256=1db7k2HtcaUx55Bja5HZzcyfYdoLH3S4kJYbLuUt4UA,5858
24
+ code_meter/storage/repository.py,sha256=cUxZYGhTt3FS3ViLAfjZ8Gy2tjz8DET8Vq_-Ib-K3b4,18229
25
+ code_meter/ui/__init__.py,sha256=Aj3tppDbAgx95tbAVL26Epo9CeSPf3BxrReIl-D0fS0,447
26
+ code_meter/ui/dashboard.py,sha256=TolFGtriUF31oVWwwjtI_Ekxup65JXOXCUow3JHeJCA,4164
27
+ code_meter/ui/tables.py,sha256=sbWQ-vyxUWj3tK2ZKe7VQN228Sgb5xZQLg7UAwuLPmw,7686
28
+ code_meter-0.1.0.dist-info/licenses/LICENSE,sha256=-NSD_0ce_j3dDtbi0bFZwI_H-FxN4Azs2rZYS7x-jsw,1085
29
+ code_meter-0.1.0.dist-info/METADATA,sha256=LfMqIJgpPziJJ-HLEXG7oKztYMh98ackEZoRUZ_etCc,7066
30
+ code_meter-0.1.0.dist-info/WHEEL,sha256=YVMoNqKzERt-wjUZwJ33xBGAwnFl-4cqbYkTtWa4itE,91
31
+ code_meter-0.1.0.dist-info/entry_points.txt,sha256=CFYkJagPpqiZ3QhpMG7gM-v2a0QuMAdGefYB2l6uKMw,187
32
+ code_meter-0.1.0.dist-info/top_level.txt,sha256=uQ4_CPWZF2It5bwBU8HV0EZCxmdCgevpHh5HWTdEktM,11
33
+ code_meter-0.1.0.dist-info/RECORD,,
@@ -0,0 +1,5 @@
1
+ Wheel-Version: 1.0
2
+ Generator: setuptools (84.0.0)
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
5
+
@@ -0,0 +1,6 @@
1
+ [console_scripts]
2
+ agy-meter = code_meter.cli:app
3
+ antigravity-meter = code_meter.cli:app
4
+ claude-meter = code_meter.cli:app
5
+ code-meter = code_meter.cli:app
6
+ codex-meter = code_meter.cli:app
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Antigravity Team
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 WARRANTY OF ANY KIND,
16
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO
18
+ EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
19
+ OTHER 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 @@
1
+ code_meter