@yusukeshib/pi-colored-model-status 0.1.1 → 0.1.2
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 +27 -9
- package/extensions/colored-model-status.ts +47 -30
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -4,7 +4,7 @@ A [pi](https://pi.dev) extension that color-codes the active model in the
|
|
|
4
4
|
footer, so you can tell at a glance which model family is in use.
|
|
5
5
|
|
|
6
6
|
It replaces the plain `claude-opus-4-8 • medium` text in the bottom-right of
|
|
7
|
-
pi's footer with
|
|
7
|
+
pi's footer with independently background-colored model and thinking badges. Everything else the default
|
|
8
8
|
footer shows (cwd, git branch, token stats, context %, and other extensions'
|
|
9
9
|
status line) is faithfully reproduced.
|
|
10
10
|
|
|
@@ -17,15 +17,27 @@ strongly distinct hues:
|
|
|
17
17
|
|
|
18
18
|
| Family | Color |
|
|
19
19
|
| ------------------------- | ---------------- |
|
|
20
|
-
| `opus`
|
|
21
|
-
| `sonnet`
|
|
22
|
-
| `fable`
|
|
20
|
+
| `opus`, `terra` | deep purple |
|
|
21
|
+
| `sonnet`, `luna` | bright cyan-blue |
|
|
22
|
+
| `fable`, `sol` | vivid orange |
|
|
23
23
|
| `haiku` | green |
|
|
24
24
|
| `gpt`, `o1`, `o3`, `o4` | OpenAI teal |
|
|
25
25
|
| `gemini` | Google blue |
|
|
26
26
|
| `grok` | slate |
|
|
27
27
|
| anything else | gray (fallback) |
|
|
28
28
|
|
|
29
|
+
Thinking effort has its own independent color scale:
|
|
30
|
+
|
|
31
|
+
| Level | Color |
|
|
32
|
+
| --------- | --------- |
|
|
33
|
+
| `off` | gray |
|
|
34
|
+
| `minimal` | blue-gray |
|
|
35
|
+
| `low` | green |
|
|
36
|
+
| `medium` | amber |
|
|
37
|
+
| `high` | orange |
|
|
38
|
+
| `xhigh` | red |
|
|
39
|
+
| `max` | magenta |
|
|
40
|
+
|
|
29
41
|
The foreground color (black or white) is chosen automatically from the
|
|
30
42
|
background's luminance for readability. The badge follows model changes made
|
|
31
43
|
via `/model` or `Ctrl+P`.
|
|
@@ -50,18 +62,24 @@ pi -e npm:@yusukeshib/pi-colored-model-status
|
|
|
50
62
|
|
|
51
63
|
## Customize
|
|
52
64
|
|
|
53
|
-
Edit the `
|
|
65
|
+
Edit the `MODEL_BADGES` and `THINKING_BADGES` arrays at the top of
|
|
54
66
|
[`extensions/colored-model-status.ts`](extensions/colored-model-status.ts).
|
|
55
67
|
Each entry maps substring keywords to an RGB background (and an optional `fg`):
|
|
56
68
|
|
|
57
69
|
```ts
|
|
58
|
-
const
|
|
59
|
-
{ match: ["opus"], bg: [147, 51, 234] },
|
|
60
|
-
{ match: ["sonnet"], bg: [14, 165, 233] },
|
|
61
|
-
{ match: ["fable"], bg: [234, 88, 12] },
|
|
70
|
+
const MODEL_BADGES = [
|
|
71
|
+
{ match: ["opus", "terra"], bg: [147, 51, 234] },
|
|
72
|
+
{ match: ["sonnet", "luna"], bg: [14, 165, 233] },
|
|
73
|
+
{ match: ["fable", "sol"], bg: [234, 88, 12] },
|
|
62
74
|
// …add your own, e.g.:
|
|
63
75
|
{ match: ["deepseek"], bg: [30, 90, 200] },
|
|
64
76
|
];
|
|
77
|
+
|
|
78
|
+
const THINKING_BADGES = [
|
|
79
|
+
{ match: ["low"], bg: [22, 163, 74] },
|
|
80
|
+
{ match: ["high"], bg: [234, 88, 12] },
|
|
81
|
+
// …
|
|
82
|
+
];
|
|
65
83
|
```
|
|
66
84
|
|
|
67
85
|
Matching is a case-insensitive substring test against the model id, so `gpt`
|
|
@@ -26,22 +26,33 @@ interface Badge {
|
|
|
26
26
|
fg?: Rgb;
|
|
27
27
|
}
|
|
28
28
|
|
|
29
|
-
//
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
{ match: ["
|
|
33
|
-
{ match: ["
|
|
29
|
+
// Model families and thinking levels are colored independently.
|
|
30
|
+
// Each list is matched top-to-bottom; first hit wins.
|
|
31
|
+
const MODEL_BADGES: readonly Badge[] = [
|
|
32
|
+
{ match: ["opus", "terra"], bg: [147, 51, 234] }, // deep purple
|
|
33
|
+
{ match: ["sonnet", "luna"], bg: [14, 165, 233] }, // bright cyan-blue
|
|
34
|
+
{ match: ["fable", "sol"], bg: [234, 88, 12] }, // vivid orange
|
|
34
35
|
{ match: ["haiku"], bg: [22, 163, 74] }, // green
|
|
35
36
|
{ match: ["gpt", "o1", "o3", "o4"], bg: [16, 163, 127] }, // OpenAI teal
|
|
36
37
|
{ match: ["gemini"], bg: [66, 133, 244] }, // Google blue
|
|
37
38
|
{ match: ["grok"], bg: [30, 41, 59] }, // slate
|
|
38
39
|
];
|
|
39
40
|
|
|
41
|
+
const THINKING_BADGES: readonly Badge[] = [
|
|
42
|
+
{ match: ["off"], bg: [82, 82, 91] }, // gray
|
|
43
|
+
{ match: ["minimal"], bg: [71, 85, 105] }, // blue-gray
|
|
44
|
+
{ match: ["low"], bg: [22, 163, 74] }, // green
|
|
45
|
+
{ match: ["medium"], bg: [202, 138, 4] }, // amber
|
|
46
|
+
{ match: ["xhigh"], bg: [220, 38, 38] }, // red
|
|
47
|
+
{ match: ["high"], bg: [234, 88, 12] }, // orange
|
|
48
|
+
{ match: ["max"], bg: [219, 39, 119] }, // magenta
|
|
49
|
+
];
|
|
50
|
+
|
|
40
51
|
const FALLBACK: Badge = { match: [], bg: [82, 82, 91] }; // gray
|
|
41
52
|
|
|
42
|
-
function pickBadge(
|
|
43
|
-
const lower =
|
|
44
|
-
return
|
|
53
|
+
function pickBadge(value: string, badges: readonly Badge[]): Badge {
|
|
54
|
+
const lower = value.toLowerCase();
|
|
55
|
+
return badges.find((badge) => badge.match.some((keyword) => lower.includes(keyword))) ?? FALLBACK;
|
|
45
56
|
}
|
|
46
57
|
|
|
47
58
|
/** Pick a contrasting foreground (black/white) from the background luminance. */
|
|
@@ -159,38 +170,44 @@ export default function (pi: ExtensionAPI) {
|
|
|
159
170
|
statsLeftWidth = visibleWidth(statsLeft);
|
|
160
171
|
}
|
|
161
172
|
|
|
162
|
-
// --- Right side: model
|
|
173
|
+
// --- Right side: independently colored model and thinking badges ---
|
|
163
174
|
const modelName = model?.id || "no-model";
|
|
164
|
-
let
|
|
165
|
-
if (model?.reasoning) {
|
|
166
|
-
const level = pi.getThinkingLevel() || "off";
|
|
167
|
-
rightText = level === "off" ? `${modelName} • thinking off` : `${modelName} • ${level}`;
|
|
168
|
-
}
|
|
169
|
-
// Prefix (provider) when more than one provider is available
|
|
175
|
+
let modelText = modelName;
|
|
170
176
|
if (footerData.getAvailableProviderCount() > 1 && model) {
|
|
171
|
-
|
|
177
|
+
modelText = `(${model.provider}) ${modelText}`;
|
|
172
178
|
}
|
|
173
|
-
|
|
174
|
-
const
|
|
175
|
-
|
|
176
|
-
const
|
|
179
|
+
const thinkingLevel = model?.reasoning ? pi.getThinkingLevel() || "off" : undefined;
|
|
180
|
+
const thinkingText = thinkingLevel === "off" ? "thinking off" : thinkingLevel;
|
|
181
|
+
const modelBadge = pickBadge(modelName, MODEL_BADGES);
|
|
182
|
+
const thinkingBadge = thinkingLevel
|
|
183
|
+
? pickBadge(thinkingLevel, THINKING_BADGES)
|
|
184
|
+
: undefined;
|
|
185
|
+
const thinkingWidth = thinkingText && thinkingBadge ? visibleWidth(thinkingText) + 2 : 0;
|
|
186
|
+
const rightWidth = visibleWidth(modelText) + 2 + thinkingWidth;
|
|
177
187
|
|
|
178
188
|
const minPadding = 2;
|
|
179
189
|
const dimStatsLeft = theme.fg("dim", statsLeft);
|
|
180
190
|
let statsLine: string;
|
|
181
191
|
if (statsLeftWidth + minPadding + rightWidth <= width) {
|
|
182
192
|
const pad = " ".repeat(width - statsLeftWidth - rightWidth);
|
|
183
|
-
|
|
193
|
+
const thinking =
|
|
194
|
+
thinkingText && thinkingBadge ? paintBadge(thinkingText, thinkingBadge) : "";
|
|
195
|
+
statsLine =
|
|
196
|
+
dimStatsLeft + theme.fg("dim", pad) + paintBadge(modelText, modelBadge) + thinking;
|
|
184
197
|
} else {
|
|
185
|
-
//
|
|
186
|
-
const
|
|
187
|
-
if (
|
|
188
|
-
const
|
|
189
|
-
const
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
);
|
|
193
|
-
statsLine =
|
|
198
|
+
// Preserve the thinking badge when possible and truncate only the model badge.
|
|
199
|
+
const modelAvail = width - statsLeftWidth - minPadding - thinkingWidth - 2;
|
|
200
|
+
if (modelAvail > 0) {
|
|
201
|
+
const truncatedModel = truncateToWidth(modelText, modelAvail, "");
|
|
202
|
+
const thinking =
|
|
203
|
+
thinkingText && thinkingBadge ? paintBadge(thinkingText, thinkingBadge) : "";
|
|
204
|
+
const paintedWidth = visibleWidth(truncatedModel) + 2 + thinkingWidth;
|
|
205
|
+
const pad = " ".repeat(Math.max(0, width - statsLeftWidth - paintedWidth));
|
|
206
|
+
statsLine =
|
|
207
|
+
dimStatsLeft +
|
|
208
|
+
theme.fg("dim", pad) +
|
|
209
|
+
paintBadge(truncatedModel, modelBadge) +
|
|
210
|
+
thinking;
|
|
194
211
|
} else {
|
|
195
212
|
statsLine = dimStatsLeft;
|
|
196
213
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@yusukeshib/pi-colored-model-status",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.2",
|
|
4
4
|
"description": "Color-code the active model in pi's footer so you can tell at a glance which model family (opus, sonnet, fable, gpt, gemini, …) is in use.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"pi-package",
|