coding-agent-tools 0.1.0__tar.gz → 0.1.2__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.
- {coding_agent_tools-0.1.0 → coding_agent_tools-0.1.2}/.gitignore +3 -0
- coding_agent_tools-0.1.2/PKG-INFO +173 -0
- coding_agent_tools-0.1.2/README.md +165 -0
- {coding_agent_tools-0.1.0 → coding_agent_tools-0.1.2}/coding_agent_tools/__init__.py +1 -1
- {coding_agent_tools-0.1.0 → coding_agent_tools-0.1.2}/coding_agent_tools/agent_usage.py +137 -76
- {coding_agent_tools-0.1.0 → coding_agent_tools-0.1.2}/pyproject.toml +1 -1
- coding_agent_tools-0.1.0/PKG-INFO +0 -107
- coding_agent_tools-0.1.0/README.md +0 -99
- {coding_agent_tools-0.1.0 → coding_agent_tools-0.1.2}/coding_agent_tools/claude_sessions.py +0 -0
- {coding_agent_tools-0.1.0 → coding_agent_tools-0.1.2}/coding_agent_tools/codex_sessions.py +0 -0
- {coding_agent_tools-0.1.0 → coding_agent_tools-0.1.2}/coding_agent_tools/find_session.py +0 -0
- {coding_agent_tools-0.1.0 → coding_agent_tools-0.1.2}/coding_agent_tools/opencode_sessions.py +0 -0
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: coding-agent-tools
|
|
3
|
+
Version: 0.1.2
|
|
4
|
+
Summary: Session search and unified usage analytics for coding agents
|
|
5
|
+
Requires-Python: >=3.11
|
|
6
|
+
Requires-Dist: rich>=13.0.0
|
|
7
|
+
Description-Content-Type: text/markdown
|
|
8
|
+
|
|
9
|
+
# CodingAgentTools
|
|
10
|
+
|
|
11
|
+
`coding-agent-tools` is a practical CLI bundle for local coding-agent workflows.
|
|
12
|
+
|
|
13
|
+
It currently provides:
|
|
14
|
+
|
|
15
|
+
- `find-session`: search and resume sessions across Claude Code, Codex, and OpenCode
|
|
16
|
+
- `agent-usage`: unified usage and estimated USD-equivalent cost across Claude Code, Codex, OpenClaw, OpenCode, and OpenWhispr
|
|
17
|
+
|
|
18
|
+
## Why this repo exists
|
|
19
|
+
|
|
20
|
+
This consolidates earlier standalone tools into one package:
|
|
21
|
+
|
|
22
|
+
- `find-session` (now here)
|
|
23
|
+
- local `allusage` script (now `agent-usage`)
|
|
24
|
+
|
|
25
|
+
The goal is one install, one command surface, one place to improve.
|
|
26
|
+
|
|
27
|
+
## Install
|
|
28
|
+
|
|
29
|
+
From PyPI (recommended):
|
|
30
|
+
|
|
31
|
+
```bash
|
|
32
|
+
uv tool install coding-agent-tools
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
Alternative:
|
|
36
|
+
|
|
37
|
+
```bash
|
|
38
|
+
pipx install coding-agent-tools
|
|
39
|
+
# or
|
|
40
|
+
pip install coding-agent-tools
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
From source:
|
|
44
|
+
|
|
45
|
+
```bash
|
|
46
|
+
uv tool install .
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
## Quickstart
|
|
50
|
+
|
|
51
|
+
```bash
|
|
52
|
+
# Find sessions in current project across all supported agents
|
|
53
|
+
find-session "auth,refactor"
|
|
54
|
+
|
|
55
|
+
# Search all projects
|
|
56
|
+
find-session -g
|
|
57
|
+
|
|
58
|
+
# Usage report (daily default)
|
|
59
|
+
agent-usage
|
|
60
|
+
|
|
61
|
+
# Weekly report with per-model expansion
|
|
62
|
+
agent-usage weekly --breakdown
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
## `find-session`
|
|
66
|
+
|
|
67
|
+
Unified session search with interactive selection, resume, and export/copy actions.
|
|
68
|
+
|
|
69
|
+
```bash
|
|
70
|
+
# Search current project
|
|
71
|
+
find-session "redis,bug"
|
|
72
|
+
|
|
73
|
+
# Search all projects
|
|
74
|
+
find-session -g
|
|
75
|
+
|
|
76
|
+
# Limit to one agent
|
|
77
|
+
find-session "checkpoint" --agents codex
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
### Preview behavior
|
|
81
|
+
|
|
82
|
+
Session previews now include both ends of user intent:
|
|
83
|
+
|
|
84
|
+
- `First: ...`
|
|
85
|
+
- `Last: ...`
|
|
86
|
+
|
|
87
|
+
If only one meaningful user message is found, it displays as `First/Last: ...`.
|
|
88
|
+
|
|
89
|
+
## `agent-usage`
|
|
90
|
+
|
|
91
|
+
Token usage and estimated cost tables by period.
|
|
92
|
+
|
|
93
|
+
```bash
|
|
94
|
+
# Daily usage for all sources
|
|
95
|
+
agent-usage
|
|
96
|
+
|
|
97
|
+
# Weekly with per-model breakdown
|
|
98
|
+
agent-usage weekly --breakdown
|
|
99
|
+
|
|
100
|
+
# Restrict sources
|
|
101
|
+
agent-usage monthly opencode codex
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
### Sources and aliases
|
|
105
|
+
|
|
106
|
+
- `claude` / `cc`
|
|
107
|
+
- `codex` / `cx`
|
|
108
|
+
- `openclaw` / `oc` / `claw`
|
|
109
|
+
- `opencode` / `oe` / `code`
|
|
110
|
+
- `openwhispr` / `ow` / `whispr`
|
|
111
|
+
|
|
112
|
+
### Cost model
|
|
113
|
+
|
|
114
|
+
`agent-usage` estimates costs from token counts using live LiteLLM pricing metadata.
|
|
115
|
+
|
|
116
|
+
- This avoids misleading `$0` totals for subscription-backed traffic (especially OpenCode).
|
|
117
|
+
- If a model is missing in the pricing registry, it falls back to source-observed cost when present.
|
|
118
|
+
|
|
119
|
+
## Data sources
|
|
120
|
+
|
|
121
|
+
- Claude Code: `~/.claude/projects/*/*.jsonl`
|
|
122
|
+
- Codex: `~/.codex/sessions/**/rollout-*.jsonl`
|
|
123
|
+
- OpenCode: `~/.local/share/opencode/opencode.db`
|
|
124
|
+
- OpenClaw: `~/.openclaw/agents/*/sessions/*.jsonl`
|
|
125
|
+
- OpenWhispr: `~/Library/Application Support/open-whispr/transcriptions.db`
|
|
126
|
+
|
|
127
|
+
## Beautiful terminal demos (yes, via subprocess recording)
|
|
128
|
+
|
|
129
|
+
Yes: you can generate polished terminal renders by recording commands as subprocesses.
|
|
130
|
+
|
|
131
|
+
This repo includes ready-to-run VHS tapes in `demo/`:
|
|
132
|
+
|
|
133
|
+
```bash
|
|
134
|
+
# macOS
|
|
135
|
+
brew install vhs
|
|
136
|
+
|
|
137
|
+
# render animated gifs from deterministic command scripts
|
|
138
|
+
./scripts/render-demos.sh
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
How it works:
|
|
142
|
+
|
|
143
|
+
- `vhs` launches a shell subprocess
|
|
144
|
+
- runs scripted commands (sample queries and real command output)
|
|
145
|
+
- renders a styled terminal recording directly to GIF
|
|
146
|
+
|
|
147
|
+
Use these as README assets, release previews, or social clips.
|
|
148
|
+
|
|
149
|
+
### `find-session` demo
|
|
150
|
+
|
|
151
|
+

|
|
152
|
+
|
|
153
|
+
### `agent-usage` demo
|
|
154
|
+
|
|
155
|
+

|
|
156
|
+
|
|
157
|
+
## Development
|
|
158
|
+
|
|
159
|
+
```bash
|
|
160
|
+
python3 -m pip install -e .
|
|
161
|
+
find-session --help
|
|
162
|
+
agent-usage --help
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
## References
|
|
166
|
+
|
|
167
|
+
- `ccusage` (inspiration for usage/cost reporting style): https://github.com/ryoppippi/ccusage
|
|
168
|
+
- `claude-code-tools` (Cloud/Claude Code tools reference and prior consolidation work): https://github.com/charlesnchr/claude-code-tools
|
|
169
|
+
- LiteLLM model pricing registry: https://github.com/BerriAI/litellm/blob/main/model_prices_and_context_window.json
|
|
170
|
+
|
|
171
|
+
## License
|
|
172
|
+
|
|
173
|
+
MIT
|
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
# CodingAgentTools
|
|
2
|
+
|
|
3
|
+
`coding-agent-tools` is a practical CLI bundle for local coding-agent workflows.
|
|
4
|
+
|
|
5
|
+
It currently provides:
|
|
6
|
+
|
|
7
|
+
- `find-session`: search and resume sessions across Claude Code, Codex, and OpenCode
|
|
8
|
+
- `agent-usage`: unified usage and estimated USD-equivalent cost across Claude Code, Codex, OpenClaw, OpenCode, and OpenWhispr
|
|
9
|
+
|
|
10
|
+
## Why this repo exists
|
|
11
|
+
|
|
12
|
+
This consolidates earlier standalone tools into one package:
|
|
13
|
+
|
|
14
|
+
- `find-session` (now here)
|
|
15
|
+
- local `allusage` script (now `agent-usage`)
|
|
16
|
+
|
|
17
|
+
The goal is one install, one command surface, one place to improve.
|
|
18
|
+
|
|
19
|
+
## Install
|
|
20
|
+
|
|
21
|
+
From PyPI (recommended):
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
uv tool install coding-agent-tools
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
Alternative:
|
|
28
|
+
|
|
29
|
+
```bash
|
|
30
|
+
pipx install coding-agent-tools
|
|
31
|
+
# or
|
|
32
|
+
pip install coding-agent-tools
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
From source:
|
|
36
|
+
|
|
37
|
+
```bash
|
|
38
|
+
uv tool install .
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
## Quickstart
|
|
42
|
+
|
|
43
|
+
```bash
|
|
44
|
+
# Find sessions in current project across all supported agents
|
|
45
|
+
find-session "auth,refactor"
|
|
46
|
+
|
|
47
|
+
# Search all projects
|
|
48
|
+
find-session -g
|
|
49
|
+
|
|
50
|
+
# Usage report (daily default)
|
|
51
|
+
agent-usage
|
|
52
|
+
|
|
53
|
+
# Weekly report with per-model expansion
|
|
54
|
+
agent-usage weekly --breakdown
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
## `find-session`
|
|
58
|
+
|
|
59
|
+
Unified session search with interactive selection, resume, and export/copy actions.
|
|
60
|
+
|
|
61
|
+
```bash
|
|
62
|
+
# Search current project
|
|
63
|
+
find-session "redis,bug"
|
|
64
|
+
|
|
65
|
+
# Search all projects
|
|
66
|
+
find-session -g
|
|
67
|
+
|
|
68
|
+
# Limit to one agent
|
|
69
|
+
find-session "checkpoint" --agents codex
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
### Preview behavior
|
|
73
|
+
|
|
74
|
+
Session previews now include both ends of user intent:
|
|
75
|
+
|
|
76
|
+
- `First: ...`
|
|
77
|
+
- `Last: ...`
|
|
78
|
+
|
|
79
|
+
If only one meaningful user message is found, it displays as `First/Last: ...`.
|
|
80
|
+
|
|
81
|
+
## `agent-usage`
|
|
82
|
+
|
|
83
|
+
Token usage and estimated cost tables by period.
|
|
84
|
+
|
|
85
|
+
```bash
|
|
86
|
+
# Daily usage for all sources
|
|
87
|
+
agent-usage
|
|
88
|
+
|
|
89
|
+
# Weekly with per-model breakdown
|
|
90
|
+
agent-usage weekly --breakdown
|
|
91
|
+
|
|
92
|
+
# Restrict sources
|
|
93
|
+
agent-usage monthly opencode codex
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
### Sources and aliases
|
|
97
|
+
|
|
98
|
+
- `claude` / `cc`
|
|
99
|
+
- `codex` / `cx`
|
|
100
|
+
- `openclaw` / `oc` / `claw`
|
|
101
|
+
- `opencode` / `oe` / `code`
|
|
102
|
+
- `openwhispr` / `ow` / `whispr`
|
|
103
|
+
|
|
104
|
+
### Cost model
|
|
105
|
+
|
|
106
|
+
`agent-usage` estimates costs from token counts using live LiteLLM pricing metadata.
|
|
107
|
+
|
|
108
|
+
- This avoids misleading `$0` totals for subscription-backed traffic (especially OpenCode).
|
|
109
|
+
- If a model is missing in the pricing registry, it falls back to source-observed cost when present.
|
|
110
|
+
|
|
111
|
+
## Data sources
|
|
112
|
+
|
|
113
|
+
- Claude Code: `~/.claude/projects/*/*.jsonl`
|
|
114
|
+
- Codex: `~/.codex/sessions/**/rollout-*.jsonl`
|
|
115
|
+
- OpenCode: `~/.local/share/opencode/opencode.db`
|
|
116
|
+
- OpenClaw: `~/.openclaw/agents/*/sessions/*.jsonl`
|
|
117
|
+
- OpenWhispr: `~/Library/Application Support/open-whispr/transcriptions.db`
|
|
118
|
+
|
|
119
|
+
## Beautiful terminal demos (yes, via subprocess recording)
|
|
120
|
+
|
|
121
|
+
Yes: you can generate polished terminal renders by recording commands as subprocesses.
|
|
122
|
+
|
|
123
|
+
This repo includes ready-to-run VHS tapes in `demo/`:
|
|
124
|
+
|
|
125
|
+
```bash
|
|
126
|
+
# macOS
|
|
127
|
+
brew install vhs
|
|
128
|
+
|
|
129
|
+
# render animated gifs from deterministic command scripts
|
|
130
|
+
./scripts/render-demos.sh
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
How it works:
|
|
134
|
+
|
|
135
|
+
- `vhs` launches a shell subprocess
|
|
136
|
+
- runs scripted commands (sample queries and real command output)
|
|
137
|
+
- renders a styled terminal recording directly to GIF
|
|
138
|
+
|
|
139
|
+
Use these as README assets, release previews, or social clips.
|
|
140
|
+
|
|
141
|
+
### `find-session` demo
|
|
142
|
+
|
|
143
|
+

|
|
144
|
+
|
|
145
|
+
### `agent-usage` demo
|
|
146
|
+
|
|
147
|
+

|
|
148
|
+
|
|
149
|
+
## Development
|
|
150
|
+
|
|
151
|
+
```bash
|
|
152
|
+
python3 -m pip install -e .
|
|
153
|
+
find-session --help
|
|
154
|
+
agent-usage --help
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
## References
|
|
158
|
+
|
|
159
|
+
- `ccusage` (inspiration for usage/cost reporting style): https://github.com/ryoppippi/ccusage
|
|
160
|
+
- `claude-code-tools` (Cloud/Claude Code tools reference and prior consolidation work): https://github.com/charlesnchr/claude-code-tools
|
|
161
|
+
- LiteLLM model pricing registry: https://github.com/BerriAI/litellm/blob/main/model_prices_and_context_window.json
|
|
162
|
+
|
|
163
|
+
## License
|
|
164
|
+
|
|
165
|
+
MIT
|
|
@@ -252,15 +252,25 @@ def print_table(
|
|
|
252
252
|
totals: ModelBucket,
|
|
253
253
|
mode: str,
|
|
254
254
|
breakdown: bool,
|
|
255
|
+
col_labels: Optional[dict[str, str]] = None,
|
|
255
256
|
input_header: str = "Input",
|
|
256
257
|
) -> None:
|
|
257
258
|
if not usage_by_period:
|
|
258
259
|
print(f"\n{title}\nNo data found.")
|
|
259
260
|
return
|
|
260
261
|
|
|
261
|
-
|
|
262
|
+
entries = []
|
|
262
263
|
for period in sorted(usage_by_period.keys()):
|
|
264
|
+
parts = period.split("-")
|
|
265
|
+
year = parts[0]
|
|
266
|
+
period_tail = ""
|
|
267
|
+
if mode == "daily":
|
|
268
|
+
period_tail = f"{parts[1]}-{parts[2]}" if len(parts) == 3 else ""
|
|
269
|
+
elif mode in ("monthly", "weekly"):
|
|
270
|
+
period_tail = parts[1] if len(parts) > 1 else ""
|
|
271
|
+
|
|
263
272
|
models = sorted(usage_by_period[period].keys())
|
|
273
|
+
|
|
264
274
|
if not breakdown and len(models) > 1:
|
|
265
275
|
agg = ModelBucket()
|
|
266
276
|
for name in models:
|
|
@@ -271,10 +281,11 @@ def print_table(
|
|
|
271
281
|
agg.cache_write += item.cache_write
|
|
272
282
|
agg.total += item.total
|
|
273
283
|
agg.cost += item.cost
|
|
274
|
-
|
|
284
|
+
entries.append(
|
|
275
285
|
{
|
|
276
|
-
"
|
|
277
|
-
"
|
|
286
|
+
"type": "data",
|
|
287
|
+
"date": year,
|
|
288
|
+
"model": f"- Multiple ({len(models)})",
|
|
278
289
|
"input": fmt_int(agg.input),
|
|
279
290
|
"output": fmt_int(agg.output),
|
|
280
291
|
"cache_w": fmt_int(agg.cache_write),
|
|
@@ -283,6 +294,9 @@ def print_table(
|
|
|
283
294
|
"cost": fmt_cost(agg.cost),
|
|
284
295
|
}
|
|
285
296
|
)
|
|
297
|
+
if period_tail:
|
|
298
|
+
entries.append({"type": "date_cont", "date": period_tail})
|
|
299
|
+
entries.append({"type": "sep"})
|
|
286
300
|
continue
|
|
287
301
|
|
|
288
302
|
if breakdown and len(models) > 1:
|
|
@@ -295,10 +309,11 @@ def print_table(
|
|
|
295
309
|
agg.cache_write += item.cache_write
|
|
296
310
|
agg.total += item.total
|
|
297
311
|
agg.cost += item.cost
|
|
298
|
-
|
|
312
|
+
entries.append(
|
|
299
313
|
{
|
|
300
|
-
"
|
|
301
|
-
"
|
|
314
|
+
"type": "data",
|
|
315
|
+
"date": year,
|
|
316
|
+
"model": "",
|
|
302
317
|
"input": fmt_int(agg.input),
|
|
303
318
|
"output": fmt_int(agg.output),
|
|
304
319
|
"cache_w": fmt_int(agg.cache_write),
|
|
@@ -307,12 +322,17 @@ def print_table(
|
|
|
307
322
|
"cost": fmt_cost(agg.cost),
|
|
308
323
|
}
|
|
309
324
|
)
|
|
310
|
-
|
|
325
|
+
if period_tail:
|
|
326
|
+
entries.append({"type": "date_cont", "date": period_tail})
|
|
327
|
+
entries.append({"type": "sep"})
|
|
328
|
+
for idx, name in enumerate(models):
|
|
311
329
|
item = usage_by_period[period][name]
|
|
312
|
-
|
|
330
|
+
marker = "└─" if idx == len(models) - 1 else "├─"
|
|
331
|
+
entries.append(
|
|
313
332
|
{
|
|
314
|
-
"
|
|
315
|
-
"
|
|
333
|
+
"type": "data",
|
|
334
|
+
"date": f" {marker}",
|
|
335
|
+
"model": model_label(name, item.provider),
|
|
316
336
|
"input": fmt_int(item.input),
|
|
317
337
|
"output": fmt_int(item.output),
|
|
318
338
|
"cache_w": fmt_int(item.cache_write),
|
|
@@ -321,14 +341,16 @@ def print_table(
|
|
|
321
341
|
"cost": fmt_cost(item.cost),
|
|
322
342
|
}
|
|
323
343
|
)
|
|
344
|
+
entries.append({"type": "sep"})
|
|
324
345
|
continue
|
|
325
346
|
|
|
326
347
|
model_name = models[0]
|
|
327
348
|
item = usage_by_period[period][model_name]
|
|
328
|
-
|
|
349
|
+
entries.append(
|
|
329
350
|
{
|
|
330
|
-
"
|
|
331
|
-
"
|
|
351
|
+
"type": "data",
|
|
352
|
+
"date": year,
|
|
353
|
+
"model": f"- {model_label(model_name, item.provider)}",
|
|
332
354
|
"input": fmt_int(item.input),
|
|
333
355
|
"output": fmt_int(item.output),
|
|
334
356
|
"cache_w": fmt_int(item.cache_write),
|
|
@@ -337,78 +359,111 @@ def print_table(
|
|
|
337
359
|
"cost": fmt_cost(item.cost),
|
|
338
360
|
}
|
|
339
361
|
)
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
{
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
period_name = {"daily": "Date", "weekly": "Week", "monthly": "Month"}[mode]
|
|
355
|
-
widths = {
|
|
356
|
-
"period": max(len(period_name), max(len(r["period"]) for r in rows)),
|
|
357
|
-
"model": max(len("Model"), max(len(r["model"]) for r in rows)),
|
|
358
|
-
"input": max(len(input_header), max(len(r["input"]) for r in rows)),
|
|
359
|
-
"output": max(len("Output"), max(len(r["output"]) for r in rows)),
|
|
360
|
-
"cache_w": max(len("CacheW"), max(len(r["cache_w"]) for r in rows)),
|
|
361
|
-
"cache_r": max(len("CacheR"), max(len(r["cache_r"]) for r in rows)),
|
|
362
|
-
"total": max(len("Total"), max(len(r["total"]) for r in rows)),
|
|
363
|
-
"cost": max(len("Cost USD"), max(len(r["cost"]) for r in rows)),
|
|
362
|
+
if period_tail:
|
|
363
|
+
entries.append({"type": "date_cont", "date": period_tail})
|
|
364
|
+
entries.append({"type": "sep"})
|
|
365
|
+
|
|
366
|
+
total_row = {
|
|
367
|
+
"date": "Total",
|
|
368
|
+
"model": "",
|
|
369
|
+
"input": fmt_int(totals.input),
|
|
370
|
+
"output": fmt_int(totals.output),
|
|
371
|
+
"cache_w": fmt_int(totals.cache_write),
|
|
372
|
+
"cache_r": fmt_int(totals.cache_read),
|
|
373
|
+
"total": fmt_int(totals.total),
|
|
374
|
+
"cost": fmt_cost(totals.cost),
|
|
364
375
|
}
|
|
365
376
|
|
|
366
|
-
|
|
377
|
+
all_data = [e for e in entries if e["type"] == "data"] + [total_row]
|
|
378
|
+
all_dates = [e for e in entries if e["type"] in ("data", "date_cont")]
|
|
379
|
+
|
|
380
|
+
dw = max(9, max((len(e["date"]) for e in all_dates), default=9))
|
|
381
|
+
mw = max(20, max((len(e["model"]) for e in all_data), default=20))
|
|
382
|
+
iw = max(len(input_header), max(len(e["input"]) for e in all_data))
|
|
383
|
+
ow = max(len("Output"), max(len(e["output"]) for e in all_data))
|
|
384
|
+
cww = max(len("Create"), max(len(e["cache_w"]) for e in all_data))
|
|
385
|
+
crw = max(len("Read"), max(len(e["cache_r"]) for e in all_data))
|
|
386
|
+
tw = max(len("Tokens"), max(len(e["total"]) for e in all_data))
|
|
387
|
+
cow = max(len("(USD)"), max(len(e["cost"]) for e in all_data))
|
|
388
|
+
|
|
389
|
+
use_color = sys.stdout.isatty() and not os.getenv("NO_COLOR")
|
|
390
|
+
dim = "\033[90m" if use_color else ""
|
|
391
|
+
cyan = "\033[36m" if use_color else ""
|
|
392
|
+
reset = "\033[39m" if use_color else ""
|
|
393
|
+
|
|
394
|
+
def hl(l: str, m: str, r: str) -> str:
|
|
395
|
+
segs = [f"{'─' * (w + 2)}" for w in (dw, mw, iw, ow, cww, crw, tw, cow)]
|
|
396
|
+
return f"{dim}{l}{m.join(segs)}{r}{reset}"
|
|
397
|
+
|
|
398
|
+
def rl(
|
|
399
|
+
d: str,
|
|
400
|
+
m: str,
|
|
401
|
+
i: str,
|
|
402
|
+
o: str,
|
|
403
|
+
cw: str,
|
|
404
|
+
cr: str,
|
|
405
|
+
t: str,
|
|
406
|
+
c: str,
|
|
407
|
+
color: str = "",
|
|
408
|
+
) -> str:
|
|
409
|
+
ec = reset if color else ""
|
|
367
410
|
return (
|
|
368
|
-
f"
|
|
369
|
-
f"
|
|
370
|
-
f"
|
|
371
|
-
f"
|
|
372
|
-
f"
|
|
373
|
-
f"
|
|
374
|
-
f"
|
|
375
|
-
f"
|
|
411
|
+
f"{dim}│{reset}{color} {d.ljust(dw)} {ec}"
|
|
412
|
+
f"{dim}│{reset}{color} {m.ljust(mw)} {ec}"
|
|
413
|
+
f"{dim}│{reset}{color} {i.rjust(iw)} {ec}"
|
|
414
|
+
f"{dim}│{reset}{color} {o.rjust(ow)} {ec}"
|
|
415
|
+
f"{dim}│{reset}{color} {cw.rjust(cww)} {ec}"
|
|
416
|
+
f"{dim}│{reset}{color} {cr.rjust(crw)} {ec}"
|
|
417
|
+
f"{dim}│{reset}{color} {t.rjust(tw)} {ec}"
|
|
418
|
+
f"{dim}│{reset}{color} {c.rjust(cow)} {ec}{dim}│{reset}"
|
|
376
419
|
)
|
|
377
420
|
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
f"| {row['cache_r']:>{widths['cache_r']}} "
|
|
386
|
-
f"| {row['total']:>{widths['total']}} "
|
|
387
|
-
f"| {row['cost']:>{widths['cost']}} |"
|
|
388
|
-
)
|
|
421
|
+
col1 = {"weekly": "Week", "monthly": "Month"}.get(mode, "Date")
|
|
422
|
+
labels = col_labels or {}
|
|
423
|
+
h_input = labels.get("input", input_header)
|
|
424
|
+
h_col5 = labels.get("col5", "Cache")
|
|
425
|
+
h_col5_sub = labels.get("col5_sub", "Create")
|
|
426
|
+
h_col6 = labels.get("col6", "Cache")
|
|
427
|
+
h_col6_sub = labels.get("col6_sub", "Read")
|
|
389
428
|
|
|
390
429
|
print(f"\n{title}")
|
|
391
|
-
print(
|
|
430
|
+
print(f"\n{hl('┌', '┬', '┐')}")
|
|
431
|
+
print(rl(col1, "Models", h_input, "Output", h_col5, h_col6, "Total", "Cost", cyan))
|
|
432
|
+
print(rl("", "", "", "", h_col5_sub, h_col6_sub, "Tokens", "(USD)", cyan))
|
|
433
|
+
print(hl("├", "┼", "┤"))
|
|
434
|
+
|
|
435
|
+
for e in entries:
|
|
436
|
+
if e["type"] == "sep":
|
|
437
|
+
print(hl("├", "┼", "┤"))
|
|
438
|
+
elif e["type"] == "date_cont":
|
|
439
|
+
print(rl(e["date"], "", "", "", "", "", "", ""))
|
|
440
|
+
elif e["type"] == "data":
|
|
441
|
+
print(
|
|
442
|
+
rl(
|
|
443
|
+
e["date"],
|
|
444
|
+
e["model"],
|
|
445
|
+
e["input"],
|
|
446
|
+
e["output"],
|
|
447
|
+
e["cache_w"],
|
|
448
|
+
e["cache_r"],
|
|
449
|
+
e["total"],
|
|
450
|
+
e["cost"],
|
|
451
|
+
)
|
|
452
|
+
)
|
|
453
|
+
|
|
392
454
|
print(
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
"cost": "Cost USD",
|
|
403
|
-
}
|
|
455
|
+
rl(
|
|
456
|
+
total_row["date"],
|
|
457
|
+
total_row["model"],
|
|
458
|
+
total_row["input"],
|
|
459
|
+
total_row["output"],
|
|
460
|
+
total_row["cache_w"],
|
|
461
|
+
total_row["cache_r"],
|
|
462
|
+
total_row["total"],
|
|
463
|
+
total_row["cost"],
|
|
404
464
|
)
|
|
405
465
|
)
|
|
406
|
-
print(
|
|
407
|
-
for row in rows[:-1]:
|
|
408
|
-
print(render(row))
|
|
409
|
-
print(sep())
|
|
410
|
-
print(render(rows[-1]))
|
|
411
|
-
print(sep())
|
|
466
|
+
print(hl("└", "┴", "┘"))
|
|
412
467
|
|
|
413
468
|
|
|
414
469
|
def collect_claude(
|
|
@@ -975,6 +1030,12 @@ def main() -> None:
|
|
|
975
1030
|
totals,
|
|
976
1031
|
mode,
|
|
977
1032
|
breakdown,
|
|
1033
|
+
col_labels={
|
|
1034
|
+
"col5": "",
|
|
1035
|
+
"col5_sub": "",
|
|
1036
|
+
"col6": "",
|
|
1037
|
+
"col6_sub": "",
|
|
1038
|
+
},
|
|
978
1039
|
input_header="Audio",
|
|
979
1040
|
)
|
|
980
1041
|
|
|
@@ -1,107 +0,0 @@
|
|
|
1
|
-
Metadata-Version: 2.4
|
|
2
|
-
Name: coding-agent-tools
|
|
3
|
-
Version: 0.1.0
|
|
4
|
-
Summary: Session search and unified usage analytics for coding agents
|
|
5
|
-
Requires-Python: >=3.11
|
|
6
|
-
Requires-Dist: rich>=13.0.0
|
|
7
|
-
Description-Content-Type: text/markdown
|
|
8
|
-
|
|
9
|
-
# CodingAgentTools
|
|
10
|
-
|
|
11
|
-
`CodingAgentTools` is a focused toolbox for local AI coding workflows.
|
|
12
|
-
|
|
13
|
-
It currently ships two high-leverage commands:
|
|
14
|
-
|
|
15
|
-
- `find-session`: search and resume sessions across Claude Code, Codex, and OpenCode.
|
|
16
|
-
- `agent-usage`: unified usage + estimated cost reporting across Claude Code, Codex, OpenClaw, OpenCode, and OpenWhispr.
|
|
17
|
-
|
|
18
|
-
## Why this repo exists
|
|
19
|
-
|
|
20
|
-
This repository consolidates tools that were previously split across multiple projects/scripts:
|
|
21
|
-
|
|
22
|
-
- `find-session` (now embedded here)
|
|
23
|
-
- local `allusage` script (now `agent-usage`)
|
|
24
|
-
|
|
25
|
-
The goal is one installable package, one docs surface, and one place for improvements.
|
|
26
|
-
|
|
27
|
-
## Install
|
|
28
|
-
|
|
29
|
-
```bash
|
|
30
|
-
uv tool install .
|
|
31
|
-
```
|
|
32
|
-
|
|
33
|
-
or with pip:
|
|
34
|
-
|
|
35
|
-
```bash
|
|
36
|
-
pip install .
|
|
37
|
-
```
|
|
38
|
-
|
|
39
|
-
## Command: find-session
|
|
40
|
-
|
|
41
|
-
Search and resume sessions across agents from one interface.
|
|
42
|
-
|
|
43
|
-
```bash
|
|
44
|
-
# Search current project
|
|
45
|
-
find-session "auth,refactor"
|
|
46
|
-
|
|
47
|
-
# Search across all projects
|
|
48
|
-
find-session -g
|
|
49
|
-
|
|
50
|
-
# Limit to one agent
|
|
51
|
-
find-session "redis" --agents codex
|
|
52
|
-
```
|
|
53
|
-
|
|
54
|
-
Supported agents:
|
|
55
|
-
|
|
56
|
-
- Claude Code (`~/.claude/projects/*.jsonl`)
|
|
57
|
-
- Codex (`~/.codex/sessions/**/rollout-*.jsonl`)
|
|
58
|
-
- OpenCode (`~/.local/share/opencode/opencode.db`)
|
|
59
|
-
|
|
60
|
-
## Command: agent-usage
|
|
61
|
-
|
|
62
|
-
Show token usage and estimated USD-equivalent cost by period.
|
|
63
|
-
|
|
64
|
-
```bash
|
|
65
|
-
# Daily usage for all sources
|
|
66
|
-
agent-usage
|
|
67
|
-
|
|
68
|
-
# Weekly with per-model breakdown
|
|
69
|
-
agent-usage weekly --breakdown
|
|
70
|
-
|
|
71
|
-
# Only OpenCode + Codex
|
|
72
|
-
agent-usage monthly opencode codex
|
|
73
|
-
```
|
|
74
|
-
|
|
75
|
-
### Sources and aliases
|
|
76
|
-
|
|
77
|
-
- `claude` / `cc`
|
|
78
|
-
- `codex` / `cx`
|
|
79
|
-
- `openclaw` / `oc` / `claw`
|
|
80
|
-
- `opencode` / `oe` / `code`
|
|
81
|
-
- `openwhispr` / `ow` / `whispr`
|
|
82
|
-
|
|
83
|
-
### Pricing model
|
|
84
|
-
|
|
85
|
-
`agent-usage` estimates cost from token counts using live LiteLLM pricing metadata.
|
|
86
|
-
|
|
87
|
-
- If a source already reports non-zero cost, estimated pricing is still preferred when model pricing is available.
|
|
88
|
-
- This avoids misleading `0` totals for subscription-backed usage (for example OpenCode sessions routed through subscription plans).
|
|
89
|
-
- For models not present in the pricing registry, the tool falls back to observed/source-reported cost when available.
|
|
90
|
-
|
|
91
|
-
## References
|
|
92
|
-
|
|
93
|
-
- `ccusage` (inspiration for usage/cost reporting style): https://github.com/ryoppippi/ccusage
|
|
94
|
-
- `claude-code-tools` (Cloud/Claude Code tools reference and prior consolidation work): https://github.com/charlesnchr/claude-code-tools
|
|
95
|
-
- LiteLLM model pricing registry: https://github.com/BerriAI/litellm/blob/main/model_prices_and_context_window.json
|
|
96
|
-
|
|
97
|
-
## Development
|
|
98
|
-
|
|
99
|
-
```bash
|
|
100
|
-
python3 -m pip install -e .
|
|
101
|
-
find-session --help
|
|
102
|
-
agent-usage --help
|
|
103
|
-
```
|
|
104
|
-
|
|
105
|
-
## License
|
|
106
|
-
|
|
107
|
-
MIT
|
|
@@ -1,99 +0,0 @@
|
|
|
1
|
-
# CodingAgentTools
|
|
2
|
-
|
|
3
|
-
`CodingAgentTools` is a focused toolbox for local AI coding workflows.
|
|
4
|
-
|
|
5
|
-
It currently ships two high-leverage commands:
|
|
6
|
-
|
|
7
|
-
- `find-session`: search and resume sessions across Claude Code, Codex, and OpenCode.
|
|
8
|
-
- `agent-usage`: unified usage + estimated cost reporting across Claude Code, Codex, OpenClaw, OpenCode, and OpenWhispr.
|
|
9
|
-
|
|
10
|
-
## Why this repo exists
|
|
11
|
-
|
|
12
|
-
This repository consolidates tools that were previously split across multiple projects/scripts:
|
|
13
|
-
|
|
14
|
-
- `find-session` (now embedded here)
|
|
15
|
-
- local `allusage` script (now `agent-usage`)
|
|
16
|
-
|
|
17
|
-
The goal is one installable package, one docs surface, and one place for improvements.
|
|
18
|
-
|
|
19
|
-
## Install
|
|
20
|
-
|
|
21
|
-
```bash
|
|
22
|
-
uv tool install .
|
|
23
|
-
```
|
|
24
|
-
|
|
25
|
-
or with pip:
|
|
26
|
-
|
|
27
|
-
```bash
|
|
28
|
-
pip install .
|
|
29
|
-
```
|
|
30
|
-
|
|
31
|
-
## Command: find-session
|
|
32
|
-
|
|
33
|
-
Search and resume sessions across agents from one interface.
|
|
34
|
-
|
|
35
|
-
```bash
|
|
36
|
-
# Search current project
|
|
37
|
-
find-session "auth,refactor"
|
|
38
|
-
|
|
39
|
-
# Search across all projects
|
|
40
|
-
find-session -g
|
|
41
|
-
|
|
42
|
-
# Limit to one agent
|
|
43
|
-
find-session "redis" --agents codex
|
|
44
|
-
```
|
|
45
|
-
|
|
46
|
-
Supported agents:
|
|
47
|
-
|
|
48
|
-
- Claude Code (`~/.claude/projects/*.jsonl`)
|
|
49
|
-
- Codex (`~/.codex/sessions/**/rollout-*.jsonl`)
|
|
50
|
-
- OpenCode (`~/.local/share/opencode/opencode.db`)
|
|
51
|
-
|
|
52
|
-
## Command: agent-usage
|
|
53
|
-
|
|
54
|
-
Show token usage and estimated USD-equivalent cost by period.
|
|
55
|
-
|
|
56
|
-
```bash
|
|
57
|
-
# Daily usage for all sources
|
|
58
|
-
agent-usage
|
|
59
|
-
|
|
60
|
-
# Weekly with per-model breakdown
|
|
61
|
-
agent-usage weekly --breakdown
|
|
62
|
-
|
|
63
|
-
# Only OpenCode + Codex
|
|
64
|
-
agent-usage monthly opencode codex
|
|
65
|
-
```
|
|
66
|
-
|
|
67
|
-
### Sources and aliases
|
|
68
|
-
|
|
69
|
-
- `claude` / `cc`
|
|
70
|
-
- `codex` / `cx`
|
|
71
|
-
- `openclaw` / `oc` / `claw`
|
|
72
|
-
- `opencode` / `oe` / `code`
|
|
73
|
-
- `openwhispr` / `ow` / `whispr`
|
|
74
|
-
|
|
75
|
-
### Pricing model
|
|
76
|
-
|
|
77
|
-
`agent-usage` estimates cost from token counts using live LiteLLM pricing metadata.
|
|
78
|
-
|
|
79
|
-
- If a source already reports non-zero cost, estimated pricing is still preferred when model pricing is available.
|
|
80
|
-
- This avoids misleading `0` totals for subscription-backed usage (for example OpenCode sessions routed through subscription plans).
|
|
81
|
-
- For models not present in the pricing registry, the tool falls back to observed/source-reported cost when available.
|
|
82
|
-
|
|
83
|
-
## References
|
|
84
|
-
|
|
85
|
-
- `ccusage` (inspiration for usage/cost reporting style): https://github.com/ryoppippi/ccusage
|
|
86
|
-
- `claude-code-tools` (Cloud/Claude Code tools reference and prior consolidation work): https://github.com/charlesnchr/claude-code-tools
|
|
87
|
-
- LiteLLM model pricing registry: https://github.com/BerriAI/litellm/blob/main/model_prices_and_context_window.json
|
|
88
|
-
|
|
89
|
-
## Development
|
|
90
|
-
|
|
91
|
-
```bash
|
|
92
|
-
python3 -m pip install -e .
|
|
93
|
-
find-session --help
|
|
94
|
-
agent-usage --help
|
|
95
|
-
```
|
|
96
|
-
|
|
97
|
-
## License
|
|
98
|
-
|
|
99
|
-
MIT
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{coding_agent_tools-0.1.0 → coding_agent_tools-0.1.2}/coding_agent_tools/opencode_sessions.py
RENAMED
|
File without changes
|