tokengolf 0.5.1 → 0.5.2
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/CLAUDE.md +2 -2
- package/dist/cli.js +45 -5
- package/hooks/statusline.sh +2 -2
- package/package.json +1 -1
- package/src/lib/install.js +54 -5
package/CLAUDE.md
CHANGED
|
@@ -349,11 +349,11 @@ Nine hooks in `hooks/` directory, installed via `tokengolf install`. Most comple
|
|
|
349
349
|
- Receives live session JSON (cost, context %, model) via stdin
|
|
350
350
|
- **Design D accent bar**: `██` prefix on each line, color-coded (yellow normal, red when budget >75%)
|
|
351
351
|
- Line 1: `██ ⛳ quest $cost/budget ▓▓▓░░░ pct% RATING model F1/5`
|
|
352
|
-
- Line 2 (
|
|
352
|
+
- Line 2 (always shown when context data available): `██ 🧠 ▓▓▓▓░░░ ctx% 🪶/🎒/📦`
|
|
353
353
|
- Budget progress bar: `▓` filled, `░` empty, 11 chars wide. Red when >75%, yellow otherwise
|
|
354
354
|
- Context progress bar: `▓░` 10 chars wide. Green (50–74%), yellow (75–89%), red (90%+); hidden below 50%
|
|
355
355
|
- Model label: `⚔️ Sonnet`, `⚔️ Sonnet·High`, `🏹 Haiku`, `🧙 Opus·Max`, etc. Effort appended only when explicitly set in settings.json (medium omitted — it's the default)
|
|
356
|
-
-
|
|
356
|
+
- Always 2 lines when context data is available from Claude Code
|
|
357
357
|
- statusLine config must be an object: `{type:"command", command:"...statusline.sh", padding:1}`
|
|
358
358
|
|
|
359
359
|
### Hook installation
|
package/dist/cli.js
CHANGED
|
@@ -1796,8 +1796,50 @@ function installHooks() {
|
|
|
1796
1796
|
}
|
|
1797
1797
|
const existing = settings.statusLine;
|
|
1798
1798
|
const existingCmd = typeof existing === "string" ? existing : existing?.command ?? null;
|
|
1799
|
-
const
|
|
1800
|
-
|
|
1799
|
+
const isTgStatusline = (cmd) => cmd && (cmd.includes("tokengolf/hooks/statusline") || cmd.includes("tokengolf\\hooks\\statusline"));
|
|
1800
|
+
const alreadyOurs = isTgStatusline(existingCmd);
|
|
1801
|
+
if (alreadyOurs) {
|
|
1802
|
+
let userStatusline = null;
|
|
1803
|
+
if (existingCmd.includes("statusline-wrapper")) {
|
|
1804
|
+
try {
|
|
1805
|
+
const wrapperContent = fs4.readFileSync(existingCmd, "utf8");
|
|
1806
|
+
const lines = wrapperContent.split("\n").filter((l) => l.includes('echo "$SESSION_JSON"'));
|
|
1807
|
+
for (const line of lines) {
|
|
1808
|
+
const match = line.match(/echo "\$SESSION_JSON" \| (.+?)( 2>|$)/);
|
|
1809
|
+
if (match && !isTgStatusline(match[1])) {
|
|
1810
|
+
userStatusline = match[1];
|
|
1811
|
+
break;
|
|
1812
|
+
}
|
|
1813
|
+
}
|
|
1814
|
+
} catch {
|
|
1815
|
+
}
|
|
1816
|
+
}
|
|
1817
|
+
if (userStatusline) {
|
|
1818
|
+
fs4.writeFileSync(
|
|
1819
|
+
WRAPPER_PATH,
|
|
1820
|
+
[
|
|
1821
|
+
"#!/usr/bin/env bash",
|
|
1822
|
+
"SESSION_JSON=$(cat)",
|
|
1823
|
+
`echo "$SESSION_JSON" | ${userStatusline} 2>/dev/null || true`,
|
|
1824
|
+
`echo "$SESSION_JSON" | bash ${STATUSLINE_PATH}`
|
|
1825
|
+
].join("\n") + "\n"
|
|
1826
|
+
);
|
|
1827
|
+
fs4.chmodSync(WRAPPER_PATH, 493);
|
|
1828
|
+
settings.statusLine = {
|
|
1829
|
+
type: "command",
|
|
1830
|
+
command: WRAPPER_PATH,
|
|
1831
|
+
padding: existing?.padding ?? 1
|
|
1832
|
+
};
|
|
1833
|
+
console.log(" \u2713 statusLine \u2192 updated paths (kept your existing statusline)");
|
|
1834
|
+
} else {
|
|
1835
|
+
settings.statusLine = {
|
|
1836
|
+
type: "command",
|
|
1837
|
+
command: STATUSLINE_PATH,
|
|
1838
|
+
padding: existing?.padding ?? 1
|
|
1839
|
+
};
|
|
1840
|
+
console.log(" \u2713 statusLine \u2192 updated to current install path");
|
|
1841
|
+
}
|
|
1842
|
+
} else if (existingCmd) {
|
|
1801
1843
|
fs4.writeFileSync(
|
|
1802
1844
|
WRAPPER_PATH,
|
|
1803
1845
|
[
|
|
@@ -1814,15 +1856,13 @@ function installHooks() {
|
|
|
1814
1856
|
padding: 1
|
|
1815
1857
|
};
|
|
1816
1858
|
console.log(" \u2713 statusLine \u2192 wrapped your existing statusline + tokengolf HUD");
|
|
1817
|
-
} else
|
|
1859
|
+
} else {
|
|
1818
1860
|
settings.statusLine = {
|
|
1819
1861
|
type: "command",
|
|
1820
1862
|
command: STATUSLINE_PATH,
|
|
1821
1863
|
padding: 1
|
|
1822
1864
|
};
|
|
1823
1865
|
console.log(" \u2713 statusLine \u2192 live HUD in every Claude session");
|
|
1824
|
-
} else {
|
|
1825
|
-
console.log(" \u2713 statusLine \u2192 already installed");
|
|
1826
1866
|
}
|
|
1827
1867
|
fs4.writeFileSync(CLAUDE_SETTINGS, JSON.stringify(settings, null, 2));
|
|
1828
1868
|
console.log(" \u2713 SessionStart \u2192 injects run context into Claude");
|
package/hooks/statusline.sh
CHANGED
|
@@ -72,9 +72,9 @@ else:
|
|
|
72
72
|
cost_str = f"{tier_emoji} ${cost:.2f}"
|
|
73
73
|
rating_str = ''
|
|
74
74
|
|
|
75
|
-
# Context bar (line 2,
|
|
75
|
+
# Context bar (line 2, always shown)
|
|
76
76
|
ctx_line = None
|
|
77
|
-
if ctx_pct is not None
|
|
77
|
+
if ctx_pct is not None:
|
|
78
78
|
ctx_w = 10
|
|
79
79
|
ctx_filled = min(ctx_w, int(ctx_pct / 100 * ctx_w + 0.5))
|
|
80
80
|
ctx_empty = ctx_w - ctx_filled
|
package/package.json
CHANGED
package/src/lib/install.js
CHANGED
|
@@ -149,9 +149,59 @@ export function installHooks() {
|
|
|
149
149
|
|
|
150
150
|
const existing = settings.statusLine;
|
|
151
151
|
const existingCmd = typeof existing === 'string' ? existing : (existing?.command ?? null);
|
|
152
|
-
|
|
152
|
+
// Detect any tokengolf statusline (from any install path — npm, homebrew, project dir)
|
|
153
|
+
const isTgStatusline = (cmd) =>
|
|
154
|
+
cmd &&
|
|
155
|
+
(cmd.includes('tokengolf/hooks/statusline') || cmd.includes('tokengolf\\hooks\\statusline'));
|
|
156
|
+
const alreadyOurs = isTgStatusline(existingCmd);
|
|
157
|
+
|
|
158
|
+
if (alreadyOurs) {
|
|
159
|
+
// Check if existing wrapper has a non-TG statusline we should preserve
|
|
160
|
+
let userStatusline = null;
|
|
161
|
+
if (existingCmd.includes('statusline-wrapper')) {
|
|
162
|
+
try {
|
|
163
|
+
const wrapperContent = fs.readFileSync(existingCmd, 'utf8');
|
|
164
|
+
const lines = wrapperContent.split('\n').filter((l) => l.includes('echo "$SESSION_JSON"'));
|
|
165
|
+
// Find the line that calls a non-tokengolf statusline
|
|
166
|
+
for (const line of lines) {
|
|
167
|
+
const match = line.match(/echo "\$SESSION_JSON" \| (.+?)( 2>|$)/);
|
|
168
|
+
if (match && !isTgStatusline(match[1])) {
|
|
169
|
+
userStatusline = match[1];
|
|
170
|
+
break;
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
} catch {}
|
|
174
|
+
}
|
|
153
175
|
|
|
154
|
-
|
|
176
|
+
if (userStatusline) {
|
|
177
|
+
// Re-wrap: preserve user's statusline + update tokengolf path
|
|
178
|
+
fs.writeFileSync(
|
|
179
|
+
WRAPPER_PATH,
|
|
180
|
+
[
|
|
181
|
+
'#!/usr/bin/env bash',
|
|
182
|
+
'SESSION_JSON=$(cat)',
|
|
183
|
+
`echo "$SESSION_JSON" | ${userStatusline} 2>/dev/null || true`,
|
|
184
|
+
`echo "$SESSION_JSON" | bash ${STATUSLINE_PATH}`,
|
|
185
|
+
].join('\n') + '\n'
|
|
186
|
+
);
|
|
187
|
+
fs.chmodSync(WRAPPER_PATH, 0o755);
|
|
188
|
+
settings.statusLine = {
|
|
189
|
+
type: 'command',
|
|
190
|
+
command: WRAPPER_PATH,
|
|
191
|
+
padding: existing?.padding ?? 1,
|
|
192
|
+
};
|
|
193
|
+
console.log(' ✓ statusLine → updated paths (kept your existing statusline)');
|
|
194
|
+
} else {
|
|
195
|
+
// Direct install — no user statusline to preserve
|
|
196
|
+
settings.statusLine = {
|
|
197
|
+
type: 'command',
|
|
198
|
+
command: STATUSLINE_PATH,
|
|
199
|
+
padding: existing?.padding ?? 1,
|
|
200
|
+
};
|
|
201
|
+
console.log(' ✓ statusLine → updated to current install path');
|
|
202
|
+
}
|
|
203
|
+
} else if (existingCmd) {
|
|
204
|
+
// User has a non-TG statusline — wrap it
|
|
155
205
|
fs.writeFileSync(
|
|
156
206
|
WRAPPER_PATH,
|
|
157
207
|
[
|
|
@@ -168,15 +218,14 @@ export function installHooks() {
|
|
|
168
218
|
padding: 1,
|
|
169
219
|
};
|
|
170
220
|
console.log(' ✓ statusLine → wrapped your existing statusline + tokengolf HUD');
|
|
171
|
-
} else
|
|
221
|
+
} else {
|
|
222
|
+
// No existing statusline — install directly
|
|
172
223
|
settings.statusLine = {
|
|
173
224
|
type: 'command',
|
|
174
225
|
command: STATUSLINE_PATH,
|
|
175
226
|
padding: 1,
|
|
176
227
|
};
|
|
177
228
|
console.log(' ✓ statusLine → live HUD in every Claude session');
|
|
178
|
-
} else {
|
|
179
|
-
console.log(' ✓ statusLine → already installed');
|
|
180
229
|
}
|
|
181
230
|
|
|
182
231
|
fs.writeFileSync(CLAUDE_SETTINGS, JSON.stringify(settings, null, 2));
|