openlimiter 0.1.0 → 0.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.
@@ -0,0 +1,328 @@
1
+ import { PROVIDER_CODES, floorFixed, freshness } from "@openlimiter/core";
2
+ import { STATUSLINE_BAR_SEGMENTS, meterBar } from "./render.js";
3
+ /**
4
+ * Statusline layout, version two.
5
+ *
6
+ * Version one was one plain line of provider names and percentages, and every
7
+ * person who wanted to see pressure at a glance ended up drawing their own bar
8
+ * around it. This module draws it instead: one compact cell per provider,
9
+ * `NAME bar percent`, with the overall reason code leading the row, and a
10
+ * second row when the first one runs out of columns.
11
+ *
12
+ * The old line is still here. `bars false` returns it byte for byte through the
13
+ * adapter that has always produced it, because a format somebody wrote a script
14
+ * against is a promise, and the way to change a promise is to leave the old one
15
+ * reachable.
16
+ *
17
+ * Nothing in this file decides a number. Percentages, freshness, the reason
18
+ * code and the recommendation all arrive already decided by the engine; this is
19
+ * ordering, measuring and wrapping.
20
+ */
21
+ /**
22
+ * Which half of the row a provider belongs in.
23
+ *
24
+ * A subscription is a window that refills on a clock, so its percentage is
25
+ * about how much of today is left. A credit or API balance is money, so its
26
+ * percentage is about how much of the plan is left forever. Reading the two
27
+ * kinds in one undifferentiated row invites treating a spent balance like a
28
+ * window that will come back, so the subscriptions come first and the priced
29
+ * meters sit at the end where they read as a different kind of fact.
30
+ *
31
+ * The table is exhaustive over the provider codes on purpose: a provider added
32
+ * to the engine will not compile until somebody says which half it is in.
33
+ */
34
+ const PROVIDER_CLASS = {
35
+ CLAUDE: "subscription",
36
+ CODEX: "subscription",
37
+ ANTIGRAVITY: "subscription",
38
+ OPENCODE: "subscription",
39
+ MANUAL: "subscription",
40
+ OPENROUTER: "api"
41
+ };
42
+ export const DEFAULT_PROVIDER_ORDER = [
43
+ ...PROVIDER_CODES.filter((code) => PROVIDER_CLASS[code] === "subscription"),
44
+ ...PROVIDER_CODES.filter((code) => PROVIDER_CLASS[code] === "api")
45
+ ];
46
+ const providerCodes = new Set(PROVIDER_CODES);
47
+ /**
48
+ * The order the configured ids ask for, completed by the built in order.
49
+ *
50
+ * An id this version does not know, and an id named twice, are both dropped
51
+ * rather than rejected. This runs on every redraw of somebody else's status
52
+ * row; a stale provider id left in a configuration file is not a reason to
53
+ * stop drawing the providers that are still there.
54
+ */
55
+ export function resolveProviderOrder(configured) {
56
+ const listed = [];
57
+ for (const id of configured) {
58
+ const code = id.toUpperCase();
59
+ if (!providerCodes.has(code))
60
+ continue;
61
+ const provider = code;
62
+ if (listed.includes(provider))
63
+ continue;
64
+ listed.push(provider);
65
+ }
66
+ return [
67
+ ...listed,
68
+ ...DEFAULT_PROVIDER_ORDER.filter((code) => !listed.includes(code))
69
+ ];
70
+ }
71
+ /** Shortest window first, then money, then anything unrecognised. */
72
+ const METER_CLASS_RANK = {
73
+ session: 0,
74
+ daily: 1,
75
+ weekly: 2,
76
+ monthly: 3,
77
+ credits: 4,
78
+ other: 5
79
+ };
80
+ const SIX_HOURS = 21_600;
81
+ const ONE_DAY = 86_400;
82
+ const SEVEN_DAYS = 604_800;
83
+ const THIRTY_ONE_DAYS = 2_678_400;
84
+ /**
85
+ * The classes a meter name maps to when its window states no duration.
86
+ *
87
+ * Only names this project already emits, plus the obvious synonyms a hand
88
+ * written manual document reaches for. Anything else is `other` and sorts
89
+ * last, which is the honest answer: an unrecognised name is not evidence of a
90
+ * short window.
91
+ */
92
+ const METER_NAME_CLASS = {
93
+ SESSION: "session",
94
+ PRIMARY: "session",
95
+ FIVE_HOUR: "session",
96
+ HOURLY: "session",
97
+ DAILY: "daily",
98
+ DAY: "daily",
99
+ WEEKLY: "weekly",
100
+ WEEK: "weekly",
101
+ SEVEN_DAY: "weekly",
102
+ MONTHLY: "monthly",
103
+ MONTH: "monthly",
104
+ CREDITS: "credits",
105
+ BALANCE: "credits"
106
+ };
107
+ /**
108
+ * Which kind of window a reading measures.
109
+ *
110
+ * The window's own duration decides it wherever a connector states one,
111
+ * because a duration is a fact and a name is a label. The name table is the
112
+ * fallback for the connectors that state a window kind and no length.
113
+ */
114
+ export function meterClass(snapshot) {
115
+ if (snapshot.unit === "CREDITS" || snapshot.window.kind === "lifetime") {
116
+ return "credits";
117
+ }
118
+ const duration = snapshot.window.durationSeconds;
119
+ if (duration !== undefined) {
120
+ if (duration <= SIX_HOURS)
121
+ return "session";
122
+ if (duration <= ONE_DAY)
123
+ return "daily";
124
+ if (duration <= SEVEN_DAYS)
125
+ return "weekly";
126
+ if (duration <= THIRTY_ONE_DAYS)
127
+ return "monthly";
128
+ return "other";
129
+ }
130
+ return METER_NAME_CLASS[snapshot.meter] ?? "other";
131
+ }
132
+ /** Two spaces between cells, so a reader can tell one cell from the next. */
133
+ export const CELL_GAP = " ";
134
+ function buildCell(label, snapshot, state, color, wide) {
135
+ const percent = floorFixed(snapshot.value, 1) + "%";
136
+ const bar = (paint) => meterBar(snapshot.value, state, paint, STATUSLINE_BAR_SEGMENTS, wide);
137
+ return {
138
+ plain: label + " " + bar(false) + " " + percent,
139
+ painted: label + " " + bar(color) + " " + percent,
140
+ percent: snapshot.value
141
+ };
142
+ }
143
+ function readingsFor(snapshots, provider, now) {
144
+ return snapshots
145
+ .filter((snapshot) => snapshot.provider === provider && snapshot.unit === "PERCENT")
146
+ .map((snapshot) => ({
147
+ snapshot,
148
+ state: freshness(snapshot.observedAt, snapshot.expiresAt, now)
149
+ }))
150
+ .filter((reading) => reading.state !== "unknown")
151
+ .sort((left, right) => {
152
+ const rank = METER_CLASS_RANK[meterClass(left.snapshot)] -
153
+ METER_CLASS_RANK[meterClass(right.snapshot)];
154
+ if (rank !== 0)
155
+ return rank;
156
+ return left.snapshot.meter < right.snapshot.meter ? -1 : 1;
157
+ });
158
+ }
159
+ /**
160
+ * One cell per provider, or one per meter.
161
+ *
162
+ * The filter is the same one the advice policy uses, so the cells and the
163
+ * reason code leading them are always describing the same set of readings. A
164
+ * provider with several meters shows its worst one, because a status row exists
165
+ * to tell you what is about to stop you, and the meter closest to its cap is
166
+ * that. The full set is one `openlimiter snapshot` away, and `meters all` puts
167
+ * it back in the row for anyone who wants it there.
168
+ *
169
+ * `wide` is the terminal's 256 colour claim, handed straight to the shared bar
170
+ * so a statusline cell and a table row draw the same reading in the same band
171
+ * colour. Left off, the bar reads the environment for itself.
172
+ */
173
+ export function statuslineCells(snapshots, now, order, meters, color, wide) {
174
+ const cells = [];
175
+ for (const provider of order) {
176
+ const readings = readingsFor(snapshots, provider, now);
177
+ if (readings.length === 0)
178
+ continue;
179
+ if (meters === "all") {
180
+ for (const reading of readings) {
181
+ cells.push(buildCell(provider + ":" + reading.snapshot.meter, reading.snapshot, reading.state, color, wide));
182
+ }
183
+ continue;
184
+ }
185
+ let worst = readings[0];
186
+ for (const reading of readings.slice(1)) {
187
+ if (reading.snapshot.value > worst.snapshot.value)
188
+ worst = reading;
189
+ }
190
+ cells.push(buildCell(provider, worst.snapshot, worst.state, color, wide));
191
+ }
192
+ return cells;
193
+ }
194
+ /* ------------------------------------------------------------------ layout */
195
+ /**
196
+ * Everything that is not a cell.
197
+ *
198
+ * The reason code, the recommendation and the unknown list are the same three
199
+ * fields the 0.1.0 line carried and they carry the same words, moved to the
200
+ * front so that the row can end wherever the cells end. They are never wrapped
201
+ * and never dropped: a row of bars with no verdict in front of it is a picture,
202
+ * not a status.
203
+ */
204
+ export function statuslineHead(advice) {
205
+ const recommendation = advice.recommendation.code === "PREFER"
206
+ ? " PREFER " + advice.recommendation.provider
207
+ : " NONE";
208
+ const unknown = advice.unknownProviders.length === 0
209
+ ? ""
210
+ : " UNKNOWN " + advice.unknownProviders.join(",");
211
+ return "OpenLimiter " + advice.reason + recommendation + unknown;
212
+ }
213
+ function moreCell(dropped) {
214
+ const text = "+" + String(dropped) + " more";
215
+ return { plain: text, painted: text, percent: Number.NEGATIVE_INFINITY };
216
+ }
217
+ /**
218
+ * Fill the rows left to right and report where it got to.
219
+ *
220
+ * A cell is placed whole or not at all, so the break always lands between two
221
+ * cells. Nothing is ever cut in half, because half a bar reads as a reading and
222
+ * is not one.
223
+ */
224
+ function packed(head, cells, width, rows) {
225
+ const laid = [];
226
+ let index = 0;
227
+ for (let row = 0; row < rows; row += 1) {
228
+ const current = [];
229
+ let used = row === 0 ? head.length : 0;
230
+ while (index < cells.length) {
231
+ const cell = cells[index];
232
+ const needed = used === 0
233
+ ? cell.plain.length
234
+ : used + CELL_GAP.length + cell.plain.length;
235
+ if (needed > width)
236
+ break;
237
+ used = needed;
238
+ current.push(cell);
239
+ index += 1;
240
+ }
241
+ laid.push(current);
242
+ }
243
+ return laid;
244
+ }
245
+ function fittedCount(rows) {
246
+ return rows.reduce((total, row) => total + row.length, 0);
247
+ }
248
+ /**
249
+ * The worst cells, restored to display order.
250
+ *
251
+ * When the row cannot hold everything, what it drops has to be the readings
252
+ * that matter least, and the reading that matters least is the one furthest
253
+ * from its cap. Ties keep display order, so the choice is stable between
254
+ * redraws of the same data.
255
+ */
256
+ function worstCells(cells, keep) {
257
+ return cells
258
+ .map((cell, index) => ({ cell, index }))
259
+ .sort((left, right) => right.cell.percent - left.cell.percent || left.index - right.index)
260
+ .slice(0, keep)
261
+ .sort((left, right) => left.index - right.index)
262
+ .map((entry) => entry.cell);
263
+ }
264
+ function paintRows(head, rows) {
265
+ const lines = [];
266
+ rows.forEach((row, index) => {
267
+ const body = row.map((cell) => cell.painted).join(CELL_GAP);
268
+ if (index === 0) {
269
+ lines.push(body === "" ? head : head + CELL_GAP + body);
270
+ return;
271
+ }
272
+ if (body !== "")
273
+ lines.push(body);
274
+ });
275
+ return lines.join("\n");
276
+ }
277
+ /** What the statusline says when it has nothing bounded to say. */
278
+ export const STATUSLINE_UNKNOWN = "OpenLimiter UNKNOWN";
279
+ /**
280
+ * Draw the whole line, stacking it rather than truncating it.
281
+ *
282
+ * The budget is a budget, not a terminal measurement: nothing here asks the
283
+ * operating system how wide the window is, because a statusline host runs this
284
+ * command with no terminal attached and the answer would be an invention. The
285
+ * number in the configuration is the number that is honoured.
286
+ */
287
+ export function renderStatuslineLayout(input) {
288
+ const { advice, config } = input;
289
+ if (!advice.inject || advice.reason === "UNKNOWN")
290
+ return STATUSLINE_UNKNOWN;
291
+ const cells = statuslineCells(input.snapshots, input.now, resolveProviderOrder(config.order), config.meters, input.color, input.wide);
292
+ if (cells.length === 0)
293
+ return STATUSLINE_UNKNOWN;
294
+ const head = statuslineHead(advice);
295
+ const whole = packed(head, cells, config.width, config.rows);
296
+ if (fittedCount(whole) === cells.length)
297
+ return paintRows(head, whole);
298
+ /*
299
+ * Something has to go. Give up one cell at a time, worst kept first, until
300
+ * what is left plus the count of what was dropped fits inside the rows. The
301
+ * search starts at the number that already fitted, which is an upper bound,
302
+ * and it is bounded below by zero, which is the row with only a head on it.
303
+ */
304
+ for (let keep = fittedCount(whole); keep >= 0; keep -= 1) {
305
+ const shown = [...worstCells(cells, keep), moreCell(cells.length - keep)];
306
+ const attempt = packed(head, shown, config.width, config.rows);
307
+ if (fittedCount(attempt) === shown.length)
308
+ return paintRows(head, attempt);
309
+ }
310
+ return head;
311
+ }
312
+ /**
313
+ * Whether this render may paint.
314
+ *
315
+ * `NO_COLOR` wins over every setting, including `always`. It is the one
316
+ * convention a person can set once, for every tool on the machine, and a
317
+ * configuration file inside one tool is not the place to overrule it.
318
+ */
319
+ export function statuslineColor(setting, environment, automatic) {
320
+ if (environment["NO_COLOR"] !== undefined)
321
+ return false;
322
+ if (setting === "never")
323
+ return false;
324
+ if (setting === "always")
325
+ return true;
326
+ return automatic;
327
+ }
328
+ //# sourceMappingURL=statusline.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"statusline.js","sourceRoot":"","sources":["../src/statusline.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "openlimiter",
3
- "version": "0.1.0",
3
+ "version": "0.4.0",
4
4
  "description": "A local command line meter for AI quota, usage, and reset times.",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -22,9 +22,9 @@
22
22
  "NOTICE"
23
23
  ],
24
24
  "dependencies": {
25
- "@openlimiter/adapters": "0.1.0",
26
- "@openlimiter/core": "0.1.0",
27
- "@openlimiter/connectors": "0.1.0"
25
+ "@openlimiter/adapters": "0.4.0",
26
+ "@openlimiter/connectors": "0.4.0",
27
+ "@openlimiter/core": "0.4.0"
28
28
  },
29
29
  "repository": {
30
30
  "type": "git",