a2zusage 1.0.7 → 1.0.9

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.
package/README.md CHANGED
@@ -78,7 +78,7 @@ a2zusage supports **14+ AI coding tools** out of the box:
78
78
  | **Cline / Roo Code** | VS Code extension storage | ✅ Exact token counts (when stored by the extension) |
79
79
  | **OpenCode** | Local JSON files | ✅ Exact token counts (when present in session/message usage fields) |
80
80
  | **OpenAI Codex** | OpenAI Usage API | ✅ Exact token counts (requires API key + org access) |
81
- | **Gemini CLI** | Local telemetry (`~/.gemini/`) | ⚠️ Partial: JSON/JSONL telemetry supported when present; protobuf `.pb` logs are detected but not yet parsed |
81
+ || **Gemini CLI** | Local telemetry (`~/.gemini/`) | Exact token counts with wrapper (see [Gemini CLI Setup](#gemini-cli-setup)) |
82
82
  | **Amazon Q Developer** | Local logs | ⚠️ Best-effort: logs may not contain token totals |
83
83
  | **Tabnine** | Local logs | ⚠️ Partial: uses explicit token fields when present; no invented prompt/context tokens |
84
84
  | **Gemini Code Assist** | Google Cloud | ⚠️ Not implemented in this repo yet |
@@ -141,6 +141,26 @@ a2zusage -v # Verbose mode with data sources
141
141
  ]
142
142
  ```
143
143
 
144
+ ## Tool-Specific Setup
145
+
146
+ ### Gemini CLI Setup
147
+
148
+ Gemini CLI stores conversation data in encrypted protobuf files. To get accurate token tracking, use our wrapper script that captures the `usageMetadata` from the `--output-format stream-json` output:
149
+
150
+ ```bash
151
+ # 1. Copy the wrapper script
152
+ curl -o ~/.local/bin/gemini-wrapper https://raw.githubusercontent.com/aezizhu/a2zaiusage/main/scripts/gemini-wrapper.sh
153
+ chmod +x ~/.local/bin/gemini-wrapper
154
+
155
+ # 2. Create an alias (add to your .bashrc or .zshrc)
156
+ alias gemini="~/.local/bin/gemini-wrapper"
157
+
158
+ # 3. Use gemini as normal - token data is now tracked!
159
+ gemini "Your prompt here"
160
+ ```
161
+
162
+ The wrapper creates `~/.gemini/a2zusage-telemetry.jsonl` with exact token counts for each request.
163
+
144
164
  ## Why This Tool?
145
165
 
146
166
  ### 🎯 Built for Hiring AI-Native Developers
package/bin/a2zusage CHANGED
Binary file
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "a2zusage",
3
- "version": "1.0.7",
3
+ "version": "1.0.9",
4
4
  "description": "Query usage statistics from all your AI coding tools in one command - Claude Code, Cursor, GitHub Copilot, Windsurf, Warp AI, and 14+ tools",
5
5
  "keywords": [
6
6
  "ai-usage",
@@ -0,0 +1,87 @@
1
+ #!/bin/bash
2
+ # Gemini CLI Wrapper for a2zusage
3
+ # This script wraps the Gemini CLI to capture usage statistics
4
+ #
5
+ # Installation:
6
+ # 1. Make this script executable: chmod +x gemini-wrapper.sh
7
+ # 2. Add alias to your shell: alias gemini='/path/to/gemini-wrapper.sh'
8
+ # Or symlink: ln -s /path/to/gemini-wrapper.sh /usr/local/bin/gemini-tracked
9
+
10
+ USAGE_FILE="${HOME}/.gemini/a2zusage-telemetry.jsonl"
11
+ REAL_GEMINI=$(which -a gemini | grep -v "gemini-wrapper" | head -1)
12
+
13
+ # If no real gemini found, try common paths
14
+ if [ -z "$REAL_GEMINI" ]; then
15
+ for path in /opt/homebrew/bin/gemini /usr/local/bin/gemini ~/.local/bin/gemini; do
16
+ if [ -x "$path" ]; then
17
+ REAL_GEMINI="$path"
18
+ break
19
+ fi
20
+ done
21
+ fi
22
+
23
+ if [ -z "$REAL_GEMINI" ]; then
24
+ echo "Error: Could not find gemini CLI" >&2
25
+ exit 1
26
+ fi
27
+
28
+ # Create usage file directory if needed
29
+ mkdir -p "$(dirname "$USAGE_FILE")"
30
+
31
+ # Check if user wants raw output (non-interactive mode)
32
+ if [[ "$*" == *"--output-format"* ]]; then
33
+ # User specified format, run as-is
34
+ exec "$REAL_GEMINI" "$@"
35
+ fi
36
+
37
+ # Run gemini with stream-json and process output
38
+ "$REAL_GEMINI" --output-format stream-json "$@" 2>&1 | while IFS= read -r line; do
39
+ # Check if line is JSON
40
+ if echo "$line" | grep -q '^{'; then
41
+ # Parse the JSON event type
42
+ event_type=$(echo "$line" | python3 -c "import sys,json; d=json.loads(sys.stdin.read()); print(d.get('type',''))" 2>/dev/null)
43
+
44
+ case "$event_type" in
45
+ "init")
46
+ # Extract model info
47
+ model=$(echo "$line" | python3 -c "import sys,json; d=json.loads(sys.stdin.read()); print(d.get('model','unknown'))" 2>/dev/null)
48
+ session_id=$(echo "$line" | python3 -c "import sys,json; d=json.loads(sys.stdin.read()); print(d.get('session_id',''))" 2>/dev/null)
49
+ ;;
50
+ "message")
51
+ # Display user/assistant messages
52
+ role=$(echo "$line" | python3 -c "import sys,json; d=json.loads(sys.stdin.read()); print(d.get('role',''))" 2>/dev/null)
53
+ content=$(echo "$line" | python3 -c "import sys,json; d=json.loads(sys.stdin.read()); print(d.get('content',''))" 2>/dev/null)
54
+ if [ "$role" = "assistant" ]; then
55
+ echo -n "$content"
56
+ fi
57
+ ;;
58
+ "result")
59
+ # This is the usage data - log it!
60
+ timestamp=$(date -u +"%Y-%m-%dT%H:%M:%SZ")
61
+ stats=$(echo "$line" | python3 -c "
62
+ import sys, json
63
+ d = json.loads(sys.stdin.read())
64
+ stats = d.get('stats', {})
65
+ print(json.dumps({
66
+ 'timestamp': '$timestamp',
67
+ 'model': '${model:-unknown}',
68
+ 'input_tokens': stats.get('input_tokens', stats.get('input', 0)),
69
+ 'output_tokens': stats.get('output_tokens', stats.get('output', 0)),
70
+ 'total_tokens': stats.get('total_tokens', 0),
71
+ 'cached_tokens': stats.get('cached', 0),
72
+ 'duration_ms': stats.get('duration_ms', 0),
73
+ 'tool_calls': stats.get('tool_calls', 0)
74
+ }))
75
+ " 2>/dev/null)
76
+
77
+ if [ -n "$stats" ]; then
78
+ echo "$stats" >> "$USAGE_FILE"
79
+ fi
80
+ echo "" # Final newline after response
81
+ ;;
82
+ esac
83
+ else
84
+ # Non-JSON output (errors, loading messages, etc.)
85
+ echo "$line" >&2
86
+ fi
87
+ done