agy-powerline 1.2.0 → 1.4.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/CHANGELOG.md +72 -0
- package/README.fr.md +243 -0
- package/README.ja.md +144 -49
- package/README.md +160 -52
- package/README.zh-CN.md +144 -49
- package/package.json +5 -2
- package/src/cli/caps.js +2 -0
- package/src/cli/configure.js +70 -172
- package/src/cli/doctor.js +12 -0
- package/src/cli/export.js +82 -0
- package/src/cli/gradient.js +121 -0
- package/src/cli/import.js +273 -0
- package/src/cli/init.js +186 -7
- package/src/cli/layout.js +2 -0
- package/src/cli/preset.js +2 -0
- package/src/cli/repo-url.js +7 -0
- package/src/cli/theme.js +2 -0
- package/src/cli/uninstall.js +6 -2
- package/src/index.js +53 -1
- package/src/lib/catalog.js +54 -2
- package/src/lib/colors.js +144 -14
- package/src/lib/config-check.js +74 -0
- package/src/lib/config.js +89 -21
- package/src/lib/exec.js +140 -21
- package/src/lib/fit.js +7 -0
- package/src/lib/formatters.js +67 -0
- package/src/lib/git.js +385 -4
- package/src/lib/layouts/lines.js +175 -28
- package/src/lib/layouts/pills.js +232 -33
- package/src/lib/paths.js +73 -13
- package/src/lib/prompt.js +30 -0
- package/src/lib/run.js +2 -0
- package/src/lib/session.js +17 -3
- package/src/lib/shared.js +13 -2
- package/src/lib/themes.js +79 -5
- package/src/lib/usage.js +524 -0
- package/src/lib/widget-options.js +194 -0
- package/src/lib/widget-style.js +45 -0
- package/src/runtime/statusline.js +15 -1
package/src/lib/catalog.js
CHANGED
|
@@ -126,8 +126,45 @@ const WIDGET_CATALOG = [
|
|
|
126
126
|
id: "git",
|
|
127
127
|
label: "VCS Branch",
|
|
128
128
|
unique: true,
|
|
129
|
-
description:
|
|
130
|
-
|
|
129
|
+
description:
|
|
130
|
+
"current branch, marked when there are uncommitted changes, with how many commits it is ahead of or behind its upstream",
|
|
131
|
+
summary: "branch, changes and ahead/behind",
|
|
132
|
+
},
|
|
133
|
+
{
|
|
134
|
+
id: "gitChanges",
|
|
135
|
+
label: "Git Line Changes",
|
|
136
|
+
unique: true,
|
|
137
|
+
description:
|
|
138
|
+
"lines added and removed since the last commit, staged or not (new files that aren't staged don't count)",
|
|
139
|
+
summary: "lines added and removed",
|
|
140
|
+
},
|
|
141
|
+
{
|
|
142
|
+
id: "gitFiles",
|
|
143
|
+
label: "Git File Counts",
|
|
144
|
+
unique: true,
|
|
145
|
+
description: "how many files are staged, modified, untracked and in conflict",
|
|
146
|
+
summary: "staged, modified, untracked file counts",
|
|
147
|
+
},
|
|
148
|
+
{
|
|
149
|
+
id: "gitSha",
|
|
150
|
+
label: "Git Commit",
|
|
151
|
+
unique: true,
|
|
152
|
+
description: "short ID of the commit checked out",
|
|
153
|
+
summary: "short commit ID",
|
|
154
|
+
},
|
|
155
|
+
{
|
|
156
|
+
id: "gitStash",
|
|
157
|
+
label: "Git Stash Count",
|
|
158
|
+
unique: true,
|
|
159
|
+
description: "how many stashes the repository holds; hidden when there are none",
|
|
160
|
+
summary: "number of stashes",
|
|
161
|
+
},
|
|
162
|
+
{
|
|
163
|
+
id: "gitWorktree",
|
|
164
|
+
label: "Git Worktree",
|
|
165
|
+
unique: true,
|
|
166
|
+
description: "name of the linked worktree you're in; hidden in the main one",
|
|
167
|
+
summary: "linked worktree name",
|
|
131
168
|
},
|
|
132
169
|
{
|
|
133
170
|
id: "plan",
|
|
@@ -220,6 +257,21 @@ const WIDGET_CATALOG = [
|
|
|
220
257
|
description: "session tokens, as a total or split into input and output",
|
|
221
258
|
summary: "session tokens, total or split",
|
|
222
259
|
},
|
|
260
|
+
{
|
|
261
|
+
id: "tokensToday",
|
|
262
|
+
label: "Tokens Today",
|
|
263
|
+
unique: true,
|
|
264
|
+
description: "tokens used today in all agy conversations, from agy's local data (Node 22.13+)",
|
|
265
|
+
summary: "tokens used today, all conversations",
|
|
266
|
+
},
|
|
267
|
+
{
|
|
268
|
+
id: "tokensWeek",
|
|
269
|
+
label: "Tokens 7 Days",
|
|
270
|
+
unique: true,
|
|
271
|
+
description:
|
|
272
|
+
"tokens used in the last 7 days in all agy conversations, from agy's local data (Node 22.13+)",
|
|
273
|
+
summary: "tokens used over 7 days",
|
|
274
|
+
},
|
|
223
275
|
{
|
|
224
276
|
id: "exec",
|
|
225
277
|
label: "Shell Command",
|
package/src/lib/colors.js
CHANGED
|
@@ -91,21 +91,24 @@ function rgb(r, g, b) {
|
|
|
91
91
|
return [r, g, b];
|
|
92
92
|
}
|
|
93
93
|
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
if (r > 248) {
|
|
101
|
-
return 231;
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
return Math.round(((r - 8) / 247) * 24) + 232;
|
|
105
|
-
}
|
|
94
|
+
// The nearest xterm color: the 6x6x6 cube's levels (0, 95, 135, ... 255) are
|
|
95
|
+
// not evenly spaced, and a near-gray reads better from the gray ramp, so both
|
|
96
|
+
// candidates are measured and the closer one wins (as tmux does).
|
|
97
|
+
const CUBE_LEVELS = [0, 95, 135, 175, 215, 255];
|
|
106
98
|
|
|
107
|
-
|
|
108
|
-
|
|
99
|
+
function rgbToAnsi256([r, g, b]) {
|
|
100
|
+
const toCube = (v) => (v < 48 ? 0 : v < 115 ? 1 : Math.floor((v - 35) / 40));
|
|
101
|
+
const [cr, cg, cb] = [toCube(r), toCube(g), toCube(b)];
|
|
102
|
+
const cube = [CUBE_LEVELS[cr], CUBE_LEVELS[cg], CUBE_LEVELS[cb]];
|
|
103
|
+
|
|
104
|
+
const average = (r + g + b) / 3;
|
|
105
|
+
const grayIndex = average > 238 ? 23 : Math.max(0, Math.floor((average - 3) / 10));
|
|
106
|
+
const level = 8 + 10 * grayIndex;
|
|
107
|
+
const distance = ([x, y, z]) => (x - r) ** 2 + (y - g) ** 2 + (z - b) ** 2;
|
|
108
|
+
|
|
109
|
+
return distance([level, level, level]) < distance(cube)
|
|
110
|
+
? 232 + grayIndex
|
|
111
|
+
: 16 + 36 * cr + 6 * cg + cb;
|
|
109
112
|
}
|
|
110
113
|
|
|
111
114
|
function colorSeq(kind, [r, g, b]) {
|
|
@@ -196,6 +199,122 @@ function parseColor(value, fallback = [200, 200, 200]) {
|
|
|
196
199
|
return fallback;
|
|
197
200
|
}
|
|
198
201
|
|
|
202
|
+
function linear(c) {
|
|
203
|
+
const v = c / 255;
|
|
204
|
+
return v <= 0.04045 ? v / 12.92 : ((v + 0.055) / 1.055) ** 2.4;
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
function gamma(v) {
|
|
208
|
+
const c = v <= 0.0031308 ? 12.92 * v : 1.055 * v ** (1 / 2.4) - 0.055;
|
|
209
|
+
return Math.max(0, Math.min(255, Math.round(c * 255)));
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
// WCAG relative luminance and contrast ratio.
|
|
213
|
+
function luminance([r, g, b]) {
|
|
214
|
+
return 0.2126 * linear(r) + 0.7152 * linear(g) + 0.0722 * linear(b);
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
function contrastRatio(a, b) {
|
|
218
|
+
const [hi, lo] = [luminance(a), luminance(b)].sort((x, y) => y - x);
|
|
219
|
+
return (hi + 0.05) / (lo + 0.05);
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
// OKLab (Björn Ottosson): mixing there keeps the middle of a gradient as
|
|
223
|
+
// bright and saturated as its ends, where sRGB mixing turns it muddy.
|
|
224
|
+
function toOklab([r, g, b]) {
|
|
225
|
+
const [lr, lg, lb] = [linear(r), linear(g), linear(b)];
|
|
226
|
+
const l = Math.cbrt(0.4122214708 * lr + 0.5363325363 * lg + 0.0514459929 * lb);
|
|
227
|
+
const m = Math.cbrt(0.2119034982 * lr + 0.6806995451 * lg + 0.1073969566 * lb);
|
|
228
|
+
const s = Math.cbrt(0.0883024619 * lr + 0.2817188376 * lg + 0.6299787005 * lb);
|
|
229
|
+
return [
|
|
230
|
+
0.2104542553 * l + 0.793617785 * m - 0.0040720468 * s,
|
|
231
|
+
1.9779984951 * l - 2.428592205 * m + 0.4505937099 * s,
|
|
232
|
+
0.0259040371 * l + 0.7827717662 * m - 0.808675766 * s,
|
|
233
|
+
];
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
function fromOklab([L, a, b]) {
|
|
237
|
+
const l = (L + 0.3963377774 * a + 0.2158037573 * b) ** 3;
|
|
238
|
+
const m = (L - 0.1055613458 * a - 0.0638541728 * b) ** 3;
|
|
239
|
+
const s = (L - 0.0894841775 * a - 1.291485548 * b) ** 3;
|
|
240
|
+
return [
|
|
241
|
+
gamma(4.0767416621 * l - 3.3077115913 * m + 0.2309699292 * s),
|
|
242
|
+
gamma(-1.2684380046 * l + 2.6097574011 * m - 0.3413193965 * s),
|
|
243
|
+
gamma(-0.0041960863 * l - 0.7034186147 * m + 1.707614701 * s),
|
|
244
|
+
];
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
const MAX_GRADIENT_STOPS = 6;
|
|
248
|
+
const HEX_STOP = /^#?([0-9a-f]{3}|[0-9a-f]{6})$/i;
|
|
249
|
+
|
|
250
|
+
// "#ff5f6d-#ffc371" (2 to 6 hex stops, "#" optional) to RGB stops, or null.
|
|
251
|
+
function parseGradientStops(spec) {
|
|
252
|
+
if (typeof spec !== "string") {
|
|
253
|
+
return null;
|
|
254
|
+
}
|
|
255
|
+
const parts = spec.trim().split("-");
|
|
256
|
+
if (parts.length < 2 || parts.length > MAX_GRADIENT_STOPS) {
|
|
257
|
+
return null;
|
|
258
|
+
}
|
|
259
|
+
if (!parts.every((part) => HEX_STOP.test(part))) {
|
|
260
|
+
return null;
|
|
261
|
+
}
|
|
262
|
+
return parts.map((part) => parseColor(part));
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
// The color t (0 to 1) of the way along the stops; the ends are exact.
|
|
266
|
+
function gradientAt(stops, t) {
|
|
267
|
+
const clamped = Math.max(0, Math.min(1, Number(t) || 0));
|
|
268
|
+
const span = clamped * (stops.length - 1);
|
|
269
|
+
const i = Math.min(stops.length - 2, Math.floor(span));
|
|
270
|
+
const local = span - i;
|
|
271
|
+
if (local === 0) {
|
|
272
|
+
return [...stops[i]];
|
|
273
|
+
}
|
|
274
|
+
if (local === 1) {
|
|
275
|
+
return [...stops[i + 1]];
|
|
276
|
+
}
|
|
277
|
+
const [a, b] = [toOklab(stops[i]), toOklab(stops[i + 1])];
|
|
278
|
+
return fromOklab(a.map((value, k) => value + (b[k] - value) * local));
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
// count evenly spaced colors from the first stop to the last.
|
|
282
|
+
function gradientColors(stops, count) {
|
|
283
|
+
if (count <= 1) {
|
|
284
|
+
return count === 1 ? [[...stops[0]]] : [];
|
|
285
|
+
}
|
|
286
|
+
return Array.from({ length: count }, (_, i) => gradientAt(stops, i / (count - 1)));
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
const MIN_CONTRAST = 4.5;
|
|
290
|
+
|
|
291
|
+
// The preferred text color if it reads on the background, else whichever of
|
|
292
|
+
// the fallbacks contrasts most.
|
|
293
|
+
function readableText(background, preferred, fallbacks) {
|
|
294
|
+
if (contrastRatio(preferred, background) >= MIN_CONTRAST) {
|
|
295
|
+
return preferred;
|
|
296
|
+
}
|
|
297
|
+
return fallbacks.reduce((best, color) =>
|
|
298
|
+
contrastRatio(color, background) > contrastRatio(best, background) ? color : best
|
|
299
|
+
);
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
// The color moved toward white (on a dark background) or black (on a light
|
|
303
|
+
// one) just far enough to reach the minimum contrast.
|
|
304
|
+
function withContrast(color, background, min = MIN_CONTRAST) {
|
|
305
|
+
if (contrastRatio(color, background) >= min) {
|
|
306
|
+
return color;
|
|
307
|
+
}
|
|
308
|
+
const target = luminance(background) < 0.5 ? [255, 255, 255] : [0, 0, 0];
|
|
309
|
+
for (let step = 1; step <= 20; step++) {
|
|
310
|
+
const moved = mix(color, target, step / 20);
|
|
311
|
+
if (contrastRatio(moved, background) >= min) {
|
|
312
|
+
return moved;
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
return target;
|
|
316
|
+
}
|
|
317
|
+
|
|
199
318
|
module.exports = {
|
|
200
319
|
CSI,
|
|
201
320
|
RESET,
|
|
@@ -221,4 +340,15 @@ module.exports = {
|
|
|
221
340
|
shade,
|
|
222
341
|
mix,
|
|
223
342
|
parseColor,
|
|
343
|
+
luminance,
|
|
344
|
+
contrastRatio,
|
|
345
|
+
toOklab,
|
|
346
|
+
fromOklab,
|
|
347
|
+
MAX_GRADIENT_STOPS,
|
|
348
|
+
parseGradientStops,
|
|
349
|
+
gradientAt,
|
|
350
|
+
gradientColors,
|
|
351
|
+
MIN_CONTRAST,
|
|
352
|
+
readableText,
|
|
353
|
+
withContrast,
|
|
224
354
|
};
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
const { defaultConfig, canonicalThemeId, LAYOUTS } = require("./shared");
|
|
4
|
+
const { THEMES, normalizeGradient } = require("./themes");
|
|
5
|
+
const { VALID_WIDGET_IDS } = require("./config");
|
|
6
|
+
const { COLOR_MODES } = require("./colors");
|
|
7
|
+
const { isMeterStyle } = require("./widget-style");
|
|
8
|
+
|
|
9
|
+
const KNOWN_KEYS = new Set([
|
|
10
|
+
...Object.keys(defaultConfig()),
|
|
11
|
+
"customTheme",
|
|
12
|
+
"gradient",
|
|
13
|
+
"meterStyle",
|
|
14
|
+
]);
|
|
15
|
+
|
|
16
|
+
// Control characters shown as \uXXXX: the text is printed, never interpreted
|
|
17
|
+
// by the terminal or the browser.
|
|
18
|
+
function visible(text) {
|
|
19
|
+
return String(text).replace(
|
|
20
|
+
/[\x00-\x1f\x7f-\x9f\u2028\u2029\u202A-\u202E\u2066-\u2069]/g,
|
|
21
|
+
(char) => `\\u${char.charCodeAt(0).toString(16).padStart(4, "0")}`
|
|
22
|
+
);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
// Settings the raw config has that the bar can't use, so they don't come over
|
|
26
|
+
// on import or in the web configurator.
|
|
27
|
+
function droppedSettings(raw) {
|
|
28
|
+
if (!raw || typeof raw !== "object" || Array.isArray(raw)) {
|
|
29
|
+
return ["config is not an object"];
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
const dropped = [];
|
|
33
|
+
for (const key of Object.keys(raw)) {
|
|
34
|
+
if (!KNOWN_KEYS.has(key)) {
|
|
35
|
+
dropped.push(`unknown setting "${visible(key)}"`);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
if (Array.isArray(raw.widgets)) {
|
|
39
|
+
for (const widget of raw.widgets) {
|
|
40
|
+
if (!widget || typeof widget !== "object" || !VALID_WIDGET_IDS.has(widget.id)) {
|
|
41
|
+
dropped.push(`unknown widget ${visible(JSON.stringify(widget?.id ?? widget) ?? "")}`);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
} else if (raw.widgets !== undefined) {
|
|
45
|
+
dropped.push("widgets (not a list)");
|
|
46
|
+
}
|
|
47
|
+
if (raw.theme !== undefined && !THEMES[canonicalThemeId(raw.theme)]) {
|
|
48
|
+
dropped.push(`unknown theme ${visible(JSON.stringify(raw.theme))}`);
|
|
49
|
+
}
|
|
50
|
+
if (raw.layout !== undefined && !LAYOUTS[raw.layout]) {
|
|
51
|
+
dropped.push(`unknown layout ${visible(JSON.stringify(raw.layout))}`);
|
|
52
|
+
}
|
|
53
|
+
if (raw.color !== undefined && !COLOR_MODES.includes(raw.color)) {
|
|
54
|
+
dropped.push(`unknown color mode ${visible(JSON.stringify(raw.color))}`);
|
|
55
|
+
}
|
|
56
|
+
if (
|
|
57
|
+
raw.gradient !== undefined &&
|
|
58
|
+
raw.gradient !== null &&
|
|
59
|
+
raw.gradient !== "off" &&
|
|
60
|
+
!normalizeGradient(raw.gradient)
|
|
61
|
+
) {
|
|
62
|
+
dropped.push(`invalid gradient ${visible(JSON.stringify(raw.gradient))}`);
|
|
63
|
+
}
|
|
64
|
+
if (raw.meterStyle !== undefined && !isMeterStyle(raw.meterStyle)) {
|
|
65
|
+
dropped.push(`unknown meter style ${visible(JSON.stringify(raw.meterStyle))}`);
|
|
66
|
+
}
|
|
67
|
+
return dropped;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
module.exports = {
|
|
71
|
+
KNOWN_KEYS,
|
|
72
|
+
visible,
|
|
73
|
+
droppedSettings,
|
|
74
|
+
};
|
package/src/lib/config.js
CHANGED
|
@@ -3,10 +3,11 @@
|
|
|
3
3
|
const fs = require("fs");
|
|
4
4
|
const path = require("path");
|
|
5
5
|
const { resolveColorModeId } = require("./colors");
|
|
6
|
-
const { resolveThemeId } = require("./themes");
|
|
6
|
+
const { resolveThemeId, normalizeGradient } = require("./themes");
|
|
7
7
|
const { stripControl, normalizeClock } = require("./formatters");
|
|
8
8
|
const { normalizePowerline } = require("./powerline");
|
|
9
9
|
const { writeFileAtomic, PRIVATE_FILE_MODE } = require("./paths");
|
|
10
|
+
const { isMeterStyle } = require("./widget-style");
|
|
10
11
|
|
|
11
12
|
// Display text in widget configs is printed as-is, so strip terminal control
|
|
12
13
|
// from it. cmd/command are left alone: they are executed, not printed.
|
|
@@ -39,6 +40,11 @@ const VALID_WIDGET_IDS = new Set([
|
|
|
39
40
|
"cwd",
|
|
40
41
|
"project",
|
|
41
42
|
"git",
|
|
43
|
+
"gitChanges",
|
|
44
|
+
"gitFiles",
|
|
45
|
+
"gitSha",
|
|
46
|
+
"gitStash",
|
|
47
|
+
"gitWorktree",
|
|
42
48
|
"plan",
|
|
43
49
|
"agentState",
|
|
44
50
|
"artifacts",
|
|
@@ -52,6 +58,8 @@ const VALID_WIDGET_IDS = new Set([
|
|
|
52
58
|
"cacheCreate",
|
|
53
59
|
"cacheHit",
|
|
54
60
|
"totalTokens",
|
|
61
|
+
"tokensToday",
|
|
62
|
+
"tokensWeek",
|
|
55
63
|
"exec",
|
|
56
64
|
"customText",
|
|
57
65
|
"separator",
|
|
@@ -83,9 +91,14 @@ const LAYOUTS = {
|
|
|
83
91
|
name: "Lines",
|
|
84
92
|
description: "Plain colored text with dividers and dot meters",
|
|
85
93
|
},
|
|
94
|
+
classic: {
|
|
95
|
+
id: "classic",
|
|
96
|
+
name: "Classic",
|
|
97
|
+
description: "Plain colored text with | dividers and █░│ block meters",
|
|
98
|
+
},
|
|
86
99
|
};
|
|
87
100
|
|
|
88
|
-
const LAYOUT_ORDER = ["pills", "lines"];
|
|
101
|
+
const LAYOUT_ORDER = ["pills", "lines", "classic"];
|
|
89
102
|
|
|
90
103
|
function resolveLayoutId(layoutId) {
|
|
91
104
|
return LAYOUTS[layoutId] ? layoutId : "pills";
|
|
@@ -175,6 +188,17 @@ function mergeConfig(raw) {
|
|
|
175
188
|
result.customTheme = raw.customTheme;
|
|
176
189
|
}
|
|
177
190
|
|
|
191
|
+
// An unknown meter style is left out: each layout then draws its own.
|
|
192
|
+
if (isMeterStyle(raw?.meterStyle)) {
|
|
193
|
+
result.meterStyle = raw.meterStyle;
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
// Only a valid gradient is kept; anything else renders the plain theme.
|
|
197
|
+
const gradient = normalizeGradient(raw?.gradient);
|
|
198
|
+
if (gradient) {
|
|
199
|
+
result.gradient = gradient;
|
|
200
|
+
}
|
|
201
|
+
|
|
178
202
|
return result;
|
|
179
203
|
}
|
|
180
204
|
|
|
@@ -236,11 +260,12 @@ function saveConfig(config) {
|
|
|
236
260
|
}
|
|
237
261
|
|
|
238
262
|
// Presets set the widget list only; the layout (Pills or Lines) stays the one
|
|
239
|
-
// the user picked. Each keeps all its widgets at 80
|
|
263
|
+
// the user picked. Each answers one question and keeps all its widgets at 80
|
|
264
|
+
// columns (full at 100); widgets with nothing to show hide on their own.
|
|
240
265
|
const PRESETS = {
|
|
241
266
|
default: {
|
|
242
267
|
id: "default",
|
|
243
|
-
name: "
|
|
268
|
+
name: "Default",
|
|
244
269
|
description: "Model, context and git; 5h and 7d quotas with resets on a second row",
|
|
245
270
|
widgets: [
|
|
246
271
|
{ id: "model" },
|
|
@@ -258,41 +283,84 @@ const PRESETS = {
|
|
|
258
283
|
},
|
|
259
284
|
compact: {
|
|
260
285
|
id: "compact",
|
|
261
|
-
name: "
|
|
262
|
-
description: "
|
|
286
|
+
name: "Compact",
|
|
287
|
+
description: "One row: short model, tightest quota, context % and git",
|
|
263
288
|
widgets: [{ id: "model", short: true }, { id: "quota" }, { id: "contextPct" }, { id: "git" }],
|
|
264
289
|
},
|
|
265
|
-
|
|
266
|
-
id: "
|
|
267
|
-
name: "
|
|
268
|
-
description: "
|
|
290
|
+
agent: {
|
|
291
|
+
id: "agent",
|
|
292
|
+
name: "Agent activity",
|
|
293
|
+
description: "Agent state, subagents, title and mode; context, artifacts, quota",
|
|
294
|
+
widgets: [
|
|
295
|
+
{ id: "agentState" },
|
|
296
|
+
{ id: "tasks" },
|
|
297
|
+
{ id: "title" },
|
|
298
|
+
{ id: "separator" },
|
|
299
|
+
{ id: "mode" },
|
|
300
|
+
{ id: "sandbox" },
|
|
301
|
+
{ id: "lineBreak" },
|
|
302
|
+
{ id: "model", short: true },
|
|
303
|
+
{ id: "contextPct" },
|
|
304
|
+
{ id: "artifacts" },
|
|
305
|
+
{ id: "separator" },
|
|
306
|
+
{ id: "quota" },
|
|
307
|
+
],
|
|
308
|
+
},
|
|
309
|
+
git: {
|
|
310
|
+
id: "git",
|
|
311
|
+
name: "Git focus",
|
|
312
|
+
description: "Project, branch, worktree, stash; changed files and lines, commit",
|
|
269
313
|
widgets: [
|
|
270
314
|
{ id: "project" },
|
|
271
315
|
{ id: "git" },
|
|
272
|
-
{ id: "
|
|
316
|
+
{ id: "gitWorktree" },
|
|
317
|
+
{ id: "gitStash" },
|
|
273
318
|
{ id: "separator" },
|
|
274
319
|
{ id: "model", short: true },
|
|
275
320
|
{ id: "lineBreak" },
|
|
276
|
-
{ id: "
|
|
321
|
+
{ id: "gitFiles" },
|
|
322
|
+
{ id: "gitChanges" },
|
|
323
|
+
{ id: "gitSha" },
|
|
277
324
|
{ id: "separator" },
|
|
325
|
+
{ id: "contextPct" },
|
|
278
326
|
{ id: "quota" },
|
|
279
|
-
{ id: "mode" },
|
|
280
327
|
],
|
|
281
328
|
},
|
|
282
|
-
|
|
283
|
-
id: "
|
|
284
|
-
name: "
|
|
285
|
-
description: "
|
|
329
|
+
tokens: {
|
|
330
|
+
id: "tokens",
|
|
331
|
+
name: "Token usage",
|
|
332
|
+
description: "Session tokens in and out, cache hit; tokens today and over 7 days",
|
|
286
333
|
widgets: [
|
|
334
|
+
{ id: "model", short: true },
|
|
335
|
+
{ id: "contextTokens" },
|
|
336
|
+
{ id: "separator" },
|
|
337
|
+
{ id: "totalTokens", split: true },
|
|
338
|
+
{ id: "cacheHit" },
|
|
339
|
+
{ id: "lineBreak" },
|
|
340
|
+
{ id: "tokensToday" },
|
|
341
|
+
{ id: "tokensWeek" },
|
|
342
|
+
{ id: "separator" },
|
|
343
|
+
{ id: "quota" },
|
|
344
|
+
],
|
|
345
|
+
},
|
|
346
|
+
quotas: {
|
|
347
|
+
id: "quotas",
|
|
348
|
+
name: "Quota watch",
|
|
349
|
+
description: "Plan and model; 5h and 7d quotas side by side; third-party and Argon",
|
|
350
|
+
widgets: [
|
|
351
|
+
{ id: "plan" },
|
|
352
|
+
{ id: "separator" },
|
|
353
|
+
{ id: "model", short: true },
|
|
354
|
+
{ id: "lineBreak" },
|
|
287
355
|
{ id: "fiveHourBar" },
|
|
288
356
|
{ id: "fiveHourReset" },
|
|
289
|
-
{ id: "
|
|
357
|
+
{ id: "separator" },
|
|
290
358
|
{ id: "weeklyBar" },
|
|
291
359
|
{ id: "weeklyReset" },
|
|
292
360
|
{ id: "lineBreak" },
|
|
293
361
|
{ id: "thirdPartyFiveHour" },
|
|
294
362
|
{ id: "thirdPartyWeekly" },
|
|
295
|
-
{ id: "
|
|
363
|
+
{ id: "separator" },
|
|
296
364
|
{ id: "argonWeekly" },
|
|
297
365
|
{ id: "argonReset" },
|
|
298
366
|
],
|
|
@@ -300,7 +368,7 @@ const PRESETS = {
|
|
|
300
368
|
full: {
|
|
301
369
|
id: "full",
|
|
302
370
|
name: "Everything",
|
|
303
|
-
description: "Session, project and git; context, tokens and cache; both quotas
|
|
371
|
+
description: "Session, project and git; context, tokens and cache; both quotas",
|
|
304
372
|
widgets: [
|
|
305
373
|
{ id: "agentState" },
|
|
306
374
|
{ id: "tasks" },
|
|
@@ -325,7 +393,7 @@ const PRESETS = {
|
|
|
325
393
|
},
|
|
326
394
|
};
|
|
327
395
|
|
|
328
|
-
const PRESET_ORDER = ["default", "compact", "
|
|
396
|
+
const PRESET_ORDER = ["default", "compact", "agent", "git", "tokens", "quotas", "full"];
|
|
329
397
|
|
|
330
398
|
function applyPreset(baseConfig, presetName) {
|
|
331
399
|
const preset = PRESETS[presetName] || PRESETS.default;
|