agy-powerline 1.4.0 → 1.5.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 +16 -0
- package/README.fr.md +11 -9
- package/README.ja.md +11 -9
- package/README.md +13 -11
- package/README.zh-CN.md +11 -9
- package/llms.txt +127 -0
- package/package.json +6 -3
- package/src/cli/configure.js +8 -8
- package/src/cli/doctor.js +17 -1
- package/src/lib/catalog.js +21 -0
- package/src/lib/config.js +3 -0
- package/src/lib/fit.js +3 -0
- package/src/lib/formatters.js +107 -4
- package/src/lib/layouts/lines.js +48 -11
- package/src/lib/layouts/pills.js +48 -11
- package/src/lib/session.js +49 -1
- package/src/lib/widget-options.js +108 -14
- package/src/lib/widget-style.js +100 -4
package/src/lib/formatters.js
CHANGED
|
@@ -374,7 +374,23 @@ function homePath(value) {
|
|
|
374
374
|
return "";
|
|
375
375
|
}
|
|
376
376
|
|
|
377
|
-
const
|
|
377
|
+
const input = String(value);
|
|
378
|
+
if (input === "~" || /^~[\\/]/.test(input)) {
|
|
379
|
+
return input;
|
|
380
|
+
}
|
|
381
|
+
const windowsAbsolute = /^[a-z]:[\\/]|^\\\\/i.test(input);
|
|
382
|
+
const posixAbsolute = input.startsWith("/");
|
|
383
|
+
|
|
384
|
+
// Payload paths can come from another OS. Preserve absolute paths in that
|
|
385
|
+
// format instead of resolving them relative to this machine's cwd.
|
|
386
|
+
if (
|
|
387
|
+
(windowsAbsolute && process.platform !== "win32") ||
|
|
388
|
+
(posixAbsolute && process.platform === "win32")
|
|
389
|
+
) {
|
|
390
|
+
return input;
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
const resolved = path.resolve(input);
|
|
378
394
|
const home = path.resolve(os.homedir());
|
|
379
395
|
const prefix =
|
|
380
396
|
process.platform === "win32"
|
|
@@ -388,6 +404,60 @@ function homePath(value) {
|
|
|
388
404
|
return resolved;
|
|
389
405
|
}
|
|
390
406
|
|
|
407
|
+
function isValidDepth(value) {
|
|
408
|
+
return Number.isInteger(value) && value >= 1 && value <= 10;
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
// Keep the path's root and final `depth` folders, replacing any middle
|
|
412
|
+
// folders with one ellipsis. Accept either OS's path separators on every OS.
|
|
413
|
+
function shortenPath(value, depth, ascii = false) {
|
|
414
|
+
const text = String(value ?? "");
|
|
415
|
+
if (!text || !isValidDepth(depth)) {
|
|
416
|
+
return text;
|
|
417
|
+
}
|
|
418
|
+
|
|
419
|
+
let root = "";
|
|
420
|
+
let rest = text;
|
|
421
|
+
let separator = text.match(/[\\/]/)?.[0] || "/";
|
|
422
|
+
// A network share keeps \\server\share (or //server/share) as its root.
|
|
423
|
+
const unc = text.match(/^([\\/]{2}[^\\/]+[\\/][^\\/]+)([\\/])?(.*)$/);
|
|
424
|
+
const drive = text.match(/^([a-z]:)([\\/])(.*)$/i);
|
|
425
|
+
|
|
426
|
+
if (unc) {
|
|
427
|
+
root = unc[1];
|
|
428
|
+
separator = unc[2] || separator;
|
|
429
|
+
rest = unc[3];
|
|
430
|
+
} else if (drive) {
|
|
431
|
+
root = drive[1];
|
|
432
|
+
separator = drive[2];
|
|
433
|
+
rest = drive[3];
|
|
434
|
+
} else if (text === "~" || /^~[\\/]/.test(text)) {
|
|
435
|
+
root = "~";
|
|
436
|
+
if (text.length > 1) {
|
|
437
|
+
separator = text[1];
|
|
438
|
+
rest = text.slice(2);
|
|
439
|
+
} else {
|
|
440
|
+
rest = "";
|
|
441
|
+
}
|
|
442
|
+
} else if (text[0] === "/" || text[0] === "\\") {
|
|
443
|
+
root = text[0];
|
|
444
|
+
separator = text[0];
|
|
445
|
+
rest = text.slice(1);
|
|
446
|
+
}
|
|
447
|
+
|
|
448
|
+
const folders = rest.split(/[\\/]+/).filter(Boolean);
|
|
449
|
+
if (folders.length <= depth) {
|
|
450
|
+
return text;
|
|
451
|
+
}
|
|
452
|
+
|
|
453
|
+
const suffix = folders.slice(-depth).join(separator);
|
|
454
|
+
const ellipsis = ascii ? "..." : "…";
|
|
455
|
+
if (root === "/" || root === "\\") {
|
|
456
|
+
return `${root}${ellipsis}${separator}${suffix}`;
|
|
457
|
+
}
|
|
458
|
+
return `${root ? `${root}${separator}` : ""}${ellipsis}${separator}${suffix}`;
|
|
459
|
+
}
|
|
460
|
+
|
|
391
461
|
function label(emojis, emoji, named, value) {
|
|
392
462
|
if (emojis) {
|
|
393
463
|
return named ? ` ${emoji} ${named}: ${value} ` : ` ${emoji} ${value} `;
|
|
@@ -560,15 +630,44 @@ function clipText(text, max, ascii = false) {
|
|
|
560
630
|
const ellipsis = ascii ? "..." : "…";
|
|
561
631
|
let out = "";
|
|
562
632
|
let width = 0;
|
|
563
|
-
|
|
564
|
-
|
|
633
|
+
let index = 0;
|
|
634
|
+
const escape = /\x1b(?:\[[0-?]*[ -/]*[@-~]|\]8;;[^\x1b\x07]*(?:\x07|\x1b\\))/y;
|
|
635
|
+
while (index < value.length) {
|
|
636
|
+
if (value[index] === "\x1b") {
|
|
637
|
+
escape.lastIndex = index;
|
|
638
|
+
const match = escape.exec(value);
|
|
639
|
+
if (match) {
|
|
640
|
+
out += match[0];
|
|
641
|
+
index += match[0].length;
|
|
642
|
+
continue;
|
|
643
|
+
}
|
|
644
|
+
}
|
|
645
|
+
|
|
646
|
+
const code = value.codePointAt(index);
|
|
647
|
+
const char = String.fromCodePoint(code);
|
|
648
|
+
const w = charWidth(code);
|
|
565
649
|
if (width + w > max - ellipsis.length) {
|
|
566
650
|
break;
|
|
567
651
|
}
|
|
568
652
|
out += char;
|
|
569
653
|
width += w;
|
|
654
|
+
index += char.length;
|
|
570
655
|
}
|
|
571
|
-
|
|
656
|
+
const clipped = out.trimEnd() + ellipsis;
|
|
657
|
+
return /\x1b\[[0-?]*[ -/]*m/.test(clipped) ? `${clipped}\x1b[0m` : clipped;
|
|
658
|
+
}
|
|
659
|
+
|
|
660
|
+
function isValidMaxWidth(value) {
|
|
661
|
+
return Number.isInteger(value) && value >= 4 && value <= 200;
|
|
662
|
+
}
|
|
663
|
+
|
|
664
|
+
function limitWidth(value, widget, ascii = false, fallback) {
|
|
665
|
+
const width = isValidMaxWidth(widget?.maxWidth)
|
|
666
|
+
? widget.maxWidth
|
|
667
|
+
: isValidMaxWidth(fallback)
|
|
668
|
+
? fallback
|
|
669
|
+
: null;
|
|
670
|
+
return width === null ? value : clipText(value, width, ascii);
|
|
572
671
|
}
|
|
573
672
|
|
|
574
673
|
// Removes escape sequences and control characters from text that did not
|
|
@@ -656,6 +755,10 @@ module.exports = {
|
|
|
656
755
|
formatTasks,
|
|
657
756
|
formatMode,
|
|
658
757
|
clipText,
|
|
758
|
+
limitWidth,
|
|
759
|
+
isValidMaxWidth,
|
|
760
|
+
shortenPath,
|
|
761
|
+
isValidDepth,
|
|
659
762
|
quotaColor,
|
|
660
763
|
contextColor,
|
|
661
764
|
resolveQuotaThresholds,
|
package/src/lib/layouts/lines.js
CHANGED
|
@@ -17,6 +17,7 @@ const {
|
|
|
17
17
|
basenameOf,
|
|
18
18
|
homePath,
|
|
19
19
|
formatResetText,
|
|
20
|
+
formatClockTime,
|
|
20
21
|
paceIndex,
|
|
21
22
|
paceGlyph,
|
|
22
23
|
formatGitSync,
|
|
@@ -25,7 +26,8 @@ const {
|
|
|
25
26
|
gitFileParts,
|
|
26
27
|
formatTasks,
|
|
27
28
|
formatMode,
|
|
28
|
-
|
|
29
|
+
limitWidth,
|
|
30
|
+
shortenPath,
|
|
29
31
|
formatTokens,
|
|
30
32
|
formatContextTokens,
|
|
31
33
|
shortModelName,
|
|
@@ -42,10 +44,12 @@ const {
|
|
|
42
44
|
resolveColor,
|
|
43
45
|
widgetColors,
|
|
44
46
|
widgetTag,
|
|
47
|
+
OS_ICONS,
|
|
45
48
|
isRaw,
|
|
46
49
|
isPaced,
|
|
47
50
|
METER_STYLES,
|
|
48
51
|
meterStyle,
|
|
52
|
+
hiddenByThreshold,
|
|
49
53
|
hasNoData,
|
|
50
54
|
RAM_CAUTION,
|
|
51
55
|
RAM_DANGER,
|
|
@@ -197,7 +201,7 @@ function rampColor(at, palette) {
|
|
|
197
201
|
function buildLinesSegment(id, session, palette, emojis, ascii = false, widget = {}, config = {}) {
|
|
198
202
|
// Raw widgets keep only their value: no icon, no label.
|
|
199
203
|
const raw = isRaw(widget, config);
|
|
200
|
-
const tag = (icon) => widgetTag(id, { emojis, raw, icon });
|
|
204
|
+
const tag = (icon) => widgetTag(id, { emojis, raw, icon, widget, ascii });
|
|
201
205
|
// Meters: 25 cells, or 12 when the bar is fitted to a narrow terminal;
|
|
202
206
|
// Classic draws the same cells as blocks.
|
|
203
207
|
const classic = config.layout === "classic";
|
|
@@ -266,11 +270,14 @@ function buildLinesSegment(id, session, palette, emojis, ascii = false, widget =
|
|
|
266
270
|
return { thresh, blinkSeq, color };
|
|
267
271
|
}
|
|
268
272
|
|
|
269
|
-
if (hasNoData(id, session)) {
|
|
273
|
+
if (hasNoData(id, session) || hiddenByThreshold(id, widget, session)) {
|
|
270
274
|
return null;
|
|
271
275
|
}
|
|
272
276
|
|
|
273
277
|
switch (id) {
|
|
278
|
+
case "clock":
|
|
279
|
+
return fg(palette.text) + tag() + formatClockTime(new Date(), config.clock) + RESET;
|
|
280
|
+
|
|
274
281
|
case "model":
|
|
275
282
|
if (!session.model) {
|
|
276
283
|
return null;
|
|
@@ -278,7 +285,11 @@ function buildLinesSegment(id, session, palette, emojis, ascii = false, widget =
|
|
|
278
285
|
return (
|
|
279
286
|
fg(palette.model) +
|
|
280
287
|
tag() +
|
|
281
|
-
(
|
|
288
|
+
limitWidth(
|
|
289
|
+
widget?.short ? shortModelName(session.model, ascii) : session.model,
|
|
290
|
+
widget,
|
|
291
|
+
ascii
|
|
292
|
+
) +
|
|
282
293
|
RESET
|
|
283
294
|
);
|
|
284
295
|
|
|
@@ -389,7 +400,11 @@ function buildLinesSegment(id, session, palette, emojis, ascii = false, widget =
|
|
|
389
400
|
}
|
|
390
401
|
|
|
391
402
|
case "cwd": {
|
|
392
|
-
const dirname =
|
|
403
|
+
const dirname = limitWidth(
|
|
404
|
+
shortenPath(homePath(session.cwd), widget?.depth, ascii),
|
|
405
|
+
widget,
|
|
406
|
+
ascii
|
|
407
|
+
);
|
|
393
408
|
if (!dirname) {
|
|
394
409
|
return null;
|
|
395
410
|
}
|
|
@@ -397,13 +412,28 @@ function buildLinesSegment(id, session, palette, emojis, ascii = false, widget =
|
|
|
397
412
|
}
|
|
398
413
|
|
|
399
414
|
case "project": {
|
|
400
|
-
const proj = basenameOf(session.project);
|
|
415
|
+
const proj = limitWidth(basenameOf(session.project), widget, ascii);
|
|
401
416
|
if (!proj) {
|
|
402
417
|
return null;
|
|
403
418
|
}
|
|
404
419
|
return fg(palette.location) + tag() + proj + RESET;
|
|
405
420
|
}
|
|
406
421
|
|
|
422
|
+
case "os": {
|
|
423
|
+
if (!session.os) {
|
|
424
|
+
return null;
|
|
425
|
+
}
|
|
426
|
+
return fg(palette.location) + tag(OS_ICONS[session.os]) + session.os + RESET;
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
case "host": {
|
|
430
|
+
if (!session.hostname) {
|
|
431
|
+
return null;
|
|
432
|
+
}
|
|
433
|
+
const name = session.username ? `${session.username}@${session.hostname}` : session.hostname;
|
|
434
|
+
return fg(palette.location) + tag() + name + RESET;
|
|
435
|
+
}
|
|
436
|
+
|
|
407
437
|
case "git": {
|
|
408
438
|
if (!session.git || !session.git.branch) {
|
|
409
439
|
return null;
|
|
@@ -411,11 +441,12 @@ function buildLinesSegment(id, session, palette, emojis, ascii = false, widget =
|
|
|
411
441
|
const opStr = widget.operation === false ? "" : formatGitOperation(session.git.operation);
|
|
412
442
|
const syncStr = formatGitSync(session.git.ahead, session.git.behind, ascii);
|
|
413
443
|
const syncPart = syncStr ? ` ${syncStr}` : "";
|
|
444
|
+
const branch = limitWidth(session.git.branch, widget, ascii);
|
|
414
445
|
return (
|
|
415
446
|
fg(palette.git) +
|
|
416
447
|
tag() +
|
|
417
448
|
"(" +
|
|
418
|
-
|
|
449
|
+
branch +
|
|
419
450
|
(session.git.dirty ? `${fg(palette.gitDirty)}*` : "") +
|
|
420
451
|
(opStr ? `${fg(palette.gitDirty)} ${opStr}` : "") +
|
|
421
452
|
(syncPart ? `${fg(palette.git)}${syncPart}` : "") +
|
|
@@ -469,7 +500,9 @@ function buildLinesSegment(id, session, palette, emojis, ascii = false, widget =
|
|
|
469
500
|
if (!session.gitDetails?.worktree) {
|
|
470
501
|
return null;
|
|
471
502
|
}
|
|
472
|
-
return
|
|
503
|
+
return (
|
|
504
|
+
fg(palette.git) + tag() + limitWidth(session.gitDetails.worktree, widget, ascii) + RESET
|
|
505
|
+
);
|
|
473
506
|
|
|
474
507
|
case "plan":
|
|
475
508
|
if (!session.plan) {
|
|
@@ -506,7 +539,7 @@ function buildLinesSegment(id, session, palette, emojis, ascii = false, widget =
|
|
|
506
539
|
if (!session.title) {
|
|
507
540
|
return null;
|
|
508
541
|
}
|
|
509
|
-
return fg(palette.text) + tag() +
|
|
542
|
+
return fg(palette.text) + tag() + limitWidth(session.title, widget, ascii, TITLE_MAX) + RESET;
|
|
510
543
|
|
|
511
544
|
case "sandbox": {
|
|
512
545
|
if (!session.sandbox) {
|
|
@@ -603,11 +636,15 @@ function buildLinesSegment(id, session, palette, emojis, ascii = false, widget =
|
|
|
603
636
|
if (!widget?.text) {
|
|
604
637
|
return null;
|
|
605
638
|
}
|
|
606
|
-
return fg(palette.text) + tag() + widget.text + RESET;
|
|
639
|
+
return fg(palette.text) + tag() + limitWidth(widget.text, widget, ascii) + RESET;
|
|
607
640
|
}
|
|
608
641
|
|
|
609
642
|
case "exec": {
|
|
610
|
-
|
|
643
|
+
// Only real output is cut: the [cmd] preview and blocked markers stay whole.
|
|
644
|
+
const output =
|
|
645
|
+
session.execMode === "run"
|
|
646
|
+
? limitWidth(execWidgetOutput(widget, session), widget, ascii)
|
|
647
|
+
: execWidgetOutput(widget, session);
|
|
611
648
|
if (!output) {
|
|
612
649
|
return null;
|
|
613
650
|
}
|
package/src/lib/layouts/pills.js
CHANGED
|
@@ -20,6 +20,7 @@ const { pickGlyph, glyphChar } = require("../powerline");
|
|
|
20
20
|
const {
|
|
21
21
|
quotaColor,
|
|
22
22
|
contextColor,
|
|
23
|
+
formatClockTime,
|
|
23
24
|
resolveQuotaThresholds,
|
|
24
25
|
resolveContextThresholds,
|
|
25
26
|
shouldBlink,
|
|
@@ -34,7 +35,8 @@ const {
|
|
|
34
35
|
gitFileParts,
|
|
35
36
|
formatTasks,
|
|
36
37
|
formatMode,
|
|
37
|
-
|
|
38
|
+
limitWidth,
|
|
39
|
+
shortenPath,
|
|
38
40
|
homePath,
|
|
39
41
|
basenameOf,
|
|
40
42
|
label,
|
|
@@ -48,10 +50,12 @@ const {
|
|
|
48
50
|
resolveColor,
|
|
49
51
|
widgetColors,
|
|
50
52
|
widgetTag,
|
|
53
|
+
OS_ICONS,
|
|
51
54
|
isRaw,
|
|
52
55
|
isPaced,
|
|
53
56
|
METER_STYLES,
|
|
54
57
|
meterStyle,
|
|
58
|
+
hiddenByThreshold,
|
|
55
59
|
hasNoData,
|
|
56
60
|
RAM_CAUTION,
|
|
57
61
|
RAM_DANGER,
|
|
@@ -169,7 +173,7 @@ function pill(color, text, blink = false) {
|
|
|
169
173
|
function buildSegment(id, session, colors, emojis, ascii = false, widget = {}, config = {}) {
|
|
170
174
|
// Raw widgets keep only their value: no icon, no label.
|
|
171
175
|
const raw = isRaw(widget, config);
|
|
172
|
-
const tag = (icon) => widgetTag(id, { emojis, raw, icon });
|
|
176
|
+
const tag = (icon) => widgetTag(id, { emojis, raw, icon, widget, ascii });
|
|
173
177
|
const lbl = (value, icon) => ` ${tag(icon)}${value} `;
|
|
174
178
|
// The pill frames a colored meter; plain-text meters (ASCII) get brackets.
|
|
175
179
|
const open = ascii ? "[" : "";
|
|
@@ -178,18 +182,27 @@ function buildSegment(id, session, colors, emojis, ascii = false, widget = {}, c
|
|
|
178
182
|
const pace = (quota) => (isPaced(widget, config) ? quota.elapsedPct : null);
|
|
179
183
|
const over200k = session.exceeds200k ? " >200k" : "";
|
|
180
184
|
|
|
181
|
-
if (hasNoData(id, session)) {
|
|
185
|
+
if (hasNoData(id, session) || hiddenByThreshold(id, widget, session)) {
|
|
182
186
|
return null;
|
|
183
187
|
}
|
|
184
188
|
|
|
185
189
|
switch (id) {
|
|
190
|
+
case "clock":
|
|
191
|
+
return pill(colors.meta, lbl(formatClockTime(new Date(), config.clock)));
|
|
192
|
+
|
|
186
193
|
case "model":
|
|
187
194
|
if (!session.model) {
|
|
188
195
|
return null;
|
|
189
196
|
}
|
|
190
197
|
return pill(
|
|
191
198
|
colors.model,
|
|
192
|
-
lbl(
|
|
199
|
+
lbl(
|
|
200
|
+
limitWidth(
|
|
201
|
+
widget?.short ? shortModelName(session.model, ascii) : session.model,
|
|
202
|
+
widget,
|
|
203
|
+
ascii
|
|
204
|
+
)
|
|
205
|
+
)
|
|
193
206
|
);
|
|
194
207
|
|
|
195
208
|
case "quota": {
|
|
@@ -480,7 +493,11 @@ function buildSegment(id, session, colors, emojis, ascii = false, widget = {}, c
|
|
|
480
493
|
}
|
|
481
494
|
|
|
482
495
|
case "cwd": {
|
|
483
|
-
const name =
|
|
496
|
+
const name = limitWidth(
|
|
497
|
+
shortenPath(homePath(session.cwd), widget?.depth, ascii),
|
|
498
|
+
widget,
|
|
499
|
+
ascii
|
|
500
|
+
);
|
|
484
501
|
if (!name) {
|
|
485
502
|
return null;
|
|
486
503
|
}
|
|
@@ -488,13 +505,28 @@ function buildSegment(id, session, colors, emojis, ascii = false, widget = {}, c
|
|
|
488
505
|
}
|
|
489
506
|
|
|
490
507
|
case "project": {
|
|
491
|
-
const name = basenameOf(session.project);
|
|
508
|
+
const name = limitWidth(basenameOf(session.project), widget, ascii);
|
|
492
509
|
if (!name) {
|
|
493
510
|
return null;
|
|
494
511
|
}
|
|
495
512
|
return pill(colors.meta, lbl(name));
|
|
496
513
|
}
|
|
497
514
|
|
|
515
|
+
case "os": {
|
|
516
|
+
if (!session.os) {
|
|
517
|
+
return null;
|
|
518
|
+
}
|
|
519
|
+
return pill(colors.meta, lbl(session.os, OS_ICONS[session.os]));
|
|
520
|
+
}
|
|
521
|
+
|
|
522
|
+
case "host": {
|
|
523
|
+
if (!session.hostname) {
|
|
524
|
+
return null;
|
|
525
|
+
}
|
|
526
|
+
const name = session.username ? `${session.username}@${session.hostname}` : session.hostname;
|
|
527
|
+
return pill(colors.meta, lbl(name));
|
|
528
|
+
}
|
|
529
|
+
|
|
498
530
|
case "git": {
|
|
499
531
|
// Antigravity can send vcs.type without a branch; an empty pill says nothing.
|
|
500
532
|
if (!session.git?.branch) {
|
|
@@ -505,9 +537,10 @@ function buildSegment(id, session, colors, emojis, ascii = false, widget = {}, c
|
|
|
505
537
|
const opPart = opStr ? `|${opStr}` : "";
|
|
506
538
|
const syncStr = formatGitSync(session.git.ahead, session.git.behind, ascii);
|
|
507
539
|
const syncPart = syncStr ? ` ${syncStr}` : "";
|
|
540
|
+
const branch = limitWidth(session.git.branch, widget, ascii);
|
|
508
541
|
return pill(
|
|
509
542
|
session.git.dirty ? colors.gitDirty : colors.git,
|
|
510
|
-
lbl(`${mark}${
|
|
543
|
+
lbl(`${mark}${branch}${opPart}${syncPart}`)
|
|
511
544
|
);
|
|
512
545
|
}
|
|
513
546
|
|
|
@@ -545,7 +578,7 @@ function buildSegment(id, session, colors, emojis, ascii = false, widget = {}, c
|
|
|
545
578
|
if (!session.gitDetails?.worktree) {
|
|
546
579
|
return null;
|
|
547
580
|
}
|
|
548
|
-
return pill(colors.git, lbl(session.gitDetails.worktree));
|
|
581
|
+
return pill(colors.git, lbl(limitWidth(session.gitDetails.worktree, widget, ascii)));
|
|
549
582
|
|
|
550
583
|
case "plan":
|
|
551
584
|
if (!session.plan) {
|
|
@@ -590,7 +623,7 @@ function buildSegment(id, session, colors, emojis, ascii = false, widget = {}, c
|
|
|
590
623
|
if (!session.title) {
|
|
591
624
|
return null;
|
|
592
625
|
}
|
|
593
|
-
return pill(colors.meta, lbl(
|
|
626
|
+
return pill(colors.meta, lbl(limitWidth(session.title, widget, ascii, TITLE_MAX)));
|
|
594
627
|
|
|
595
628
|
case "ram": {
|
|
596
629
|
const pct = session.ramPct ?? 0;
|
|
@@ -679,11 +712,15 @@ function buildSegment(id, session, colors, emojis, ascii = false, widget = {}, c
|
|
|
679
712
|
if (!widget?.text) {
|
|
680
713
|
return null;
|
|
681
714
|
}
|
|
682
|
-
return pill(colors.meta, lbl(widget.text));
|
|
715
|
+
return pill(colors.meta, lbl(limitWidth(widget.text, widget, ascii)));
|
|
683
716
|
}
|
|
684
717
|
|
|
685
718
|
case "exec": {
|
|
686
|
-
|
|
719
|
+
// Only real output is cut: the [cmd] preview and blocked markers stay whole.
|
|
720
|
+
const output =
|
|
721
|
+
session.execMode === "run"
|
|
722
|
+
? limitWidth(execWidgetOutput(widget, session), widget, ascii)
|
|
723
|
+
: execWidgetOutput(widget, session);
|
|
687
724
|
if (!output) {
|
|
688
725
|
return null;
|
|
689
726
|
}
|
package/src/lib/session.js
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
|
|
3
3
|
const os = require("os");
|
|
4
|
-
const { formatReset, resetInSeconds, firstText } = require("./formatters");
|
|
4
|
+
const { formatReset, resetInSeconds, firstText, stripControl } = require("./formatters");
|
|
5
5
|
const { resolveGit, resolveGitDetails } = require("./git");
|
|
6
6
|
const { resolveUsage } = require("./usage");
|
|
7
|
+
const { isWsl } = require("./paths");
|
|
7
8
|
|
|
8
9
|
const FIVE_HOURS = 5 * 3600;
|
|
9
10
|
const SEVEN_DAYS = 7 * 86400;
|
|
@@ -22,6 +23,46 @@ const QUOTA_BUCKETS = {
|
|
|
22
23
|
// No quota window lasts a year: a reset further out is a broken value.
|
|
23
24
|
const MAX_RESET_SECONDS = 366 * 86400;
|
|
24
25
|
|
|
26
|
+
// Node's platform ids, spelled the way people write them.
|
|
27
|
+
const OS_NAMES = {
|
|
28
|
+
win32: "Windows",
|
|
29
|
+
darwin: "macOS",
|
|
30
|
+
linux: "Linux",
|
|
31
|
+
android: "Android",
|
|
32
|
+
freebsd: "FreeBSD",
|
|
33
|
+
openbsd: "OpenBSD",
|
|
34
|
+
sunos: "SunOS",
|
|
35
|
+
aix: "AIX",
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
function currentOsName() {
|
|
39
|
+
if (process.platform === "linux" && isWsl()) {
|
|
40
|
+
return "WSL";
|
|
41
|
+
}
|
|
42
|
+
return OS_NAMES[process.platform] || process.platform;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
function currentUserAndHost() {
|
|
46
|
+
let userInfoName = "";
|
|
47
|
+
try {
|
|
48
|
+
userInfoName = os.userInfo().username;
|
|
49
|
+
} catch {
|
|
50
|
+
// Some containers have no passwd entry for the current user.
|
|
51
|
+
}
|
|
52
|
+
const username =
|
|
53
|
+
[userInfoName, process.env.USER, process.env.USERNAME]
|
|
54
|
+
.map((name) => stripControl(name).trim())
|
|
55
|
+
.find(Boolean) || "";
|
|
56
|
+
|
|
57
|
+
let hostname = "";
|
|
58
|
+
try {
|
|
59
|
+
hostname = stripControl(os.hostname()).split(".")[0].trim();
|
|
60
|
+
} catch {
|
|
61
|
+
// The host widget hides when the OS cannot provide a name.
|
|
62
|
+
}
|
|
63
|
+
return { username, hostname };
|
|
64
|
+
}
|
|
65
|
+
|
|
25
66
|
// Payload numbers can be strings, negative or absurd. The bar must never show
|
|
26
67
|
// NaN, a negative count or more than 100%.
|
|
27
68
|
function count(value) {
|
|
@@ -193,9 +234,15 @@ function extractSession(data, config, options = {}) {
|
|
|
193
234
|
const cacheHitPct = cacheTotal > 0 ? Math.round((cacheReadTokens * 100) / cacheTotal) : 0;
|
|
194
235
|
|
|
195
236
|
const modelName = firstText(data.model?.display_name, data.model?.id);
|
|
237
|
+
const uses = (id) => Boolean(config?.widgets?.some((widget) => widget?.id === id));
|
|
238
|
+
const osName = uses("os") ? currentOsName() : "";
|
|
239
|
+
const { username, hostname } = uses("host") ? currentUserAndHost() : {};
|
|
196
240
|
|
|
197
241
|
return {
|
|
242
|
+
os: osName,
|
|
198
243
|
ramPct,
|
|
244
|
+
username: username || "",
|
|
245
|
+
hostname: hostname || "",
|
|
199
246
|
model: modelName,
|
|
200
247
|
contextPct,
|
|
201
248
|
contextSize,
|
|
@@ -254,5 +301,6 @@ module.exports = {
|
|
|
254
301
|
readQuota,
|
|
255
302
|
tightestQuota,
|
|
256
303
|
contextUsedPercent,
|
|
304
|
+
currentUserAndHost,
|
|
257
305
|
extractSession,
|
|
258
306
|
};
|