agy-statusblocks 0.1.2 → 0.1.3
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 +18 -2
- package/dist/cli.js +53 -18
- package/dist/config.d.ts +3 -1
- package/dist/config.js +28 -0
- package/dist/layout.d.ts +17 -1
- package/dist/layout.js +50 -21
- package/dist/segments/usage.js +28 -6
- package/dist/types.d.ts +2 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -47,14 +47,30 @@ On narrow/split-pane terminals, the layout degrades gracefully to stacked single
|
|
|
47
47
|
|
|
48
48
|
```json
|
|
49
49
|
{
|
|
50
|
-
"segments": ["context", "model", "usage", "state", "git"]
|
|
50
|
+
"segments": ["context", "model", "usage", "state", "git"],
|
|
51
|
+
"border": "rounded"
|
|
51
52
|
}
|
|
52
53
|
```
|
|
53
54
|
|
|
54
|
-
|
|
55
|
+
Border styles supported:
|
|
56
|
+
- `rounded` (default) — `╭─╮` `╰─╯` `│` `─`
|
|
57
|
+
- `square` — `┌─┐` `└─┘` `│` `─`
|
|
58
|
+
- `double` — `╔═╗` `╚═╝` `║` `═`
|
|
59
|
+
- `thick` — `┏━┓` `┗━┛` `┃` `━`
|
|
60
|
+
- `ascii` — `+-+` `+-+` `|` `-` (clean standard 7-bit ASCII)
|
|
61
|
+
- `none` — clean padded columns without frame borders
|
|
62
|
+
|
|
63
|
+
Or configure via environment variables:
|
|
55
64
|
|
|
56
65
|
```sh
|
|
57
66
|
AGY_STATUSBLOCKS_SEGMENTS=context,model,usage
|
|
67
|
+
AGY_STATUSBLOCKS_BORDER=double
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
Or pass via CLI flag:
|
|
71
|
+
|
|
72
|
+
```sh
|
|
73
|
+
npx agy-statusblocks preview --border double
|
|
58
74
|
```
|
|
59
75
|
|
|
60
76
|
## Preview
|
package/dist/cli.js
CHANGED
|
@@ -4,7 +4,7 @@ import { join, dirname, basename, sep } from 'path';
|
|
|
4
4
|
import { homedir } from 'os';
|
|
5
5
|
import { fileURLToPath } from 'url';
|
|
6
6
|
import { render } from './layout.js';
|
|
7
|
-
import { loadConfig } from './config.js';
|
|
7
|
+
import { loadConfig, normalizeBorderStyle } from './config.js';
|
|
8
8
|
import { color, c } from './colors.js';
|
|
9
9
|
import { isValidVersion, isNewerVersion } from './version.js';
|
|
10
10
|
const PACKAGE_VERSION = (() => {
|
|
@@ -134,9 +134,26 @@ function runUninstall() {
|
|
|
134
134
|
}
|
|
135
135
|
console.log(color('✓ agy-statusblocks uninstalled and reverted to built-in status line', c.green));
|
|
136
136
|
}
|
|
137
|
-
function
|
|
137
|
+
function parseBorderFlag(argv) {
|
|
138
|
+
for (let i = 0; i < argv.length; i++) {
|
|
139
|
+
const arg = argv[i];
|
|
140
|
+
if (arg === '--border' || arg === '-b') {
|
|
141
|
+
const next = argv[i + 1];
|
|
142
|
+
if (next)
|
|
143
|
+
return normalizeBorderStyle(next);
|
|
144
|
+
}
|
|
145
|
+
else if (arg && arg.startsWith('--border=')) {
|
|
146
|
+
return normalizeBorderStyle(arg.slice('--border='.length));
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
return undefined;
|
|
150
|
+
}
|
|
151
|
+
function runPreview(borderOverride) {
|
|
138
152
|
process.env['AGY_STATUSBLOCKS_NO_REMOTE'] = '1';
|
|
139
153
|
const config = loadConfig();
|
|
154
|
+
if (borderOverride) {
|
|
155
|
+
config.border = borderOverride;
|
|
156
|
+
}
|
|
140
157
|
const now = Date.now() / 1000;
|
|
141
158
|
const mockData = {
|
|
142
159
|
product: 'antigravity',
|
|
@@ -186,7 +203,8 @@ function runPreview() {
|
|
|
186
203
|
level: 'medium',
|
|
187
204
|
},
|
|
188
205
|
};
|
|
189
|
-
|
|
206
|
+
const styleLabel = config.border ?? 'rounded';
|
|
207
|
+
console.log(`\n${color('agy-statusblocks', c.bold, c.gemini)} preview ${color(`[border: ${styleLabel}]`, c.dim)}\n`);
|
|
190
208
|
for (const width of [120, 80, 50]) {
|
|
191
209
|
console.log(color('─'.repeat(width), c.gray));
|
|
192
210
|
console.log(`${width} cols:`);
|
|
@@ -199,12 +217,12 @@ function showHelp() {
|
|
|
199
217
|
${color('agy-statusblocks', c.bold, c.gemini)} — block-based status line for Antigravity CLI (agy)
|
|
200
218
|
|
|
201
219
|
${color('Usage:', c.bold)}
|
|
202
|
-
agy-statusblocks init
|
|
203
|
-
agy-statusblocks update
|
|
204
|
-
agy-statusblocks preview
|
|
205
|
-
agy-statusblocks uninstall
|
|
206
|
-
agy-statusblocks --version
|
|
207
|
-
agy-statusblocks help
|
|
220
|
+
agy-statusblocks init Install into Antigravity CLI settings
|
|
221
|
+
agy-statusblocks update Update installed files (--force to downgrade)
|
|
222
|
+
agy-statusblocks preview [--border <style>] Preview with mock data at various widths
|
|
223
|
+
agy-statusblocks uninstall Revert to built-in statusline
|
|
224
|
+
agy-statusblocks --version Print the installed package version
|
|
225
|
+
agy-statusblocks help Show this help
|
|
208
226
|
|
|
209
227
|
${color('Blocks:', c.bold)}
|
|
210
228
|
context Context window fill bar, percentage, token counts
|
|
@@ -213,13 +231,22 @@ ${color('Blocks:', c.bold)}
|
|
|
213
231
|
state Agent state pill and task/subagent/artifact counters
|
|
214
232
|
git Branch, staged/modified counts, lines added/removed
|
|
215
233
|
|
|
234
|
+
${color('Borders:', c.bold)}
|
|
235
|
+
rounded (default), square, double, thick, ascii, none
|
|
236
|
+
|
|
216
237
|
${color('Customize:', c.bold)}
|
|
217
|
-
~/.agy-statusblocks.json: { "segments": ["context", "model", "usage", "state", "git"] }
|
|
238
|
+
~/.agy-statusblocks.json: { "segments": ["context", "model", "usage", "state", "git"], "border": "rounded" }
|
|
218
239
|
Env vars: AGY_STATUSBLOCKS_SEGMENTS=context,model,usage
|
|
240
|
+
AGY_STATUSBLOCKS_BORDER=rounded|square|double|thick|ascii|none
|
|
241
|
+
CLI flags: --border, -b <style>
|
|
219
242
|
`);
|
|
220
243
|
}
|
|
221
|
-
const
|
|
222
|
-
|
|
244
|
+
const borderFlag = parseBorderFlag(process.argv.slice(2));
|
|
245
|
+
if (borderFlag) {
|
|
246
|
+
process.env['AGY_STATUSBLOCKS_BORDER'] = borderFlag;
|
|
247
|
+
}
|
|
248
|
+
const firstPositional = process.argv.slice(2).find(arg => !arg.startsWith('-'));
|
|
249
|
+
switch (firstPositional) {
|
|
223
250
|
case 'init':
|
|
224
251
|
runInit();
|
|
225
252
|
break;
|
|
@@ -227,18 +254,26 @@ switch (cmd) {
|
|
|
227
254
|
runUpdate(process.argv.includes('--force'));
|
|
228
255
|
break;
|
|
229
256
|
case 'preview':
|
|
230
|
-
runPreview();
|
|
257
|
+
runPreview(borderFlag);
|
|
231
258
|
break;
|
|
232
259
|
case 'uninstall':
|
|
233
260
|
runUninstall();
|
|
234
261
|
break;
|
|
235
|
-
case
|
|
236
|
-
|
|
237
|
-
|
|
262
|
+
case undefined:
|
|
263
|
+
if (process.argv.includes('--version') || process.argv.includes('-v')) {
|
|
264
|
+
console.log(PACKAGE_VERSION);
|
|
265
|
+
}
|
|
266
|
+
else if (process.argv.includes('--help') || process.argv.includes('-h')) {
|
|
267
|
+
showHelp();
|
|
268
|
+
}
|
|
269
|
+
else if (process.stdin.isTTY) {
|
|
270
|
+
showHelp();
|
|
271
|
+
}
|
|
272
|
+
else {
|
|
273
|
+
import('./index.js');
|
|
274
|
+
}
|
|
238
275
|
break;
|
|
239
276
|
case 'help':
|
|
240
|
-
case '--help':
|
|
241
|
-
case '-h':
|
|
242
277
|
showHelp();
|
|
243
278
|
break;
|
|
244
279
|
default:
|
package/dist/config.d.ts
CHANGED
|
@@ -1,2 +1,4 @@
|
|
|
1
|
-
import type { StatusBlocksConfig } from './types.js';
|
|
1
|
+
import type { StatusBlocksConfig, BorderStyle } from './types.js';
|
|
2
|
+
export declare const VALID_BORDER_STYLES: readonly BorderStyle[];
|
|
3
|
+
export declare function normalizeBorderStyle(val: unknown): BorderStyle | undefined;
|
|
2
4
|
export declare function loadConfig(): StatusBlocksConfig;
|
package/dist/config.js
CHANGED
|
@@ -1,8 +1,26 @@
|
|
|
1
1
|
import { readFileSync } from 'fs';
|
|
2
2
|
import { join } from 'path';
|
|
3
3
|
import { homedir } from 'os';
|
|
4
|
+
export const VALID_BORDER_STYLES = [
|
|
5
|
+
'rounded',
|
|
6
|
+
'square',
|
|
7
|
+
'double',
|
|
8
|
+
'thick',
|
|
9
|
+
'ascii',
|
|
10
|
+
'none',
|
|
11
|
+
];
|
|
12
|
+
export function normalizeBorderStyle(val) {
|
|
13
|
+
if (typeof val === 'string') {
|
|
14
|
+
const lower = val.trim().toLowerCase();
|
|
15
|
+
if (VALID_BORDER_STYLES.includes(lower)) {
|
|
16
|
+
return lower;
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
return undefined;
|
|
20
|
+
}
|
|
4
21
|
export function loadConfig() {
|
|
5
22
|
const envSegments = process.env['AGY_STATUSBLOCKS_SEGMENTS'];
|
|
23
|
+
const envBorder = process.env['AGY_STATUSBLOCKS_BORDER'];
|
|
6
24
|
const config = {};
|
|
7
25
|
try {
|
|
8
26
|
const raw = readFileSync(join(homedir(), '.agy-statusblocks.json'), 'utf8');
|
|
@@ -14,10 +32,20 @@ export function loadConfig() {
|
|
|
14
32
|
config.remoteUsage = parsed.remoteUsage;
|
|
15
33
|
if (typeof parsed.stackWithDefault === 'boolean')
|
|
16
34
|
config.stackWithDefault = parsed.stackWithDefault;
|
|
35
|
+
if (parsed.border) {
|
|
36
|
+
const border = normalizeBorderStyle(parsed.border);
|
|
37
|
+
if (border)
|
|
38
|
+
config.border = border;
|
|
39
|
+
}
|
|
17
40
|
}
|
|
18
41
|
}
|
|
19
42
|
catch { /* no config file — use defaults */ }
|
|
20
43
|
if (envSegments)
|
|
21
44
|
config.segments = envSegments.split(',');
|
|
45
|
+
if (envBorder) {
|
|
46
|
+
const border = normalizeBorderStyle(envBorder);
|
|
47
|
+
if (border)
|
|
48
|
+
config.border = border;
|
|
49
|
+
}
|
|
22
50
|
return config;
|
|
23
51
|
}
|
package/dist/layout.d.ts
CHANGED
|
@@ -1,3 +1,19 @@
|
|
|
1
|
-
import type { AgyStatusData, StatusBlocksConfig } from './types.js';
|
|
1
|
+
import type { Block, AgyStatusData, StatusBlocksConfig, BorderStyle } from './types.js';
|
|
2
2
|
export declare const DEFAULT_ORDER: string[];
|
|
3
|
+
export interface BorderGlyphs {
|
|
4
|
+
tl: string;
|
|
5
|
+
tr: string;
|
|
6
|
+
bl: string;
|
|
7
|
+
br: string;
|
|
8
|
+
h: string;
|
|
9
|
+
v: string;
|
|
10
|
+
}
|
|
11
|
+
export declare const BORDER_STYLES: Record<BorderStyle, BorderGlyphs>;
|
|
12
|
+
type RowGroup = {
|
|
13
|
+
blocks: Block[];
|
|
14
|
+
widths: number[];
|
|
15
|
+
};
|
|
16
|
+
export declare function boxify(lines: string[], innerW: number, style?: BorderStyle, title?: string): string[];
|
|
17
|
+
export declare function renderRow(group: RowGroup, style?: BorderStyle): string[];
|
|
3
18
|
export declare function render(data: AgyStatusData, width: number, config?: StatusBlocksConfig): string;
|
|
19
|
+
export {};
|
package/dist/layout.js
CHANGED
|
@@ -7,35 +7,62 @@ import { gitSegment } from './segments/git.js';
|
|
|
7
7
|
const ALL_SEGMENTS = [contextSegment, modelSegment, usageSegment, stateSegment, gitSegment];
|
|
8
8
|
export const DEFAULT_ORDER = ['context', 'model', 'usage', 'state', 'git'];
|
|
9
9
|
const GAP = 1;
|
|
10
|
-
const
|
|
11
|
-
|
|
10
|
+
export const BORDER_STYLES = {
|
|
11
|
+
rounded: { tl: '╭', tr: '╮', bl: '╰', br: '╯', h: '─', v: '│' },
|
|
12
|
+
square: { tl: '┌', tr: '┐', bl: '└', br: '┘', h: '─', v: '│' },
|
|
13
|
+
double: { tl: '╔', tr: '╗', bl: '╚', br: '╝', h: '═', v: '║' },
|
|
14
|
+
thick: { tl: '┏', tr: '┓', bl: '┗', br: '┛', h: '━', v: '┃' },
|
|
15
|
+
ascii: { tl: '+', tr: '+', bl: '+', br: '+', h: '-', v: '|' },
|
|
16
|
+
none: { tl: '', tr: '', bl: '', br: '', h: '', v: '' },
|
|
17
|
+
};
|
|
18
|
+
export function boxify(lines, innerW, style = 'rounded', title) {
|
|
19
|
+
if (style === 'none') {
|
|
20
|
+
const boxed = [];
|
|
21
|
+
if (title) {
|
|
22
|
+
boxed.push(' ' + color(title, c.dim) + ' '.repeat(Math.max(0, innerW + 1 - title.length)));
|
|
23
|
+
}
|
|
24
|
+
for (const line of lines) {
|
|
25
|
+
boxed.push(' ' + padRight(line, innerW) + ' ');
|
|
26
|
+
}
|
|
27
|
+
return boxed;
|
|
28
|
+
}
|
|
29
|
+
const g = BORDER_STYLES[style] || BORDER_STYLES.rounded;
|
|
12
30
|
let top;
|
|
13
31
|
if (title) {
|
|
14
32
|
const label = ` ${title} `;
|
|
15
33
|
const remaining = Math.max(0, innerW + 2 - label.length - 1);
|
|
16
|
-
top = color(
|
|
34
|
+
top = color(g.tl + g.h, c.gray) + color(label, c.dim) + color(g.h.repeat(remaining) + g.tr, c.gray);
|
|
17
35
|
}
|
|
18
36
|
else {
|
|
19
|
-
top = color(
|
|
37
|
+
top = color(g.tl + g.h.repeat(innerW + 2) + g.tr, c.gray);
|
|
20
38
|
}
|
|
21
|
-
const bot = color(
|
|
39
|
+
const bot = color(g.bl + g.h.repeat(innerW + 2) + g.br, c.gray);
|
|
22
40
|
const boxed = [top];
|
|
23
41
|
for (const line of lines) {
|
|
24
|
-
boxed.push(color(
|
|
42
|
+
boxed.push(color(g.v, c.gray) + ' ' + padRight(line, innerW) + ' ' + color(g.v, c.gray));
|
|
25
43
|
}
|
|
26
44
|
boxed.push(bot);
|
|
27
45
|
return boxed;
|
|
28
46
|
}
|
|
29
|
-
function renderRow(group) {
|
|
47
|
+
export function renderRow(group, style = 'rounded') {
|
|
30
48
|
const { blocks, widths } = group;
|
|
31
|
-
const
|
|
32
|
-
const
|
|
49
|
+
const chrome = style === 'none' ? 2 : 4;
|
|
50
|
+
const boxes = blocks.map((b, i) => boxify(b.lines, widths[i], style, b.id));
|
|
51
|
+
const boxWidths = widths.map(w => w + chrome);
|
|
52
|
+
const g = BORDER_STYLES[style] || BORDER_STYLES.rounded;
|
|
33
53
|
const maxHeight = Math.max(...boxes.map(b => b.length));
|
|
34
54
|
for (let i = 0; i < boxes.length; i++) {
|
|
35
55
|
const box = boxes[i];
|
|
36
56
|
while (box.length < maxHeight) {
|
|
37
|
-
const blankRow =
|
|
38
|
-
|
|
57
|
+
const blankRow = style === 'none'
|
|
58
|
+
? ' '.repeat(widths[i] + 2)
|
|
59
|
+
: color(g.v, c.gray) + ' '.repeat(widths[i] + 2) + color(g.v, c.gray);
|
|
60
|
+
if (style === 'none') {
|
|
61
|
+
box.push(blankRow);
|
|
62
|
+
}
|
|
63
|
+
else {
|
|
64
|
+
box.splice(box.length - 1, 0, blankRow);
|
|
65
|
+
}
|
|
39
66
|
}
|
|
40
67
|
}
|
|
41
68
|
const rows = [];
|
|
@@ -63,12 +90,12 @@ function decodeAssignment(combo, blockCount, targetRows, blockRow, rowUsed) {
|
|
|
63
90
|
}
|
|
64
91
|
return true;
|
|
65
92
|
}
|
|
66
|
-
function computeRowWidths(blockRow, blockCount, targetRows, blockWidths, rowWidths) {
|
|
93
|
+
function computeRowWidths(blockRow, blockCount, targetRows, blockWidths, rowWidths, chrome) {
|
|
67
94
|
rowWidths.fill(0, 0, targetRows);
|
|
68
95
|
const rowCounts = new Array(targetRows).fill(0);
|
|
69
96
|
for (let b = 0; b < blockCount; b++) {
|
|
70
97
|
const r = blockRow[b];
|
|
71
|
-
rowWidths[r] = (rowWidths[r] ?? 0) + (blockWidths[b] ?? 0) +
|
|
98
|
+
rowWidths[r] = (rowWidths[r] ?? 0) + (blockWidths[b] ?? 0) + chrome;
|
|
72
99
|
rowCounts[r] = (rowCounts[r] ?? 0) + 1;
|
|
73
100
|
}
|
|
74
101
|
for (let r = 0; r < targetRows; r++) {
|
|
@@ -77,10 +104,10 @@ function computeRowWidths(blockRow, blockCount, targetRows, blockWidths, rowWidt
|
|
|
77
104
|
}
|
|
78
105
|
}
|
|
79
106
|
}
|
|
80
|
-
function solveGreedy(blocks, maxWidth) {
|
|
107
|
+
function solveGreedy(blocks, maxWidth, chrome) {
|
|
81
108
|
const rows = [];
|
|
82
109
|
for (const b of blocks) {
|
|
83
|
-
const boxW = b.width +
|
|
110
|
+
const boxW = b.width + chrome;
|
|
84
111
|
let placed = false;
|
|
85
112
|
for (const r of rows) {
|
|
86
113
|
const addedW = r.blocks.length > 0 ? boxW + GAP : boxW;
|
|
@@ -99,12 +126,12 @@ function solveGreedy(blocks, maxWidth) {
|
|
|
99
126
|
rows.sort((a, b) => a.currentW - b.currentW);
|
|
100
127
|
return rows.map(r => ({ blocks: r.blocks, widths: r.widths }));
|
|
101
128
|
}
|
|
102
|
-
function solveLayout(blocks, maxWidth) {
|
|
129
|
+
function solveLayout(blocks, maxWidth, chrome) {
|
|
103
130
|
if (blocks.length === 0)
|
|
104
131
|
return [];
|
|
105
132
|
const blockCount = blocks.length;
|
|
106
133
|
if (blockCount > 6)
|
|
107
|
-
return solveGreedy(blocks, maxWidth);
|
|
134
|
+
return solveGreedy(blocks, maxWidth, chrome);
|
|
108
135
|
const blockWidths = blocks.map(b => b.width);
|
|
109
136
|
for (let targetRows = 1; targetRows <= blockCount; targetRows++) {
|
|
110
137
|
const totalCombos = Math.pow(targetRows, blockCount);
|
|
@@ -116,7 +143,7 @@ function solveLayout(blocks, maxWidth) {
|
|
|
116
143
|
for (let combo = 0; combo < totalCombos; combo++) {
|
|
117
144
|
if (!decodeAssignment(combo, blockCount, targetRows, blockRow, rowUsed))
|
|
118
145
|
continue;
|
|
119
|
-
computeRowWidths(blockRow, blockCount, targetRows, blockWidths, rowWidths);
|
|
146
|
+
computeRowWidths(blockRow, blockCount, targetRows, blockWidths, rowWidths, chrome);
|
|
120
147
|
let fits = true;
|
|
121
148
|
let maxRowW = 0;
|
|
122
149
|
for (let r = 0; r < targetRows; r++) {
|
|
@@ -145,7 +172,7 @@ function solveLayout(blocks, maxWidth) {
|
|
|
145
172
|
rWidths.push(blocks[b].width);
|
|
146
173
|
}
|
|
147
174
|
}
|
|
148
|
-
const totalW = rWidths.reduce((a, w) => a + w +
|
|
175
|
+
const totalW = rWidths.reduce((a, w) => a + w + chrome, 0) + (rBlocks.length - 1) * GAP;
|
|
149
176
|
rows.push({ blocks: rBlocks, widths: rWidths, totalW });
|
|
150
177
|
}
|
|
151
178
|
rows.sort((a, b) => a.totalW - b.totalW);
|
|
@@ -156,15 +183,17 @@ function solveLayout(blocks, maxWidth) {
|
|
|
156
183
|
}
|
|
157
184
|
export function render(data, width, config = {}) {
|
|
158
185
|
const order = config.segments ?? DEFAULT_ORDER;
|
|
186
|
+
const borderStyle = config.border ?? 'rounded';
|
|
187
|
+
const chrome = borderStyle === 'none' ? 2 : 4;
|
|
159
188
|
const segmentsMap = new Map(ALL_SEGMENTS.map(s => [s.id, s]));
|
|
160
189
|
const activeSegments = order
|
|
161
190
|
.map(id => segmentsMap.get(id))
|
|
162
191
|
.filter((s) => !!s && s.enabled(data));
|
|
163
192
|
const blocks = activeSegments.map(s => s.render(data, width));
|
|
164
|
-
const groups = solveLayout(blocks, width);
|
|
193
|
+
const groups = solveLayout(blocks, width, chrome);
|
|
165
194
|
const lines = [];
|
|
166
195
|
for (const group of groups) {
|
|
167
|
-
lines.push(...renderRow(group));
|
|
196
|
+
lines.push(...renderRow(group, borderStyle));
|
|
168
197
|
}
|
|
169
198
|
return lines.join('\n');
|
|
170
199
|
}
|
package/dist/segments/usage.js
CHANGED
|
@@ -178,12 +178,34 @@ export const usageSegment = {
|
|
|
178
178
|
return { id: 'usage', priority: 25, width: 0, lines: [''] };
|
|
179
179
|
}
|
|
180
180
|
const BAR_WIDTH = 8;
|
|
181
|
-
const
|
|
182
|
-
|
|
183
|
-
const pctStr =
|
|
184
|
-
const
|
|
185
|
-
const
|
|
186
|
-
|
|
181
|
+
const active = limits.slice(0, 2);
|
|
182
|
+
const formatted = active.map(l => {
|
|
183
|
+
const pctStr = `${l.percent}%`;
|
|
184
|
+
const resetTime = l.resetsAt ? formatResetTime(l.resetsAt) : '';
|
|
185
|
+
const resetRaw = resetTime ? `↻ ${resetTime}` : '';
|
|
186
|
+
return {
|
|
187
|
+
limit: l,
|
|
188
|
+
pctStr,
|
|
189
|
+
resetRaw,
|
|
190
|
+
label: l.label,
|
|
191
|
+
};
|
|
192
|
+
});
|
|
193
|
+
const maxPctLen = Math.max(...formatted.map(r => r.pctStr.length));
|
|
194
|
+
const hasAnyReset = formatted.some(r => r.resetRaw.length > 0);
|
|
195
|
+
const maxResetLen = hasAnyReset ? Math.max(...formatted.map(r => r.resetRaw.length)) : 0;
|
|
196
|
+
const maxLabelLen = Math.max(...formatted.map(r => r.label.length));
|
|
197
|
+
const rows = formatted.map(r => {
|
|
198
|
+
const bar = renderBar(r.limit.percent, BAR_WIDTH);
|
|
199
|
+
const paddedPct = ' '.repeat(maxPctLen - r.pctStr.length) + r.pctStr;
|
|
200
|
+
const pctColorStr = color(paddedPct, pctColor(r.limit.percent), c.bold);
|
|
201
|
+
let resetColorStr = '';
|
|
202
|
+
if (hasAnyReset && r.resetRaw) {
|
|
203
|
+
const paddedReset = r.resetRaw + ' '.repeat(maxResetLen - r.resetRaw.length);
|
|
204
|
+
resetColorStr = color(paddedReset, c.dim);
|
|
205
|
+
}
|
|
206
|
+
const paddedLabel = ' '.repeat(maxLabelLen - r.label.length) + r.label;
|
|
207
|
+
const lbl = color(paddedLabel, c.dim);
|
|
208
|
+
const parts = [bar, pctColorStr, resetColorStr, lbl].filter(Boolean);
|
|
187
209
|
return parts.join(color(' · ', c.dim));
|
|
188
210
|
});
|
|
189
211
|
const width = Math.max(...rows.map(visibleLength));
|
package/dist/types.d.ts
CHANGED
|
@@ -76,8 +76,10 @@ export interface Segment {
|
|
|
76
76
|
render(data: AgyStatusData, allocWidth: number): Block;
|
|
77
77
|
enabled(data: AgyStatusData): boolean;
|
|
78
78
|
}
|
|
79
|
+
export type BorderStyle = 'rounded' | 'square' | 'double' | 'thick' | 'ascii' | 'none';
|
|
79
80
|
export interface StatusBlocksConfig {
|
|
80
81
|
segments?: string[];
|
|
81
82
|
stackWithDefault?: boolean;
|
|
82
83
|
remoteUsage?: boolean;
|
|
84
|
+
border?: BorderStyle;
|
|
83
85
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "agy-statusblocks",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.3",
|
|
4
4
|
"description": "Opinionated, adaptive block-based status line for Antigravity CLI (agy) with bin-packing layout, rate limit tracking, and live agent telemetry",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|