@inbrace-tech/tokenline 1.2.1 → 1.2.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 +6 -7
- package/package.json +12 -11
- package/tokenline.sh +28 -3
package/README.md
CHANGED
|
@@ -12,18 +12,17 @@
|
|
|
12
12
|
|
|
13
13
|
Run the installer for your AI coding CLI:
|
|
14
14
|
|
|
15
|
-
**Claude Code**
|
|
15
|
+
**Claude Code Per-project installation (`./.claude/settings.json`)**
|
|
16
16
|
```bash
|
|
17
|
-
# Per-project installation (./.claude/settings.json)
|
|
18
17
|
npx @inbrace-tech/tokenline init
|
|
19
|
-
|
|
20
|
-
|
|
18
|
+
```
|
|
19
|
+
**Claude Code Global installation (`~/.claude/settings.json`)**
|
|
20
|
+
```bash
|
|
21
21
|
npx @inbrace-tech/tokenline init --global
|
|
22
22
|
```
|
|
23
23
|
|
|
24
|
-
**Antigravity CLI**
|
|
24
|
+
**Antigravity CLI Global installation (`~/.gemini/antigravity-cli/settings.json`)**
|
|
25
25
|
```bash
|
|
26
|
-
# Global installation (~/.gemini/antigravity-cli/settings.json)
|
|
27
26
|
npx @inbrace-tech/tokenline init --antigravity
|
|
28
27
|
```
|
|
29
28
|
|
|
@@ -68,7 +67,7 @@ LLMs are stateless — by default, they must reread your entire codebase context
|
|
|
68
67
|
|
|
69
68
|
**Prompt Caching** solves this by saving that processed state in the provider's memory:
|
|
70
69
|
- **Cache Write (Cold):** The model reads everything and stores the state. This costs slightly more than base tokens.
|
|
71
|
-
- **Cache Hit (Warm):** If your prompt prefix matches the cached state exactly, the model skips the reading phase. This is **~90% cheaper** and starts responding almost instantly.
|
|
70
|
+
- **Cache Hit (Warm):** If your prompt prefix matches the cached state exactly, the model skips the reading phase. This is **~90% cheaper** (**97.5%** on Claude Fable 5.1 / Mythos 5.1, which bill cache hits at 0.025x base input) and starts responding almost instantly. `tokenline` picks the right multiplier from the active model.
|
|
72
71
|
- **TTL (Time-To-Live):** The cache operates as a **sliding window**. Every cache hit resets the countdown to its full duration for free. The secret to minimizing rate-limit drain is adjusting your workflow pace to keep the cache continuously **HOT**.
|
|
73
72
|
|
|
74
73
|
### 💡 Pro-tip: Forcing a 5m TTL to save rate limits
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@inbrace-tech/tokenline",
|
|
3
|
-
"version": "1.2.
|
|
3
|
+
"version": "1.2.3",
|
|
4
4
|
"description": "A cache-aware statusline for AI coding CLIs — installs tokenline.sh and wires it into your Claude Code settings.",
|
|
5
5
|
"bin": {
|
|
6
6
|
"tokenline": "dist/cli.js"
|
|
@@ -37,29 +37,30 @@
|
|
|
37
37
|
"access": "public"
|
|
38
38
|
},
|
|
39
39
|
"devDependencies": {
|
|
40
|
-
"@changesets/cli": "^
|
|
40
|
+
"@changesets/cli": "^3.0.2",
|
|
41
41
|
"@eslint/js": "10.0.1",
|
|
42
|
-
"@types/node": "24.13.
|
|
43
|
-
"@vitest/eslint-plugin": "1.6.
|
|
44
|
-
"eslint": "10.
|
|
42
|
+
"@types/node": "24.13.4",
|
|
43
|
+
"@vitest/eslint-plugin": "1.6.27",
|
|
44
|
+
"eslint": "10.10.0",
|
|
45
45
|
"eslint-config-prettier": "10.1.8",
|
|
46
|
-
"eslint-plugin-n": "18.
|
|
46
|
+
"eslint-plugin-n": "18.3.0",
|
|
47
47
|
"eslint-plugin-prettier": "5.5.6",
|
|
48
48
|
"eslint-plugin-simple-import-sort": "13.0.0",
|
|
49
|
-
"globals": "17.
|
|
50
|
-
"prettier": "3.9.
|
|
49
|
+
"globals": "17.12.0",
|
|
50
|
+
"prettier": "3.9.6",
|
|
51
51
|
"tsup": "^8.5.1",
|
|
52
52
|
"typescript": "5.9.3",
|
|
53
|
-
"typescript-eslint": "8.
|
|
54
|
-
"vitest": "4.1.
|
|
53
|
+
"typescript-eslint": "8.70.0",
|
|
54
|
+
"vitest": "4.1.11"
|
|
55
55
|
},
|
|
56
56
|
"scripts": {
|
|
57
57
|
"build": "tsup",
|
|
58
|
-
"typecheck": "tsc --noEmit -p tsconfig.json",
|
|
58
|
+
"typecheck": "tsc --noEmit -p tsconfig.json && tsc --noEmit -p scripts/tsconfig.json",
|
|
59
59
|
"lint": "eslint . --cache --cache-location node_modules/.cache/.eslintcache --fix",
|
|
60
60
|
"format": "prettier --write \"src/**/*.ts\"",
|
|
61
61
|
"format:check": "prettier --check \"src/**/*.ts\"",
|
|
62
62
|
"test": "vitest run",
|
|
63
|
+
"audit:lockfile": "node --experimental-strip-types scripts/check-lockfile-release-age.mts",
|
|
63
64
|
"test:watch": "vitest",
|
|
64
65
|
"changeset": "changeset",
|
|
65
66
|
"release": "pnpm build && changeset publish"
|
package/tokenline.sh
CHANGED
|
@@ -56,6 +56,19 @@ epoch_from_iso() {
|
|
|
56
56
|
fi
|
|
57
57
|
}
|
|
58
58
|
|
|
59
|
+
epoch_from_reset() {
|
|
60
|
+
# rate_limits.*.resets_at -> epoch seconds; empty on failure.
|
|
61
|
+
# Claude Code sends Unix epoch seconds, which `date` cannot parse as a date
|
|
62
|
+
# (GNU needs '@<n>', BSD needs '-r <n>'), so an integer is taken as-is and
|
|
63
|
+
# never reaches `date`. Anything else is tried as ISO-8601.
|
|
64
|
+
local value="$1"
|
|
65
|
+
if [[ "$value" =~ ^[0-9]+$ ]]; then
|
|
66
|
+
printf '%s' "$value"
|
|
67
|
+
elif [ -n "$value" ]; then
|
|
68
|
+
epoch_from_iso "$value"
|
|
69
|
+
fi
|
|
70
|
+
}
|
|
71
|
+
|
|
59
72
|
file_mtime() {
|
|
60
73
|
local f="$1"
|
|
61
74
|
if [ "$_stat_gnu" -eq 1 ]; then
|
|
@@ -95,7 +108,8 @@ parse_and_prepare_paths() {
|
|
|
95
108
|
(.context_window.current_usage.input_tokens // 0),
|
|
96
109
|
(.context_window.current_usage.output_tokens // 0),
|
|
97
110
|
(.context_window.current_usage.cache_creation_input_tokens // 0),
|
|
98
|
-
(.context_window.current_usage.cache_read_input_tokens // 0)
|
|
111
|
+
(.context_window.current_usage.cache_read_input_tokens // 0),
|
|
112
|
+
(.model.id // "")' 2>/dev/null)
|
|
99
113
|
|
|
100
114
|
# Malformed or empty stdin: jq emits nothing, so the array is empty. Degrade to
|
|
101
115
|
# a silent no-op render rather than leaking parse errors or rendering garbage —
|
|
@@ -108,13 +122,14 @@ parse_and_prepare_paths() {
|
|
|
108
122
|
transcript_path="${_f[3]}"
|
|
109
123
|
session_id="${_f[4]}"
|
|
110
124
|
rl_5h_pct="${_f[5]}"
|
|
111
|
-
rl_5h_reset=$(
|
|
125
|
+
rl_5h_reset=$(epoch_from_reset "${_f[6]}")
|
|
112
126
|
rl_7d_pct="${_f[7]}"
|
|
113
|
-
rl_7d_reset=$(
|
|
127
|
+
rl_7d_reset=$(epoch_from_reset "${_f[8]}")
|
|
114
128
|
cur_input="${_f[9]}"
|
|
115
129
|
cur_output="${_f[10]}"
|
|
116
130
|
cur_cwrite="${_f[11]}"
|
|
117
131
|
cur_cread="${_f[12]}"
|
|
132
|
+
model_id="${_f[13]}"
|
|
118
133
|
|
|
119
134
|
# Computed: total input-only tokens used in the current context window
|
|
120
135
|
tokens_used=$((cur_input + cur_cwrite + cur_cread))
|
|
@@ -141,6 +156,15 @@ parse_and_prepare_paths() {
|
|
|
141
156
|
is_gemini=true
|
|
142
157
|
fi
|
|
143
158
|
|
|
159
|
+
# Claude Fable 5.1 and Mythos 5.1 bill cache hits at 0.025x base input instead of
|
|
160
|
+
# the standard 0.1x. Match the API id (claude-fable-5-1[1m]) or the display name
|
|
161
|
+
# (Fable 5.1) so either field alone is enough.
|
|
162
|
+
discounted_cache_read=false
|
|
163
|
+
local discounted_re='(fable|mythos)[- ]5[-.]1([^0-9]|$)'
|
|
164
|
+
if [[ "${model_id,,}" =~ $discounted_re ]] || [[ "${model,,}" =~ $discounted_re ]]; then
|
|
165
|
+
discounted_cache_read=true
|
|
166
|
+
fi
|
|
167
|
+
|
|
144
168
|
# Get the current epoch timestamp once to be reused across all calculations
|
|
145
169
|
now=$(date +%s)
|
|
146
170
|
}
|
|
@@ -402,6 +426,7 @@ compute_turn_breakdown() {
|
|
|
402
426
|
output_mult="4"
|
|
403
427
|
else
|
|
404
428
|
read_mult="0.1"
|
|
429
|
+
[ "$discounted_cache_read" = true ] && read_mult="0.025"
|
|
405
430
|
write_mult="1.25"
|
|
406
431
|
[ "${ttl_label:-5m}" = "1h" ] && write_mult="2"
|
|
407
432
|
input_mult="1"
|