openlimiter 0.1.0 → 0.2.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/dist/config.js CHANGED
@@ -1,8 +1,166 @@
1
1
  import { lstat, mkdir } from "node:fs/promises";
2
2
  import path from "node:path";
3
- import { canonicalJson, resolveStateDirectory, writeFileAtomically } from "@openlimiter/core";
3
+ import { canonicalJson, readJsonFileSafely, resolveStateDirectory, writeFileAtomically } from "@openlimiter/core";
4
4
  import { connectors } from "@openlimiter/connectors";
5
5
  export const CONFIG_FILE_NAME = "openlimiter-config.json";
6
+ export const STATUSLINE_KEYS = [
7
+ "order",
8
+ "meters",
9
+ "width",
10
+ "rows",
11
+ "bars",
12
+ "color"
13
+ ];
14
+ /**
15
+ * The narrowest and widest budget a row may be given.
16
+ *
17
+ * Below forty columns not one cell and its header fit, so the setting would
18
+ * only ever produce an empty row. Above four hundred the budget stops
19
+ * describing any real terminal and starts being a way to ask for an unbounded
20
+ * line, which this tool does not print.
21
+ */
22
+ export const MIN_STATUSLINE_WIDTH = 40;
23
+ export const MAX_STATUSLINE_WIDTH = 400;
24
+ export const DEFAULT_STATUSLINE = {
25
+ order: [],
26
+ meters: "worst",
27
+ width: 140,
28
+ rows: 2,
29
+ bars: true,
30
+ color: "auto"
31
+ };
32
+ const connectorIds = connectors.map((connector) => connector.id);
33
+ /** The list of ids an error message offers back to the reader. */
34
+ const connectorIdList = connectorIds.join(", ");
35
+ function isRecord(value) {
36
+ return typeof value === "object" && value !== null && !Array.isArray(value);
37
+ }
38
+ function normalizeOrder(value) {
39
+ if (!Array.isArray(value))
40
+ return null;
41
+ if (value.length > connectorIds.length)
42
+ return null;
43
+ const order = [];
44
+ for (const entry of value) {
45
+ if (typeof entry !== "string")
46
+ return null;
47
+ const id = entry.toLowerCase();
48
+ if (!connectorIds.includes(id) || order.includes(id))
49
+ return null;
50
+ order.push(id);
51
+ }
52
+ return order;
53
+ }
54
+ function normalizeWidth(value) {
55
+ if (typeof value !== "number" || !Number.isInteger(value))
56
+ return null;
57
+ if (value < MIN_STATUSLINE_WIDTH || value > MAX_STATUSLINE_WIDTH)
58
+ return null;
59
+ return value;
60
+ }
61
+ /**
62
+ * Read a stored statusline section, key by key, keeping what is usable.
63
+ *
64
+ * A key this does not understand falls back to its default rather than
65
+ * rejecting the file. The statusline is drawn inside somebody else's tool and
66
+ * a hand edited typo in one field is not a reason to stop drawing the other
67
+ * five. Everything written through `openlimiter config set` is validated
68
+ * before it lands, so this path only ever repairs a file edited by hand.
69
+ */
70
+ export function normalizeStatusline(value) {
71
+ if (!isRecord(value))
72
+ return DEFAULT_STATUSLINE;
73
+ const meters = value["meters"];
74
+ const rows = value["rows"];
75
+ const bars = value["bars"];
76
+ const color = value["color"];
77
+ return {
78
+ order: normalizeOrder(value["order"]) ?? DEFAULT_STATUSLINE.order,
79
+ meters: meters === "worst" || meters === "all" ? meters : DEFAULT_STATUSLINE.meters,
80
+ width: normalizeWidth(value["width"]) ?? DEFAULT_STATUSLINE.width,
81
+ rows: rows === 1 || rows === 2 ? rows : DEFAULT_STATUSLINE.rows,
82
+ bars: typeof bars === "boolean" ? bars : DEFAULT_STATUSLINE.bars,
83
+ color: color === "auto" || color === "always" || color === "never"
84
+ ? color
85
+ : DEFAULT_STATUSLINE.color
86
+ };
87
+ }
88
+ /** One stored key, rendered the way `config get` prints it. */
89
+ export function statuslineValueText(statusline, key) {
90
+ if (key === "order") {
91
+ return statusline.order.length === 0 ? "NONE" : statusline.order.join(",");
92
+ }
93
+ if (key === "meters")
94
+ return statusline.meters;
95
+ if (key === "width")
96
+ return String(statusline.width);
97
+ if (key === "rows")
98
+ return String(statusline.rows);
99
+ if (key === "bars")
100
+ return statusline.bars ? "true" : "false";
101
+ return statusline.color;
102
+ }
103
+ export function isStatuslineKey(key) {
104
+ return STATUSLINE_KEYS.includes(key);
105
+ }
106
+ /**
107
+ * Apply one key from the command line, or say why it cannot be applied.
108
+ *
109
+ * Every rejection names the key and lists what it would have accepted, because
110
+ * a configuration error a person cannot fix from the message is a second
111
+ * problem on top of the first. No value is ever coerced into something near
112
+ * enough: a width of `wide` is refused rather than read as the default.
113
+ */
114
+ export function setStatuslineValue(statusline, key, value) {
115
+ if (!isStatuslineKey(key)) {
116
+ return {
117
+ ok: false,
118
+ message: "unknown statusline key. Known keys: " + STATUSLINE_KEYS.join(", ") + "."
119
+ };
120
+ }
121
+ if (key === "order") {
122
+ if (value === "" || value === "NONE" || value === "none") {
123
+ return { ok: true, statusline: { ...statusline, order: [] } };
124
+ }
125
+ const order = normalizeOrder(value.split(",").map((entry) => entry.trim()));
126
+ return order === null
127
+ ? {
128
+ ok: false,
129
+ message: "statusline.order must be a comma separated list of provider " +
130
+ "ids from " + connectorIdList + ", each named once, or NONE for the " +
131
+ "built in order."
132
+ }
133
+ : { ok: true, statusline: { ...statusline, order } };
134
+ }
135
+ if (key === "meters") {
136
+ return value === "worst" || value === "all"
137
+ ? { ok: true, statusline: { ...statusline, meters: value } }
138
+ : { ok: false, message: "statusline.meters must be worst or all." };
139
+ }
140
+ if (key === "width") {
141
+ const width = /^\d{1,4}$/u.test(value) ? normalizeWidth(Number(value)) : null;
142
+ return width === null
143
+ ? {
144
+ ok: false,
145
+ message: "statusline.width must be a whole number from " +
146
+ String(MIN_STATUSLINE_WIDTH) + " to " + String(MAX_STATUSLINE_WIDTH) + "."
147
+ }
148
+ : { ok: true, statusline: { ...statusline, width } };
149
+ }
150
+ if (key === "rows") {
151
+ return value === "1" || value === "2"
152
+ ? { ok: true, statusline: { ...statusline, rows: value === "1" ? 1 : 2 } }
153
+ : { ok: false, message: "statusline.rows must be 1 or 2." };
154
+ }
155
+ if (key === "bars") {
156
+ return value === "true" || value === "false"
157
+ ? { ok: true, statusline: { ...statusline, bars: value === "true" } }
158
+ : { ok: false, message: "statusline.bars must be true or false." };
159
+ }
160
+ return value === "auto" || value === "always" || value === "never"
161
+ ? { ok: true, statusline: { ...statusline, color: value } }
162
+ : { ok: false, message: "statusline.color must be auto, always, or never." };
163
+ }
6
164
  async function rejectSymlink(target) {
7
165
  try {
8
166
  if ((await lstat(target)).isSymbolicLink())
@@ -21,21 +179,94 @@ export async function writeConfig(config, directory = resolveStateDirectory()) {
21
179
  await rejectSymlink(target);
22
180
  await writeFileAtomically(target, canonicalJson(config));
23
181
  }
182
+ function connectorRows(environment) {
183
+ return connectors.map((connector) => ({
184
+ id: connector.id,
185
+ enabled: true,
186
+ detected: connector.detect(environment)
187
+ }));
188
+ }
189
+ function normalizeConnectors(value) {
190
+ if (!Array.isArray(value))
191
+ return [];
192
+ const rows = [];
193
+ for (const entry of value.slice(0, connectorIds.length)) {
194
+ if (!isRecord(entry))
195
+ continue;
196
+ const id = entry["id"];
197
+ if (typeof id !== "string" || !connectorIds.includes(id))
198
+ continue;
199
+ if (rows.some((row) => row.id === id))
200
+ continue;
201
+ rows.push({ id, enabled: true, detected: entry["detected"] === true });
202
+ }
203
+ return rows;
204
+ }
205
+ /**
206
+ * Read the configuration file.
207
+ *
208
+ * The document is validated the same way the cache is: an unreadable or
209
+ * unsafe file is reported rather than replaced, and a readable file with a
210
+ * field this version does not recognise keeps the fields it does. A file that
211
+ * is simply not there yet is `missing`, which is not a failure.
212
+ */
213
+ export async function readConfig(directory = resolveStateDirectory()) {
214
+ try {
215
+ await rejectSymlink(directory);
216
+ }
217
+ catch {
218
+ return { ok: false, reason: "unsafe" };
219
+ }
220
+ const document = await readJsonFileSafely(path.join(directory, CONFIG_FILE_NAME));
221
+ if (!document.ok)
222
+ return document;
223
+ if (!isRecord(document.value))
224
+ return { ok: false, reason: "corrupt" };
225
+ return {
226
+ ok: true,
227
+ config: {
228
+ version: 1,
229
+ connectors: normalizeConnectors(document.value["connectors"]),
230
+ statusline: normalizeStatusline(document.value["statusline"])
231
+ }
232
+ };
233
+ }
234
+ /**
235
+ * The statusline section, or the defaults, and never an exception.
236
+ *
237
+ * The statusline command runs inside another tool's status row on every
238
+ * redraw. It reads its own configuration the way it reads everything else:
239
+ * if the answer is not there, the answer is the default, and the line is still
240
+ * drawn.
241
+ */
242
+ export async function readStatuslineConfig(directory) {
243
+ try {
244
+ const result = await readConfig(directory);
245
+ return result.ok ? result.config.statusline : DEFAULT_STATUSLINE;
246
+ }
247
+ catch {
248
+ return DEFAULT_STATUSLINE;
249
+ }
250
+ }
24
251
  export async function initialize(environment, credentialStore, promptForSecret, directory) {
252
+ /*
253
+ * Re running init re detects the connectors and keeps the statusline the
254
+ * person configured. Detection is a fact about the machine and is meant to
255
+ * be refreshed; the layout is a preference and overwriting it would punish
256
+ * anyone who ran the command twice.
257
+ */
258
+ const existing = await readConfig(directory ?? resolveStateDirectory()).catch(() => ({ ok: false, reason: "missing" }));
25
259
  const config = {
26
260
  version: 1,
27
- connectors: connectors.map((connector) => ({
28
- id: connector.id,
29
- enabled: true,
30
- detected: connector.detect(environment)
31
- }))
261
+ connectors: connectorRows(environment),
262
+ statusline: existing.ok ? existing.config.statusline : DEFAULT_STATUSLINE
32
263
  };
33
264
  let credentialStored = false;
34
265
  const openrouter = config.connectors.find((connector) => connector.id === "openrouter");
35
266
  if (openrouter?.detected === true) {
36
267
  try {
37
- const existing = await credentialStore.get("openlimiter", "openrouter");
38
- if (existing === null) {
268
+ const existingSecret = await credentialStore.get("openlimiter", "openrouter");
269
+ if (existingSecret === null) {
39
270
  const secret = await promptForSecret();
40
271
  if (secret.length > 0 && secret.length <= 8_192) {
41
272
  await credentialStore.set("openlimiter", "openrouter", secret);
@@ -50,4 +281,18 @@ export async function initialize(environment, credentialStore, promptForSecret,
50
281
  await writeConfig(config, directory);
51
282
  return { config, credentialStored };
52
283
  }
284
+ /**
285
+ * The configuration a `config set` writes into when there is no file yet.
286
+ *
287
+ * Connector detection is redone rather than left blank, so a first `config
288
+ * set` produces the same file `init` would have produced with the chosen key
289
+ * changed, instead of a file that claims no connector exists.
290
+ */
291
+ export function defaultConfig(environment) {
292
+ return {
293
+ version: 1,
294
+ connectors: connectorRows(environment),
295
+ statusline: DEFAULT_STATUSLINE
296
+ };
297
+ }
53
298
  //# sourceMappingURL=config.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,kBAAkB,CAAC;AAChD,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EACL,aAAa,EACb,qBAAqB,EACrB,mBAAmB,EACpB,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EAAE,UAAU,EAAE,MAAM,yBAAyB,CAAC;AAGrD,MAAM,CAAC,MAAM,gBAAgB,GAAG,yBAAyB,CAAC;AAW1D,KAAK,UAAU,aAAa,CAAC,MAAc;IACzC,IAAI,CAAC;QACH,IAAI,CAAC,MAAM,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,cAAc,EAAE;YAAE,MAAM,IAAI,KAAK,CAAC,mBAAmB,CAAC,CAAC;IACnF,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,IAAK,KAA+B,CAAC,IAAI,KAAK,QAAQ;YAAE,MAAM,KAAK,CAAC;IACtE,CAAC;AACH,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,WAAW,CAC/B,MAAyB,EACzB,SAAS,GAAG,qBAAqB,EAAE;IAEnC,MAAM,aAAa,CAAC,SAAS,CAAC,CAAC;IAC/B,MAAM,KAAK,CAAC,SAAS,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;IACzD,MAAM,aAAa,CAAC,SAAS,CAAC,CAAC;IAC/B,MAAM,MAAM,GAAG,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,gBAAgB,CAAC,CAAC;IACtD,MAAM,aAAa,CAAC,MAAM,CAAC,CAAC;IAC5B,MAAM,mBAAmB,CAAC,MAAM,EAAE,aAAa,CAAC,MAAM,CAAC,CAAC,CAAC;AAC3D,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,UAAU,CAC9B,WAAyD,EACzD,eAAgC,EAChC,eAAsC,EACtC,SAAkB;IAElB,MAAM,MAAM,GAAsB;QAChC,OAAO,EAAE,CAAC;QACV,UAAU,EAAE,UAAU,CAAC,GAAG,CAAC,CAAC,SAAS,EAAE,EAAE,CAAC,CAAC;YACzC,EAAE,EAAE,SAAS,CAAC,EAAE;YAChB,OAAO,EAAE,IAAI;YACb,QAAQ,EAAE,SAAS,CAAC,MAAM,CAAC,WAAW,CAAC;SACxC,CAAC,CAAC;KACJ,CAAC;IACF,IAAI,gBAAgB,GAAG,KAAK,CAAC;IAC7B,MAAM,UAAU,GAAG,MAAM,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC,SAAS,EAAE,EAAE,CAAC,SAAS,CAAC,EAAE,KAAK,YAAY,CAAC,CAAC;IACxF,IAAI,UAAU,EAAE,QAAQ,KAAK,IAAI,EAAE,CAAC;QAClC,IAAI,CAAC;YACH,MAAM,QAAQ,GAAG,MAAM,eAAe,CAAC,GAAG,CAAC,aAAa,EAAE,YAAY,CAAC,CAAC;YACxE,IAAI,QAAQ,KAAK,IAAI,EAAE,CAAC;gBACtB,MAAM,MAAM,GAAG,MAAM,eAAe,EAAE,CAAC;gBACvC,IAAI,MAAM,CAAC,MAAM,GAAG,CAAC,IAAI,MAAM,CAAC,MAAM,IAAI,KAAK,EAAE,CAAC;oBAChD,MAAM,eAAe,CAAC,GAAG,CAAC,aAAa,EAAE,YAAY,EAAE,MAAM,CAAC,CAAC;oBAC/D,gBAAgB,GAAG,IAAI,CAAC;gBAC1B,CAAC;YACH,CAAC;QACH,CAAC;QAAC,MAAM,CAAC;YACP,gBAAgB,GAAG,KAAK,CAAC;QAC3B,CAAC;IACH,CAAC;IACD,MAAM,WAAW,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC;IACrC,OAAO,EAAE,MAAM,EAAE,gBAAgB,EAAE,CAAC;AACtC,CAAC"}
1
+ {"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"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"}
package/dist/index.d.ts CHANGED
@@ -3,5 +3,7 @@ export * from "./config.js";
3
3
  export * from "./credentials.js";
4
4
  export * from "./ingest.js";
5
5
  export * from "./qr.js";
6
+ export * from "./render.js";
6
7
  export * from "./serve.js";
8
+ export * from "./statusline.js";
7
9
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,UAAU,CAAC;AACzB,cAAc,aAAa,CAAC;AAC5B,cAAc,kBAAkB,CAAC;AACjC,cAAc,aAAa,CAAC;AAC5B,cAAc,SAAS,CAAC;AACxB,cAAc,YAAY,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,UAAU,CAAC;AACzB,cAAc,aAAa,CAAC;AAC5B,cAAc,kBAAkB,CAAC;AACjC,cAAc,aAAa,CAAC;AAC5B,cAAc,SAAS,CAAC;AACxB,cAAc,aAAa,CAAC;AAC5B,cAAc,YAAY,CAAC;AAC3B,cAAc,iBAAiB,CAAC"}
package/dist/index.js CHANGED
@@ -3,5 +3,7 @@ export * from "./config.js";
3
3
  export * from "./credentials.js";
4
4
  export * from "./ingest.js";
5
5
  export * from "./qr.js";
6
+ export * from "./render.js";
6
7
  export * from "./serve.js";
8
+ export * from "./statusline.js";
7
9
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,UAAU,CAAC;AACzB,cAAc,aAAa,CAAC;AAC5B,cAAc,kBAAkB,CAAC;AACjC,cAAc,aAAa,CAAC;AAC5B,cAAc,SAAS,CAAC;AACxB,cAAc,YAAY,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,UAAU,CAAC;AACzB,cAAc,aAAa,CAAC;AAC5B,cAAc,kBAAkB,CAAC;AACjC,cAAc,aAAa,CAAC;AAC5B,cAAc,SAAS,CAAC;AACxB,cAAc,aAAa,CAAC;AAC5B,cAAc,YAAY,CAAC;AAC3B,cAAc,iBAAiB,CAAC"}
@@ -0,0 +1,130 @@
1
+ import { type FailureCategory, type ProviderFailure, type Snapshot, type SnapshotState } from "@openlimiter/core";
2
+ /**
3
+ * How the terminal draws a reading.
4
+ *
5
+ * This is the command line tool's presentation layer and nothing else lives
6
+ * here. Every number arrives already decided by the engine; this module only
7
+ * chooses a colour band, a bar, and a form of words.
8
+ *
9
+ * THE PRESSURE BANDS, AND WHY RED IS NOT WHERE THE ENGINE WARNS
10
+ * -------------------------------------------------------------
11
+ * healthy 0 to 59 green
12
+ * watch 60 to 79 yellow
13
+ * urgent 80 to 89 orange, and yellow where there is no orange
14
+ * critical 90 and above red
15
+ *
16
+ * Eighty is not a number this file picked. packages/core/src/policy.ts calls a
17
+ * provider NEAR_CAP at 80 and stops recommending it there, so the orange band
18
+ * opens at exactly the reading where the agent stops routing work to a
19
+ * provider. The human and the agent change their mind about the same number at
20
+ * the same instant, which is the point of the fourth band.
21
+ *
22
+ * The visual red at 90 is deliberately later than that agent warning. The agent
23
+ * is told at 80 so it can route away while there is still room; the person
24
+ * watching the bar sees red at 90, when the situation is actually worth
25
+ * reacting to. Warning the agent earlier than the human sees red is the correct
26
+ * direction, and collapsing the two would either make the display cry wolf or
27
+ * make the routing act too late. Orange is what fills the gap between them.
28
+ *
29
+ * apps/web/app/app/language.ts and apps/desktop/ui/app.js carry their own copy
30
+ * of these two functions, because none of the three can import from the others.
31
+ * Those two still draw the earlier three band scale and have not been moved to
32
+ * this one yet.
33
+ */
34
+ /** The four bands, plus the band a meter with no reading gets. */
35
+ export type Pressure = "healthy" | "watch" | "urgent" | "critical" | "none";
36
+ export declare function pressureOf(percent: number): Pressure;
37
+ /** How many of the ten blocks a percentage lights, never rounding upward. */
38
+ export declare const BAR_SEGMENTS = 10;
39
+ /**
40
+ * The statusline's own density.
41
+ *
42
+ * Five blocks, not ten. A statusline shares one row with a model name, a
43
+ * branch, a directory and whatever else the host puts there, and six ten block
44
+ * bars would take the row on their own. Half the blocks at twice the price per
45
+ * block reads at a glance and still lands every reading in the right band,
46
+ * which is all a status row is for. The snapshot table keeps all ten, because
47
+ * a table is read deliberately and has the room.
48
+ */
49
+ export declare const STATUSLINE_BAR_SEGMENTS = 5;
50
+ export declare function filledSegments(percent: number, segments?: number): number;
51
+ /**
52
+ * Whether this run may emit escape codes.
53
+ *
54
+ * Two things veto colour, and either one is enough: the NO_COLOR convention,
55
+ * which any value at all switches on, and standard output not being a
56
+ * terminal, which is what a pipe into a file or another program looks like.
57
+ */
58
+ export declare function supportsColor(environment: Readonly<Record<string, string | undefined>>, isTty: boolean): boolean;
59
+ /**
60
+ * Whether this terminal has more than the eight standard colours.
61
+ *
62
+ * Two signals, either one enough. A `TERM` naming `256color` is the convention
63
+ * terminfo has used for decades, and a `COLORTERM` set to anything at all is
64
+ * what the terminals that went further than 256 announce themselves with. Both
65
+ * are claims the terminal makes about itself, not measurements, so this answers
66
+ * a question about what may safely be emitted and never about what is true.
67
+ *
68
+ * A terminal that says neither is not an error and is not a lesser rendering.
69
+ * It gets the yellow of the band below, so the reading still reads as pressure
70
+ * and only the distinction between 80 and 60 is lost. Information degrades; it
71
+ * never breaks, and no escape code is ever emitted that a terminal would print
72
+ * as literal characters.
73
+ */
74
+ export declare function supports256Color(environment: Readonly<Record<string, string | undefined>>): boolean;
75
+ /**
76
+ * The one place a band becomes a colour.
77
+ *
78
+ * Both the ten block table bar and the five block statusline bar come through
79
+ * here, so a reading is the same colour wherever it is drawn, and the orange
80
+ * fallback is decided once rather than at each call site.
81
+ */
82
+ export declare function bandCode(band: Pressure, wide: boolean): string;
83
+ /**
84
+ * The segmented bar.
85
+ *
86
+ * Ten blocks by default, the same ten the dashboard and the desktop window
87
+ * draw, and five when the statusline asks for its own density. With colour it
88
+ * is drawn in block characters and painted in the band's colour. Without colour
89
+ * it is the same positions in plain ASCII, because a terminal that reported no
90
+ * colour support may also be a log file, and a log file should carry no escape
91
+ * codes at all.
92
+ *
93
+ * The block count is the only thing the caller chooses. The band, and therefore
94
+ * the colour, comes from the reading alone, so the same percentage is the same
95
+ * colour at either density.
96
+ *
97
+ * `wide` is the terminal's own claim about its palette, and it defaults to the
98
+ * answer read off the environment so every caller gets the right one without
99
+ * carrying it. A test passes it explicitly, because a test that asks the
100
+ * machine it happens to be running on what colours it has is not a test.
101
+ */
102
+ export declare function meterBar(percent: number, state: SnapshotState, color: boolean, segments?: number, wide?: boolean): string;
103
+ /** A failure, in red, in our own fixed words. */
104
+ export declare function failureLine(provider: string, category: FailureCategory, color: boolean): string;
105
+ export declare function failureLines(failures: readonly ProviderFailure[], color: boolean): readonly string[];
106
+ /**
107
+ * Time left before the window resets, compact enough for a table column.
108
+ *
109
+ * Two units at most and no spaces, so every row stays one space separated
110
+ * record that a script can still split. A window with no reset says so rather
111
+ * than printing a zero.
112
+ */
113
+ export declare function timeToReset(resetAt: string | null, now: string): string;
114
+ /**
115
+ * Money, when the reading carries it.
116
+ *
117
+ * The three fields travel together out of the normalizer, so checking one is
118
+ * enough, and the currency is a closed literal rather than provider text.
119
+ */
120
+ export declare function amountField(snapshot: Snapshot): string;
121
+ /**
122
+ * The snapshot table.
123
+ *
124
+ * Eight columns, always eight, separated by one space. AMOUNT and RESET read
125
+ * NONE where a provider has none rather than disappearing, because a table
126
+ * whose column count moves with its data cannot be parsed by anything.
127
+ */
128
+ export declare const TABLE_HEADER = "PROVIDER METER BAR USAGE AMOUNT STATE RESET IN";
129
+ export declare function renderTable(snapshots: readonly Snapshot[], now: string, color: boolean): string;
130
+ //# sourceMappingURL=render.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"render.d.ts","sourceRoot":"","sources":["../src/render.ts"],"names":[],"mappings":"AAAA,OAAO,EAIL,KAAK,eAAe,EACpB,KAAK,eAAe,EACpB,KAAK,QAAQ,EACb,KAAK,aAAa,EACnB,MAAM,mBAAmB,CAAC;AAE3B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AAEH,kEAAkE;AAClE,MAAM,MAAM,QAAQ,GAAG,SAAS,GAAG,OAAO,GAAG,QAAQ,GAAG,UAAU,GAAG,MAAM,CAAC;AAE5E,wBAAgB,UAAU,CAAC,OAAO,EAAE,MAAM,GAAG,QAAQ,CAMpD;AAED,6EAA6E;AAC7E,eAAO,MAAM,YAAY,KAAK,CAAC;AAE/B;;;;;;;;;GASG;AACH,eAAO,MAAM,uBAAuB,IAAI,CAAC;AAEzC,wBAAgB,cAAc,CAAC,OAAO,EAAE,MAAM,EAAE,QAAQ,SAAe,GAAG,MAAM,CAK/E;AAiCD;;;;;;GAMG;AACH,wBAAgB,aAAa,CAC3B,WAAW,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,CAAC,EACzD,KAAK,EAAE,OAAO,GACb,OAAO,CAGT;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,gBAAgB,CAC9B,WAAW,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,CAAC,GACxD,OAAO,CAIT;AAED;;;;;;GAMG;AACH,wBAAgB,QAAQ,CAAC,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,OAAO,GAAG,MAAM,CAG9D;AAMD;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,QAAQ,CACtB,OAAO,EAAE,MAAM,EACf,KAAK,EAAE,aAAa,EACpB,KAAK,EAAE,OAAO,EACd,QAAQ,SAAe,EACvB,IAAI,UAAgC,GACnC,MAAM,CASR;AAED,iDAAiD;AACjD,wBAAgB,WAAW,CACzB,QAAQ,EAAE,MAAM,EAChB,QAAQ,EAAE,eAAe,EACzB,KAAK,EAAE,OAAO,GACb,MAAM,CAER;AAED,wBAAgB,YAAY,CAC1B,QAAQ,EAAE,SAAS,eAAe,EAAE,EACpC,KAAK,EAAE,OAAO,GACb,SAAS,MAAM,EAAE,CAGnB;AAQD;;;;;;GAMG;AACH,wBAAgB,WAAW,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM,CAevE;AAED;;;;;GAKG;AACH,wBAAgB,WAAW,CAAC,QAAQ,EAAE,QAAQ,GAAG,MAAM,CAOtD;AAID;;;;;;GAMG;AACH,eAAO,MAAM,YAAY,mDAAmD,CAAC;AAE7E,wBAAgB,WAAW,CACzB,SAAS,EAAE,SAAS,QAAQ,EAAE,EAC9B,GAAG,EAAE,MAAM,EACX,KAAK,EAAE,OAAO,GACb,MAAM,CAiBR"}