cc-context-stats 1.3.0

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.
Files changed (72) hide show
  1. package/.claude/commands/context-stats.md +17 -0
  2. package/.claude/settings.local.json +85 -0
  3. package/.editorconfig +60 -0
  4. package/.eslintrc.json +35 -0
  5. package/.github/dependabot.yml +44 -0
  6. package/.github/workflows/ci.yml +255 -0
  7. package/.github/workflows/release.yml +149 -0
  8. package/.pre-commit-config.yaml +74 -0
  9. package/.prettierrc +33 -0
  10. package/.shellcheckrc +10 -0
  11. package/CHANGELOG.md +100 -0
  12. package/CONTRIBUTING.md +240 -0
  13. package/PUBLISHING_GUIDE.md +69 -0
  14. package/README.md +179 -0
  15. package/config/settings-example.json +7 -0
  16. package/config/settings-node.json +7 -0
  17. package/config/settings-python.json +7 -0
  18. package/docs/configuration.md +83 -0
  19. package/docs/context-stats.md +132 -0
  20. package/docs/installation.md +195 -0
  21. package/docs/scripts.md +116 -0
  22. package/docs/troubleshooting.md +189 -0
  23. package/images/claude-statusline-token-graph.gif +0 -0
  24. package/images/claude-statusline.png +0 -0
  25. package/images/context-status-dumbzone.png +0 -0
  26. package/images/context-status.png +0 -0
  27. package/images/statusline-detail.png +0 -0
  28. package/images/token-graph.jpeg +0 -0
  29. package/images/token-graph.png +0 -0
  30. package/install +344 -0
  31. package/install.sh +272 -0
  32. package/jest.config.js +11 -0
  33. package/npm-publish.sh +33 -0
  34. package/package.json +36 -0
  35. package/publish.sh +24 -0
  36. package/pyproject.toml +113 -0
  37. package/requirements-dev.txt +12 -0
  38. package/scripts/context-stats.sh +970 -0
  39. package/scripts/statusline-full.sh +241 -0
  40. package/scripts/statusline-git.sh +32 -0
  41. package/scripts/statusline-minimal.sh +11 -0
  42. package/scripts/statusline.js +350 -0
  43. package/scripts/statusline.py +312 -0
  44. package/show_raw_claude_code_api.js +11 -0
  45. package/src/claude_statusline/__init__.py +11 -0
  46. package/src/claude_statusline/__main__.py +6 -0
  47. package/src/claude_statusline/cli/__init__.py +1 -0
  48. package/src/claude_statusline/cli/context_stats.py +379 -0
  49. package/src/claude_statusline/cli/statusline.py +172 -0
  50. package/src/claude_statusline/core/__init__.py +1 -0
  51. package/src/claude_statusline/core/colors.py +55 -0
  52. package/src/claude_statusline/core/config.py +98 -0
  53. package/src/claude_statusline/core/git.py +67 -0
  54. package/src/claude_statusline/core/state.py +266 -0
  55. package/src/claude_statusline/formatters/__init__.py +1 -0
  56. package/src/claude_statusline/formatters/time.py +50 -0
  57. package/src/claude_statusline/formatters/tokens.py +70 -0
  58. package/src/claude_statusline/graphs/__init__.py +1 -0
  59. package/src/claude_statusline/graphs/renderer.py +346 -0
  60. package/src/claude_statusline/graphs/statistics.py +58 -0
  61. package/tests/bash/test_install.bats +29 -0
  62. package/tests/bash/test_statusline_full.bats +109 -0
  63. package/tests/bash/test_statusline_git.bats +42 -0
  64. package/tests/bash/test_statusline_minimal.bats +37 -0
  65. package/tests/fixtures/json/high_usage.json +17 -0
  66. package/tests/fixtures/json/low_usage.json +17 -0
  67. package/tests/fixtures/json/medium_usage.json +17 -0
  68. package/tests/fixtures/json/valid_full.json +30 -0
  69. package/tests/fixtures/json/valid_minimal.json +9 -0
  70. package/tests/node/statusline.test.js +199 -0
  71. package/tests/python/conftest.py +84 -0
  72. package/tests/python/test_statusline.py +154 -0
