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
@@ -0,0 +1,17 @@
1
+ ---
2
+ description: Display ASCII graph of token usage for current session
3
+ argument-hint: [session_id] [--type cumulative|delta|both] [--no-color]
4
+ allowed-tools: Bash(*)
5
+ ---
6
+
7
+ # Context Stats
8
+
9
+ Display the token consumption history as ASCII graphs.
10
+
11
+ **IMPORTANT**: This command executes a bash script and displays its output directly. Do NOT analyze or interpret the results - simply show them to the user.
12
+
13
+ Execute the token graph script:
14
+
15
+ !`bash /Users/montimage/buildspace/luongnv89/claude-statusline/scripts/context-stats.sh $ARGUMENTS`
16
+
17
+ The output above shows the token usage visualization. No further analysis is needed.
@@ -0,0 +1,85 @@
1
+ {
2
+ "permissions": {
3
+ "allow": [
4
+ "Bash(/Users/montimage/buildspace/luongnv89/claude-statusline/scripts/statusline-full.sh:*)",
5
+ "Bash(find:*)",
6
+ "Bash(GIT_DIR=/Users/montimage/buildspace/luongnv89/claude-statusline/.git git add scripts/)",
7
+ "Bash(GIT_DIR=/Users/montimage/buildspace/luongnv89/claude-statusline/.git git -c core.hooksPath=/dev/null commit:*)",
8
+ "Bash(GIT_SSH_COMMAND=\"ssh -F /dev/null -o IdentityFile=~/.ssh/id_ed25519\" git push origin main)",
9
+ "Bash(/Users/montimage/buildspace/luongnv89/claude-statusline/scripts/statusline-original.sh)",
10
+ "Bash(/Users/montimage/buildspace/luongnv89/claude-statusline/scripts/statusline-git.sh)",
11
+ "Bash(/Users/montimage/buildspace/luongnv89/claude-statusline/scripts/statusline-minimal.sh:*)",
12
+ "Bash(ls:*)",
13
+ "Bash(wc:*)",
14
+ "Bash(pytest:*)",
15
+ "Bash(bats:*)",
16
+ "Bash(ruff check:*)",
17
+ "Bash(npx eslint:*)",
18
+ "Bash(shellcheck:*)",
19
+ "Bash(gh run list:*)",
20
+ "Bash(gh run view:*)",
21
+ "Bash(ruff format:*)",
22
+ "Bash(git rm:*)",
23
+ "Bash(scripts/statusline-full.sh:*)",
24
+ "Bash(./scripts/statusline-full.sh:*)",
25
+ "Bash(~/.claude/statusline.conf)",
26
+ "Bash(/Users/montimage/buildspace/luongnv89/claude-statusline/scripts/context-stats.sh:*)",
27
+ "Bash(bash -x:*)",
28
+ "Bash(timeout 5 bash:*)",
29
+ "Bash(perl -e 'alarm 10; exec @ARGV' -- /Users/montimage/buildspace/luongnv89/claude-statusline/scripts/context-stats.sh test-session --no-color)",
30
+ "Bash(bash -c '/Users/montimage/buildspace/luongnv89/claude-statusline/scripts/context-stats.sh test-session --no-color; echo \"\"Exit code: $?\"\"')",
31
+ "Bash(/bin/bash /Users/montimage/buildspace/luongnv89/claude-statusline/scripts/context-stats.sh:*)",
32
+ "Bash(/bin/bash:*)",
33
+ "Bash(/opt/homebrew/bin/bash:*)",
34
+ "Bash(COLUMNS=80 LINES=40 /bin/bash:*)",
35
+ "Bash(pre-commit:*)",
36
+ "Bash(./install.sh)",
37
+ "Bash(context-stats:*)",
38
+ "Bash(gh pr list:*)",
39
+ "Bash(apt-get update:*)",
40
+ "Bash(apt-get install:*)",
41
+ "Bash(pip install:*)",
42
+ "Bash(mypy:*)",
43
+ "Bash(npm ci:*)",
44
+ "Bash(npx prettier --check scripts/statusline.js)",
45
+ "Bash(cat:*)",
46
+ "Bash(node -c:*)",
47
+ "Bash(xxd:*)",
48
+ "Bash(node --version:*)",
49
+ "Bash(awk:*)",
50
+ "Bash(grep:*)",
51
+ "Bash(npm test:*)",
52
+ "Bash(SAMPLE_INPUT='{\"\"\"\"model\"\"\"\":{\"\"\"\"display_name\"\"\"\":\"\"\"\"Claude 3.5 Sonnet\"\"\"\"},\"\"\"\"workspace\"\"\"\":{\"\"\"\"current_dir\"\"\"\":\"\"\"\"/tmp/test\"\"\"\",\"\"\"\"project_dir\"\"\"\":\"\"\"\"/tmp/test\"\"\"\"},\"\"\"\"context_window\"\"\"\":{\"\"\"\"context_window_size\"\"\"\":200000,\"\"\"\"current_usage\"\"\"\":{\"\"\"\"input_tokens\"\"\"\":1000,\"\"\"\"cache_creation_input_tokens\"\"\"\":500,\"\"\"\"cache_read_input_tokens\"\"\"\":200}}}')",
53
+ "Bash(echo \"Testing bash scripts...\" echo \"$SAMPLE_INPUT\")",
54
+ "Bash(./scripts/statusline-git.sh echo \"$SAMPLE_INPUT\")",
55
+ "Bash(./scripts/statusline-minimal.sh:*)",
56
+ "Bash(echo \"Testing Python script...\" echo \"$SAMPLE_INPUT\")",
57
+ "Bash(python3:*)",
58
+ "Bash(echo \"Testing Node.js script...\" echo \"$SAMPLE_INPUT\")",
59
+ "Bash(node ./scripts/statusline.js:*)",
60
+ "Bash(./scripts/statusline-git.sh echo \"\" echo \"$SAMPLE_INPUT\")",
61
+ "Bash(export PATH=\"$HOME/.local/bin:$PATH\")",
62
+ "Bash(~/.local/bin/context-stats test-session:*)",
63
+ "Bash(~/.local/bin/context-stats)",
64
+ "Bash(~/.local/bin/context-stats:*)",
65
+ "Bash(gh run watch:*)",
66
+ "Bash(claude-statusline)",
67
+ "Bash(python -m build:*)",
68
+ "Bash(unzip:*)",
69
+ "Bash(twine:*)",
70
+ "WebFetch(domain:pypi.org)",
71
+ "Bash(python -m pytest:*)",
72
+ "Bash(python:*)",
73
+ "Bash(python -c:*)",
74
+ "Bash(timeout 5 context-stats:*)",
75
+ "Bash(gtimeout 5 context-stats:*)",
76
+ "Bash(./scripts/context-stats.sh:*)",
77
+ "Bash(echo:*)",
78
+ "Bash(CLAUDE_SESSION_ID=\"bf8a8370-18d6-473d-8f12-51e7f3c2a9d0\" node scripts/statusline.js:*)",
79
+ "Skill(pre-commit)",
80
+ "Bash(npm run format:check:*)",
81
+ "Bash(bash:*)",
82
+ "Bash(git tag:*)"
83
+ ]
84
+ }
85
+ }
package/.editorconfig ADDED
@@ -0,0 +1,60 @@
1
+ # EditorConfig for claude-statusline project
2
+ # https://editorconfig.org
3
+
4
+ root = true
5
+
6
+ # Default settings for all files
7
+ [*]
8
+ charset = utf-8
9
+ end_of_line = lf
10
+ insert_final_newline = true
11
+ trim_trailing_whitespace = true
12
+ indent_style = space
13
+ indent_size = 4
14
+
15
+ # Shell scripts
16
+ [*.{sh,bash}]
17
+ indent_style = space
18
+ indent_size = 4
19
+
20
+ # Python
21
+ [*.py]
22
+ indent_style = space
23
+ indent_size = 4
24
+ max_line_length = 100
25
+
26
+ # JavaScript
27
+ [*.js]
28
+ indent_style = space
29
+ indent_size = 4
30
+ max_line_length = 100
31
+
32
+ # JSON files
33
+ [*.json]
34
+ indent_style = space
35
+ indent_size = 2
36
+
37
+ # YAML files
38
+ [*.{yml,yaml}]
39
+ indent_style = space
40
+ indent_size = 2
41
+
42
+ # TOML files
43
+ [*.toml]
44
+ indent_style = space
45
+ indent_size = 4
46
+
47
+ # Markdown
48
+ [*.md]
49
+ indent_style = space
50
+ indent_size = 2
51
+ trim_trailing_whitespace = false
52
+
53
+ # Makefile
54
+ [Makefile]
55
+ indent_style = tab
56
+
57
+ # Bats test files
58
+ [*.bats]
59
+ indent_style = space
60
+ indent_size = 4
package/.eslintrc.json ADDED
@@ -0,0 +1,35 @@
1
+ {
2
+ "env": {
3
+ "node": true,
4
+ "es2022": true,
5
+ "jest": true
6
+ },
7
+ "parserOptions": {
8
+ "ecmaVersion": 2022,
9
+ "sourceType": "commonjs"
10
+ },
11
+ "extends": ["eslint:recommended"],
12
+ "rules": {
13
+ "indent": ["error", 4],
14
+ "linebreak-style": ["error", "unix"],
15
+ "quotes": ["error", "single", { "avoidEscape": true }],
16
+ "semi": ["error", "always"],
17
+ "no-unused-vars": ["error", { "argsIgnorePattern": "^_" }],
18
+ "no-console": "off",
19
+ "eqeqeq": ["error", "always"],
20
+ "curly": ["error", "all"],
21
+ "brace-style": ["error", "1tbs"],
22
+ "comma-dangle": ["error", "only-multiline"],
23
+ "comma-spacing": ["error", { "before": false, "after": true }],
24
+ "keyword-spacing": ["error", { "before": true, "after": true }],
25
+ "space-before-blocks": ["error", "always"],
26
+ "object-curly-spacing": ["error", "always"],
27
+ "array-bracket-spacing": ["error", "never"],
28
+ "no-trailing-spaces": "error",
29
+ "eol-last": ["error", "always"],
30
+ "max-len": ["warn", { "code": 100, "ignoreStrings": true, "ignoreTemplateLiterals": true }],
31
+ "prefer-const": "error",
32
+ "no-var": "error"
33
+ },
34
+ "ignorePatterns": ["node_modules/", "coverage/", "*.min.js"]
35
+ }
@@ -0,0 +1,44 @@
1
+ version: 2
2
+ updates:
3
+ # GitHub Actions
4
+ - package-ecosystem: "github-actions"
5
+ directory: "/"
6
+ schedule:
7
+ interval: "weekly"
8
+ day: "monday"
9
+ commit-message:
10
+ prefix: "ci"
11
+ labels:
12
+ - "dependencies"
13
+ - "github-actions"
14
+
15
+ # npm dependencies
16
+ - package-ecosystem: "npm"
17
+ directory: "/"
18
+ schedule:
19
+ interval: "weekly"
20
+ day: "monday"
21
+ commit-message:
22
+ prefix: "deps"
23
+ labels:
24
+ - "dependencies"
25
+ - "javascript"
26
+ groups:
27
+ dev-dependencies:
28
+ patterns:
29
+ - "*"
30
+ update-types:
31
+ - "minor"
32
+ - "patch"
33
+
34
+ # pip dependencies
35
+ - package-ecosystem: "pip"
36
+ directory: "/"
37
+ schedule:
38
+ interval: "weekly"
39
+ day: "monday"
40
+ commit-message:
41
+ prefix: "deps"
42
+ labels:
43
+ - "dependencies"
44
+ - "python"
@@ -0,0 +1,255 @@
1
+ name: CI
2
+
3
+ on:
4
+ push:
5
+ branches: [main]
6
+ pull_request:
7
+ branches: [main]
8
+
9
+ concurrency:
10
+ group: ${{ github.workflow }}-${{ github.ref }}
11
+ cancel-in-progress: true
12
+
13
+ jobs:
14
+ # ============================================
15
+ # BASH SCRIPTS - LINT AND TEST
16
+ # ============================================
17
+ bash-lint:
18
+ name: Bash Lint (ShellCheck)
19
+ runs-on: ubuntu-latest
20
+ steps:
21
+ - name: Checkout
22
+ uses: actions/checkout@v4
23
+
24
+ - name: Run ShellCheck
25
+ uses: ludeeus/action-shellcheck@master
26
+ with:
27
+ scandir: './scripts'
28
+ additional_files: 'install.sh'
29
+ severity: warning
30
+ format: tty
31
+
32
+ bash-test:
33
+ name: Bash Tests (${{ matrix.os }})
34
+ needs: bash-lint
35
+ runs-on: ${{ matrix.os }}
36
+ strategy:
37
+ fail-fast: false
38
+ matrix:
39
+ os: [ubuntu-latest, macos-latest]
40
+ steps:
41
+ - name: Checkout
42
+ uses: actions/checkout@v4
43
+
44
+ - name: Install jq
45
+ run: |
46
+ if [[ "$RUNNER_OS" == "Linux" ]]; then
47
+ sudo apt-get update && sudo apt-get install -y jq
48
+ elif [[ "$RUNNER_OS" == "macOS" ]]; then
49
+ brew install jq
50
+ fi
51
+
52
+ - name: Install Bats
53
+ run: |
54
+ if [[ "$RUNNER_OS" == "Linux" ]]; then
55
+ sudo apt-get install -y bats
56
+ elif [[ "$RUNNER_OS" == "macOS" ]]; then
57
+ brew install bats-core
58
+ fi
59
+
60
+ - name: Run Bats tests
61
+ run: bats tests/bash/*.bats
62
+
63
+ # ============================================
64
+ # PYTHON SCRIPT - LINT AND TEST
65
+ # ============================================
66
+ python-lint:
67
+ name: Python Lint
68
+ runs-on: ubuntu-latest
69
+ steps:
70
+ - name: Checkout
71
+ uses: actions/checkout@v4
72
+
73
+ - name: Set up Python
74
+ uses: actions/setup-python@v5
75
+ with:
76
+ python-version: '3.11'
77
+ cache: 'pip'
78
+ cache-dependency-path: 'requirements-dev.txt'
79
+
80
+ - name: Install dependencies
81
+ run: pip install -r requirements-dev.txt
82
+
83
+ - name: Run Ruff (linting)
84
+ run: ruff check scripts/statusline.py
85
+
86
+ - name: Run Ruff (formatting check)
87
+ run: ruff format --check scripts/statusline.py
88
+
89
+ - name: Run MyPy (type checking)
90
+ run: mypy scripts/statusline.py --ignore-missing-imports
91
+
92
+ python-test:
93
+ name: Python Tests (${{ matrix.os }}, Python ${{ matrix.python-version }})
94
+ needs: python-lint
95
+ runs-on: ${{ matrix.os }}
96
+ strategy:
97
+ fail-fast: false
98
+ matrix:
99
+ os: [ubuntu-latest, macos-latest, windows-latest]
100
+ python-version: ['3.9', '3.10', '3.11', '3.12']
101
+ steps:
102
+ - name: Checkout
103
+ uses: actions/checkout@v4
104
+
105
+ - name: Set up Python ${{ matrix.python-version }}
106
+ uses: actions/setup-python@v5
107
+ with:
108
+ python-version: ${{ matrix.python-version }}
109
+ cache: 'pip'
110
+ cache-dependency-path: 'requirements-dev.txt'
111
+
112
+ - name: Install dependencies
113
+ run: pip install -r requirements-dev.txt
114
+
115
+ - name: Run pytest with coverage
116
+ run: pytest tests/python/ -v --cov=scripts --cov-report=xml --cov-report=term
117
+
118
+ - name: Upload coverage to Codecov
119
+ if: matrix.os == 'ubuntu-latest' && matrix.python-version == '3.11'
120
+ uses: codecov/codecov-action@v4
121
+ with:
122
+ files: ./coverage.xml
123
+ flags: python
124
+ fail_ci_if_error: false
125
+
126
+ # ============================================
127
+ # NODE.JS SCRIPT - LINT AND TEST
128
+ # ============================================
129
+ node-lint:
130
+ name: Node.js Lint
131
+ runs-on: ubuntu-latest
132
+ steps:
133
+ - name: Checkout
134
+ uses: actions/checkout@v4
135
+
136
+ - name: Set up Node.js
137
+ uses: actions/setup-node@v4
138
+ with:
139
+ node-version: '20'
140
+ cache: 'npm'
141
+
142
+ - name: Install dependencies
143
+ run: npm ci
144
+
145
+ - name: Run ESLint
146
+ run: npx eslint scripts/statusline.js
147
+
148
+ - name: Run Prettier check
149
+ run: npx prettier --check scripts/statusline.js
150
+
151
+ node-test:
152
+ name: Node.js Tests (${{ matrix.os }}, Node ${{ matrix.node-version }})
153
+ needs: node-lint
154
+ runs-on: ${{ matrix.os }}
155
+ strategy:
156
+ fail-fast: false
157
+ matrix:
158
+ os: [ubuntu-latest, macos-latest, windows-latest]
159
+ node-version: ['18', '20', '22']
160
+ steps:
161
+ - name: Checkout
162
+ uses: actions/checkout@v4
163
+
164
+ - name: Set up Node.js ${{ matrix.node-version }}
165
+ uses: actions/setup-node@v4
166
+ with:
167
+ node-version: ${{ matrix.node-version }}
168
+ cache: 'npm'
169
+
170
+ - name: Install dependencies
171
+ run: npm ci
172
+
173
+ - name: Run Jest tests
174
+ run: npm test -- --coverage
175
+
176
+ - name: Upload coverage to Codecov
177
+ if: matrix.os == 'ubuntu-latest' && matrix.node-version == '20'
178
+ uses: codecov/codecov-action@v4
179
+ with:
180
+ files: ./coverage/node/lcov.info
181
+ flags: node
182
+ fail_ci_if_error: false
183
+
184
+ # ============================================
185
+ # INTEGRATION TESTS
186
+ # ============================================
187
+ integration-test:
188
+ name: Integration Tests (${{ matrix.os }})
189
+ needs: [bash-test, python-test, node-test]
190
+ runs-on: ${{ matrix.os }}
191
+ strategy:
192
+ fail-fast: false
193
+ matrix:
194
+ os: [ubuntu-latest, macos-latest]
195
+ steps:
196
+ - name: Checkout
197
+ uses: actions/checkout@v4
198
+
199
+ - name: Install jq
200
+ run: |
201
+ if [[ "$RUNNER_OS" == "Linux" ]]; then
202
+ sudo apt-get update && sudo apt-get install -y jq
203
+ elif [[ "$RUNNER_OS" == "macOS" ]]; then
204
+ brew install jq
205
+ fi
206
+
207
+ - name: Set up Python
208
+ uses: actions/setup-python@v5
209
+ with:
210
+ python-version: '3.11'
211
+
212
+ - name: Set up Node.js
213
+ uses: actions/setup-node@v4
214
+ with:
215
+ node-version: '20'
216
+
217
+ - name: Run integration tests
218
+ run: |
219
+ SAMPLE_INPUT='{"model":{"display_name":"Claude 3.5 Sonnet"},"workspace":{"current_dir":"/tmp/test","project_dir":"/tmp/test"},"context_window":{"context_window_size":200000,"current_usage":{"input_tokens":1000,"cache_creation_input_tokens":500,"cache_read_input_tokens":200}}}'
220
+
221
+ echo "Testing bash scripts..."
222
+ echo "$SAMPLE_INPUT" | ./scripts/statusline-full.sh
223
+ echo "$SAMPLE_INPUT" | ./scripts/statusline-git.sh
224
+ echo "$SAMPLE_INPUT" | ./scripts/statusline-minimal.sh
225
+
226
+ echo "Testing Python script..."
227
+ echo "$SAMPLE_INPUT" | python3 ./scripts/statusline.py
228
+
229
+ echo "Testing Node.js script..."
230
+ echo "$SAMPLE_INPUT" | node ./scripts/statusline.js
231
+
232
+ echo "All integration tests passed!"
233
+
234
+ # ============================================
235
+ # FINAL STATUS CHECK
236
+ # ============================================
237
+ ci-success:
238
+ name: CI Success
239
+ needs: [bash-lint, bash-test, python-lint, python-test, node-lint, node-test, integration-test]
240
+ runs-on: ubuntu-latest
241
+ if: always()
242
+ steps:
243
+ - name: Check all jobs passed
244
+ run: |
245
+ if [[ "${{ needs.bash-lint.result }}" != "success" ]] || \
246
+ [[ "${{ needs.bash-test.result }}" != "success" ]] || \
247
+ [[ "${{ needs.python-lint.result }}" != "success" ]] || \
248
+ [[ "${{ needs.python-test.result }}" != "success" ]] || \
249
+ [[ "${{ needs.node-lint.result }}" != "success" ]] || \
250
+ [[ "${{ needs.node-test.result }}" != "success" ]] || \
251
+ [[ "${{ needs.integration-test.result }}" != "success" ]]; then
252
+ echo "One or more jobs failed"
253
+ exit 1
254
+ fi
255
+ echo "All CI jobs passed successfully!"
@@ -0,0 +1,149 @@
1
+ name: Release
2
+
3
+ on:
4
+ push:
5
+ tags:
6
+ - 'v*'
7
+ workflow_dispatch:
8
+ inputs:
9
+ version:
10
+ description: 'Version to release (e.g., 1.2.0)'
11
+ required: true
12
+ type: string
13
+
14
+ permissions:
15
+ contents: write
16
+
17
+ jobs:
18
+ validate:
19
+ name: Validate Release
20
+ runs-on: ubuntu-latest
21
+ outputs:
22
+ version: ${{ steps.version.outputs.version }}
23
+ steps:
24
+ - name: Checkout
25
+ uses: actions/checkout@v4
26
+ with:
27
+ fetch-depth: 0
28
+
29
+ - name: Determine version
30
+ id: version
31
+ run: |
32
+ if [[ "${{ github.event_name }}" == "push" ]]; then
33
+ VERSION="${GITHUB_REF#refs/tags/v}"
34
+ else
35
+ VERSION="${{ github.event.inputs.version }}"
36
+ fi
37
+ echo "version=$VERSION" >> $GITHUB_OUTPUT
38
+ echo "Release version: $VERSION"
39
+
40
+ - name: Validate version format
41
+ run: |
42
+ VERSION="${{ steps.version.outputs.version }}"
43
+ if ! [[ "$VERSION" =~ ^[0-9]+\.[0-9]+\.[0-9]+(-[a-zA-Z0-9]+)?$ ]]; then
44
+ echo "Invalid version format: $VERSION"
45
+ echo "Expected format: X.Y.Z or X.Y.Z-suffix"
46
+ exit 1
47
+ fi
48
+
49
+ test:
50
+ name: Run Tests
51
+ needs: validate
52
+ runs-on: ubuntu-latest
53
+ steps:
54
+ - name: Checkout
55
+ uses: actions/checkout@v4
56
+
57
+ - name: Set up Python
58
+ uses: actions/setup-python@v5
59
+ with:
60
+ python-version: '3.11'
61
+
62
+ - name: Set up Node.js
63
+ uses: actions/setup-node@v4
64
+ with:
65
+ node-version: '20'
66
+ cache: 'npm'
67
+
68
+ - name: Install jq
69
+ run: sudo apt-get update && sudo apt-get install -y jq bats
70
+
71
+ - name: Install Python dependencies
72
+ run: pip install -r requirements-dev.txt
73
+
74
+ - name: Install Node.js dependencies
75
+ run: npm ci
76
+
77
+ - name: Run Python tests
78
+ run: pytest tests/python/ -v
79
+
80
+ - name: Run Node.js tests
81
+ run: npm test
82
+
83
+ - name: Run Bash tests
84
+ run: bats tests/bash/*.bats
85
+
86
+ create-release:
87
+ name: Create GitHub Release
88
+ needs: [validate, test]
89
+ runs-on: ubuntu-latest
90
+ steps:
91
+ - name: Checkout
92
+ uses: actions/checkout@v4
93
+ with:
94
+ fetch-depth: 0
95
+
96
+ - name: Generate changelog
97
+ id: changelog
98
+ run: |
99
+ # Get commits since last tag
100
+ LAST_TAG=$(git describe --tags --abbrev=0 2>/dev/null || echo "")
101
+ if [ -n "$LAST_TAG" ]; then
102
+ COMMITS=$(git log --pretty=format:"- %s" "$LAST_TAG"..HEAD)
103
+ else
104
+ COMMITS=$(git log --pretty=format:"- %s")
105
+ fi
106
+
107
+ # Create changelog
108
+ {
109
+ echo 'changelog<<EOF'
110
+ echo "## What's Changed"
111
+ echo ""
112
+ echo "$COMMITS"
113
+ echo ""
114
+ echo "**Full Changelog**: https://github.com/${{ github.repository }}/compare/${LAST_TAG}...v${{ needs.validate.outputs.version }}"
115
+ echo 'EOF'
116
+ } >> $GITHUB_OUTPUT
117
+
118
+ - name: Create Release Archive
119
+ run: |
120
+ VERSION="${{ needs.validate.outputs.version }}"
121
+ mkdir -p dist
122
+
123
+ # Create tarball
124
+ tar -czf dist/claude-statusline-${VERSION}.tar.gz \
125
+ scripts/ \
126
+ config/ \
127
+ install.sh \
128
+ README.md
129
+
130
+ # Create zip
131
+ zip -r dist/claude-statusline-${VERSION}.zip \
132
+ scripts/ \
133
+ config/ \
134
+ install.sh \
135
+ README.md
136
+
137
+ - name: Create GitHub Release
138
+ uses: softprops/action-gh-release@v2
139
+ with:
140
+ tag_name: v${{ needs.validate.outputs.version }}
141
+ name: Release v${{ needs.validate.outputs.version }}
142
+ body: ${{ steps.changelog.outputs.changelog }}
143
+ draft: false
144
+ prerelease: ${{ contains(needs.validate.outputs.version, '-') }}
145
+ files: |
146
+ dist/claude-statusline-*.tar.gz
147
+ dist/claude-statusline-*.zip
148
+ env:
149
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}