claude-code-pulsify 1.1.1 → 1.2.1
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 +13 -0
- package/bin/install.js +11 -1
- package/hooks/check-update.js +6 -4
- package/hooks/context-monitor.js +4 -3
- package/hooks/statusline.js +6 -29
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -34,6 +34,14 @@ npx claude-code-pulsify@latest --uninstall
|
|
|
34
34
|
- **Context monitor** -- Warns at 65% and 75% context usage via PostToolUse hook
|
|
35
35
|
- **Update checker** -- Background version check on session start, non-blocking
|
|
36
36
|
|
|
37
|
+
## Context bar
|
|
38
|
+
|
|
39
|
+
The context bar shows **usable** context, not raw token count — it accounts for Claude's autocompact buffer (~16.5% of the window), which is reserved and unavailable to you.
|
|
40
|
+
|
|
41
|
+
- **0%** = fresh session
|
|
42
|
+
- **100%** = autocompact imminent (context will be compressed)
|
|
43
|
+
- Color thresholds: **green** (<50%) → **yellow** (50-65%) → **orange** (65-80%) → **red** (>80%)
|
|
44
|
+
|
|
37
45
|
## Checking your installed version
|
|
38
46
|
|
|
39
47
|
```bash
|
|
@@ -49,3 +57,8 @@ You can also check manually:
|
|
|
49
57
|
## Configuration
|
|
50
58
|
|
|
51
59
|
Respects the `CLAUDE_CONFIG_DIR` environment variable. Defaults to `~/.claude`.
|
|
60
|
+
|
|
61
|
+
## Future Enhancements
|
|
62
|
+
|
|
63
|
+
- Lines changed display (+added / -removed)
|
|
64
|
+
- Token usage counter
|
package/bin/install.js
CHANGED
|
@@ -82,7 +82,17 @@ function install() {
|
|
|
82
82
|
// 4. Patch settings.json
|
|
83
83
|
const settings = readJSON(settingsPath)
|
|
84
84
|
|
|
85
|
-
// statusLine
|
|
85
|
+
// statusLine — check for conflicts from other tools
|
|
86
|
+
const existingCmd = settings.statusLine?.command || ''
|
|
87
|
+
if (settings.statusLine && !existingCmd.includes('claude-code-pulsify')) {
|
|
88
|
+
if (!args.includes('--force')) {
|
|
89
|
+
console.warn(`\n ⚠ Existing statusLine detected:`)
|
|
90
|
+
console.warn(` ${existingCmd || JSON.stringify(settings.statusLine)}`)
|
|
91
|
+
console.warn(` This will be overwritten. Re-run with --force to confirm, or remove it manually.\n`)
|
|
92
|
+
process.exit(1)
|
|
93
|
+
}
|
|
94
|
+
console.log(` Overwriting existing statusLine (--force)`)
|
|
95
|
+
}
|
|
86
96
|
settings.statusLine = {
|
|
87
97
|
type: 'command',
|
|
88
98
|
command: `node ${path.join(hooksTarget, 'statusline.js')}`,
|
package/hooks/check-update.js
CHANGED
|
@@ -17,11 +17,12 @@ const cacheDir = path.join(configDir, 'cache')
|
|
|
17
17
|
const cachePath = path.join(cacheDir, 'claude-code-pulsify-update.json')
|
|
18
18
|
|
|
19
19
|
async function main() {
|
|
20
|
-
// Consume stdin (required by hook protocol)
|
|
20
|
+
// Consume stdin (required by hook protocol) with timeout guard
|
|
21
21
|
let input = ''
|
|
22
|
-
|
|
23
|
-
input += chunk
|
|
24
|
-
|
|
22
|
+
await Promise.race([
|
|
23
|
+
(async () => { for await (const chunk of process.stdin) input += chunk })(),
|
|
24
|
+
new Promise((resolve) => setTimeout(resolve, 5000)),
|
|
25
|
+
])
|
|
25
26
|
|
|
26
27
|
// Read installed version
|
|
27
28
|
const versionFile = path.join(hooksDir, 'VERSION')
|
|
@@ -37,6 +38,7 @@ async function main() {
|
|
|
37
38
|
const child = spawn(process.execPath, [workerPath], {
|
|
38
39
|
detached: true,
|
|
39
40
|
stdio: 'ignore',
|
|
41
|
+
windowsHide: true,
|
|
40
42
|
env: {
|
|
41
43
|
...process.env,
|
|
42
44
|
PULSIFY_CACHE_PATH: cachePath,
|
package/hooks/context-monitor.js
CHANGED
|
@@ -47,9 +47,10 @@ function writeState(sessionId, state) {
|
|
|
47
47
|
|
|
48
48
|
async function main() {
|
|
49
49
|
let input = ''
|
|
50
|
-
|
|
51
|
-
input += chunk
|
|
52
|
-
|
|
50
|
+
await Promise.race([
|
|
51
|
+
(async () => { for await (const chunk of process.stdin) input += chunk })(),
|
|
52
|
+
new Promise((resolve) => setTimeout(resolve, 5000)),
|
|
53
|
+
])
|
|
53
54
|
|
|
54
55
|
let hookData
|
|
55
56
|
try {
|
package/hooks/statusline.js
CHANGED
|
@@ -121,28 +121,13 @@ function formatCost(costUsd) {
|
|
|
121
121
|
return `${WHITE}$${str}${RESET}`
|
|
122
122
|
}
|
|
123
123
|
|
|
124
|
-
function formatLinesChanged(added, removed) {
|
|
125
|
-
const parts = []
|
|
126
|
-
if (added) parts.push(`${GREEN}+${added}${RESET}`)
|
|
127
|
-
if (removed) parts.push(`${RED}-${removed}${RESET}`)
|
|
128
|
-
return parts.join(' ')
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
function formatTokenCount(input, output) {
|
|
132
|
-
const total = (input || 0) + (output || 0)
|
|
133
|
-
if (!total) return ''
|
|
134
|
-
let compact
|
|
135
|
-
if (total >= 1e6) compact = `${(total / 1e6).toFixed(1)}M`
|
|
136
|
-
else if (total >= 1e3) compact = `${(total / 1e3).toFixed(1)}k`
|
|
137
|
-
else compact = `${total}`
|
|
138
|
-
return `${DIM}${compact} tok${RESET}`
|
|
139
|
-
}
|
|
140
124
|
|
|
141
125
|
async function main() {
|
|
142
126
|
let input = ''
|
|
143
|
-
|
|
144
|
-
input += chunk
|
|
145
|
-
|
|
127
|
+
await Promise.race([
|
|
128
|
+
(async () => { for await (const chunk of process.stdin) input += chunk })(),
|
|
129
|
+
new Promise((resolve) => setTimeout(resolve, 5000)),
|
|
130
|
+
])
|
|
146
131
|
|
|
147
132
|
let data
|
|
148
133
|
try {
|
|
@@ -178,10 +163,6 @@ async function main() {
|
|
|
178
163
|
const remainingPct = data.context_window?.remaining_percentage ?? 100
|
|
179
164
|
const sessionId = data.session?.id || data.session_id || null
|
|
180
165
|
const costUsd = data.cost?.total_cost_usd ?? 0
|
|
181
|
-
const linesAdded = data.cost?.total_lines_added ?? 0
|
|
182
|
-
const linesRemoved = data.cost?.total_lines_removed ?? 0
|
|
183
|
-
const totalInputTokens = data.context_window?.total_input_tokens ?? 0
|
|
184
|
-
const totalOutputTokens = data.context_window?.total_output_tokens ?? 0
|
|
185
166
|
|
|
186
167
|
// Normalize and build bar
|
|
187
168
|
const usedPct = normalizeUsage(remainingPct)
|
|
@@ -206,10 +187,8 @@ async function main() {
|
|
|
206
187
|
model,
|
|
207
188
|
})
|
|
208
189
|
|
|
209
|
-
// Format
|
|
190
|
+
// Format cost
|
|
210
191
|
const cost = formatCost(costUsd)
|
|
211
|
-
const lines = formatLinesChanged(linesAdded, linesRemoved)
|
|
212
|
-
const tokenCount = formatTokenCount(totalInputTokens, totalOutputTokens)
|
|
213
192
|
|
|
214
193
|
// Build segments array (only include non-empty optional segments)
|
|
215
194
|
const segments = [
|
|
@@ -217,9 +196,7 @@ async function main() {
|
|
|
217
196
|
dirLabel,
|
|
218
197
|
]
|
|
219
198
|
if (cost) segments.push(cost)
|
|
220
|
-
|
|
221
|
-
const barWithTokens = tokenCount ? `${bar} ${tokenCount}` : bar
|
|
222
|
-
segments.push(barWithTokens)
|
|
199
|
+
segments.push(bar)
|
|
223
200
|
|
|
224
201
|
// Output statusline
|
|
225
202
|
const line = segments.join(` ${SEPARATOR} `) + taskSegment + updateIndicator
|