package/install.sh ADDED
@@ -0,0 +1,272 @@
1
+ #!/bin/bash
2
+ #
3
+ # Claude Code Status Line Installer
4
+ # Installs and configures a status line for Claude Code
5
+ #
6
+ # Usage:
7
+ # Local: ./install.sh
8
+ # Remote: curl -fsSL https://raw.githubusercontent.com/luongnv89/cc-context-stats/main/install.sh | bash
9
+ #
10
+
11
+ set -e
12
+
13
+ # Colors for output
14
+ RED='\033[0;31m'
15
+ GREEN='\033[0;32m'
16
+ YELLOW='\033[0;33m'
17
+ BLUE='\033[0;34m'
18
+ RESET='\033[0m'
19
+
20
+ CLAUDE_DIR="$HOME/.claude"
21
+ SETTINGS_FILE="$CLAUDE_DIR/settings.json"
22
+ LOCAL_BIN="$HOME/.local/bin"
23
+
24
+ # GitHub repository info for remote installation
25
+ GITHUB_RAW_URL="https://raw.githubusercontent.com/luongnv89/cc-context-stats/main"
26
+ GITHUB_API_URL="https://api.github.com/repos/luongnv89/cc-context-stats"
27
+
28
+ # Detect if running from pipe (curl) or locally
29
+ detect_install_mode() {
30
+ # Check if we have a valid script file with scripts directory
31
+ if [ -n "${BASH_SOURCE[0]}" ] && [ -f "${BASH_SOURCE[0]}" ]; then
32
+ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
33
+ if [ -d "$SCRIPT_DIR/scripts" ]; then
34
+ INSTALL_MODE="local"
35
+ INTERACTIVE=true
36
+ [ -t 0 ] || INTERACTIVE=false
37
+ return
38
+ fi
39
+ fi
40
+ # Running from curl/pipe or script directory not found
41
+ INSTALL_MODE="remote"
42
+ INTERACTIVE=false
43
+ }
44
+
45
+ echo -e "${BLUE}Claude Code Status Line Installer${RESET}"
46
+ echo "=================================="
47
+ echo
48
+
49
+ detect_install_mode
50
+
51
+ if [ "$INSTALL_MODE" = "remote" ]; then
52
+ echo -e "${YELLOW}Remote installation mode${RESET}"
53
+ echo "Downloading from GitHub..."
54
+ echo
55
+ else
56
+ echo -e "${GREEN}Local installation mode${RESET}"
57
+ echo
58
+ fi
59
+
60
+ # Check for curl (required for remote installation)
61
+ check_curl() {
62
+ if [ "$INSTALL_MODE" = "remote" ]; then
63
+ if ! command -v curl &>/dev/null; then
64
+ echo -e "${RED}Error: 'curl' is required for remote installation${RESET}"
65
+ exit 1
66
+ fi
67
+ fi
68
+ }
69
+
70
+ # Check for jq (required for bash scripts)
71
+ check_jq() {
72
+ if ! command -v jq &>/dev/null; then
73
+ echo -e "${YELLOW}Warning: 'jq' is not installed.${RESET}"
74
+ echo "jq is required for bash status line scripts."
75
+ echo
76
+ if [[ "$OSTYPE" == "darwin"* ]]; then
77
+ echo "Install with: brew install jq"
78
+ else
79
+ echo "Install with: sudo apt install jq (Debian/Ubuntu)"
80
+ echo " or: sudo yum install jq (RHEL/CentOS)"
81
+ fi
82
+ echo
83
+ if [ "$INTERACTIVE" = true ]; then
84
+ read -p "Continue anyway? (y/n) " -n 1 -r
85
+ echo
86
+ if [[ ! $REPLY =~ ^[Yy]$ ]]; then
87
+ exit 1
88
+ fi
89
+ fi
90
+ else
91
+ echo -e "${GREEN}✓${RESET} jq is installed"
92
+ fi
93
+ }
94
+
95
+ # Download a file from GitHub
96
+ download_file() {
97
+ local remote_path="$1"
98
+ local dest_path="$2"
99
+ local url="$GITHUB_RAW_URL/$remote_path"
100
+
101
+ if curl -fsSL "$url" -o "$dest_path"; then
102
+ chmod +x "$dest_path"
103
+ return 0
104
+ else
105
+ echo -e "${RED}Error: Failed to download $remote_path${RESET}"
106
+ return 1
107
+ fi
108
+ }
109
+
110
+ # Get latest commit hash from GitHub
111
+ get_remote_commit_hash() {
112
+ local hash
113
+ hash=$(curl -fsSL "$GITHUB_API_URL/commits/main" 2>/dev/null | grep -m1 '"sha"' | cut -d'"' -f4 | head -c7)
114
+ echo "${hash:-unknown}"
115
+ }
116
+
117
+ # Set script to install (full featured bash script)
118
+ select_script() {
119
+ SCRIPT_REMOTE="scripts/statusline-full.sh"
120
+ SCRIPT_NAME="statusline.sh"
121
+
122
+ if [ "$INSTALL_MODE" = "local" ]; then
123
+ SCRIPT_SRC="$SCRIPT_DIR/$SCRIPT_REMOTE"
124
+ fi
125
+ }
126
+
127
+ # Create .claude directory if needed
128
+ ensure_claude_dir() {
129
+ if [ ! -d "$CLAUDE_DIR" ]; then
130
+ echo -e "${YELLOW}Creating $CLAUDE_DIR directory...${RESET}"
131
+ mkdir -p "$CLAUDE_DIR"
132
+ fi
133
+ echo -e "${GREEN}✓${RESET} Claude directory exists: $CLAUDE_DIR"
134
+ }
135
+
136
+ # Install/copy script
137
+ install_script() {
138
+ DEST="$CLAUDE_DIR/$SCRIPT_NAME"
139
+
140
+ if [ "$INSTALL_MODE" = "local" ]; then
141
+ cp "$SCRIPT_SRC" "$DEST"
142
+ chmod +x "$DEST"
143
+ else
144
+ download_file "$SCRIPT_REMOTE" "$DEST"
145
+ fi
146
+ echo -e "${GREEN}✓${RESET} Installed: $DEST"
147
+ }
148
+
149
+ # Install context-stats CLI tool
150
+ install_context_stats() {
151
+ # Create ~/.local/bin if it doesn't exist
152
+ if [ ! -d "$LOCAL_BIN" ]; then
153
+ mkdir -p "$LOCAL_BIN"
154
+ fi
155
+
156
+ DEST="$LOCAL_BIN/context-stats"
157
+
158
+ # Get commit hash for version embedding
159
+ local commit_hash
160
+ if [ "$INSTALL_MODE" = "local" ]; then
161
+ commit_hash=$(git -C "$SCRIPT_DIR" rev-parse --short HEAD 2>/dev/null || echo "unknown")
162
+ cp "$SCRIPT_DIR/scripts/context-stats.sh" "$DEST"
163
+ else
164
+ commit_hash=$(get_remote_commit_hash)
165
+ download_file "scripts/context-stats.sh" "$DEST"
166
+ fi
167
+
168
+ # Embed commit hash
169
+ sed -i.bak "s/COMMIT_HASH=\"dev\"/COMMIT_HASH=\"$commit_hash\"/" "$DEST" && rm -f "$DEST.bak"
170
+ chmod +x "$DEST"
171
+ echo -e "${GREEN}✓${RESET} Installed: $DEST"
172
+
173
+ # Check if ~/.local/bin is in PATH
174
+ if [[ ":$PATH:" != *":$LOCAL_BIN:"* ]]; then
175
+ echo
176
+ echo -e "${YELLOW}Note: $LOCAL_BIN is not in your PATH${RESET}"
177
+ echo "Add it to your shell configuration:"
178
+ echo
179
+ if [[ "$SHELL" == *"zsh"* ]]; then
180
+ echo " echo 'export PATH=\"\$HOME/.local/bin:\$PATH\"' >> ~/.zshrc"
181
+ echo " source ~/.zshrc"
182
+ else
183
+ echo " echo 'export PATH=\"\$HOME/.local/bin:\$PATH\"' >> ~/.bashrc"
184
+ echo " source ~/.bashrc"
185
+ fi
186
+ fi
187
+ }
188
+
189
+ # Create config file with defaults if it doesn't exist
190
+ create_config() {
191
+ CONFIG_FILE="$CLAUDE_DIR/statusline.conf"
192
+
193
+ if [ -f "$CONFIG_FILE" ]; then
194
+ echo -e "${GREEN}✓${RESET} Config file exists: $CONFIG_FILE"
195
+ return
196
+ fi
197
+
198
+ cat >"$CONFIG_FILE" <<'EOF'
199
+ # Autocompact setting - sync with Claude Code's /config
200
+ autocompact=true
201
+
202
+ # Token display format
203
+ token_detail=true
204
+
205
+ # Show token delta since last refresh (adds file I/O on every refresh)
206
+ # Disable if you don't need it to reduce overhead
207
+ show_delta=true
208
+
209
+ # Show session_id in status line
210
+ show_session=true
211
+ EOF
212
+ echo -e "${GREEN}✓${RESET} Created config file: $CONFIG_FILE"
213
+ }
214
+
215
+ # Update settings.json
216
+ update_settings() {
217
+ echo
218
+
219
+ # Create settings file if it doesn't exist
220
+ if [ ! -f "$SETTINGS_FILE" ]; then
221
+ echo '{}' >"$SETTINGS_FILE"
222
+ echo -e "${GREEN}✓${RESET} Created $SETTINGS_FILE"
223
+ fi
224
+
225
+ # Check if jq is available for JSON manipulation
226
+ if command -v jq &>/dev/null; then
227
+ # Backup existing settings
228
+ cp "$SETTINGS_FILE" "$SETTINGS_FILE.backup"
229
+
230
+ # Add/update statusLine configuration
231
+ SCRIPT_PATH="$HOME/.claude/$SCRIPT_NAME"
232
+ jq --arg cmd "$SCRIPT_PATH" '.statusLine = {"type": "command", "command": $cmd}' \
233
+ "$SETTINGS_FILE.backup" >"$SETTINGS_FILE"
234
+
235
+ rm "$SETTINGS_FILE.backup"
236
+ echo -e "${GREEN}✓${RESET} Updated settings.json with statusLine configuration"
237
+ else
238
+ echo -e "${YELLOW}Note: Could not update settings.json (jq not installed)${RESET}"
239
+ echo
240
+ echo "Please add this to $SETTINGS_FILE manually:"
241
+ echo
242
+ echo ' "statusLine": {'
243
+ echo ' "type": "command",'
244
+ echo " \"command\": \"~/.claude/$SCRIPT_NAME\""
245
+ echo ' }'
246
+ fi
247
+ }
248
+
249
+ # Main installation
250
+ main() {
251
+ check_curl
252
+ check_jq
253
+ ensure_claude_dir
254
+ select_script
255
+ install_script
256
+ install_context_stats
257
+ create_config
258
+ update_settings
259
+
260
+ echo
261
+ echo -e "${GREEN}Installation complete!${RESET}"
262
+ echo
263
+ echo "Your status line is now configured."
264
+ echo "Restart Claude Code to see the changes."
265
+ echo
266
+ echo "To customize, edit: $CLAUDE_DIR/$SCRIPT_NAME"
267
+ echo "To change settings, edit: $CLAUDE_DIR/statusline.conf"
268
+ echo
269
+ echo "Run 'context-stats' to visualize token usage for any session."
270
+ }
271
+
272
+ main
package/jest.config.js ADDED
@@ -0,0 +1,11 @@
1
+ /** @type {import('jest').Config} */
2
+ module.exports = {
3
+ testEnvironment: 'node',
4
+ testMatch: ['**/tests/node/**/*.test.js'],
5
+ collectCoverageFrom: ['scripts/statusline.js'],
6
+ coverageDirectory: 'coverage/node',
7
+ coverageReporters: ['text', 'lcov', 'html'],
8
+ modulePathIgnorePatterns: ['<rootDir>/tests/fixtures/'],
9
+ verbose: true,
10
+ testTimeout: 10000,
11
+ };
package/npm-publish.sh ADDED
@@ -0,0 +1,33 @@
1
+ #!/bin/bash
2
+
3
+ if [ $# -eq 0 ]; then
4
+ echo "❌ Error: Please provide your 6-digit OTP code"
5
+ echo ""
6
+ echo "Usage: ./npm-publish.sh 123456"
7
+ echo ""
8
+ echo "Get your code from Microsoft Authenticator app"
9
+ exit 1
10
+ fi
11
+
12
+ echo "🚀 Publishing cc-context-stats to npm..."
13
+ echo "📦 Package: cc-context-stats@1.3.0"
14
+ echo "🔐 Using OTP: $1"
15
+ echo ""
16
+
17
+ npm publish --otp=$1
18
+
19
+ if [ $? -eq 0 ]; then
20
+ echo ""
21
+ echo "✅ SUCCESS! Package published to npm!"
22
+ echo "📦 Package name: cc-context-stats"
23
+ echo "📦 Version: 1.3.0"
24
+ echo "📦 Install with: npm install cc-context-stats"
25
+ echo "🌐 View at: https://www.npmjs.com/package/cc-context-stats"
26
+ else
27
+ echo ""
28
+ echo "❌ FAILED! Publishing failed."
29
+ echo "💡 Tips:"
30
+ echo " - Make sure your OTP code is current (changes every 30 seconds)"
31
+ echo " - Double-check the 6-digit code"
32
+ echo " - If you lost access, use a recovery code on npm website"
33
+ fi
package/package.json ADDED
@@ -0,0 +1,36 @@
1
+ {
2
+ "name": "cc-context-stats",
3
+ "version": "1.3.0",
4
+ "description": "Custom status line scripts for Claude Code",
5
+ "main": "scripts/statusline.js",
6
+ "scripts": {
7
+ "test": "jest",
8
+ "test:watch": "jest --watch",
9
+ "test:coverage": "jest --coverage",
10
+ "lint": "eslint scripts/statusline.js",
11
+ "lint:fix": "eslint scripts/statusline.js --fix",
12
+ "format": "prettier --write 'scripts/*.js' '*.json' '*.md'",
13
+ "format:check": "prettier --check 'scripts/*.js' '*.json' '*.md'"
14
+ },
15
+ "keywords": [
16
+ "claude",
17
+ "claude-code",
18
+ "statusline",
19
+ "terminal",
20
+ "cli"
21
+ ],
22
+ "author": "luongnv89",
23
+ "license": "MIT",
24
+ "repository": {
25
+ "type": "git",
26
+ "url": "https://github.com/luongnv89/cc-context-stats.git"
27
+ },
28
+ "devDependencies": {
29
+ "eslint": "^8.56.0",
30
+ "jest": "^29.7.0",
31
+ "prettier": "^3.2.0"
32
+ },
33
+ "engines": {
34
+ "node": ">=18"
35
+ }
36
+ }
package/publish.sh ADDED
@@ -0,0 +1,24 @@
1
+ #!/bin/bash
2
+
3
+ echo "npm publish with OTP"
4
+ echo "Usage: ./publish.sh <6-digit-otp-code>"
5
+ echo ""
6
+
7
+ if [ $# -eq 0 ]; then
8
+ echo "Please provide your 6-digit OTP code:"
9
+ echo " ./publish.sh 123456"
10
+ exit 1
11
+ fi
12
+
13
+ echo "Publishing cc-context-stats to npm..."
14
+ npm publish --otp=$1
15
+
16
+ if [ $? -eq 0 ]; then
17
+ echo ""
18
+ echo "✅ Successfully published to npm!"
19
+ echo "Package: cc-context-stats@1.3.0"
20
+ echo "Install with: npm install cc-context-stats"
21
+ else
22
+ echo ""
23
+ echo "❌ Publishing failed. Please check your OTP code."
24
+ fi
package/pyproject.toml ADDED
@@ -0,0 +1,113 @@
1
+ [build-system]
2
+ requires = ["hatchling"]
3
+ build-backend = "hatchling.build"
4
+
5
+ [project]
6
+ name = "cc-context-stats"
7
+ version = "1.3.0"
8
+ description = "Never run out of context unexpectedly - monitor your session context in real-time"
9
+ readme = "README.md"
10
+ license = { text = "MIT" }
11
+ requires-python = ">=3.9"
12
+ authors = [
13
+ { name = "Nguyen Luong", email = "luongnv89@gmail.com" }
14
+ ]
15
+ keywords = [
16
+ "claude",
17
+ "claude-code",
18
+ "tokens",
19
+ "context-window",
20
+ "monitoring",
21
+ "visualization",
22
+ "cli",
23
+ ]
24
+ classifiers = [
25
+ "Development Status :: 4 - Beta",
26
+ "Environment :: Console",
27
+ "Intended Audience :: Developers",
28
+ "License :: OSI Approved :: MIT License",
29
+ "Operating System :: OS Independent",
30
+ "Programming Language :: Python :: 3",
31
+ "Programming Language :: Python :: 3.9",
32
+ "Programming Language :: Python :: 3.10",
33
+ "Programming Language :: Python :: 3.11",
34
+ "Programming Language :: Python :: 3.12",
35
+ "Programming Language :: Python :: 3.13",
36
+ "Topic :: Software Development :: Libraries :: Python Modules",
37
+ "Topic :: Utilities",
38
+ ]
39
+ dependencies = []
40
+
41
+ [project.scripts]
42
+ claude-statusline = "claude_statusline.cli.statusline:main"
43
+ context-stats = "claude_statusline.cli.context_stats:main"
44
+
45
+ [project.urls]
46
+ Homepage = "https://github.com/luongnv89/cc-context-stats"
47
+ Documentation = "https://github.com/luongnv89/cc-context-stats#readme"
48
+ Repository = "https://github.com/luongnv89/cc-context-stats"
49
+ Issues = "https://github.com/luongnv89/cc-context-stats/issues"
50
+
51
+ [project.optional-dependencies]
52
+ dev = [
53
+ "pytest>=7.4.0",
54
+ "pytest-cov>=4.1.0",
55
+ "ruff>=0.1.0",
56
+ "mypy>=1.7.0",
57
+ "build>=1.0.0",
58
+ "twine>=4.0.0",
59
+ ]
60
+
61
+ [tool.hatch.build.targets.wheel]
62
+ packages = ["src/claude_statusline"]
63
+
64
+ [tool.hatch.build.targets.sdist]
65
+ include = [
66
+ "/src",
67
+ "/README.md",
68
+ "/LICENSE",
69
+ ]
70
+
71
+ [tool.ruff]
72
+ target-version = "py39"
73
+ line-length = 100
74
+ src = ["src"]
75
+
76
+ [tool.ruff.lint]
77
+ select = [
78
+ "E", # pycodestyle errors
79
+ "W", # pycodestyle warnings
80
+ "F", # Pyflakes
81
+ "I", # isort
82
+ "B", # flake8-bugbear
83
+ "C4", # flake8-comprehensions
84
+ "UP", # pyupgrade
85
+ ]
86
+ ignore = ["E501"] # line too long (handled by formatter)
87
+
88
+ [tool.ruff.format]
89
+ quote-style = "double"
90
+ indent-style = "space"
91
+
92
+ [tool.mypy]
93
+ python_version = "3.9"
94
+ warn_return_any = true
95
+ warn_unused_ignores = true
96
+ strict_optional = true
97
+ ignore_missing_imports = true
98
+
99
+ [tool.pytest.ini_options]
100
+ testpaths = ["tests/python"]
101
+ addopts = "-v --tb=short"
102
+ python_files = ["test_*.py"]
103
+ python_functions = ["test_*"]
104
+
105
+ [tool.coverage.run]
106
+ source = ["src/claude_statusline"]
107
+ omit = ["tests/*"]
108
+
109
+ [tool.coverage.report]
110
+ exclude_lines = [
111
+ "pragma: no cover",
112
+ "if __name__ == .__main__.:",
113
+ ]
@@ -0,0 +1,12 @@
1
+ # Development dependencies for claude-statusline
2
+
3
+ # Testing
4
+ pytest>=7.4.0
5
+ pytest-cov>=4.1.0
6
+
7
+ # Linting and formatting
8
+ ruff>=0.1.0
9
+ mypy>=1.7.0
10
+
11
+ # Pre-commit hooks
12
+ pre-commit>=3.6.0