claude-code-token-saver 0.1.0 → 0.1.3
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 +28 -1
- package/bin/cli.js +6 -1
- package/package.json +1 -1
- package/setup-claude-code.sh +87 -6
package/README.md
CHANGED
|
@@ -38,6 +38,7 @@ Cả 3 cách đều **không ghi đè** file đã tồn tại. Toàn bộ nội
|
|
|
38
38
|
|----|---------|
|
|
39
39
|
| `--force` | Ghi đè cả những file đã tồn tại (mặc định: bỏ qua) |
|
|
40
40
|
| `--no-detect` | Không tự dò lệnh build/test/lint |
|
|
41
|
+
| `--no-usage` | Không thêm status line theo dõi usage 5 giờ (mặc định là **có**) |
|
|
41
42
|
| `-h`, `--help` | Hiện hướng dẫn |
|
|
42
43
|
|
|
43
44
|
Ví dụ:
|
|
@@ -99,6 +100,7 @@ Trong lúc đó các hook tự chạy ngầm: chặn lệnh nguy hiểm, tự fo
|
|
|
99
100
|
| `.claude/settings.json` | Hooks + danh sách chặn quyền (chặn đọc `.env`, `secrets/`) — **nên commit** |
|
|
100
101
|
| `.claude/hooks/guard-bash.sh` | Chặn lệnh shell nguy hiểm (`rm -rf /`, fork bomb, `git push --force`, `chmod -R 777`, pipe script từ mạng vào shell) |
|
|
101
102
|
| `.claude/hooks/format-file.sh` | Tự động format file sau khi Claude ghi (prettier / ruff / gofmt / rustfmt) |
|
|
103
|
+
| `.claude/hooks/statusline.js` | Vẽ thanh usage 5 giờ ở đáy phiên (chỉ khi bật usage; xem mục bên dưới) |
|
|
102
104
|
| `.claude/agents/explorer.md` | Subagent điều tra codebase **read-only**, chạy model `haiku` để tiết kiệm token |
|
|
103
105
|
| `.claude/agents/verifier.md` | Subagent kiểm chứng độc lập — chạy test/build/lint, soi diff, báo PASS/FAIL |
|
|
104
106
|
| `.claude/commands/*.md` | Các slash command: `/plan`, `/save`, `/verify`, `/wrap` |
|
|
@@ -108,6 +110,30 @@ Script tự nhận diện stack (**Node/TS, Python, Go, Rust**) và điền sẵ
|
|
|
108
110
|
|
|
109
111
|
---
|
|
110
112
|
|
|
113
|
+
## Theo dõi usage 5 giờ (status line)
|
|
114
|
+
|
|
115
|
+
Mặc định, tool thêm một **thanh tiến trình usage 5 giờ** vào đáy phiên Claude Code (trong VSCode), kiểu giống hệt widget native của Claude, tự cập nhật:
|
|
116
|
+
|
|
117
|
+
```
|
|
118
|
+
Current session ███████████████████░░░░░ 80% used
|
|
119
|
+
Resets in 1 hr 5 min
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
- Thanh amber lấp đầy theo **% usage đã dùng** của khối 5 giờ, kèm thời gian còn lại tới reset.
|
|
123
|
+
- Màu đổi theo mức: xanh < 50%, amber 50–85%, đỏ > 85%.
|
|
124
|
+
|
|
125
|
+
Con số là **chính xác** — bằng đúng số `/usage` hiển thị. Nó đọc thẳng field `rate_limits.five_hour` mà **Claude Code truyền sẵn vào status line**, nên **không cần công cụ ngoài** (không ccusage, không gọi API).
|
|
126
|
+
|
|
127
|
+
**Yêu cầu:** Claude Code ≥ 2.1.x, tài khoản **Claude.ai Pro/Max**, và có **`node`** trên máy. Thanh chỉ hiện **sau tin nhắn đầu tiên** của phiên (lúc `rate_limits` mới có); tài khoản API/không phải Pro-Max sẽ không có dữ liệu này → thanh tự ẩn, không lỗi.
|
|
128
|
+
|
|
129
|
+
Không muốn tính năng này? Cài bằng `--no-usage`:
|
|
130
|
+
|
|
131
|
+
```bash
|
|
132
|
+
npx claude-code-token-saver --no-usage
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
---
|
|
136
|
+
|
|
111
137
|
## Các slash command
|
|
112
138
|
|
|
113
139
|
| Lệnh | Tác dụng |
|
|
@@ -136,5 +162,6 @@ Script tự nhận diện stack (**Node/TS, Python, Go, Rust**) và điền sẵ
|
|
|
136
162
|
## Yêu cầu
|
|
137
163
|
|
|
138
164
|
- `bash`
|
|
139
|
-
- `
|
|
165
|
+
- `node` — cần cho cách cài `npx` và cho thanh usage 5 giờ (`statusline.js`)
|
|
166
|
+
- `python3` (dùng để hai hook guard/format đọc JSON từ stdin — không cần `jq`)
|
|
140
167
|
- Tùy chọn: `jq` (dò script trong `package.json` chính xác hơn), và các trình format (`prettier`, `ruff`, `gofmt`, `rustfmt`)
|
package/bin/cli.js
CHANGED
|
@@ -42,8 +42,13 @@ function candidateBashes() {
|
|
|
42
42
|
|
|
43
43
|
const args = process.argv.slice(2);
|
|
44
44
|
|
|
45
|
+
// Pass a forward-slash path to bash. On Windows the script path uses
|
|
46
|
+
// backslashes (C:\Users\...), which bash would treat as escape sequences and
|
|
47
|
+
// mangle (C:UsersAdmin...). Git Bash / MSYS accept C:/Users/... just fine.
|
|
48
|
+
const scriptArg = script.replace(/\\/g, "/");
|
|
49
|
+
|
|
45
50
|
for (const bash of candidateBashes()) {
|
|
46
|
-
const res = spawnSync(bash, [
|
|
51
|
+
const res = spawnSync(bash, [scriptArg, ...args], {
|
|
47
52
|
stdio: "inherit",
|
|
48
53
|
cwd: process.cwd(),
|
|
49
54
|
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "claude-code-token-saver",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.3",
|
|
4
4
|
"description": "One-shot installer that adds token-saving Claude Code rails (CLAUDE.md, hooks, subagents, slash commands, dev-docs) to any git repo.",
|
|
5
5
|
"bin": {
|
|
6
6
|
"claude-code-token-saver": "bin/cli.js",
|
package/setup-claude-code.sh
CHANGED
|
@@ -19,16 +19,21 @@ set -euo pipefail
|
|
|
19
19
|
# ---------- options ---------------------------------------------------------
|
|
20
20
|
FORCE=0
|
|
21
21
|
SKIP_DETECT=0
|
|
22
|
+
USAGE=1 # add a live 5-hour usage status line (ccusage) by default
|
|
22
23
|
for arg in "$@"; do
|
|
23
24
|
case "$arg" in
|
|
24
25
|
--force) FORCE=1 ;;
|
|
25
26
|
--no-detect) SKIP_DETECT=1 ;;
|
|
27
|
+
--usage) USAGE=1 ;;
|
|
28
|
+
--no-usage) USAGE=0 ;;
|
|
26
29
|
-h|--help)
|
|
27
30
|
cat <<'EOF'
|
|
28
|
-
Usage: bash setup-claude-code.sh [--force] [--no-detect]
|
|
31
|
+
Usage: bash setup-claude-code.sh [--force] [--no-detect] [--no-usage]
|
|
29
32
|
|
|
30
33
|
--force Overwrite files that already exist (default: skip them)
|
|
31
34
|
--no-detect Do not auto-detect build/test/lint commands
|
|
35
|
+
--no-usage Do not add the 5-hour usage status line (ccusage)
|
|
36
|
+
--usage Add the usage status line (this is the default)
|
|
32
37
|
EOF
|
|
33
38
|
exit 0 ;;
|
|
34
39
|
*) echo "Unknown option: $arg" >&2; exit 1 ;;
|
|
@@ -143,10 +148,22 @@ EOF
|
|
|
143
148
|
# ===========================================================================
|
|
144
149
|
# Quality gate: block `git commit` unless tests pass.
|
|
145
150
|
# Safety gate: block obviously destructive shell commands.
|
|
146
|
-
|
|
151
|
+
# Usage line: a native-style amber bar showing the current 5-hour usage % + reset
|
|
152
|
+
# countdown at the bottom of the Claude Code session. Numbers come straight from
|
|
153
|
+
# rate_limits.five_hour on the statusLine stdin (exact, same as /usage) — no
|
|
154
|
+
# external tool. Rendered by .claude/hooks/statusline.js (below). Off: --no-usage.
|
|
155
|
+
if [[ $USAGE -eq 1 ]]; then
|
|
156
|
+
STATUSLINE_BLOCK=$' "statusLine": {\n "type": "command",\n "command": "node \\"$CLAUDE_PROJECT_DIR/.claude/hooks/statusline.js\\""\n },\n'
|
|
157
|
+
else
|
|
158
|
+
STATUSLINE_BLOCK=""
|
|
159
|
+
fi
|
|
160
|
+
|
|
161
|
+
# NOTE: unquoted heredoc so ${STATUSLINE_BLOCK} expands. Everything Claude Code
|
|
162
|
+
# must see literally ($schema, $CLAUDE_PROJECT_DIR) is backslash-escaped.
|
|
163
|
+
write_file ".claude/settings.json" <<EOF
|
|
147
164
|
{
|
|
148
|
-
"
|
|
149
|
-
"permissions": {
|
|
165
|
+
"\$schema": "https://json.schemastore.org/claude-code-settings.json",
|
|
166
|
+
${STATUSLINE_BLOCK} "permissions": {
|
|
150
167
|
"deny": [
|
|
151
168
|
"Read(./.env)",
|
|
152
169
|
"Read(./.env.*)",
|
|
@@ -160,7 +177,7 @@ write_file ".claude/settings.json" <<'EOF'
|
|
|
160
177
|
"hooks": [
|
|
161
178
|
{
|
|
162
179
|
"type": "command",
|
|
163
|
-
"command": "\"
|
|
180
|
+
"command": "\"\$CLAUDE_PROJECT_DIR/.claude/hooks/guard-bash.sh\""
|
|
164
181
|
}
|
|
165
182
|
]
|
|
166
183
|
}
|
|
@@ -171,7 +188,7 @@ write_file ".claude/settings.json" <<'EOF'
|
|
|
171
188
|
"hooks": [
|
|
172
189
|
{
|
|
173
190
|
"type": "command",
|
|
174
|
-
"command": "\"
|
|
191
|
+
"command": "\"\$CLAUDE_PROJECT_DIR/.claude/hooks/format-file.sh\""
|
|
175
192
|
}
|
|
176
193
|
]
|
|
177
194
|
}
|
|
@@ -180,6 +197,61 @@ write_file ".claude/settings.json" <<'EOF'
|
|
|
180
197
|
}
|
|
181
198
|
EOF
|
|
182
199
|
|
|
200
|
+
# 2c. Usage status line renderer (Node, zero deps). Reads the statusLine JSON on
|
|
201
|
+
# stdin and draws a native-style amber 5-hour usage bar. Numbers come from
|
|
202
|
+
# rate_limits.five_hour (exact, same as /usage) — present for Claude.ai Pro/Max
|
|
203
|
+
# after the first API response; renders nothing otherwise. Only written with --usage.
|
|
204
|
+
if [[ $USAGE -eq 1 ]]; then
|
|
205
|
+
write_file ".claude/hooks/statusline.js" <<'EOF'
|
|
206
|
+
#!/usr/bin/env node
|
|
207
|
+
// Claude Code statusLine renderer: a native-style amber "Current session" bar
|
|
208
|
+
// showing 5-hour usage % + reset countdown. Zero dependencies (Node only).
|
|
209
|
+
// Data is read straight from rate_limits.five_hour on stdin (exact, same as
|
|
210
|
+
// /usage); that field is present for Claude.ai Pro/Max after the first API
|
|
211
|
+
// response. When it is absent, this prints nothing so the footer stays clean.
|
|
212
|
+
"use strict";
|
|
213
|
+
|
|
214
|
+
let input = "";
|
|
215
|
+
process.stdin.setEncoding("utf8");
|
|
216
|
+
process.stdin.on("data", function (d) { input += d; });
|
|
217
|
+
process.stdin.on("end", function () {
|
|
218
|
+
let data = {};
|
|
219
|
+
try { data = JSON.parse(input); } catch (e) { process.exit(0); }
|
|
220
|
+
|
|
221
|
+
const rl = data.rate_limits && data.rate_limits.five_hour;
|
|
222
|
+
if (!rl || rl.used_percentage == null) process.exit(0); // no data yet
|
|
223
|
+
|
|
224
|
+
let pct = Number(rl.used_percentage);
|
|
225
|
+
if (!isFinite(pct)) process.exit(0);
|
|
226
|
+
pct = Math.max(0, Math.min(100, pct));
|
|
227
|
+
|
|
228
|
+
// reset countdown from resets_at (unix epoch seconds)
|
|
229
|
+
let resetStr = "";
|
|
230
|
+
if (rl.resets_at) {
|
|
231
|
+
let secs = Math.floor(Number(rl.resets_at) - Date.now() / 1000);
|
|
232
|
+
if (secs < 0) secs = 0;
|
|
233
|
+
const h = Math.floor(secs / 3600);
|
|
234
|
+
const m = Math.floor((secs % 3600) / 60);
|
|
235
|
+
resetStr = h > 0 ? h + " hr " + m + " min" : m + " min";
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
// colour by level, mirroring Claude's own coding: green < 50, amber 50-85, red > 85
|
|
239
|
+
const RESET = "\x1b[0m";
|
|
240
|
+
const DIM = "\x1b[2m";
|
|
241
|
+
const fill = pct > 85 ? "\x1b[38;5;203m" : pct >= 50 ? "\x1b[38;5;214m" : "\x1b[38;5;42m";
|
|
242
|
+
const track = "\x1b[38;5;238m";
|
|
243
|
+
|
|
244
|
+
const width = 24;
|
|
245
|
+
const filled = Math.round((pct / 100) * width);
|
|
246
|
+
const bar = fill + "█".repeat(filled) + track + "█".repeat(width - filled) + RESET;
|
|
247
|
+
|
|
248
|
+
const line1 = "Current session " + bar + " " + fill + Math.round(pct) + "% used" + RESET;
|
|
249
|
+
const line2 = resetStr ? DIM + "Resets in " + resetStr + RESET : "";
|
|
250
|
+
process.stdout.write(line2 ? line1 + "\n" + line2 : line1);
|
|
251
|
+
});
|
|
252
|
+
EOF
|
|
253
|
+
fi
|
|
254
|
+
|
|
183
255
|
# 2a. Safety hook — blocks destructive Bash commands (exit 2 = block)
|
|
184
256
|
write_file ".claude/hooks/guard-bash.sh" <<'EOF'
|
|
185
257
|
#!/usr/bin/env bash
|
|
@@ -383,3 +455,12 @@ ${c_ylw}Next:${c_reset}
|
|
|
383
455
|
${c_dim}Note: hooks run real shell commands. Read the two scripts in
|
|
384
456
|
.claude/hooks/ before trusting them on a sensitive repo.${c_reset}
|
|
385
457
|
EOF
|
|
458
|
+
|
|
459
|
+
if [[ $USAGE -eq 1 ]]; then
|
|
460
|
+
echo
|
|
461
|
+
info "5-hour usage bar added (statusLine → .claude/hooks/statusline.js)."
|
|
462
|
+
printf " %sA native-style amber bar showing your 5h usage %% + reset countdown at\n" "$c_dim"
|
|
463
|
+
printf " the bottom of the session. Reads exact numbers from Claude Code's\n"
|
|
464
|
+
printf " rate_limits (Claude.ai Pro/Max, after the first message; needs node).\n"
|
|
465
|
+
printf " Disable with --no-usage.%s\n" "$c_reset"
|
|
466
|
+
fi
|