claude-prospector 0.7.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.
- claude_prospector-0.7.0/LICENSE +21 -0
- claude_prospector-0.7.0/PKG-INFO +11 -0
- claude_prospector-0.7.0/README.md +335 -0
- claude_prospector-0.7.0/claude_prospector/__init__.py +10 -0
- claude_prospector-0.7.0/claude_prospector/__main__.py +53 -0
- claude_prospector-0.7.0/claude_prospector/aggregator.py +270 -0
- claude_prospector-0.7.0/claude_prospector/cli/__init__.py +1 -0
- claude_prospector-0.7.0/claude_prospector/cli/config.py +143 -0
- claude_prospector-0.7.0/claude_prospector/cli/dashboard.py +212 -0
- claude_prospector-0.7.0/claude_prospector/cli/session_summary.py +816 -0
- claude_prospector-0.7.0/claude_prospector/constants.py +17 -0
- claude_prospector-0.7.0/claude_prospector/models.py +99 -0
- claude_prospector-0.7.0/claude_prospector/parser.py +399 -0
- claude_prospector-0.7.0/claude_prospector/paths.py +223 -0
- claude_prospector-0.7.0/claude_prospector/renderer.py +77 -0
- claude_prospector-0.7.0/claude_prospector/skill_tracking.py +309 -0
- claude_prospector-0.7.0/claude_prospector.egg-info/PKG-INFO +11 -0
- claude_prospector-0.7.0/claude_prospector.egg-info/SOURCES.txt +39 -0
- claude_prospector-0.7.0/claude_prospector.egg-info/dependency_links.txt +1 -0
- claude_prospector-0.7.0/claude_prospector.egg-info/requires.txt +5 -0
- claude_prospector-0.7.0/claude_prospector.egg-info/top_level.txt +1 -0
- claude_prospector-0.7.0/pyproject.toml +24 -0
- claude_prospector-0.7.0/setup.cfg +4 -0
- claude_prospector-0.7.0/tests/test_aggregator.py +448 -0
- claude_prospector-0.7.0/tests/test_aggregator_adoption.py +159 -0
- claude_prospector-0.7.0/tests/test_cli.py +220 -0
- claude_prospector-0.7.0/tests/test_cli_config.py +165 -0
- claude_prospector-0.7.0/tests/test_cli_subcommands.py +47 -0
- claude_prospector-0.7.0/tests/test_dashboard_regen_hook.py +578 -0
- claude_prospector-0.7.0/tests/test_dashboard_snapshot.py +80 -0
- claude_prospector-0.7.0/tests/test_e2e.py +418 -0
- claude_prospector-0.7.0/tests/test_models.py +313 -0
- claude_prospector-0.7.0/tests/test_parser.py +969 -0
- claude_prospector-0.7.0/tests/test_paths.py +406 -0
- claude_prospector-0.7.0/tests/test_phase1_fixtures.py +243 -0
- claude_prospector-0.7.0/tests/test_renderer.py +281 -0
- claude_prospector-0.7.0/tests/test_session_summary.py +1683 -0
- claude_prospector-0.7.0/tests/test_skill_pipeline_sync.py +72 -0
- claude_prospector-0.7.0/tests/test_skill_tracker_hook.py +922 -0
- claude_prospector-0.7.0/tests/test_skill_tracking.py +249 -0
- claude_prospector-0.7.0/tests/test_version_flag.py +66 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Christopher Beaulieu
|
|
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,11 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: claude-prospector
|
|
3
|
+
Version: 0.7.0
|
|
4
|
+
Summary: Claude Code token usage analyzer with optimization recommendations. Surfaces what's eating your budget across the 5h / 7d / Sonnet-7d billing windows, with per-model and nested per-agent attribution and skill adoption tracking. Ships both an interactive dashboard and a conversational analysis skill.
|
|
5
|
+
Requires-Python: >=3.10
|
|
6
|
+
License-File: LICENSE
|
|
7
|
+
Requires-Dist: jinja2>=3.1
|
|
8
|
+
Provides-Extra: dev
|
|
9
|
+
Requires-Dist: ruff~=0.6.0; extra == "dev"
|
|
10
|
+
Requires-Dist: pytest~=8.0; extra == "dev"
|
|
11
|
+
Dynamic: license-file
|
|
@@ -0,0 +1,335 @@
|
|
|
1
|
+
# claude-prospector
|
|
2
|
+
|
|
3
|
+
Token usage analyzer for Claude Code that surfaces where your budget is going across all three billing windows, with per-model and per-agent attribution and concrete optimization recommendations.
|
|
4
|
+
|
|
5
|
+
## Why
|
|
6
|
+
|
|
7
|
+
Claude Code tracks three billing buckets (5h rolling, 7d rolling, Sonnet-only 7d) but provides no per-agent or per-skill visibility. This tool reads Claude Code's local JSONL session files and generates a dashboard that breaks down where your tokens are going.
|
|
8
|
+
|
|
9
|
+
## Install as a Claude Code plugin
|
|
10
|
+
|
|
11
|
+
The easiest way to use `claude-prospector` is as a Claude Code plugin — no manual
|
|
12
|
+
cloning or path configuration required.
|
|
13
|
+
|
|
14
|
+
```bash
|
|
15
|
+
claude plugin marketplace add glitchwerks/plugins
|
|
16
|
+
claude plugin install claude-prospector@glitchwerks
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
### Prerequisite: Python package
|
|
20
|
+
|
|
21
|
+
The plugin invokes `python -m claude_prospector` under the hood, so the Python
|
|
22
|
+
package must be importable in the environment Claude Code uses. Install with either:
|
|
23
|
+
|
|
24
|
+
- **From a local clone**: `uv pip install -e .`
|
|
25
|
+
- **Directly from GitHub**: `uv pip install "git+https://github.com/glitchwerks/claude-prospector.git"`
|
|
26
|
+
|
|
27
|
+
> A future enhancement (#67) tracks eliminating this two-step install so `claude plugin update` is sufficient on its own.
|
|
28
|
+
|
|
29
|
+
## First-run setup
|
|
30
|
+
|
|
31
|
+
After installing claude-prospector for the first time (or after a plugin
|
|
32
|
+
update), open a new Claude Code session. You'll see a banner:
|
|
33
|
+
|
|
34
|
+
> claude-prospector requires setup. Run /setup-prospector to materialise
|
|
35
|
+
> the Python venv.
|
|
36
|
+
|
|
37
|
+
Run `/setup-prospector` once. The skill will:
|
|
38
|
+
|
|
39
|
+
1. Discover a Python 3.10+ interpreter on your system.
|
|
40
|
+
2. Create a plugin-owned venv at `${CLAUDE_PLUGIN_DATA}/venv/`.
|
|
41
|
+
3. Install `claude-prospector` from PyPI into that venv.
|
|
42
|
+
4. Verify the install and record a setup-state flag.
|
|
43
|
+
|
|
44
|
+
After setup completes, open a new session — the banner will be gone and
|
|
45
|
+
the dashboard, skill-tracking, and usage-analysis features will work
|
|
46
|
+
normally.
|
|
47
|
+
|
|
48
|
+
You'll need to re-run `/setup-prospector` only when:
|
|
49
|
+
|
|
50
|
+
- The plugin updates to a new version (banner: "venv is for vX but
|
|
51
|
+
plugin is vY").
|
|
52
|
+
- The venv is corrupted or deleted (banner: "venv at <path> is
|
|
53
|
+
unreachable or corrupt").
|
|
54
|
+
- You move to a new machine (per-machine setup; flag is not portable
|
|
55
|
+
across machines).
|
|
56
|
+
|
|
57
|
+
**Note:** The plugin's hook scripts still run under the harness-provided
|
|
58
|
+
`python` and require a working harness-environment Python interpreter.
|
|
59
|
+
The venv created by `/setup-prospector` is used by the hooks for
|
|
60
|
+
subprocess spawning only.
|
|
61
|
+
|
|
62
|
+
### Migration from v0.6.0
|
|
63
|
+
|
|
64
|
+
After upgrading to v0.7.0, open a new Claude Code session. A banner will
|
|
65
|
+
prompt you to run `/setup-prospector`. This is a one-time action per
|
|
66
|
+
machine.
|
|
67
|
+
|
|
68
|
+
If you previously installed `claude-prospector` into `~/.claude/.venv`,
|
|
69
|
+
you can leave that install in place — Pattern W hooks always use the
|
|
70
|
+
plugin-owned venv via an absolute path. To reclaim disk you may
|
|
71
|
+
`uv pip uninstall claude-prospector` from `~/.claude/.venv` after setup;
|
|
72
|
+
this is optional.
|
|
73
|
+
|
|
74
|
+
## What the plugin provides
|
|
75
|
+
|
|
76
|
+
v0.4.0 ships the full plugin surface:
|
|
77
|
+
|
|
78
|
+
- **Interactive dashboard** — HTML report with three-bucket budget gauges (5h / 7d / Sonnet-7d), per-model donut and bar charts, per-agent token attribution with nested sub-agent tracing, skill-invocation counts, and per-project breakdowns.
|
|
79
|
+
- **`usage-analysis` skill** — conversational analysis with recommendations. Answers questions like "am I close to my Sonnet limit?", "where are my tokens going?", and "which agent uses the most?". Triggered by natural-language phrases.
|
|
80
|
+
- **`usage-dashboard` skill** — bare regeneration surface. Triggered by phrases like "regenerate the dashboard" or "rebuild my usage dashboard"; writes the HTML file and reports the path, without interpreting the data.
|
|
81
|
+
- **`skill-tracker` hook** (PreToolUse, always-on) — logs `Skill` tool-use events to the state directory for the `by_skill` and skill-passed-vs-invoked analyses.
|
|
82
|
+
- **`dashboard-regen` hook** (Stop, opt-in) — auto-regenerates the dashboard after every session when the `autoregen` user-config is enabled via the plugin manager (`/plugin reconfigure claude-prospector` or at install time).
|
|
83
|
+
|
|
84
|
+
### Configuration (autoregen)
|
|
85
|
+
|
|
86
|
+
The `dashboard-regen` Stop hook is opt-in. Toggle it through the Claude Code
|
|
87
|
+
plugin manager — no manual file edits required:
|
|
88
|
+
|
|
89
|
+
```
|
|
90
|
+
/plugin reconfigure claude-prospector
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
You will be prompted to enable or disable `autoregen`. You can also set it at
|
|
94
|
+
install time when the plugin manager shows the initial configuration prompt.
|
|
95
|
+
|
|
96
|
+
To inspect the current plugin state, use the read-only CLI:
|
|
97
|
+
|
|
98
|
+
```bash
|
|
99
|
+
python -m claude_prospector config --show
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
This prints the legacy `config.json` contents if present. The authoritative
|
|
103
|
+
value is the `autoregen` setting shown in the plugin manager.
|
|
104
|
+
|
|
105
|
+
> **Upgrading from v0.4.x?** If you previously ran
|
|
106
|
+
> `python -m claude_prospector config --enable-autoregen`, your old
|
|
107
|
+
> `config.json` is still readable via `--show`. The hook will log a one-time
|
|
108
|
+
> advisory message to `hook.log` the first time it runs with the new
|
|
109
|
+
> user-config path. Re-toggle via `/plugin reconfigure claude-prospector` to
|
|
110
|
+
> move to the managed setting. The old `config.json` file is not deleted.
|
|
111
|
+
|
|
112
|
+
### State storage
|
|
113
|
+
|
|
114
|
+
When running as a plugin, state (dashboard HTML, hook log, skill-tracking JSONL files) is stored under the `${CLAUDE_PLUGIN_DATA}` directory — the Anthropic-documented persistent state location that survives plugin updates.
|
|
115
|
+
|
|
116
|
+
Users upgrading from v0.4.0 get a **one-time automatic migration**: on the first session after upgrade, any existing files from `~/.claude/claude-prospector/` are moved into `${CLAUDE_PLUGIN_DATA}` and the legacy directory is removed.
|
|
117
|
+
|
|
118
|
+
For testing or non-plugin use, set `CLAUDE_PROSPECTOR_BASE_DIR` to override the location entirely (takes priority over `${CLAUDE_PLUGIN_DATA}`).
|
|
119
|
+
|
|
120
|
+
## Development / Standalone CLI
|
|
121
|
+
|
|
122
|
+
For working on the package directly, or running it without the Claude Code plugin.
|
|
123
|
+
|
|
124
|
+
### Install for development
|
|
125
|
+
|
|
126
|
+
```bash
|
|
127
|
+
git clone https://github.com/cbeaulieu-gt/claude-prospector.git
|
|
128
|
+
cd claude-prospector
|
|
129
|
+
uv pip install -e ".[dev]" # installs runtime + ruff + pytest
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
Requires Python 3.10+.
|
|
133
|
+
|
|
134
|
+
### Run the CLI directly
|
|
135
|
+
|
|
136
|
+
```bash
|
|
137
|
+
# Default: last 7 days, opens in browser
|
|
138
|
+
python -m claude_prospector
|
|
139
|
+
|
|
140
|
+
# Rolling window matching billing buckets
|
|
141
|
+
python -m claude_prospector --window 5h
|
|
142
|
+
python -m claude_prospector --window 7d
|
|
143
|
+
|
|
144
|
+
# Custom date range
|
|
145
|
+
python -m claude_prospector --from 2026-04-01 --to 2026-04-09
|
|
146
|
+
|
|
147
|
+
# Output to file instead of opening browser
|
|
148
|
+
python -m claude_prospector --output report.html --no-open
|
|
149
|
+
|
|
150
|
+
# Custom Claude data directory
|
|
151
|
+
python -m claude_prospector --data-dir "D:\other\.claude"
|
|
152
|
+
|
|
153
|
+
# Set budget limits for gauge percentages
|
|
154
|
+
python -m claude_prospector --limit-5h 600000 --limit-7d 4000000 --limit-sonnet-7d 2000000
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
### Subcommands
|
|
158
|
+
|
|
159
|
+
All functionality is accessed through named subcommands. Bare `claude-prospector` prints help and exits 0.
|
|
160
|
+
|
|
161
|
+
#### `dashboard` — interactive HTML dashboard
|
|
162
|
+
|
|
163
|
+
```bash
|
|
164
|
+
# Default: last 7 days, opens in browser
|
|
165
|
+
claude-prospector dashboard
|
|
166
|
+
|
|
167
|
+
# Rolling window matching Claude billing buckets
|
|
168
|
+
claude-prospector dashboard --window 5h
|
|
169
|
+
claude-prospector dashboard --window 7d
|
|
170
|
+
|
|
171
|
+
# Custom date range
|
|
172
|
+
claude-prospector dashboard --from 2026-04-01 --to 2026-04-09
|
|
173
|
+
|
|
174
|
+
# Output to file instead of opening browser
|
|
175
|
+
claude-prospector dashboard --output report.html --no-open
|
|
176
|
+
|
|
177
|
+
# Custom Claude data directory
|
|
178
|
+
claude-prospector dashboard --data-dir "D:\other\.claude"
|
|
179
|
+
|
|
180
|
+
# Set budget limits for gauge percentages
|
|
181
|
+
claude-prospector dashboard --limit-5h 600000 --limit-7d 4000000 \
|
|
182
|
+
--limit-sonnet-7d 2000000
|
|
183
|
+
|
|
184
|
+
# Emit JSON (for scripting / CI)
|
|
185
|
+
claude-prospector dashboard --format json
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
All flags are unchanged from the pre-refactor form — only their location
|
|
189
|
+
moved (now under the `dashboard` subparser).
|
|
190
|
+
|
|
191
|
+
#### `session-summary` — deterministic session recap (new in v0.2.0)
|
|
192
|
+
|
|
193
|
+
Reads a single Claude Code transcript JSONL file and emits a structured
|
|
194
|
+
JSON summary suitable for consumption by the `/whats-next` skill or any
|
|
195
|
+
other tool that needs to know what a session did.
|
|
196
|
+
|
|
197
|
+
```bash
|
|
198
|
+
claude-prospector session-summary --path ~/.claude/projects/<hash>/<session>.jsonl
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
**Flags:**
|
|
202
|
+
|
|
203
|
+
| Flag | Default | Description |
|
|
204
|
+
|---|---|---|
|
|
205
|
+
| `--path PATH` | *(required)* | Path to the transcript JSONL file |
|
|
206
|
+
| `--format {json,text}` | `json` | Output format. `json` is the machine-readable contract; `text` is a human-readable debug view |
|
|
207
|
+
| `--max-actions N` | `50` | Cap on emitted actions. `0` disables the cap |
|
|
208
|
+
|
|
209
|
+
**Sample output (`--format json`):**
|
|
210
|
+
|
|
211
|
+
```json
|
|
212
|
+
{
|
|
213
|
+
"project": "claude-prospector",
|
|
214
|
+
"intent": "Implement the session-summary subcommand for the /whats-next skill",
|
|
215
|
+
"actions": [
|
|
216
|
+
"Edited claude_prospector/cli/session_summary.py",
|
|
217
|
+
"Created tests/test_session_summary.py",
|
|
218
|
+
"Ran pytest tests/test_session_summary.py -x",
|
|
219
|
+
"Dispatched code-reviewer sub-agent"
|
|
220
|
+
],
|
|
221
|
+
"stoppedNaturally": true
|
|
222
|
+
}
|
|
223
|
+
```
|
|
224
|
+
|
|
225
|
+
**Exit codes:**
|
|
226
|
+
|
|
227
|
+
| Code | Meaning | stderr |
|
|
228
|
+
|---|---|---|
|
|
229
|
+
| `0` | Success — JSON written to stdout | *(silent)* |
|
|
230
|
+
| `1` | IO failure reading `--path` (file missing, permission denied, etc.) | `session-summary: cannot read transcript at '<path>': <OSError class>: <message>` |
|
|
231
|
+
| `2` | File readable but contains no external user turns (empty session, zero-byte file, whitespace-only file) | `session-summary: transcript '<path>' contains no user turns` |
|
|
232
|
+
| `3` | File has content but none of it parses as JSONL | `session-summary: transcript '<path>' is not valid JSONL` |
|
|
233
|
+
|
|
234
|
+
On any non-zero exit, stdout is empty and stderr contains exactly one line.
|
|
235
|
+
|
|
236
|
+
#### Migration note
|
|
237
|
+
|
|
238
|
+
The old flag-only form **no longer works** after v0.2.0:
|
|
239
|
+
|
|
240
|
+
```bash
|
|
241
|
+
# REMOVED — will print help and exit 0, not run the dashboard
|
|
242
|
+
claude-prospector --format json
|
|
243
|
+
|
|
244
|
+
# CORRECT — migrate all callers to:
|
|
245
|
+
claude-prospector dashboard --format json
|
|
246
|
+
```
|
|
247
|
+
|
|
248
|
+
Any script, skill, or CI step that invokes `claude-prospector` with bare flags
|
|
249
|
+
(no subcommand) must be updated to use `claude-prospector dashboard [flags]`.
|
|
250
|
+
|
|
251
|
+
### Testing
|
|
252
|
+
|
|
253
|
+
```bash
|
|
254
|
+
pytest # ~151 tests, typically finishes in under 5 seconds
|
|
255
|
+
```
|
|
256
|
+
|
|
257
|
+
### Linting & formatting
|
|
258
|
+
|
|
259
|
+
```bash
|
|
260
|
+
ruff check . # lint
|
|
261
|
+
ruff format . # autoformat in-place
|
|
262
|
+
ruff format --check . # format gate (used in CI — exits non-zero on drift)
|
|
263
|
+
```
|
|
264
|
+
|
|
265
|
+
### CI
|
|
266
|
+
|
|
267
|
+
GitHub Actions runs on every PR and push to `main`:
|
|
268
|
+
|
|
269
|
+
- **lint** (Ubuntu): `ruff check .` + `ruff format --check .`
|
|
270
|
+
- **test** (Ubuntu + Windows, Python 3.10): `pytest`
|
|
271
|
+
|
|
272
|
+
Both jobs must be green before a PR can merge.
|
|
273
|
+
|
|
274
|
+
## Nested agent attribution
|
|
275
|
+
|
|
276
|
+
When Claude Code sessions dispatch sub-agents that themselves dispatch further
|
|
277
|
+
sub-agents, `claude-prospector` traces the full depth and attributes tokens to the
|
|
278
|
+
complete root-to-leaf chain rather than just the immediate leaf.
|
|
279
|
+
|
|
280
|
+
- **Data model.** Each `MessageRecord` carries an `agent_path: tuple[str, ...]`
|
|
281
|
+
field (e.g. `("general-purpose", "project-planner", "Explore")`) and a
|
|
282
|
+
parallel `agent_type: str` stored field. Both are populated together at parse
|
|
283
|
+
time; the parser enforces the invariant `agent_type == agent_path[-1]` (when
|
|
284
|
+
`agent_path` is non-empty). `agent_type` is not a computed property — it is a
|
|
285
|
+
plain dataclass field, so consumers that construct `MessageRecord` with an
|
|
286
|
+
explicit `agent_type=` argument continue to work without change. The two
|
|
287
|
+
fields are kept in sync by the parser, not by the dataclass itself.
|
|
288
|
+
|
|
289
|
+
- **`by_agent` keys.** The aggregator's `by_agent` dict is keyed by the full
|
|
290
|
+
path joined with U+2192 (`→`), for example
|
|
291
|
+
`"general-purpose→project-planner→Explore"`. Depth-1 sessions produce
|
|
292
|
+
single-segment keys identical to the pre-change shape, so existing
|
|
293
|
+
integrations are unaffected.
|
|
294
|
+
|
|
295
|
+
- **Per-session `agents` list.** Each session's `agents` list contains only
|
|
296
|
+
the deepest-leaf path per chain (e.g. a depth-3 chain
|
|
297
|
+
`general-purpose → project-planner → Explore` contributes one entry,
|
|
298
|
+
`"general-purpose→project-planner→Explore"`). Sibling chains that share a
|
|
299
|
+
leaf name but differ in their ancestor are both kept — neither is a prefix
|
|
300
|
+
of the other. This rule preserves the dashboard JS's per-agent token
|
|
301
|
+
apportionment, which divides session totals by `s.agents.length`.
|
|
302
|
+
|
|
303
|
+
- **Depth limit.** Path tuples may contain up to **10 segments** total —
|
|
304
|
+
the root agent plus up to 9 levels of nested sub-agents
|
|
305
|
+
(`_MAX_AGENT_PATH_LENGTH = 10`). Beyond that, the parser emits a single
|
|
306
|
+
`UserWarning` and stops descending; deeper messages are bucketed under the
|
|
307
|
+
last walked ancestor. The warning fires at most once per session parse (not
|
|
308
|
+
once per overflowing message), as do the cycle and OSError warnings below.
|
|
309
|
+
On Windows, junction-based cycles are caught by this same cap rather than
|
|
310
|
+
by the POSIX visited-set short-circuit.
|
|
311
|
+
|
|
312
|
+
- **Sanitization.** A literal `→` appearing inside an agent name is replaced
|
|
313
|
+
with `﹖` (U+FE56) at parse time and a `UserWarning` fires. The sanitized
|
|
314
|
+
name is used throughout (parse, aggregation, dashboard key) so attribution
|
|
315
|
+
data is preserved even when the invariant is violated.
|
|
316
|
+
|
|
317
|
+
- **Deferred.** Dashboard tree visualization (sunburst, indented tree,
|
|
318
|
+
expand/collapse) is out of scope for this release. The existing flat agent
|
|
319
|
+
list in the dashboard JS receives path-keyed entries but no hierarchical
|
|
320
|
+
rendering yet.
|
|
321
|
+
|
|
322
|
+
## Dashboard
|
|
323
|
+
|
|
324
|
+
The generated HTML dashboard includes:
|
|
325
|
+
|
|
326
|
+
- **Budget gauges** - estimated usage against each billing bucket (5h, 7d, Sonnet-only 7d)
|
|
327
|
+
- **Model breakdown** - donut chart and daily stacked bar chart (Opus/Sonnet/Haiku)
|
|
328
|
+
- **Agent breakdown** - token usage per agent with model attribution
|
|
329
|
+
- **Skill usage** - invocation counts per skill
|
|
330
|
+
- **Project breakdown** - tokens per project
|
|
331
|
+
- **Session drill-down** - click a day to see individual sessions with agents, tokens, and model split
|
|
332
|
+
|
|
333
|
+
## How It Works
|
|
334
|
+
|
|
335
|
+
Reads JSONL session files from `~/.claude/projects/`. Each session file contains timestamped assistant messages with model name and token usage. Subagent metadata (`.meta.json`) maps child agent tokens to their agent type. Skill invocations are extracted from `Skill` tool-use entries.
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
"""CLI entry point for claude-prospector — subparser dispatcher."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import sys
|
|
6
|
+
|
|
7
|
+
import claude_prospector
|
|
8
|
+
from claude_prospector.cli import config, dashboard, session_summary
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
def main() -> None:
|
|
12
|
+
"""Parse top-level subcommand and dispatch to the appropriate runner."""
|
|
13
|
+
import argparse
|
|
14
|
+
|
|
15
|
+
parser = argparse.ArgumentParser(
|
|
16
|
+
prog="claude-prospector",
|
|
17
|
+
description=(
|
|
18
|
+
"Claude Code token usage tools. "
|
|
19
|
+
"Run 'claude-prospector <subcommand> --help' for details."
|
|
20
|
+
),
|
|
21
|
+
)
|
|
22
|
+
parser.add_argument(
|
|
23
|
+
"--version",
|
|
24
|
+
action="version",
|
|
25
|
+
version=f"claude-prospector {claude_prospector.__version__}",
|
|
26
|
+
)
|
|
27
|
+
subparsers = parser.add_subparsers(
|
|
28
|
+
dest="subcommand",
|
|
29
|
+
metavar="subcommand",
|
|
30
|
+
)
|
|
31
|
+
|
|
32
|
+
dashboard.build_parser(subparsers)
|
|
33
|
+
session_summary.build_parser(subparsers)
|
|
34
|
+
config.build_parser(subparsers)
|
|
35
|
+
|
|
36
|
+
args = parser.parse_args()
|
|
37
|
+
|
|
38
|
+
if args.subcommand is None:
|
|
39
|
+
parser.print_help()
|
|
40
|
+
sys.exit(0)
|
|
41
|
+
|
|
42
|
+
if args.subcommand == "dashboard":
|
|
43
|
+
sys.exit(dashboard.run(args))
|
|
44
|
+
|
|
45
|
+
if args.subcommand == "session-summary":
|
|
46
|
+
sys.exit(session_summary.run(args))
|
|
47
|
+
|
|
48
|
+
if args.subcommand == "config":
|
|
49
|
+
sys.exit(config.run(args))
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
if __name__ == "__main__":
|
|
53
|
+
main()
|