claude-blip 1.0.3 → 1.0.5

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
@@ -2,86 +2,46 @@
2
2
 
3
3
  # claude-blip
4
4
 
5
- **A single-file statusline for Claude Code.**
6
- *Zero dependencies. One command. Just a blip.*
5
+ *green when fresh, yellow when warm, red when you're cooked*
7
6
 
8
7
  [![npm](https://img.shields.io/npm/v/claude-blip)](https://www.npmjs.com/package/claude-blip)
9
8
  [![install size](https://packagephobia.com/badge?p=claude-blip)](https://packagephobia.com/result?p=claude-blip)
10
- [![license](https://img.shields.io/npm/l/claude-blip)](LICENSE)
11
9
 
12
10
  ![variants](variants.gif)
13
11
 
14
- *dim when chill, yellow when warm, red when you should probably wrap up*
15
-
16
12
  </div>
17
13
 
18
- Four segments. No config files. No themes. No plugins.
19
- It just shows you what matters and gets out of the way.
20
-
21
14
  ## Install
22
15
 
23
16
  ```sh
24
17
  npx claude-blip
25
18
  ```
26
19
 
27
- That's it. Restart Claude Code. Done.
20
+ Restart Claude Code.
28
21
 
29
- ## What you get
22
+ ## Segments
30
23
 
31
- | Segment | What it shows | Style |
32
- |---------|--------------|-------|
33
- | **Project** | Directory name | dim |
34
- | **Branch** | Current git branch | dim |
35
- | **Model** | opus, sonnet, haiku | dim |
36
- | **Context** | Usage bar + token count | green yellow red |
24
+ | Segment | Shows | Style |
25
+ |---------|-------|-------|
26
+ | Project | Directory name | dim |
27
+ | Branch | Current git branch | dim |
28
+ | Model | opus, sonnet, haiku | dim |
29
+ | Context | Usage bar + token count | green / yellow / red |
37
30
 
38
- Everything is dim except the context bar your eyes go to the thing that matters.
31
+ The context bar scales to 80% - roughly where Claude starts compressing history.
39
32
 
40
- Terminal too narrow? Segments drop off the left. Context bar always stays.
33
+ Terminal too narrow? Segments drop from the left. Context bar stays.
41
34
 
42
- ## Scopes
35
+ ## Uninstall
43
36
 
44
37
  ```sh
45
- npx claude-blip # global (recommended)
46
- npx claude-blip --project # .claude/settings.json (shareable with team)
47
- npx claude-blip --local # .claude/settings.local.json (just you)
48
- npx claude-blip --uninstall # clean removal from all scopes
38
+ npx claude-blip --uninstall
49
39
  ```
50
40
 
51
41
  ## How it works
52
42
 
53
- One file. ~150 lines. Node.js only (ships with Claude Code nothing to install).
54
-
55
- Claude Code pipes session JSON to your statusline script via stdin. This script reads it, picks out the useful bits, formats them, writes one line to stdout. That's the whole thing.
56
-
57
- The context bar scales to 80% capacity — that's roughly where Claude starts compressing context, so 100% on the bar means "you're about to lose history."
58
-
59
- <details>
60
- <summary><strong>Debug mode</strong></summary>
61
-
62
- Set `debug: true` in the CONFIG object at top of `statusline.js` to dump the full JSON payload to stderr:
63
-
64
- ```js
65
- const CONFIG = {
66
- debug: true, // logs to stderr
67
- // ...
68
- };
69
- ```
70
-
71
- </details>
72
-
73
- ## Contributing
74
-
75
- Found a bug? Want a feature? PRs welcome. Keep it simple — the whole point is one file with zero dependencies.
43
+ Claude Code pipes session JSON via stdin. This script reads it, formats one line, writes it to stdout. ~140 lines of Node.js.
76
44
 
77
45
  ## License
78
46
 
79
- MIT — do whatever you want with it.
80
-
81
- ---
82
-
83
- <div align="center">
84
-
85
- *Built for developers with mass context window anxiety.*
86
-
87
- </div>
47
+ MIT
package/bin/setup.js CHANGED
@@ -1,68 +1,44 @@
1
1
  #!/usr/bin/env node
2
- // claude-blip setup one command, done.
2
+ // claude-blip setup - one command, done.
3
3
  //
4
4
  // Usage:
5
- // npx claude-blip (global — recommended)
6
- // npx claude-blip --project (this project, shareable)
7
- // npx claude-blip --local (this project, gitignored)
8
- // npx claude-blip --uninstall (remove from all scopes)
5
+ // npx claude-blip (install)
6
+ // npx claude-blip --uninstall (remove)
9
7
 
10
8
  const fs = require("fs");
11
9
  const path = require("path");
12
10
  const os = require("os");
13
11
 
14
12
  const HOOK_SOURCE = path.resolve(__dirname, "..", "statusline.js");
13
+ const HOOKS_DIR = path.join(os.homedir(), ".claude", "hooks");
14
+ const SETTINGS_PATH = path.join(os.homedir(), ".claude", "settings.json");
15
15
 
16
- const SCOPES = {
17
- global: () => path.join(os.homedir(), ".claude", "settings.json"),
18
- project: () => path.join(process.cwd(), ".claude", "settings.json"),
19
- local: () => path.join(process.cwd(), ".claude", "settings.local.json"),
20
- };
21
-
22
- const args = process.argv.slice(2);
23
- const uninstall = args.includes("--uninstall");
24
- const scope = args.includes("--project")
25
- ? "project"
26
- : args.includes("--local")
27
- ? "local"
28
- : "global";
16
+ const uninstall = process.argv.includes("--uninstall");
29
17
 
30
18
  const DIM = "\x1b[2m";
31
19
  const BOLD = "\x1b[1m";
32
20
  const GREEN = "\x1b[32m";
33
- const RED = "\x1b[31m";
34
21
  const RESET = "\x1b[0m";
35
22
 
36
23
  function log(msg) {
37
24
  console.log(` ${msg}`);
38
25
  }
39
26
 
40
- function getInstallDir() {
41
- if (scope === "global") {
42
- return path.join(os.homedir(), ".claude", "hooks");
43
- }
44
- return path.join(process.cwd(), ".claude", "hooks");
45
- }
46
-
47
27
  function install() {
48
- const installDir = getInstallDir();
49
- const dest = path.join(installDir, "statusline.js");
50
- const settingsPath = SCOPES[scope]();
51
- const settingsDir = path.dirname(settingsPath);
28
+ const dest = path.join(HOOKS_DIR, "statusline.js");
52
29
 
53
30
  // 1. Copy the statusline script
54
- fs.mkdirSync(installDir, { recursive: true });
31
+ fs.mkdirSync(HOOKS_DIR, { recursive: true });
55
32
  fs.copyFileSync(HOOK_SOURCE, dest);
56
33
  fs.chmodSync(dest, 0o755);
57
34
 
58
35
  // 2. Update settings.json
59
- fs.mkdirSync(settingsDir, { recursive: true });
60
36
  let settings = {};
61
- if (fs.existsSync(settingsPath)) {
37
+ if (fs.existsSync(SETTINGS_PATH)) {
62
38
  try {
63
- settings = JSON.parse(fs.readFileSync(settingsPath, "utf8"));
39
+ settings = JSON.parse(fs.readFileSync(SETTINGS_PATH, "utf8"));
64
40
  } catch {
65
- // Corrupted settings start fresh
41
+ // Corrupted settings - start fresh
66
42
  }
67
43
  }
68
44
 
@@ -71,65 +47,51 @@ function install() {
71
47
  command: dest,
72
48
  };
73
49
 
74
- fs.writeFileSync(settingsPath, JSON.stringify(settings, null, 2) + "\n");
50
+ fs.writeFileSync(SETTINGS_PATH, JSON.stringify(settings, null, 2) + "\n");
75
51
 
76
52
  console.log();
77
53
  log(`${GREEN}${BOLD}blip${RESET} ${DIM}installed${RESET}`);
78
- log(`${DIM}scope: ${RESET}${scope}`);
79
54
  log(`${DIM}hook: ${RESET}${dest}`);
80
- log(`${DIM}config: ${RESET}${settingsPath}`);
55
+ log(`${DIM}config: ${RESET}${SETTINGS_PATH}`);
81
56
  console.log();
82
57
  log(`${DIM}Restart Claude Code to see it.${RESET}`);
83
58
  console.log();
84
59
  }
85
60
 
86
- function removeStatusLine(settingsPath) {
87
- if (!fs.existsSync(settingsPath)) return false;
88
- try {
89
- const settings = JSON.parse(fs.readFileSync(settingsPath, "utf8"));
90
- if (!settings.statusLine) return false;
91
- delete settings.statusLine;
92
- fs.writeFileSync(settingsPath, JSON.stringify(settings, null, 2) + "\n");
93
- return true;
94
- } catch {
95
- return false;
96
- }
97
- }
98
-
99
61
  function uninstallAll() {
100
62
  let removed = false;
101
63
 
102
- // Remove from all settings scopes
103
- for (const [name, getPath] of Object.entries(SCOPES)) {
104
- if (removeStatusLine(getPath())) {
105
- log(`${DIM}Removed statusLine from ${name} settings${RESET}`);
106
- removed = true;
64
+ // Remove statusLine from global settings
65
+ if (fs.existsSync(SETTINGS_PATH)) {
66
+ try {
67
+ const settings = JSON.parse(fs.readFileSync(SETTINGS_PATH, "utf8"));
68
+ if (settings.statusLine) {
69
+ delete settings.statusLine;
70
+ fs.writeFileSync(SETTINGS_PATH, JSON.stringify(settings, null, 2) + "\n");
71
+ removed = true;
72
+ }
73
+ } catch {
74
+ // ignore
107
75
  }
108
76
  }
109
77
 
110
- // Remove hook files
111
- const locations = [
112
- path.join(os.homedir(), ".claude", "hooks", "statusline.js"),
113
- path.join(process.cwd(), ".claude", "hooks", "statusline.js"),
114
- ];
115
- for (const loc of locations) {
116
- if (fs.existsSync(loc)) {
117
- fs.unlinkSync(loc);
118
- log(`${DIM}Removed ${loc}${RESET}`);
119
- removed = true;
120
- }
78
+ // Remove hook file
79
+ const hookPath = path.join(HOOKS_DIR, "statusline.js");
80
+ if (fs.existsSync(hookPath)) {
81
+ fs.unlinkSync(hookPath);
82
+ removed = true;
121
83
  }
122
84
 
123
85
  console.log();
124
86
  if (removed) {
125
87
  log(`${GREEN}${BOLD}blip${RESET} ${DIM}uninstalled${RESET}`);
126
88
  } else {
127
- log(`${DIM}Nothing to remove blip wasn't installed.${RESET}`);
89
+ log(`${DIM}Nothing to remove - blip wasn't installed.${RESET}`);
128
90
  }
129
91
  console.log();
130
92
  }
131
93
 
132
- // ─────────────────────────────────────────────────────────────
94
+ // -----------------------------------------------------------------
133
95
 
134
96
  if (uninstall) {
135
97
  uninstallAll();
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "claude-blip",
3
- "version": "1.0.3",
4
- "description": "A single-file statusline for Claude Code. Zero dependencies. Just a blip.",
3
+ "version": "1.0.5",
4
+ "description": "A minimal statusline for Claude Code",
5
5
  "license": "MIT",
6
6
  "author": "davebream",
7
7
  "repository": {
package/statusline.js CHANGED
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- // claude-blip a single-file statusline for Claude Code
2
+ // claude-blip - a single-file statusline for Claude Code
3
3
  // Shows: project │ branch │ model │ context usage
4
4
 
5
5
  const { execSync } = require("child_process");
@@ -117,7 +117,7 @@ function buildStatusline(input) {
117
117
  parts.push(ctx);
118
118
  }
119
119
 
120
- // Truncate if wider than terminal drops segments from the left
120
+ // Truncate if wider than terminal - drops segments from the left
121
121
  const sep = dim(" \u00B7 ");
122
122
  const cols = process.stdout.columns || 80;
123
123
  while (parts.length > 1 && stripAnsi(parts.join(sep)).length > cols) {
@@ -138,6 +138,6 @@ process.stdin.on("end", () => {
138
138
  const output = buildStatusline(input);
139
139
  process.stdout.write(output);
140
140
  } catch {
141
- // Silent fail a broken statusline should never interrupt your flow
141
+ // Silent fail - a broken statusline should never interrupt your flow
142
142
  }
143
143
  });