@owloops/claude-powerline 1.24.4 → 1.25.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/dist/browser.d.ts +676 -0
- package/dist/browser.js +3 -0
- package/dist/index.mjs +10 -10
- package/package.json +9 -1
- package/plugin/templates/config-tui-compact.json +4 -4
- package/plugin/templates/config-tui-full.json +5 -5
- package/plugin/templates/config-tui-standard.json +5 -5
- package/src/browser.ts +203 -0
- package/src/config/defaults.ts +79 -0
- package/src/config/loader.ts +462 -0
- package/src/index.ts +90 -0
- package/src/powerline.ts +904 -0
- package/src/segments/block.ts +31 -0
- package/src/segments/context.ts +221 -0
- package/src/segments/git.ts +492 -0
- package/src/segments/index.ts +25 -0
- package/src/segments/metrics.ts +175 -0
- package/src/segments/pricing.ts +454 -0
- package/src/segments/renderer.ts +796 -0
- package/src/segments/session.ts +207 -0
- package/src/segments/tmux.ts +35 -0
- package/src/segments/today.ts +191 -0
- package/src/themes/dark.ts +52 -0
- package/src/themes/gruvbox.ts +52 -0
- package/src/themes/index.ts +131 -0
- package/src/themes/light.ts +52 -0
- package/src/themes/nord.ts +52 -0
- package/src/themes/rose-pine.ts +52 -0
- package/src/themes/tokyo-night.ts +52 -0
- package/src/tui/grid.ts +712 -0
- package/src/tui/index.ts +4 -0
- package/src/tui/layouts.ts +285 -0
- package/src/tui/primitives.ts +175 -0
- package/src/tui/renderer.ts +206 -0
- package/src/tui/sections.ts +1080 -0
- package/src/tui/types.ts +181 -0
- package/src/utils/budget.ts +47 -0
- package/src/utils/cache.ts +247 -0
- package/src/utils/claude.ts +489 -0
- package/src/utils/color-support.ts +118 -0
- package/src/utils/colors.ts +120 -0
- package/src/utils/constants.ts +176 -0
- package/src/utils/formatters.ts +160 -0
- package/src/utils/logger.ts +5 -0
- package/src/utils/terminal-width.ts +117 -0
- package/src/utils/terminal.ts +11 -0
|
@@ -0,0 +1,207 @@
|
|
|
1
|
+
import { debug } from "../utils/logger";
|
|
2
|
+
import { PricingService } from "./pricing";
|
|
3
|
+
import {
|
|
4
|
+
findTranscriptFile,
|
|
5
|
+
findAgentTranscripts,
|
|
6
|
+
parseJsonlFile,
|
|
7
|
+
type ParsedEntry,
|
|
8
|
+
type ClaudeHookData,
|
|
9
|
+
} from "../utils/claude";
|
|
10
|
+
import { dirname } from "node:path";
|
|
11
|
+
|
|
12
|
+
export interface SessionUsageEntry {
|
|
13
|
+
timestamp: string;
|
|
14
|
+
message: {
|
|
15
|
+
usage: {
|
|
16
|
+
input_tokens: number;
|
|
17
|
+
output_tokens: number;
|
|
18
|
+
cache_creation_input_tokens?: number;
|
|
19
|
+
cache_read_input_tokens?: number;
|
|
20
|
+
};
|
|
21
|
+
};
|
|
22
|
+
costUSD?: number;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export interface SessionUsage {
|
|
26
|
+
totalCost: number;
|
|
27
|
+
entries: SessionUsageEntry[];
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export interface TokenBreakdown {
|
|
31
|
+
input: number;
|
|
32
|
+
output: number;
|
|
33
|
+
cacheCreation: number;
|
|
34
|
+
cacheRead: number;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export interface SessionInfo {
|
|
38
|
+
cost: number | null;
|
|
39
|
+
calculatedCost: number | null;
|
|
40
|
+
officialCost: number | null;
|
|
41
|
+
tokens: number | null;
|
|
42
|
+
tokenBreakdown: TokenBreakdown | null;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export interface UsageInfo {
|
|
46
|
+
session: SessionInfo;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
function convertToSessionEntry(entry: ParsedEntry): SessionUsageEntry {
|
|
50
|
+
return {
|
|
51
|
+
timestamp: entry.timestamp.toISOString(),
|
|
52
|
+
message: {
|
|
53
|
+
usage: {
|
|
54
|
+
input_tokens: entry.message?.usage?.input_tokens || 0,
|
|
55
|
+
output_tokens: entry.message?.usage?.output_tokens || 0,
|
|
56
|
+
cache_creation_input_tokens:
|
|
57
|
+
entry.message?.usage?.cache_creation_input_tokens,
|
|
58
|
+
cache_read_input_tokens: entry.message?.usage?.cache_read_input_tokens,
|
|
59
|
+
},
|
|
60
|
+
},
|
|
61
|
+
costUSD: entry.costUSD,
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
export class SessionProvider {
|
|
66
|
+
async getSessionUsage(sessionId: string): Promise<SessionUsage | null> {
|
|
67
|
+
try {
|
|
68
|
+
const transcriptPath = await findTranscriptFile(sessionId);
|
|
69
|
+
if (!transcriptPath) {
|
|
70
|
+
debug(`No transcript found for session: ${sessionId}`);
|
|
71
|
+
return null;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
debug(`Found transcript at: ${transcriptPath}`);
|
|
75
|
+
|
|
76
|
+
const parsedEntries = await parseJsonlFile(transcriptPath);
|
|
77
|
+
const projectPath = dirname(transcriptPath);
|
|
78
|
+
const agentTranscripts = await findAgentTranscripts(
|
|
79
|
+
sessionId,
|
|
80
|
+
projectPath,
|
|
81
|
+
);
|
|
82
|
+
|
|
83
|
+
debug(`Found ${agentTranscripts.length} agent transcripts for session`);
|
|
84
|
+
|
|
85
|
+
for (const agentPath of agentTranscripts) {
|
|
86
|
+
const agentEntries = await parseJsonlFile(agentPath);
|
|
87
|
+
parsedEntries.push(...agentEntries);
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
if (parsedEntries.length === 0) {
|
|
91
|
+
return { totalCost: 0, entries: [] };
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
const entries: SessionUsageEntry[] = [];
|
|
95
|
+
let totalCost = 0;
|
|
96
|
+
|
|
97
|
+
for (const entry of parsedEntries) {
|
|
98
|
+
if (entry.message?.usage) {
|
|
99
|
+
const sessionEntry = convertToSessionEntry(entry);
|
|
100
|
+
|
|
101
|
+
if (sessionEntry.costUSD !== undefined) {
|
|
102
|
+
totalCost += sessionEntry.costUSD;
|
|
103
|
+
} else {
|
|
104
|
+
const cost = await PricingService.calculateCostForEntry(entry.raw);
|
|
105
|
+
sessionEntry.costUSD = cost;
|
|
106
|
+
totalCost += cost;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
entries.push(sessionEntry);
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
debug(
|
|
114
|
+
`Parsed ${entries.length} usage entries, total cost: $${totalCost.toFixed(4)}`,
|
|
115
|
+
);
|
|
116
|
+
return { totalCost, entries };
|
|
117
|
+
} catch (error) {
|
|
118
|
+
debug(`Error reading session usage for ${sessionId}:`, error);
|
|
119
|
+
return null;
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
calculateTokenBreakdown(entries: SessionUsageEntry[]): TokenBreakdown {
|
|
124
|
+
return entries.reduce(
|
|
125
|
+
(breakdown, entry) => ({
|
|
126
|
+
input: breakdown.input + (entry.message.usage.input_tokens || 0),
|
|
127
|
+
output: breakdown.output + (entry.message.usage.output_tokens || 0),
|
|
128
|
+
cacheCreation:
|
|
129
|
+
breakdown.cacheCreation +
|
|
130
|
+
(entry.message.usage.cache_creation_input_tokens || 0),
|
|
131
|
+
cacheRead:
|
|
132
|
+
breakdown.cacheRead +
|
|
133
|
+
(entry.message.usage.cache_read_input_tokens || 0),
|
|
134
|
+
}),
|
|
135
|
+
{ input: 0, output: 0, cacheCreation: 0, cacheRead: 0 },
|
|
136
|
+
);
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
async getSessionInfo(
|
|
140
|
+
sessionId: string,
|
|
141
|
+
hookData?: ClaudeHookData,
|
|
142
|
+
): Promise<SessionInfo> {
|
|
143
|
+
const sessionUsage = await this.getSessionUsage(sessionId);
|
|
144
|
+
|
|
145
|
+
if (!sessionUsage || sessionUsage.entries.length === 0) {
|
|
146
|
+
return {
|
|
147
|
+
cost: null,
|
|
148
|
+
calculatedCost: null,
|
|
149
|
+
officialCost: null,
|
|
150
|
+
tokens: null,
|
|
151
|
+
tokenBreakdown: null,
|
|
152
|
+
};
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
const tokenBreakdown = this.calculateTokenBreakdown(sessionUsage.entries);
|
|
156
|
+
const totalTokens =
|
|
157
|
+
tokenBreakdown.input +
|
|
158
|
+
tokenBreakdown.output +
|
|
159
|
+
tokenBreakdown.cacheCreation +
|
|
160
|
+
tokenBreakdown.cacheRead;
|
|
161
|
+
|
|
162
|
+
const calculatedCost = sessionUsage.totalCost;
|
|
163
|
+
const hookDataCost = hookData?.cost?.total_cost_usd ?? null;
|
|
164
|
+
const cost = calculatedCost ?? hookDataCost;
|
|
165
|
+
|
|
166
|
+
return {
|
|
167
|
+
cost,
|
|
168
|
+
calculatedCost,
|
|
169
|
+
officialCost: hookDataCost,
|
|
170
|
+
tokens: totalTokens,
|
|
171
|
+
tokenBreakdown,
|
|
172
|
+
};
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
export class UsageProvider {
|
|
177
|
+
private sessionProvider = new SessionProvider();
|
|
178
|
+
|
|
179
|
+
async getUsageInfo(
|
|
180
|
+
sessionId: string,
|
|
181
|
+
hookData?: ClaudeHookData,
|
|
182
|
+
): Promise<UsageInfo> {
|
|
183
|
+
try {
|
|
184
|
+
debug(`Starting usage info retrieval for session: ${sessionId}`);
|
|
185
|
+
|
|
186
|
+
const sessionInfo = await this.sessionProvider.getSessionInfo(
|
|
187
|
+
sessionId,
|
|
188
|
+
hookData,
|
|
189
|
+
);
|
|
190
|
+
|
|
191
|
+
return {
|
|
192
|
+
session: sessionInfo,
|
|
193
|
+
};
|
|
194
|
+
} catch (error) {
|
|
195
|
+
debug(`Error getting usage info for session ${sessionId}:`, error);
|
|
196
|
+
return {
|
|
197
|
+
session: {
|
|
198
|
+
cost: null,
|
|
199
|
+
calculatedCost: null,
|
|
200
|
+
officialCost: null,
|
|
201
|
+
tokens: null,
|
|
202
|
+
tokenBreakdown: null,
|
|
203
|
+
},
|
|
204
|
+
};
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { exec } from "node:child_process";
|
|
2
|
+
import { promisify } from "node:util";
|
|
3
|
+
import { debug } from "../utils/logger";
|
|
4
|
+
|
|
5
|
+
const execAsync = promisify(exec);
|
|
6
|
+
|
|
7
|
+
export class TmuxService {
|
|
8
|
+
async getSessionId(): Promise<string | null> {
|
|
9
|
+
try {
|
|
10
|
+
if (!process.env.TMUX_PANE) {
|
|
11
|
+
debug(`TMUX_PANE not set, not in tmux session`);
|
|
12
|
+
return null;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
debug(`Getting tmux session ID, TMUX_PANE: ${process.env.TMUX_PANE}`);
|
|
16
|
+
|
|
17
|
+
const result = await execAsync("tmux display-message -p '#S'", {
|
|
18
|
+
encoding: "utf8",
|
|
19
|
+
timeout: 1000,
|
|
20
|
+
});
|
|
21
|
+
const sessionId = result.stdout.trim();
|
|
22
|
+
|
|
23
|
+
debug(`Tmux session ID: ${sessionId || "empty"}`);
|
|
24
|
+
|
|
25
|
+
return sessionId || null;
|
|
26
|
+
} catch (error) {
|
|
27
|
+
debug(`Error getting tmux session ID:`, error);
|
|
28
|
+
return null;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
isInTmux(): boolean {
|
|
33
|
+
return !!process.env.TMUX_PANE;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
import type { ParsedEntry } from "../utils/claude";
|
|
2
|
+
import type { TokenBreakdown } from "./session";
|
|
3
|
+
|
|
4
|
+
import { debug } from "../utils/logger";
|
|
5
|
+
import { PricingService } from "./pricing";
|
|
6
|
+
import { CacheManager } from "../utils/cache";
|
|
7
|
+
import { loadEntriesFromProjects } from "../utils/claude";
|
|
8
|
+
|
|
9
|
+
export interface TodayUsageEntry {
|
|
10
|
+
timestamp: Date;
|
|
11
|
+
usage: {
|
|
12
|
+
inputTokens: number;
|
|
13
|
+
outputTokens: number;
|
|
14
|
+
cacheCreationInputTokens: number;
|
|
15
|
+
cacheReadInputTokens: number;
|
|
16
|
+
};
|
|
17
|
+
costUSD: number;
|
|
18
|
+
model: string;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export interface TodayInfo {
|
|
22
|
+
cost: number | null;
|
|
23
|
+
tokens: number | null;
|
|
24
|
+
tokenBreakdown: TokenBreakdown | null;
|
|
25
|
+
date: string;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
function formatDate(date: Date): string {
|
|
29
|
+
const year = date.getFullYear();
|
|
30
|
+
const month = String(date.getMonth() + 1).padStart(2, "0");
|
|
31
|
+
const day = String(date.getDate()).padStart(2, "0");
|
|
32
|
+
return `${year}-${month}-${day}`;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
function getTotalTokens(usage: TodayUsageEntry["usage"]): number {
|
|
36
|
+
return (
|
|
37
|
+
usage.inputTokens +
|
|
38
|
+
usage.outputTokens +
|
|
39
|
+
usage.cacheCreationInputTokens +
|
|
40
|
+
usage.cacheReadInputTokens
|
|
41
|
+
);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
function convertToTodayEntry(entry: ParsedEntry): TodayUsageEntry {
|
|
45
|
+
return {
|
|
46
|
+
timestamp: entry.timestamp,
|
|
47
|
+
usage: {
|
|
48
|
+
inputTokens: entry.message?.usage?.input_tokens || 0,
|
|
49
|
+
outputTokens: entry.message?.usage?.output_tokens || 0,
|
|
50
|
+
cacheCreationInputTokens:
|
|
51
|
+
entry.message?.usage?.cache_creation_input_tokens || 0,
|
|
52
|
+
cacheReadInputTokens: entry.message?.usage?.cache_read_input_tokens || 0,
|
|
53
|
+
},
|
|
54
|
+
costUSD: entry.costUSD || 0,
|
|
55
|
+
model: entry.message?.model || "unknown",
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
export class TodayProvider {
|
|
60
|
+
private async loadTodayEntries(): Promise<TodayUsageEntry[]> {
|
|
61
|
+
const today = new Date();
|
|
62
|
+
const todayDateString = formatDate(today);
|
|
63
|
+
|
|
64
|
+
debug(`Today segment: Loading entries for date ${todayDateString}`);
|
|
65
|
+
|
|
66
|
+
const latestMtime = await CacheManager.getLatestTranscriptMtime();
|
|
67
|
+
|
|
68
|
+
const sharedCached = (await CacheManager.getUsageCache(
|
|
69
|
+
"today",
|
|
70
|
+
latestMtime,
|
|
71
|
+
)) as TodayUsageEntry[] | null;
|
|
72
|
+
if (sharedCached) {
|
|
73
|
+
debug("Using shared today usage cache");
|
|
74
|
+
return sharedCached;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
const yesterday = new Date();
|
|
78
|
+
yesterday.setDate(yesterday.getDate() - 1);
|
|
79
|
+
yesterday.setHours(0, 0, 0, 0);
|
|
80
|
+
|
|
81
|
+
const fileFilter = (_filePath: string, modTime: Date): boolean => {
|
|
82
|
+
return modTime >= yesterday;
|
|
83
|
+
};
|
|
84
|
+
|
|
85
|
+
const todayMidnight = new Date();
|
|
86
|
+
todayMidnight.setHours(0, 0, 0, 0);
|
|
87
|
+
|
|
88
|
+
const timeFilter = (entry: ParsedEntry): boolean => {
|
|
89
|
+
return entry.timestamp >= todayMidnight;
|
|
90
|
+
};
|
|
91
|
+
|
|
92
|
+
const parsedEntries = await loadEntriesFromProjects(
|
|
93
|
+
timeFilter,
|
|
94
|
+
fileFilter,
|
|
95
|
+
true,
|
|
96
|
+
);
|
|
97
|
+
const todayEntries: TodayUsageEntry[] = [];
|
|
98
|
+
|
|
99
|
+
let entriesFound = 0;
|
|
100
|
+
|
|
101
|
+
for (const entry of parsedEntries) {
|
|
102
|
+
const entryDateString = formatDate(entry.timestamp);
|
|
103
|
+
|
|
104
|
+
if (entryDateString === todayDateString && entry.message?.usage) {
|
|
105
|
+
const todayEntry = convertToTodayEntry(entry);
|
|
106
|
+
|
|
107
|
+
if (!todayEntry.costUSD && entry.raw) {
|
|
108
|
+
todayEntry.costUSD = await PricingService.calculateCostForEntry(
|
|
109
|
+
entry.raw,
|
|
110
|
+
);
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
todayEntries.push(todayEntry);
|
|
114
|
+
entriesFound++;
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
debug(
|
|
119
|
+
`Today segment: Found ${entriesFound} entries for today (${todayDateString})`,
|
|
120
|
+
);
|
|
121
|
+
|
|
122
|
+
await CacheManager.setUsageCache("today", todayEntries, latestMtime);
|
|
123
|
+
|
|
124
|
+
return todayEntries;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
private async getTodayEntries(): Promise<TodayUsageEntry[]> {
|
|
128
|
+
try {
|
|
129
|
+
return await this.loadTodayEntries();
|
|
130
|
+
} catch (error) {
|
|
131
|
+
debug("Error loading today's entries:", error);
|
|
132
|
+
return [];
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
async getTodayInfo(): Promise<TodayInfo> {
|
|
137
|
+
try {
|
|
138
|
+
const entries = await this.getTodayEntries();
|
|
139
|
+
|
|
140
|
+
if (entries.length === 0) {
|
|
141
|
+
return {
|
|
142
|
+
cost: null,
|
|
143
|
+
tokens: null,
|
|
144
|
+
tokenBreakdown: null,
|
|
145
|
+
date: formatDate(new Date()),
|
|
146
|
+
};
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
const totalCost = entries.reduce((sum, entry) => sum + entry.costUSD, 0);
|
|
150
|
+
const totalTokens = entries.reduce(
|
|
151
|
+
(sum, entry) => sum + getTotalTokens(entry.usage),
|
|
152
|
+
0,
|
|
153
|
+
);
|
|
154
|
+
|
|
155
|
+
const tokenBreakdown = entries.reduce(
|
|
156
|
+
(breakdown, entry) => ({
|
|
157
|
+
input: breakdown.input + entry.usage.inputTokens,
|
|
158
|
+
output: breakdown.output + entry.usage.outputTokens,
|
|
159
|
+
cacheCreation:
|
|
160
|
+
breakdown.cacheCreation + entry.usage.cacheCreationInputTokens,
|
|
161
|
+
cacheRead: breakdown.cacheRead + entry.usage.cacheReadInputTokens,
|
|
162
|
+
}),
|
|
163
|
+
{
|
|
164
|
+
input: 0,
|
|
165
|
+
output: 0,
|
|
166
|
+
cacheCreation: 0,
|
|
167
|
+
cacheRead: 0,
|
|
168
|
+
},
|
|
169
|
+
);
|
|
170
|
+
|
|
171
|
+
debug(
|
|
172
|
+
`Today segment: $${totalCost.toFixed(2)}, ${totalTokens} tokens total`,
|
|
173
|
+
);
|
|
174
|
+
|
|
175
|
+
return {
|
|
176
|
+
cost: totalCost,
|
|
177
|
+
tokens: totalTokens,
|
|
178
|
+
tokenBreakdown,
|
|
179
|
+
date: formatDate(new Date()),
|
|
180
|
+
};
|
|
181
|
+
} catch (error) {
|
|
182
|
+
debug("Error getting today's info:", error);
|
|
183
|
+
return {
|
|
184
|
+
cost: null,
|
|
185
|
+
tokens: null,
|
|
186
|
+
tokenBreakdown: null,
|
|
187
|
+
date: formatDate(new Date()),
|
|
188
|
+
};
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import type { ColorTheme } from "./index";
|
|
2
|
+
|
|
3
|
+
export const darkTheme: ColorTheme = {
|
|
4
|
+
directory: { bg: "#8b4513", fg: "#ffffff" },
|
|
5
|
+
git: { bg: "#404040", fg: "#ffffff" },
|
|
6
|
+
model: { bg: "#2d2d2d", fg: "#ffffff" },
|
|
7
|
+
session: { bg: "#202020", fg: "#00ffff" },
|
|
8
|
+
block: { bg: "#2a2a2a", fg: "#87ceeb" },
|
|
9
|
+
today: { bg: "#1a1a1a", fg: "#98fb98" },
|
|
10
|
+
tmux: { bg: "#2f4f2f", fg: "#90ee90" },
|
|
11
|
+
context: { bg: "#4a5568", fg: "#cbd5e0" },
|
|
12
|
+
contextWarning: { bg: "#92400e", fg: "#fbbf24" },
|
|
13
|
+
contextCritical: { bg: "#991b1b", fg: "#fca5a5" },
|
|
14
|
+
metrics: { bg: "#374151", fg: "#d1d5db" },
|
|
15
|
+
version: { bg: "#3a3a4a", fg: "#b8b8d0" },
|
|
16
|
+
env: { bg: "#2d2d3d", fg: "#d0a0d0" },
|
|
17
|
+
weekly: { bg: "#2a2a3a", fg: "#a0c4e8" },
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
export const darkAnsi256Theme: ColorTheme = {
|
|
21
|
+
directory: { bg: "#af5f00", fg: "#ffffff" },
|
|
22
|
+
git: { bg: "#444444", fg: "#ffffff" },
|
|
23
|
+
model: { bg: "#3a3a3a", fg: "#ffffff" },
|
|
24
|
+
session: { bg: "#262626", fg: "#00ffff" },
|
|
25
|
+
block: { bg: "#303030", fg: "#87ceeb" },
|
|
26
|
+
today: { bg: "#1c1c1c", fg: "#87ff87" },
|
|
27
|
+
tmux: { bg: "#444444", fg: "#87ff87" },
|
|
28
|
+
context: { bg: "#585858", fg: "#d0d0d0" },
|
|
29
|
+
contextWarning: { bg: "#af5f00", fg: "#ffaf00" },
|
|
30
|
+
contextCritical: { bg: "#870000", fg: "#ff8787" },
|
|
31
|
+
metrics: { bg: "#4e4e4e", fg: "#d0d0d0" },
|
|
32
|
+
version: { bg: "#444444", fg: "#d7afff" },
|
|
33
|
+
env: { bg: "#3a3a3a", fg: "#d787d7" },
|
|
34
|
+
weekly: { bg: "#303030", fg: "#87afd7" },
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
export const darkAnsiTheme: ColorTheme = {
|
|
38
|
+
directory: { bg: "#d75f00", fg: "#ffffff" },
|
|
39
|
+
git: { bg: "#585858", fg: "#ffffff" },
|
|
40
|
+
model: { bg: "#444444", fg: "#ffffff" },
|
|
41
|
+
session: { bg: "#303030", fg: "#00ffff" },
|
|
42
|
+
block: { bg: "#3a3a3a", fg: "#5fafff" },
|
|
43
|
+
today: { bg: "#262626", fg: "#00ff00" },
|
|
44
|
+
tmux: { bg: "#585858", fg: "#00ff00" },
|
|
45
|
+
context: { bg: "#808080", fg: "#ffffff" },
|
|
46
|
+
contextWarning: { bg: "#d75f00", fg: "#ffff00" },
|
|
47
|
+
contextCritical: { bg: "#af0000", fg: "#ff0000" },
|
|
48
|
+
metrics: { bg: "#666666", fg: "#ffffff" },
|
|
49
|
+
version: { bg: "#585858", fg: "#af87ff" },
|
|
50
|
+
env: { bg: "#444444", fg: "#ff87ff" },
|
|
51
|
+
weekly: { bg: "#3a3a3a", fg: "#5fafff" },
|
|
52
|
+
};
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import type { ColorTheme } from "./index";
|
|
2
|
+
|
|
3
|
+
export const gruvboxTheme: ColorTheme = {
|
|
4
|
+
directory: { bg: "#504945", fg: "#ebdbb2" },
|
|
5
|
+
git: { bg: "#3c3836", fg: "#b8bb26" },
|
|
6
|
+
model: { bg: "#665c54", fg: "#83a598" },
|
|
7
|
+
session: { bg: "#282828", fg: "#8ec07c" },
|
|
8
|
+
block: { bg: "#3c3836", fg: "#83a598" },
|
|
9
|
+
today: { bg: "#282828", fg: "#fabd2f" },
|
|
10
|
+
tmux: { bg: "#282828", fg: "#fe8019" },
|
|
11
|
+
context: { bg: "#458588", fg: "#ebdbb2" },
|
|
12
|
+
contextWarning: { bg: "#d79921", fg: "#282828" },
|
|
13
|
+
contextCritical: { bg: "#cc241d", fg: "#ebdbb2" },
|
|
14
|
+
metrics: { bg: "#d3869b", fg: "#282828" },
|
|
15
|
+
version: { bg: "#504945", fg: "#8ec07c" },
|
|
16
|
+
env: { bg: "#3c3836", fg: "#d3869b" },
|
|
17
|
+
weekly: { bg: "#3c3836", fg: "#8ec07c" },
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
export const gruvboxAnsi256Theme: ColorTheme = {
|
|
21
|
+
directory: { bg: "#585858", fg: "#ffffaf" },
|
|
22
|
+
git: { bg: "#444444", fg: "#afaf00" },
|
|
23
|
+
model: { bg: "#6c6c6c", fg: "#87afaf" },
|
|
24
|
+
session: { bg: "#303030", fg: "#87af87" },
|
|
25
|
+
block: { bg: "#444444", fg: "#87afaf" },
|
|
26
|
+
today: { bg: "#303030", fg: "#ffaf00" },
|
|
27
|
+
tmux: { bg: "#303030", fg: "#ff8700" },
|
|
28
|
+
context: { bg: "#5f8787", fg: "#ffffaf" },
|
|
29
|
+
contextWarning: { bg: "#d7af00", fg: "#303030" },
|
|
30
|
+
contextCritical: { bg: "#d70000", fg: "#ffffaf" },
|
|
31
|
+
metrics: { bg: "#d787af", fg: "#303030" },
|
|
32
|
+
version: { bg: "#585858", fg: "#87af87" },
|
|
33
|
+
env: { bg: "#444444", fg: "#d787af" },
|
|
34
|
+
weekly: { bg: "#444444", fg: "#87af87" },
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
export const gruvboxAnsiTheme: ColorTheme = {
|
|
38
|
+
directory: { bg: "#808080", fg: "#ffff00" },
|
|
39
|
+
git: { bg: "#585858", fg: "#00ff00" },
|
|
40
|
+
model: { bg: "#808080", fg: "#00afff" },
|
|
41
|
+
session: { bg: "#444444", fg: "#00d787" },
|
|
42
|
+
block: { bg: "#585858", fg: "#00afff" },
|
|
43
|
+
today: { bg: "#444444", fg: "#ffaf00" },
|
|
44
|
+
tmux: { bg: "#444444", fg: "#ff8700" },
|
|
45
|
+
context: { bg: "#008787", fg: "#ffffff" },
|
|
46
|
+
contextWarning: { bg: "#d7af00", fg: "#000000" },
|
|
47
|
+
contextCritical: { bg: "#d70000", fg: "#ffffff" },
|
|
48
|
+
metrics: { bg: "#ff87af", fg: "#444444" },
|
|
49
|
+
version: { bg: "#808080", fg: "#00d787" },
|
|
50
|
+
env: { bg: "#585858", fg: "#ff87af" },
|
|
51
|
+
weekly: { bg: "#585858", fg: "#00d787" },
|
|
52
|
+
};
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
import { darkTheme, darkAnsi256Theme, darkAnsiTheme } from "./dark";
|
|
2
|
+
import { lightTheme, lightAnsi256Theme, lightAnsiTheme } from "./light";
|
|
3
|
+
import { nordTheme, nordAnsi256Theme, nordAnsiTheme } from "./nord";
|
|
4
|
+
import {
|
|
5
|
+
tokyoNightTheme,
|
|
6
|
+
tokyoNightAnsi256Theme,
|
|
7
|
+
tokyoNightAnsiTheme,
|
|
8
|
+
} from "./tokyo-night";
|
|
9
|
+
import {
|
|
10
|
+
rosePineTheme,
|
|
11
|
+
rosePineAnsi256Theme,
|
|
12
|
+
rosePineAnsiTheme,
|
|
13
|
+
} from "./rose-pine";
|
|
14
|
+
import { gruvboxTheme, gruvboxAnsi256Theme, gruvboxAnsiTheme } from "./gruvbox";
|
|
15
|
+
|
|
16
|
+
export interface SegmentColor {
|
|
17
|
+
bg: string;
|
|
18
|
+
fg: string;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export interface ColorTheme {
|
|
22
|
+
directory: SegmentColor;
|
|
23
|
+
git: SegmentColor;
|
|
24
|
+
model: SegmentColor;
|
|
25
|
+
session: SegmentColor;
|
|
26
|
+
block: SegmentColor;
|
|
27
|
+
today: SegmentColor;
|
|
28
|
+
tmux: SegmentColor;
|
|
29
|
+
context: SegmentColor;
|
|
30
|
+
contextWarning: SegmentColor;
|
|
31
|
+
contextCritical: SegmentColor;
|
|
32
|
+
metrics: SegmentColor;
|
|
33
|
+
version: SegmentColor;
|
|
34
|
+
env: SegmentColor;
|
|
35
|
+
weekly: SegmentColor;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export interface PowerlineColors {
|
|
39
|
+
reset: string;
|
|
40
|
+
modeBg: string;
|
|
41
|
+
modeFg: string;
|
|
42
|
+
gitBg: string;
|
|
43
|
+
gitFg: string;
|
|
44
|
+
modelBg: string;
|
|
45
|
+
modelFg: string;
|
|
46
|
+
sessionBg: string;
|
|
47
|
+
sessionFg: string;
|
|
48
|
+
blockBg: string;
|
|
49
|
+
blockFg: string;
|
|
50
|
+
todayBg: string;
|
|
51
|
+
todayFg: string;
|
|
52
|
+
tmuxBg: string;
|
|
53
|
+
tmuxFg: string;
|
|
54
|
+
contextBg: string;
|
|
55
|
+
contextFg: string;
|
|
56
|
+
contextWarningBg: string;
|
|
57
|
+
contextWarningFg: string;
|
|
58
|
+
contextCriticalBg: string;
|
|
59
|
+
contextCriticalFg: string;
|
|
60
|
+
metricsBg: string;
|
|
61
|
+
metricsFg: string;
|
|
62
|
+
versionBg: string;
|
|
63
|
+
versionFg: string;
|
|
64
|
+
envBg: string;
|
|
65
|
+
envFg: string;
|
|
66
|
+
weeklyBg: string;
|
|
67
|
+
weeklyFg: string;
|
|
68
|
+
partFg: Record<string, string>;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
export const BUILT_IN_THEMES: Record<string, ColorTheme> = {
|
|
72
|
+
dark: darkTheme,
|
|
73
|
+
"dark-ansi256": darkAnsi256Theme,
|
|
74
|
+
"dark-ansi": darkAnsiTheme,
|
|
75
|
+
light: lightTheme,
|
|
76
|
+
"light-ansi256": lightAnsi256Theme,
|
|
77
|
+
"light-ansi": lightAnsiTheme,
|
|
78
|
+
nord: nordTheme,
|
|
79
|
+
"nord-ansi256": nordAnsi256Theme,
|
|
80
|
+
"nord-ansi": nordAnsiTheme,
|
|
81
|
+
"tokyo-night": tokyoNightTheme,
|
|
82
|
+
"tokyo-night-ansi256": tokyoNightAnsi256Theme,
|
|
83
|
+
"tokyo-night-ansi": tokyoNightAnsiTheme,
|
|
84
|
+
"rose-pine": rosePineTheme,
|
|
85
|
+
"rose-pine-ansi256": rosePineAnsi256Theme,
|
|
86
|
+
"rose-pine-ansi": rosePineAnsiTheme,
|
|
87
|
+
gruvbox: gruvboxTheme,
|
|
88
|
+
"gruvbox-ansi256": gruvboxAnsi256Theme,
|
|
89
|
+
"gruvbox-ansi": gruvboxAnsiTheme,
|
|
90
|
+
};
|
|
91
|
+
|
|
92
|
+
export function getTheme(
|
|
93
|
+
themeName: string,
|
|
94
|
+
colorSupport?: "none" | "ansi" | "ansi256" | "truecolor",
|
|
95
|
+
): ColorTheme | null {
|
|
96
|
+
const baseTheme = BUILT_IN_THEMES[themeName];
|
|
97
|
+
if (!baseTheme) return null;
|
|
98
|
+
|
|
99
|
+
if (colorSupport === "none" || colorSupport === "ansi") {
|
|
100
|
+
const ansiVariant = BUILT_IN_THEMES[`${themeName}-ansi`];
|
|
101
|
+
if (ansiVariant) return ansiVariant;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
if (colorSupport === "ansi256") {
|
|
105
|
+
const ansi256Variant = BUILT_IN_THEMES[`${themeName}-ansi256`];
|
|
106
|
+
if (ansi256Variant) return ansi256Variant;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
return baseTheme;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
export {
|
|
113
|
+
darkTheme,
|
|
114
|
+
darkAnsi256Theme,
|
|
115
|
+
darkAnsiTheme,
|
|
116
|
+
lightTheme,
|
|
117
|
+
lightAnsi256Theme,
|
|
118
|
+
lightAnsiTheme,
|
|
119
|
+
nordTheme,
|
|
120
|
+
nordAnsi256Theme,
|
|
121
|
+
nordAnsiTheme,
|
|
122
|
+
tokyoNightTheme,
|
|
123
|
+
tokyoNightAnsi256Theme,
|
|
124
|
+
tokyoNightAnsiTheme,
|
|
125
|
+
rosePineTheme,
|
|
126
|
+
rosePineAnsi256Theme,
|
|
127
|
+
rosePineAnsiTheme,
|
|
128
|
+
gruvboxTheme,
|
|
129
|
+
gruvboxAnsi256Theme,
|
|
130
|
+
gruvboxAnsiTheme,
|
|
131
|
+
};
|