a2zusage 1.0.8 → 1.0.11

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
@@ -28,8 +28,9 @@
28
28
  ├────────────────┼──────────┼───────────────┼─────────────┼─────────────┼───────────────┤
29
29
  │ Claude Code │ ✓ Active │ 321K tokens │ 1.4M tokens │ 6.1M tokens │ 24.2M tokens │
30
30
  │ Cursor │ ✓ Active │ - │ - │ - │ 32.5K tokens │
31
- │ Windsurf │ ✓ Active │ - - - 7.1M tokens
31
+ │ Windsurf │ ✓ Active │ 1 req 1 req 1 req 21 reqs
32
32
  │ Warp AI │ ✓ Active │ - │ - │ 8.2M tokens │ 167.1M tokens │
33
+ │ Gemini CLI │ ✓ Active │ - │ 72K tokens │ 101K tokens │ 48.1M tokens │
33
34
  │ GitHub Copilot │ ○ N/A │ - │ - │ - │ - │
34
35
  │ ... │ ... │ ... │ ... │ ... │ ... │
35
36
  ╰────────────────┴──────────┴───────────────┴─────────────┴─────────────┴───────────────╯
@@ -73,12 +74,12 @@ a2zusage supports **14+ AI coding tools** out of the box:
73
74
  | **Claude Code** | Local JSONL (`~/.claude/projects/`) | ✅ Exact token counts (input/output + cache tokens when present) |
74
75
  | **Cursor** | SQLite database | ✅ Exact token counts (when present in DB) |
75
76
  | **GitHub Copilot** | GitHub API + Local logs | ⚠️ Usage count / requests only (GitHub does not expose reliable token totals here) |
76
- | **Windsurf** | Cascade logs (`~/.codeium/`) | ⚠️ Partial: JSON/JSONL token fields supported; protobuf `.pb` logs are detected but not yet parsed |
77
+ || **Windsurf** | Cascade sessions (`~/.codeium/`) | ℹ️ Session count only (token data encrypted). Visit windsurf.ai for detailed usage. |
77
78
  | **Warp AI** | SQLite database | ✅ Total tokens (Warp does not expose a reliable input/output split) |
78
79
  | **Cline / Roo Code** | VS Code extension storage | ✅ Exact token counts (when stored by the extension) |
79
80
  | **OpenCode** | Local JSON files | ✅ Exact token counts (when present in session/message usage fields) |
80
81
  | **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 |
82
+ || **Gemini CLI** | Native sessions (`~/.gemini/tmp/`) | Exact token counts from native session files (no setup required) |
82
83
  | **Amazon Q Developer** | Local logs | ⚠️ Best-effort: logs may not contain token totals |
83
84
  | **Tabnine** | Local logs | ⚠️ Partial: uses explicit token fields when present; no invented prompt/context tokens |
84
85
  | **Gemini Code Assist** | Google Cloud | ⚠️ Not implemented in this repo yet |
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "a2zusage",
3
- "version": "1.0.8",
3
+ "version": "1.0.11",
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