@ravshansbox/pi-statusline 1.4.0 → 1.6.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 +2 -3
- package/index.ts +15 -64
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -14,9 +14,8 @@ Add `-l` to install it in project settings.
|
|
|
14
14
|
|
|
15
15
|
Pi loads the extension from `./index.ts`. It replaces the built-in footer with a statusline that shows:
|
|
16
16
|
|
|
17
|
-
- the
|
|
18
|
-
- token usage, cache hit rate
|
|
19
|
-
- the provider, model and thinking level
|
|
17
|
+
- the directory name, git branch, model and thinking level
|
|
18
|
+
- token usage, cache hit rate and context usage
|
|
20
19
|
- statuses set by other extensions
|
|
21
20
|
|
|
22
21
|
## Development
|
package/index.ts
CHANGED
|
@@ -1,13 +1,12 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { basename } from 'node:path';
|
|
2
2
|
import { type ExtensionAPI, type ExtensionContext } from '@earendil-works/pi-coding-agent';
|
|
3
|
-
import { truncateToWidth
|
|
3
|
+
import { truncateToWidth } from '@earendil-works/pi-tui';
|
|
4
4
|
|
|
5
5
|
type Usage = {
|
|
6
6
|
input: number;
|
|
7
7
|
output: number;
|
|
8
8
|
cacheRead: number;
|
|
9
9
|
cacheWrite: number;
|
|
10
|
-
cost: { total: number };
|
|
11
10
|
};
|
|
12
11
|
|
|
13
12
|
function sanitizeStatusText(text: string): string {
|
|
@@ -23,23 +22,14 @@ function formatTokens(count: number): string {
|
|
|
23
22
|
return `${Math.round(count / 1000000)}m`;
|
|
24
23
|
}
|
|
25
24
|
|
|
26
|
-
function formatCwd(cwd: string, home: string | undefined): string {
|
|
27
|
-
if (!home) return cwd;
|
|
28
|
-
const rel = relative(resolve(home), resolve(cwd));
|
|
29
|
-
const inside = rel === '' || (rel !== '..' && !rel.startsWith(`..${sep}`) && !isAbsolute(rel));
|
|
30
|
-
if (!inside) return cwd;
|
|
31
|
-
return rel === '' ? '~' : `~${sep}${rel}`;
|
|
32
|
-
}
|
|
33
|
-
|
|
34
25
|
function getUsage(ctx: ExtensionContext) {
|
|
35
|
-
const totals = { input: 0, output: 0, cacheRead: 0, cacheWrite: 0
|
|
26
|
+
const totals = { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 };
|
|
36
27
|
let latestCacheHitRate: number | undefined;
|
|
37
28
|
const add = (u: Usage) => {
|
|
38
29
|
totals.input += u.input;
|
|
39
30
|
totals.output += u.output;
|
|
40
31
|
totals.cacheRead += u.cacheRead;
|
|
41
32
|
totals.cacheWrite += u.cacheWrite;
|
|
42
|
-
totals.cost += u.cost.total;
|
|
43
33
|
};
|
|
44
34
|
for (const entry of ctx.sessionManager.getEntries()) {
|
|
45
35
|
if (entry.type === 'usage') {
|
|
@@ -79,14 +69,16 @@ export default function (pi: ExtensionAPI) {
|
|
|
79
69
|
const contextPercent =
|
|
80
70
|
contextUsage?.percent != null ? contextPercentValue.toFixed(0) : '?';
|
|
81
71
|
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
process.env['HOME'] || process.env['USERPROFILE'],
|
|
85
|
-
);
|
|
72
|
+
const modelName = model?.id.replace(/^claude-/, '') || 'no-model';
|
|
73
|
+
const topParts = [basename(ctx.sessionManager.getCwd())];
|
|
86
74
|
const branch = footerData.getGitBranch();
|
|
87
|
-
if (branch)
|
|
88
|
-
|
|
89
|
-
if (
|
|
75
|
+
if (branch) topParts.push(branch);
|
|
76
|
+
topParts.push(modelName);
|
|
77
|
+
if (model?.reasoning) {
|
|
78
|
+
const level = ctx.thinkingLevel || 'off';
|
|
79
|
+
topParts.push(level === 'off' ? 'thinking off' : level);
|
|
80
|
+
}
|
|
81
|
+
const top = topParts.join(' • ');
|
|
90
82
|
|
|
91
83
|
const statsParts: string[] = [];
|
|
92
84
|
if (totals.input) statsParts.push(`↑${formatTokens(totals.input)}`);
|
|
@@ -97,15 +89,6 @@ export default function (pi: ExtensionAPI) {
|
|
|
97
89
|
statsParts.push(`CH${latestCacheHitRate.toFixed(0)}%`);
|
|
98
90
|
}
|
|
99
91
|
|
|
100
|
-
const usingSubscription = model
|
|
101
|
-
? model.provider === 'kimi-coding' ||
|
|
102
|
-
(ctx.modelRegistry.isUsingOAuth(model) &&
|
|
103
|
-
ctx.modelRegistry.getProvider(model.provider)?.auth.oauth?.isSubscription === true)
|
|
104
|
-
: false;
|
|
105
|
-
if (totals.cost || usingSubscription) {
|
|
106
|
-
statsParts.push(`$${totals.cost.toFixed(2)}${usingSubscription ? ' (sub)' : ''}`);
|
|
107
|
-
}
|
|
108
|
-
|
|
109
92
|
const contextDisplay =
|
|
110
93
|
contextPercent === '?'
|
|
111
94
|
? `?/${formatTokens(contextWindow)}`
|
|
@@ -118,41 +101,9 @@ export default function (pi: ExtensionAPI) {
|
|
|
118
101
|
statsParts.push(`${theme.fg('dim', '•')} ${theme.bold(theme.fg('warning', 'xp'))}`);
|
|
119
102
|
}
|
|
120
103
|
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
statsLeft = truncateToWidth(statsLeft, width, '...');
|
|
125
|
-
statsLeftWidth = visibleWidth(statsLeft);
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
const minPadding = 2;
|
|
129
|
-
const modelName = model?.id.replace(/^claude-/, '') || 'no-model';
|
|
130
|
-
let right = modelName;
|
|
131
|
-
if (model?.reasoning) {
|
|
132
|
-
const level = ctx.thinkingLevel || 'off';
|
|
133
|
-
right = level === 'off' ? `${modelName} • thinking off` : `${modelName} • ${level}`;
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
const rightWidth = visibleWidth(right);
|
|
137
|
-
let statsLine: string;
|
|
138
|
-
if (statsLeftWidth + minPadding + rightWidth <= width) {
|
|
139
|
-
statsLine = statsLeft + ' '.repeat(width - statsLeftWidth - rightWidth) + right;
|
|
140
|
-
} else {
|
|
141
|
-
const available = width - statsLeftWidth - minPadding;
|
|
142
|
-
if (available > 0) {
|
|
143
|
-
const truncatedRight = truncateToWidth(right, available, '');
|
|
144
|
-
const padding = ' '.repeat(
|
|
145
|
-
Math.max(0, width - statsLeftWidth - visibleWidth(truncatedRight)),
|
|
146
|
-
);
|
|
147
|
-
statsLine = statsLeft + padding + truncatedRight;
|
|
148
|
-
} else {
|
|
149
|
-
statsLine = statsLeft;
|
|
150
|
-
}
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
const remainder = statsLine.slice(statsLeft.length);
|
|
154
|
-
const pwdLine = truncateToWidth(theme.fg('dim', pwd), width, theme.fg('dim', '...'));
|
|
155
|
-
const lines = [pwdLine, theme.fg('dim', statsLeft) + theme.fg('dim', remainder)];
|
|
104
|
+
const statsLine = truncateToWidth(statsParts.join(' '), width, '...');
|
|
105
|
+
const topLine = truncateToWidth(theme.fg('dim', top), width, theme.fg('dim', '...'));
|
|
106
|
+
const lines = [topLine, theme.fg('dim', statsLine)];
|
|
156
107
|
|
|
157
108
|
const statuses = footerData.getExtensionStatuses();
|
|
158
109
|
if (statuses.size > 0) {
|