claude-friends 0.4.9 → 0.4.11
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/package.json +1 -1
- package/statusline.js +37 -13
package/package.json
CHANGED
package/statusline.js
CHANGED
|
@@ -7,6 +7,20 @@ import { join, basename } from "path";
|
|
|
7
7
|
import { homedir } from "os";
|
|
8
8
|
import { execSync } from "child_process";
|
|
9
9
|
|
|
10
|
+
// ANSI colors
|
|
11
|
+
const RESET = "\x1b[0m";
|
|
12
|
+
const BOLD = "\x1b[1m";
|
|
13
|
+
const DIM = "\x1b[2m";
|
|
14
|
+
const GRAY = "\x1b[90m";
|
|
15
|
+
const WHITE = "\x1b[97m";
|
|
16
|
+
const CYAN = "\x1b[36m";
|
|
17
|
+
const GREEN = "\x1b[32m";
|
|
18
|
+
const YELLOW = "\x1b[33m";
|
|
19
|
+
const MAGENTA = "\x1b[35m";
|
|
20
|
+
const BLUE = "\x1b[34m";
|
|
21
|
+
|
|
22
|
+
const SEP = ` ${GRAY}|${RESET} `;
|
|
23
|
+
|
|
10
24
|
// Read JSON from stdin
|
|
11
25
|
let input = "";
|
|
12
26
|
try {
|
|
@@ -23,7 +37,7 @@ const segments = [];
|
|
|
23
37
|
// 1. Project name
|
|
24
38
|
const projectDir = data.workspace?.project_dir || data.cwd || "";
|
|
25
39
|
if (projectDir) {
|
|
26
|
-
segments.push(basename(projectDir));
|
|
40
|
+
segments.push(`${WHITE}${basename(projectDir)}${RESET}`);
|
|
27
41
|
}
|
|
28
42
|
|
|
29
43
|
// 2. Git branch
|
|
@@ -33,7 +47,7 @@ try {
|
|
|
33
47
|
stdio: ["pipe", "pipe", "pipe"],
|
|
34
48
|
}).toString().trim();
|
|
35
49
|
if (branch) {
|
|
36
|
-
segments.push(
|
|
50
|
+
segments.push(`${MAGENTA}\u2387 ${branch}${RESET}`);
|
|
37
51
|
}
|
|
38
52
|
} catch {}
|
|
39
53
|
|
|
@@ -47,7 +61,7 @@ if (data.model) {
|
|
|
47
61
|
.replace("opus-4-6", "Opus 4.6")
|
|
48
62
|
.replace("sonnet-4-6", "Sonnet 4.6")
|
|
49
63
|
.replace("haiku-4-5-20251001", "Haiku 4.5");
|
|
50
|
-
segments.push(
|
|
64
|
+
segments.push(`${CYAN}\u{1F916} ${short}${RESET}`);
|
|
51
65
|
}
|
|
52
66
|
|
|
53
67
|
// 4. Tokens
|
|
@@ -55,7 +69,7 @@ const totalIn = data.context_window?.total_input_tokens;
|
|
|
55
69
|
const totalOut = data.context_window?.total_output_tokens;
|
|
56
70
|
if (totalIn != null || totalOut != null) {
|
|
57
71
|
const total = (totalIn || 0) + (totalOut || 0);
|
|
58
|
-
segments.push(`${formatNum(total)} tokens`);
|
|
72
|
+
segments.push(`${BLUE}${formatNum(total)} tokens${RESET}`);
|
|
59
73
|
}
|
|
60
74
|
|
|
61
75
|
// 5. Tool calls (grep count only — never reads conversation content)
|
|
@@ -66,30 +80,41 @@ if (data.transcript_path) {
|
|
|
66
80
|
{ stdio: ["pipe", "pipe", "pipe"] }
|
|
67
81
|
).toString().trim();
|
|
68
82
|
const n = parseInt(count, 10);
|
|
69
|
-
if (n > 0) segments.push(
|
|
83
|
+
if (n > 0) segments.push(`${YELLOW}\u{1F527} ${n}${RESET}`);
|
|
70
84
|
} catch {}
|
|
71
85
|
}
|
|
72
86
|
|
|
73
87
|
// 6. Cost
|
|
74
88
|
if (data.cost?.total_cost_usd != null) {
|
|
75
|
-
|
|
89
|
+
const cost = data.cost.total_cost_usd;
|
|
90
|
+
const color = cost > 10 ? YELLOW : GREEN;
|
|
91
|
+
segments.push(`${color}$${cost.toFixed(2)}${RESET}`);
|
|
76
92
|
}
|
|
77
93
|
|
|
78
|
-
//
|
|
79
|
-
|
|
94
|
+
// 7. Streak
|
|
95
|
+
const streak = getStreak();
|
|
96
|
+
segments.push(`\u{1F525} ${streak}d`);
|
|
80
97
|
|
|
81
98
|
// 8. Friends online
|
|
82
99
|
const friends = getFriendsOnline();
|
|
100
|
+
const onlineColor = friends.count > 0 ? GREEN : GRAY;
|
|
83
101
|
const dot = friends.count > 0 ? "\u{1F7E2}" : "\u25CB";
|
|
84
102
|
const names = friends.names.length > 0
|
|
85
103
|
? ` (${friends.names.slice(0, 3).join(", ")}${friends.names.length > 3 ? "\u2026" : ""})`
|
|
86
104
|
: "";
|
|
87
|
-
segments.push(`${dot} ${friends.count} online${names}`);
|
|
105
|
+
segments.push(`${onlineColor}${dot} ${friends.count} online${names}${RESET}`);
|
|
88
106
|
|
|
89
|
-
process.stdout.write(segments.join(
|
|
107
|
+
process.stdout.write(segments.join(SEP));
|
|
90
108
|
|
|
91
109
|
// --- Helpers ---
|
|
92
110
|
|
|
111
|
+
function localDateStr(d) {
|
|
112
|
+
const y = d.getFullYear();
|
|
113
|
+
const m = String(d.getMonth() + 1).padStart(2, "0");
|
|
114
|
+
const day = String(d.getDate()).padStart(2, "0");
|
|
115
|
+
return `${y}-${m}-${day}`;
|
|
116
|
+
}
|
|
117
|
+
|
|
93
118
|
function formatNum(n) {
|
|
94
119
|
if (n >= 1_000_000) return `${(n / 1_000_000).toFixed(1)}M`;
|
|
95
120
|
if (n >= 1_000) return `${(n / 1_000).toFixed(1)}K`;
|
|
@@ -107,7 +132,6 @@ function getFriendsOnline() {
|
|
|
107
132
|
}
|
|
108
133
|
|
|
109
134
|
function getStreak() {
|
|
110
|
-
// Collect dates of all session file modifications
|
|
111
135
|
const sessionsDir = join(homedir(), ".claude", "projects");
|
|
112
136
|
try {
|
|
113
137
|
if (!existsSync(sessionsDir)) return 0;
|
|
@@ -119,7 +143,7 @@ function getStreak() {
|
|
|
119
143
|
for (let i = 0; i < 365; i++) {
|
|
120
144
|
const d = new Date(today);
|
|
121
145
|
d.setDate(d.getDate() - i);
|
|
122
|
-
const dateStr = d
|
|
146
|
+
const dateStr = localDateStr(d);
|
|
123
147
|
if (activeDates.has(dateStr)) {
|
|
124
148
|
streak++;
|
|
125
149
|
} else if (i > 0) {
|
|
@@ -142,7 +166,7 @@ function scanForDates(dir, dates, depth) {
|
|
|
142
166
|
} else if (entry.name.endsWith(".jsonl")) {
|
|
143
167
|
try {
|
|
144
168
|
const mtime = statSync(full).mtime;
|
|
145
|
-
dates.add(mtime
|
|
169
|
+
dates.add(localDateStr(mtime));
|
|
146
170
|
} catch {}
|
|
147
171
|
}
|
|
148
172
|
}
|