claude-code-pulsify 1.1.0 → 1.2.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.
package/README.md CHANGED
@@ -34,6 +34,18 @@ 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
+ ## Checking your installed version
38
+
39
+ ```bash
40
+ npx claude-code-pulsify --status
41
+ ```
42
+
43
+ This shows the currently installed version, hooks location, and whether an update is available.
44
+
45
+ You can also check manually:
46
+ - **VERSION file:** `~/.claude/hooks/claude-code-pulsify/VERSION`
47
+ - **Update cache:** `~/.claude/cache/claude-code-pulsify-update.json` — written on each session start, contains `installed`, `latest`, and `updateAvailable` fields
48
+
37
49
  ## Configuration
38
50
 
39
51
  Respects the `CLAUDE_CONFIG_DIR` environment variable. Defaults to `~/.claude`.
package/bin/install.js CHANGED
@@ -69,14 +69,30 @@ function install() {
69
69
  fs.writeFileSync(path.join(hooksTarget, 'VERSION'), PACKAGE_VERSION, 'utf8')
70
70
  console.log(` Wrote VERSION (${PACKAGE_VERSION})`)
71
71
 
72
- // 3. Clear stale update cache so the indicator disappears immediately
73
- const updateCachePath = path.join(configDir, 'cache', 'claude-code-pulsify-update.json')
74
- try { fs.unlinkSync(updateCachePath) } catch { /* doesn't exist — fine */ }
72
+ // 3. Clear update cache so stale "update available" indicators don't persist after install.
73
+ // The background worker will refresh it on next session.
74
+ const cachePath = path.join(configDir, 'cache', 'claude-code-pulsify-update.json')
75
+ try {
76
+ fs.unlinkSync(cachePath)
77
+ console.log(` Cleared update cache`)
78
+ } catch {
79
+ // Doesn't exist — fine
80
+ }
75
81
 
76
82
  // 4. Patch settings.json
77
83
  const settings = readJSON(settingsPath)
78
84
 
79
- // 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
+ }
80
96
  settings.statusLine = {
81
97
  type: 'command',
82
98
  command: `node ${path.join(hooksTarget, 'statusline.js')}`,
@@ -170,6 +186,26 @@ const args = process.argv.slice(2)
170
186
 
171
187
  if (args.includes('--version')) {
172
188
  console.log(PACKAGE_VERSION)
189
+ } else if (args.includes('--status')) {
190
+ const versionFile = path.join(hooksTarget, 'VERSION')
191
+ const cachePath = path.join(configDir, 'cache', 'claude-code-pulsify-update.json')
192
+ const installed = fs.existsSync(versionFile) ? fs.readFileSync(versionFile, 'utf8').trim() : null
193
+ if (!installed) {
194
+ console.log('claude-code-pulsify is not installed.')
195
+ process.exit(1)
196
+ }
197
+ console.log(`Installed: v${installed}`)
198
+ console.log(`Hooks: ${hooksTarget}`)
199
+ try {
200
+ const cache = JSON.parse(fs.readFileSync(cachePath, 'utf8'))
201
+ if (cache.updateAvailable && cache.latest) {
202
+ console.log(`Latest: v${cache.latest} (update available)`)
203
+ } else {
204
+ console.log(`Latest: v${cache.latest || installed} (up to date)`)
205
+ }
206
+ } catch {
207
+ console.log(`Latest: unknown (run a Claude Code session to check)`)
208
+ }
173
209
  } else if (args.includes('--uninstall')) {
174
210
  uninstall()
175
211
  } else {
@@ -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
- for await (const chunk of process.stdin) {
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,
@@ -47,9 +47,10 @@ function writeState(sessionId, state) {
47
47
 
48
48
  async function main() {
49
49
  let input = ''
50
- for await (const chunk of process.stdin) {
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 {
@@ -140,9 +140,10 @@ function formatTokenCount(input, output) {
140
140
 
141
141
  async function main() {
142
142
  let input = ''
143
- for await (const chunk of process.stdin) {
144
- input += chunk
145
- }
143
+ await Promise.race([
144
+ (async () => { for await (const chunk of process.stdin) input += chunk })(),
145
+ new Promise((resolve) => setTimeout(resolve, 5000)),
146
+ ])
146
147
 
147
148
  let data
148
149
  try {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "claude-code-pulsify",
3
- "version": "1.1.0",
3
+ "version": "1.2.0",
4
4
  "description": "Context-aware statusline and context monitor for Claude Code",
5
5
  "bin": {
6
6
  "claude-code-pulsify": "bin/install.js"