@oorn/claw-statusline 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/.claude/settings.json +18 -0
- package/.claude/settings.local.json +13 -0
- package/.claude/statusline-command.sh +135 -0
- package/README.md +120 -0
- package/bin/cli.js +129 -0
- package/package.json +26 -0
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
{
|
|
2
|
+
"env": {
|
|
3
|
+
"CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS": "1"
|
|
4
|
+
},
|
|
5
|
+
"statusLine": {
|
|
6
|
+
"type": "command",
|
|
7
|
+
"command": "bash ~/.claude/statusline-command.sh"
|
|
8
|
+
},
|
|
9
|
+
"skipDangerousModePermissionPrompt": true,
|
|
10
|
+
"preferences": {
|
|
11
|
+
"tmuxSplitPanes": true
|
|
12
|
+
},
|
|
13
|
+
"voiceEnabled": true,
|
|
14
|
+
"voice": {
|
|
15
|
+
"enabled": true,
|
|
16
|
+
"mode": "hold"
|
|
17
|
+
}
|
|
18
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
{
|
|
2
|
+
"permissions": {
|
|
3
|
+
"allow": [
|
|
4
|
+
"Bash(cp /Users/petereai/.claude/rules/git-commits.md /Users/petereai/Desktop/projects/petereaI/dot-claude/.claude/rules/git-commits.md)",
|
|
5
|
+
"Bash(git -C /Users/petereai/Desktop/projects/petereaI/dot-claude add .claude/rules/git-commits.md)",
|
|
6
|
+
"Bash(git -C /Users/petereai/Desktop/projects/petereaI/dot-claude commit -m \"Add global rule to suppress AI attribution in git commits\")",
|
|
7
|
+
"Bash(git -C /Users/petereai/Desktop/projects/petereaI/dot-claude push)",
|
|
8
|
+
"Bash(mkdir -p /Users/petereai/Desktop/projects/petereaI/dot-claude/.claude/rules)",
|
|
9
|
+
"Bash(rm /Users/petereai/Desktop/projects/petereaI/dot-claude/.claude/rules/git-commits.md)",
|
|
10
|
+
"Bash(rm /Users/petereai/.claude/rules/git-commits.md)"
|
|
11
|
+
]
|
|
12
|
+
}
|
|
13
|
+
}
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# Claude Code status line — usage bar style
|
|
3
|
+
# Receives JSON on stdin from Claude Code
|
|
4
|
+
|
|
5
|
+
input=$(cat)
|
|
6
|
+
ESC=$'\033'
|
|
7
|
+
|
|
8
|
+
# --- Parse JSON ---
|
|
9
|
+
model=$(echo "$input" | jq -r '.model.display_name // "Claude"')
|
|
10
|
+
model_id=$(echo "$input" | jq -r '.model.id // ""')
|
|
11
|
+
used_pct=$(echo "$input" | jq -r '.context_window.used_percentage // "0"')
|
|
12
|
+
total_tokens=$(echo "$input" | jq -r '.context_window.context_window_size // "0"')
|
|
13
|
+
five_pct=$(echo "$input" | jq -r '.rate_limits.five_hour.used_percentage // empty')
|
|
14
|
+
five_reset=$(echo "$input" | jq -r '.rate_limits.five_hour.resets_at // empty')
|
|
15
|
+
week_pct=$(echo "$input" | jq -r '.rate_limits.seven_day.used_percentage // empty')
|
|
16
|
+
|
|
17
|
+
# --- Mode detection ---
|
|
18
|
+
# Subscription plans populate rate_limits; API key usage does not
|
|
19
|
+
if [ -n "$five_pct" ] || [ -n "$week_pct" ]; then
|
|
20
|
+
mode="subscription"
|
|
21
|
+
else
|
|
22
|
+
mode="api"
|
|
23
|
+
fi
|
|
24
|
+
|
|
25
|
+
# --- Build progress bar ---
|
|
26
|
+
bar_width=20
|
|
27
|
+
used_int=$(printf "%.0f" "$used_pct")
|
|
28
|
+
filled=$(( used_int * bar_width / 100 ))
|
|
29
|
+
empty=$(( bar_width - filled ))
|
|
30
|
+
|
|
31
|
+
# Color based on usage
|
|
32
|
+
if [ "$used_int" -lt 50 ]; then
|
|
33
|
+
bar_color="${ESC}[32m" # green
|
|
34
|
+
elif [ "$used_int" -lt 80 ]; then
|
|
35
|
+
bar_color="${ESC}[33m" # yellow
|
|
36
|
+
else
|
|
37
|
+
bar_color="${ESC}[31m" # red
|
|
38
|
+
fi
|
|
39
|
+
|
|
40
|
+
# Build bar string
|
|
41
|
+
bar_filled=""
|
|
42
|
+
bar_empty=""
|
|
43
|
+
for ((i=0; i<filled; i++)); do bar_filled+="█"; done
|
|
44
|
+
for ((i=0; i<empty; i++)); do bar_empty+=" "; done
|
|
45
|
+
|
|
46
|
+
# Format token counts (used/total)
|
|
47
|
+
format_tokens() {
|
|
48
|
+
local t=$1
|
|
49
|
+
if [ "$t" -ge 1000 ] 2>/dev/null; then
|
|
50
|
+
echo "$(( t / 1000 ))k"
|
|
51
|
+
else
|
|
52
|
+
echo "$t"
|
|
53
|
+
fi
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
used_tokens=$(( total_tokens * used_int / 100 ))
|
|
57
|
+
used_display=$(format_tokens "$used_tokens")
|
|
58
|
+
total_display=$(format_tokens "$total_tokens")
|
|
59
|
+
|
|
60
|
+
# --- Right-side info: rate limits (subscription) or cost estimate (API) ---
|
|
61
|
+
right_info=""
|
|
62
|
+
|
|
63
|
+
if [ "$mode" = "subscription" ]; then
|
|
64
|
+
# Rate limits — subscription mode
|
|
65
|
+
if [ -n "$five_pct" ]; then
|
|
66
|
+
five_int=$(printf "%.0f" "$five_pct")
|
|
67
|
+
countdown=""
|
|
68
|
+
if [ -n "$five_reset" ]; then
|
|
69
|
+
now=$(date +%s)
|
|
70
|
+
secs_left=$(( five_reset - now ))
|
|
71
|
+
if [ "$secs_left" -gt 0 ]; then
|
|
72
|
+
hrs=$(( secs_left / 3600 ))
|
|
73
|
+
mins=$(( (secs_left % 3600) / 60 ))
|
|
74
|
+
countdown=" (${hrs}h${mins}m)"
|
|
75
|
+
else
|
|
76
|
+
countdown=" (now)"
|
|
77
|
+
fi
|
|
78
|
+
fi
|
|
79
|
+
right_info="${ESC}[36m5h:${five_int}%${countdown}${ESC}[0m"
|
|
80
|
+
fi
|
|
81
|
+
if [ -n "$week_pct" ]; then
|
|
82
|
+
week_int=$(printf "%.0f" "$week_pct")
|
|
83
|
+
[ -n "$right_info" ] && right_info="$right_info "
|
|
84
|
+
right_info="${right_info}${ESC}[36m7d:${week_int}%${ESC}[0m"
|
|
85
|
+
fi
|
|
86
|
+
elif [[ "$model_id" == claude-* ]]; then
|
|
87
|
+
# Cost estimate — Anthropic API mode only
|
|
88
|
+
# Pricing per million tokens (input/output). Approximate 70/30 split.
|
|
89
|
+
input_price_per_mtok=3.0
|
|
90
|
+
output_price_per_mtok=15.0
|
|
91
|
+
|
|
92
|
+
case "$model_id" in
|
|
93
|
+
claude-opus-4*)
|
|
94
|
+
input_price_per_mtok=15.0
|
|
95
|
+
output_price_per_mtok=75.0
|
|
96
|
+
;;
|
|
97
|
+
claude-sonnet-4*|claude-sonnet-3-7*)
|
|
98
|
+
input_price_per_mtok=3.0
|
|
99
|
+
output_price_per_mtok=15.0
|
|
100
|
+
;;
|
|
101
|
+
claude-haiku-4*|claude-haiku-3*)
|
|
102
|
+
input_price_per_mtok=0.8
|
|
103
|
+
output_price_per_mtok=4.0
|
|
104
|
+
;;
|
|
105
|
+
esac
|
|
106
|
+
|
|
107
|
+
# Estimate cost using 70/30 input/output split of used tokens
|
|
108
|
+
cost=$(awk -v tokens="$used_tokens" \
|
|
109
|
+
-v in_price="$input_price_per_mtok" \
|
|
110
|
+
-v out_price="$output_price_per_mtok" \
|
|
111
|
+
'BEGIN {
|
|
112
|
+
input_tok = tokens * 0.70
|
|
113
|
+
output_tok = tokens * 0.30
|
|
114
|
+
cost = (input_tok * in_price + output_tok * out_price) / 1000000
|
|
115
|
+
printf "~$%.4f", cost
|
|
116
|
+
}')
|
|
117
|
+
|
|
118
|
+
right_info="${ESC}[36m${cost}${ESC}[0m"
|
|
119
|
+
# else: non-Anthropic API — tokens already shown in the bar, skip right_info
|
|
120
|
+
fi
|
|
121
|
+
|
|
122
|
+
if [ -n "$right_info" ]; then
|
|
123
|
+
right_info=" ${ESC}[90m|${ESC}[0m ${right_info}"
|
|
124
|
+
fi
|
|
125
|
+
|
|
126
|
+
# --- Output ---
|
|
127
|
+
printf "%s ${ESC}[90m|${ESC}[0m [%s%s%s${ESC}[0m] %s%% ${ESC}[90m|${ESC}[0m %s/%s%s\n" \
|
|
128
|
+
"$model" \
|
|
129
|
+
"$bar_color" \
|
|
130
|
+
"$bar_filled" \
|
|
131
|
+
"$bar_empty" \
|
|
132
|
+
"$used_int" \
|
|
133
|
+
"$used_display" \
|
|
134
|
+
"$total_display" \
|
|
135
|
+
"$right_info"
|
package/README.md
ADDED
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
# claw-statusline
|
|
2
|
+
|
|
3
|
+
Shared Claude Code configuration for the team — statusline, settings, and rules.
|
|
4
|
+
|
|
5
|
+
## Install
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npx @oorn/claw-statusline init
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
`jq` is required for the statusline. The installer will attempt to install it automatically via the available package manager on your system (Homebrew, apt, dnf, yum, pacman, zypper, apk, winget, Chocolatey, or Scoop). If auto-install fails, you'll be shown the manual command.
|
|
12
|
+
|
|
13
|
+
To update to the latest version:
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
npx @oorn/claw-statusline@latest init
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
## What gets installed
|
|
20
|
+
|
|
21
|
+
| File | Destination | Description |
|
|
22
|
+
|------|-------------|-------------|
|
|
23
|
+
| `settings.json` | `~/.claude/settings.json` | Claude Code preferences |
|
|
24
|
+
| `statusline-command.sh` | `~/.claude/statusline-command.sh` | Status line script |
|
|
25
|
+
|
|
26
|
+
## Statusline
|
|
27
|
+
|
|
28
|
+
The status line is mode-aware — it adapts based on whether you're on a subscription plan or using an API key.
|
|
29
|
+
|
|
30
|
+
**Subscription (Pro/Max):**
|
|
31
|
+
```
|
|
32
|
+
Claude Sonnet 4.6 | [████ ] 42% | 84k/200k | 5h:37% (1h22m) 7d:15%
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
**Anthropic API key (`claude-*` models):**
|
|
36
|
+
```
|
|
37
|
+
Claude Sonnet 4.6 | [████ ] 42% | 84k/200k | ~$0.5544
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
**3rd-party API (Gemini, MiniMax, etc.):**
|
|
41
|
+
```
|
|
42
|
+
Gemini 2.5 Pro | [███████████ ] 55% | 550k/1000k
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
| Segment | Description |
|
|
46
|
+
|---------|-------------|
|
|
47
|
+
| Model name | Current model display name |
|
|
48
|
+
| `[████ ]` | Context window usage bar (green < 50%, yellow < 80%, red ≥ 80%) |
|
|
49
|
+
| `42%` | Context used percentage |
|
|
50
|
+
| `84k/200k` | Used tokens / total context window size |
|
|
51
|
+
| `5h:37% (1h22m)` | 5-hour rate limit usage + countdown to reset *(subscription only)* |
|
|
52
|
+
| `7d:15%` | 7-day rate limit usage *(subscription only)* |
|
|
53
|
+
| `~$0.5544` | Estimated session cost *(Anthropic API only)* |
|
|
54
|
+
|
|
55
|
+
Cost is estimated using a 70/30 input/output token split with per-model pricing:
|
|
56
|
+
|
|
57
|
+
| Model | Input | Output |
|
|
58
|
+
|-------|-------|--------|
|
|
59
|
+
| Opus 4.x | $15/MTok | $75/MTok |
|
|
60
|
+
| Sonnet 4.x / 3.7 | $3/MTok | $15/MTok |
|
|
61
|
+
| Haiku 4.x / 3.x | $0.8/MTok | $4/MTok |
|
|
62
|
+
|
|
63
|
+
For 3rd-party models the right section is omitted — token usage is already visible in the bar.
|
|
64
|
+
|
|
65
|
+
### How it works
|
|
66
|
+
|
|
67
|
+
Claude Code invokes `statusline-command.sh` after each response, passing a JSON payload via stdin. The script parses the JSON with `jq` and prints a formatted line with ANSI colors.
|
|
68
|
+
|
|
69
|
+
The script is wired up in `settings.json`:
|
|
70
|
+
|
|
71
|
+
```json
|
|
72
|
+
"statusLine": {
|
|
73
|
+
"type": "command",
|
|
74
|
+
"command": "bash ~/.claude/statusline-command.sh"
|
|
75
|
+
}
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
### Available JSON fields
|
|
79
|
+
|
|
80
|
+
The full payload Claude Code sends to the script includes:
|
|
81
|
+
|
|
82
|
+
```json
|
|
83
|
+
{
|
|
84
|
+
"model": { "id": "claude-sonnet-4-6", "display_name": "Sonnet 4.6" },
|
|
85
|
+
"context_window": {
|
|
86
|
+
"used_percentage": 21,
|
|
87
|
+
"remaining_percentage": 79,
|
|
88
|
+
"context_window_size": 200000,
|
|
89
|
+
"total_input_tokens": 44,
|
|
90
|
+
"total_output_tokens": 7202,
|
|
91
|
+
"current_usage": {
|
|
92
|
+
"input_tokens": 1,
|
|
93
|
+
"output_tokens": 28,
|
|
94
|
+
"cache_creation_input_tokens": 219,
|
|
95
|
+
"cache_read_input_tokens": 34414
|
|
96
|
+
}
|
|
97
|
+
},
|
|
98
|
+
"rate_limits": {
|
|
99
|
+
"five_hour": { "used_percentage": 18, "resets_at": 1775725200 },
|
|
100
|
+
"seven_day": { "used_percentage": 17, "resets_at": 1776067200 }
|
|
101
|
+
},
|
|
102
|
+
"cost": {
|
|
103
|
+
"total_cost_usd": 0.67,
|
|
104
|
+
"total_lines_added": 86,
|
|
105
|
+
"total_lines_removed": 79
|
|
106
|
+
},
|
|
107
|
+
"cwd": "/Users/you/project",
|
|
108
|
+
"version": "2.1.97"
|
|
109
|
+
}
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
## Updating the config
|
|
113
|
+
|
|
114
|
+
1. Edit files in `.claude/`
|
|
115
|
+
2. Bump version in `package.json`
|
|
116
|
+
3. Update this README to reflect the change
|
|
117
|
+
4. Publish and push:
|
|
118
|
+
```bash
|
|
119
|
+
npm publish --access public && git push
|
|
120
|
+
```
|
package/bin/cli.js
ADDED
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import { existsSync, mkdirSync, copyFileSync, readdirSync, statSync, readFileSync } from 'fs';
|
|
4
|
+
import { join, dirname } from 'path';
|
|
5
|
+
import { homedir, platform } from 'os';
|
|
6
|
+
import { fileURLToPath } from 'url';
|
|
7
|
+
import { spawnSync } from 'child_process';
|
|
8
|
+
|
|
9
|
+
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
10
|
+
const { version: VERSION } = JSON.parse(readFileSync(join(__dirname, '..', 'package.json'), 'utf8'));
|
|
11
|
+
const CLAUDE_DIR = join(homedir(), '.claude');
|
|
12
|
+
const SRC_DIR = join(__dirname, '..', '.claude');
|
|
13
|
+
|
|
14
|
+
const args = process.argv.slice(2);
|
|
15
|
+
|
|
16
|
+
if (args.includes('--version') || args.includes('-v')) {
|
|
17
|
+
console.log(VERSION);
|
|
18
|
+
process.exit(0);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
if (args[0] !== 'init') {
|
|
22
|
+
console.log(`Usage: npx @oorn/claw-statusline init`);
|
|
23
|
+
process.exit(1);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
// --- init ---
|
|
27
|
+
|
|
28
|
+
const green = (s) => `\x1b[32m${s}\x1b[0m`;
|
|
29
|
+
const dim = (s) => `\x1b[90m${s}\x1b[0m`;
|
|
30
|
+
const bold = (s) => `\x1b[1m${s}\x1b[0m`;
|
|
31
|
+
|
|
32
|
+
console.log(`\n${bold('claw-statusline')} — installing Claude Code config\n`);
|
|
33
|
+
|
|
34
|
+
function installFile(src, dest) {
|
|
35
|
+
const destDir = dirname(dest);
|
|
36
|
+
if (!existsSync(destDir)) mkdirSync(destDir, { recursive: true });
|
|
37
|
+
copyFileSync(src, dest);
|
|
38
|
+
const rel = dest.replace(homedir(), '~');
|
|
39
|
+
console.log(` ${green('✓')} ${rel}`);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
function installDir(srcDir, destDir) {
|
|
43
|
+
if (!existsSync(srcDir)) return;
|
|
44
|
+
for (const file of readdirSync(srcDir)) {
|
|
45
|
+
const src = join(srcDir, file);
|
|
46
|
+
if (statSync(src).isFile()) {
|
|
47
|
+
installFile(src, join(destDir, file));
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
// Top-level files
|
|
53
|
+
for (const file of ['settings.json', 'statusline-command.sh']) {
|
|
54
|
+
const src = join(SRC_DIR, file);
|
|
55
|
+
if (existsSync(src)) installFile(src, join(CLAUDE_DIR, file));
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
// rules/
|
|
59
|
+
installDir(join(SRC_DIR, 'rules'), join(CLAUDE_DIR, 'rules'));
|
|
60
|
+
|
|
61
|
+
// skills/
|
|
62
|
+
const skillsSrc = join(SRC_DIR, 'skills');
|
|
63
|
+
if (existsSync(skillsSrc)) {
|
|
64
|
+
for (const skill of readdirSync(skillsSrc)) {
|
|
65
|
+
const skillDir = join(skillsSrc, skill);
|
|
66
|
+
if (statSync(skillDir).isDirectory()) {
|
|
67
|
+
installDir(skillDir, join(CLAUDE_DIR, 'skills', skill));
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
// --- jq check ---
|
|
73
|
+
const yellow = (s) => `\x1b[33m${s}\x1b[0m`;
|
|
74
|
+
|
|
75
|
+
function hasCmd(cmd) {
|
|
76
|
+
return spawnSync(cmd, ['--version'], { stdio: 'ignore' }).status === 0;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
function tryInstall(label, ...args) {
|
|
80
|
+
console.log(` ${yellow('!')} jq not found — installing via ${label}…`);
|
|
81
|
+
return spawnSync(args[0], args.slice(1), { stdio: 'inherit' }).status === 0;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
function installJq() {
|
|
85
|
+
const os = platform();
|
|
86
|
+
|
|
87
|
+
if (os === 'darwin') {
|
|
88
|
+
if (hasCmd('brew')) return tryInstall('Homebrew', 'brew', 'install', 'jq');
|
|
89
|
+
if (hasCmd('port')) return tryInstall('MacPorts', 'sudo', 'port', 'install', 'jq');
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
if (os === 'linux') {
|
|
93
|
+
if (hasCmd('apt-get')) return tryInstall('apt', 'sudo', 'apt-get', 'install', '-y', 'jq');
|
|
94
|
+
if (hasCmd('dnf')) return tryInstall('dnf', 'sudo', 'dnf', 'install', '-y', 'jq');
|
|
95
|
+
if (hasCmd('yum')) return tryInstall('yum', 'sudo', 'yum', 'install', '-y', 'jq');
|
|
96
|
+
if (hasCmd('pacman')) return tryInstall('pacman', 'sudo', 'pacman', '-S', '--noconfirm', 'jq');
|
|
97
|
+
if (hasCmd('zypper')) return tryInstall('zypper', 'sudo', 'zypper', 'install', '-y', 'jq');
|
|
98
|
+
if (hasCmd('apk')) return tryInstall('apk', 'sudo', 'apk', 'add', 'jq');
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
if (os === 'win32') {
|
|
102
|
+
if (hasCmd('winget')) return tryInstall('winget', 'winget', 'install', '--id', 'jqlang.jq', '-e', '--silent');
|
|
103
|
+
if (hasCmd('choco')) return tryInstall('Chocolatey', 'choco', 'install', 'jq', '-y');
|
|
104
|
+
if (hasCmd('scoop')) return tryInstall('Scoop', 'scoop', 'install', 'jq');
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
return false;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
if (!hasCmd('jq')) {
|
|
111
|
+
const installed = installJq();
|
|
112
|
+
if (installed) {
|
|
113
|
+
console.log(` ${green('✓')} jq installed`);
|
|
114
|
+
} else {
|
|
115
|
+
console.log(`\n ${yellow('!')} jq is required for the statusline but could not be installed automatically.`);
|
|
116
|
+
console.log(` ${dim('Install it manually:')}`);
|
|
117
|
+
console.log(` ${dim(' macOS: brew install jq')}`);
|
|
118
|
+
console.log(` ${dim(' Ubuntu: sudo apt install jq')}`);
|
|
119
|
+
console.log(` ${dim(' Fedora: sudo dnf install jq')}`);
|
|
120
|
+
console.log(` ${dim(' Arch: sudo pacman -S jq')}`);
|
|
121
|
+
console.log(` ${dim(' Alpine: sudo apk add jq')}`);
|
|
122
|
+
console.log(` ${dim(' Windows: winget install jqlang.jq')}`);
|
|
123
|
+
}
|
|
124
|
+
} else {
|
|
125
|
+
console.log(` ${green('✓')} jq`);
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
console.log(`\n${dim('Claude Code will pick up changes automatically.')}`);
|
|
129
|
+
console.log(`${dim('To update: npx @oorn/claw-statusline@latest init')}\n`);
|
package/package.json
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@oorn/claw-statusline",
|
|
3
|
+
"version": "1.2.0",
|
|
4
|
+
"description": "Claude Code statusline, settings, and rules installer",
|
|
5
|
+
"bin": {
|
|
6
|
+
"claw-statusline": "bin/cli.js"
|
|
7
|
+
},
|
|
8
|
+
"files": [
|
|
9
|
+
"bin/",
|
|
10
|
+
".claude/"
|
|
11
|
+
],
|
|
12
|
+
"scripts": {
|
|
13
|
+
"prepublishOnly": "node bin/cli.js --version"
|
|
14
|
+
},
|
|
15
|
+
"keywords": [
|
|
16
|
+
"claude",
|
|
17
|
+
"claude-code",
|
|
18
|
+
"dotfiles"
|
|
19
|
+
],
|
|
20
|
+
"author": "oorn",
|
|
21
|
+
"type": "module",
|
|
22
|
+
"license": "MIT",
|
|
23
|
+
"engines": {
|
|
24
|
+
"node": ">=18"
|
|
25
|
+
}
|
|
26
|
+
}
|