osdy-pi 1.2.0 → 1.3.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.
Files changed (44) hide show
  1. package/README.md +160 -30
  2. package/bin/osdy-pi.mjs +29 -6
  3. package/bin/osdy.mjs +43 -0
  4. package/extensions/osdy-pi/account-profiles.test.ts +111 -97
  5. package/extensions/osdy-pi/account-profiles.ts +91 -162
  6. package/extensions/osdy-pi/animation.test.ts +84 -0
  7. package/extensions/osdy-pi/animation.ts +17 -8
  8. package/extensions/osdy-pi/codex-usage-ui.test.ts +1145 -0
  9. package/extensions/osdy-pi/codex-usage-ui.ts +728 -0
  10. package/extensions/osdy-pi/codex-usage.test.ts +276 -0
  11. package/extensions/osdy-pi/codex-usage.ts +276 -0
  12. package/extensions/osdy-pi/constants.ts +134 -34
  13. package/extensions/osdy-pi/context-usage-ui.test.ts +168 -0
  14. package/extensions/osdy-pi/context-usage-ui.ts +60 -0
  15. package/extensions/osdy-pi/editor-settings.test.ts +121 -23
  16. package/extensions/osdy-pi/editor-settings.ts +39 -3
  17. package/extensions/osdy-pi/metrics.test.ts +95 -0
  18. package/extensions/osdy-pi/metrics.ts +39 -1
  19. package/extensions/osdy-pi/profile-label.ts +2 -2
  20. package/extensions/osdy-pi/runtime-helpers.test.ts +220 -1
  21. package/extensions/osdy-pi/runtime-helpers.ts +42 -19
  22. package/extensions/osdy-pi/runtime.test.ts +355 -7
  23. package/extensions/osdy-pi/runtime.ts +344 -66
  24. package/extensions/osdy-pi/types.ts +26 -1
  25. package/extensions/osdy-pi/ui.test.ts +128 -0
  26. package/extensions/osdy-pi/ui.ts +57 -40
  27. package/package.json +5 -2
  28. package/scripts/osdy-pi-account-profiles.mjs +521 -76
  29. package/scripts/osdy-pi-gentle-coexistence.mjs +200 -0
  30. package/scripts/osdy-pi-profile-setup.mjs +175 -0
  31. package/themes/osdy-pi-catppuccin-frappe.json +6 -2
  32. package/themes/osdy-pi-catppuccin-latte.json +6 -2
  33. package/themes/osdy-pi-catppuccin-macchiato.json +6 -2
  34. package/themes/osdy-pi-catppuccin-mocha.json +6 -2
  35. package/themes/osdy-pi-dark.json +6 -2
  36. package/themes/osdy-pi-dracula.json +6 -2
  37. package/themes/osdy-pi-kanagawa-dragon.json +6 -2
  38. package/themes/osdy-pi-kanagawa-lotus.json +6 -2
  39. package/themes/osdy-pi-kanagawa-wave.json +6 -2
  40. package/themes/osdy-pi-lucent-orange.json +6 -2
  41. package/themes/osdy-pi-matrix.json +6 -2
  42. package/themes/osdy-pi-new.json +6 -2
  43. package/themes/osdy-pi-sexy.json +6 -2
  44. package/themes/osdy-pi-tokyo-night.json +6 -2
@@ -0,0 +1,1145 @@
1
+ import assert from "node:assert/strict";
2
+ import { existsSync, readFileSync } from "node:fs";
3
+ import { registerHooks } from "node:module";
4
+ import test from "node:test";
5
+ import { fileURLToPath } from "node:url";
6
+ import {
7
+ visibleWidth,
8
+ type Component,
9
+ type TUI,
10
+ } from "@earendil-works/pi-tui";
11
+ import type { CodexUsageSnapshot } from "./codex-usage.js";
12
+ import type { SimpleTheme } from "./types.js";
13
+ import ts from "typescript";
14
+
15
+ registerHooks({
16
+ resolve(specifier, context, nextResolve) {
17
+ if (
18
+ specifier.startsWith(".") &&
19
+ specifier.endsWith(".js") &&
20
+ context.parentURL?.endsWith(".ts")
21
+ ) {
22
+ const sourceUrl = new URL(`${specifier.slice(0, -3)}.ts`, context.parentURL);
23
+ if (existsSync(fileURLToPath(sourceUrl))) {
24
+ return { shortCircuit: true, url: sourceUrl.href };
25
+ }
26
+ }
27
+ return nextResolve(specifier, context);
28
+ },
29
+ load(url, context, nextLoad) {
30
+ if (url.endsWith(".ts")) {
31
+ const source = readFileSync(fileURLToPath(url), "utf8");
32
+ return {
33
+ format: "module",
34
+ shortCircuit: true,
35
+ source: ts.transpileModule(source, {
36
+ compilerOptions: {
37
+ module: ts.ModuleKind.ESNext,
38
+ target: ts.ScriptTarget.ES2022,
39
+ },
40
+ }).outputText,
41
+ };
42
+ }
43
+ return nextLoad(url, context);
44
+ },
45
+ });
46
+
47
+ const {
48
+ CODEX_USAGE_OVERLAY_OPTIONS,
49
+ formatCodexUsageMetadata,
50
+ formatCodexUsageWindow,
51
+ renderCompactCodexQuotaBars,
52
+ formatRemainingPercent,
53
+ renderCodexUsageDashboardLines,
54
+ renderCodexUsagePanelLines,
55
+ renderCodexUsageReadyLines,
56
+ resolveCodexUsageLayout,
57
+ showCodexUsagePanel,
58
+ } = await import("./codex-usage-ui.js");
59
+
60
+ const stripLabelSgr = (text: string): string =>
61
+ text.replaceAll("\u001B[1m", "").replaceAll("\u001B[22m", "");
62
+
63
+ const stripSgr = (text: string): string =>
64
+ text.replace(
65
+ new RegExp(`${String.fromCharCode(27)}\\[[0-?]*[ -/]*[@-~]`, "g"),
66
+ "",
67
+ );
68
+
69
+ void test("formats cached Codex quota metadata without session token activity", () => {
70
+ const snapshot = {
71
+ planType: "plus",
72
+ ordinaryUsageAllowed: true,
73
+ buckets: [
74
+ {
75
+ id: "codex",
76
+ label: undefined,
77
+ primary: { usedPercent: 37, windowMinutes: 300, resetsAt: undefined },
78
+ secondary: { usedPercent: 71, windowMinutes: 10_080, resetsAt: undefined },
79
+ },
80
+ ],
81
+ credits: undefined,
82
+ fetchedAt: 1_900_000_000_000,
83
+ };
84
+
85
+ assert.equal(formatRemainingPercent(37), "63% left");
86
+ assert.equal(
87
+ formatCodexUsageMetadata("openai-codex/gpt-5.6-sol", "medium", snapshot),
88
+ "openai-codex/gpt-5.6-sol · think medium · 5h 63% left · 7d 29% left",
89
+ );
90
+ });
91
+
92
+ void test("formats quota resets with an injected relative clock and stable UTC fallback", () => {
93
+ assert.equal(
94
+ formatCodexUsageWindow(
95
+ { usedPercent: 37, windowMinutes: 300, resetsAt: 1_893_463_200 },
96
+ 1_893_456_000_000,
97
+ ),
98
+ "5h 63% left · resets in 2h (2030-01-01 02:00 UTC)",
99
+ );
100
+ });
101
+
102
+ void test("renders reset timing for every dashboard quota window", () => {
103
+ const theme = { fg: (_name: string, text: string): string => text };
104
+ const lines = renderCodexUsageReadyLines(
105
+ theme,
106
+ {
107
+ planType: "plus",
108
+ ordinaryUsageAllowed: true,
109
+ buckets: [
110
+ {
111
+ id: "codex",
112
+ label: undefined,
113
+ primary: { usedPercent: 37, windowMinutes: 300, resetsAt: 1_893_463_200 },
114
+ secondary: {
115
+ usedPercent: 71,
116
+ windowMinutes: 10_080,
117
+ resetsAt: 1_893_455_940,
118
+ },
119
+ },
120
+ {
121
+ id: "additional",
122
+ label: "Additional",
123
+ primary: { usedPercent: 25, windowMinutes: 60, resetsAt: undefined },
124
+ secondary: {
125
+ usedPercent: 50,
126
+ windowMinutes: 120,
127
+ resetsAt: 1_893_456_030,
128
+ },
129
+ },
130
+ ],
131
+ credits: undefined,
132
+ fetchedAt: 1_900_000_000_000,
133
+ },
134
+ 1_893_456_000_000,
135
+ );
136
+
137
+ assert.deepEqual(
138
+ lines
139
+ .map(stripLabelSgr)
140
+ .filter((line) => line.startsWith("Session:") || line.startsWith("Weekly:")),
141
+ [
142
+ "Session: ██████░░░░ 63% left · resets in 2h (2030-01-01 02:00 UTC)",
143
+ "Weekly: ███░░░░░░░ 29% left · reset time passed (2029-12-31 23:59 UTC)",
144
+ "Session: ████████░░ 75% left",
145
+ "Weekly: █████░░░░░ 50% left · resets in 30s (2030-01-01 00:00 UTC)",
146
+ ],
147
+ );
148
+ });
149
+
150
+ void test("renders Session and Weekly window cards side-by-side in a wide single-bucket dashboard", () => {
151
+ const theme = { fg: (_name: string, text: string): string => text };
152
+ const lines = renderCodexUsageDashboardLines(
153
+ theme,
154
+ {
155
+ planType: "plus",
156
+ ordinaryUsageAllowed: true,
157
+ buckets: [
158
+ {
159
+ id: "codex",
160
+ label: undefined,
161
+ primary: { usedPercent: 37, windowMinutes: 300, resetsAt: 1_893_463_200 },
162
+ secondary: {
163
+ usedPercent: 71,
164
+ windowMinutes: 10_080,
165
+ resetsAt: 1_893_463_200,
166
+ },
167
+ },
168
+ ],
169
+ credits: {
170
+ hasCredits: true,
171
+ unlimited: false,
172
+ balance: "12.50",
173
+ resetCreditCount: 2,
174
+ },
175
+ fetchedAt: 1_893_456_000_000,
176
+ },
177
+ { profile: "work", provider: "openai-codex", model: "openai-codex/gpt-5.6" },
178
+ 1_893_456_000_000,
179
+ 100,
180
+ );
181
+
182
+ assert.ok(
183
+ lines.some((line) => line.includes("Session") && line.includes("Weekly")),
184
+ );
185
+ assert.ok(lines.includes("Codex [codex]"));
186
+ assert.deepEqual(
187
+ lines.filter(
188
+ (line) =>
189
+ line.includes("Plan:") ||
190
+ line.includes("Profile:") ||
191
+ line.includes("Credits:"),
192
+ ),
193
+ [
194
+ "Profile: work · Provider: openai-codex · Model: openai-codex/gpt-5.6",
195
+ "Plan: plus · Availability: allowed",
196
+ "Credits: 12.50 · Credit resets: 2",
197
+ ],
198
+ );
199
+ assert.ok(
200
+ lines.some(
201
+ (line) =>
202
+ stripLabelSgr(line).includes("Codex Session") &&
203
+ line.includes("63% left") &&
204
+ line.includes("37% used"),
205
+ ),
206
+ );
207
+ assert.ok(lines.some((line) => line.includes("Window: 5h")));
208
+ assert.ok(lines.some((line) => line.includes("Local:")));
209
+ assert.ok(lines.some((line) => line.includes("UTC: 2030-01-01 02:00 UTC")));
210
+ const mainDetailLines = lines.slice(0, lines.indexOf("Quotas + account"));
211
+ assert.ok(
212
+ !mainDetailLines.some(
213
+ (line) => line.includes("% used") || line.includes("█"),
214
+ ),
215
+ );
216
+ assert.equal(lines.at(-1)?.trim(), "r refresh · esc/q close");
217
+ });
218
+
219
+ void test("omits unavailable account fields while preserving defined false and zero values", () => {
220
+ const theme = { fg: (_name: string, text: string): string => text };
221
+ const baseSnapshot = {
222
+ planType: undefined,
223
+ ordinaryUsageAllowed: undefined,
224
+ buckets: [],
225
+ credits: {
226
+ hasCredits: true,
227
+ unlimited: false,
228
+ balance: "12.50",
229
+ resetCreditCount: undefined,
230
+ },
231
+ fetchedAt: 1_893_456_000_000,
232
+ };
233
+ const unavailableLines = renderCodexUsageDashboardLines(theme, baseSnapshot);
234
+ assert.ok(!unavailableLines.some((line) => line.includes("Plan:")));
235
+ assert.ok(!unavailableLines.some((line) => line.includes("Availability:")));
236
+ assert.ok(unavailableLines.includes("Credits: 12.50"));
237
+ assert.ok(!unavailableLines.some((line) => line.includes("Credit resets:")));
238
+
239
+ const definedLines = renderCodexUsageDashboardLines(theme, {
240
+ ...baseSnapshot,
241
+ ordinaryUsageAllowed: false,
242
+ credits: { ...baseSnapshot.credits, resetCreditCount: 0 },
243
+ });
244
+ assert.ok(definedLines.includes("Availability: not allowed"));
245
+ assert.ok(definedLines.includes("Credits: 12.50 · Credit resets: 0"));
246
+ });
247
+
248
+ void test("sanitizes presentation provider and model fields in the quota footer", () => {
249
+ const theme = { fg: (_name: string, text: string): string => text };
250
+ const snapshot = {
251
+ planType: "plus",
252
+ ordinaryUsageAllowed: true,
253
+ buckets: [
254
+ {
255
+ id: "codex",
256
+ label: undefined,
257
+ primary: { usedPercent: 37, windowMinutes: 300, resetsAt: undefined },
258
+ secondary: undefined,
259
+ },
260
+ ],
261
+ credits: undefined,
262
+ fetchedAt: 1_900_000_000_000,
263
+ };
264
+
265
+ const sanitized = renderCodexUsageDashboardLines(theme, snapshot, {
266
+ provider: "\u001B[31m custom\tprovider\u0007 \u001B[0m\n",
267
+ model: "\u001B[2J gpt\u0000-5.6\t\n",
268
+ });
269
+ assert.deepEqual(
270
+ sanitized.find((line) => line.includes("Profile:")),
271
+ "Profile: none · Provider: custom provider · Model: gpt-5.6",
272
+ );
273
+ assert.ok(
274
+ sanitized.every((line) =>
275
+ Array.from(stripLabelSgr(line)).every((character) => {
276
+ const code = character.charCodeAt(0);
277
+ return code >= 32 && (code < 127 || code > 159);
278
+ }),
279
+ ),
280
+ );
281
+
282
+ const fallback = renderCodexUsageDashboardLines(theme, snapshot, {
283
+ provider: "\u001B[31m\u001B[0m\u0000",
284
+ model: "\n\t",
285
+ });
286
+ assert.ok(
287
+ fallback.includes("Profile: none · Provider: unknown · Model: unknown"),
288
+ );
289
+ });
290
+
291
+ void test("uses a themed double outer frame and keeps controls only on its final line", () => {
292
+ const theme = { fg: (_name: string, text: string): string => text };
293
+ const lines = renderCodexUsagePanelLines(
294
+ theme,
295
+ { kind: "loading", snapshot: undefined },
296
+ {},
297
+ 1_893_456_000_000,
298
+ 60,
299
+ );
300
+ assert.match(lines[0] ?? "", /^╔.*╗$/);
301
+ assert.match(lines.at(-1) ?? "", /^╚.*╝$/);
302
+ assert.equal(
303
+ lines.filter(
304
+ (line) => line.includes("refresh") || line.includes("esc/q close"),
305
+ ).length,
306
+ 1,
307
+ );
308
+ assert.match(lines.at(-2) ?? "", /r refresh · esc\/q close/);
309
+ });
310
+
311
+ void test("fills modal footer quota bars from remaining capacity", () => {
312
+ const theme = { fg: (_name: string, text: string): string => text };
313
+ for (const { usedPercent, filled } of [
314
+ { usedPercent: 0, filled: 28 },
315
+ { usedPercent: 37, filled: 18 },
316
+ { usedPercent: 100, filled: 0 },
317
+ ]) {
318
+ const lines = renderCodexUsageDashboardLines(
319
+ theme,
320
+ {
321
+ planType: "plus",
322
+ ordinaryUsageAllowed: true,
323
+ buckets: [
324
+ {
325
+ id: "codex",
326
+ label: undefined,
327
+ primary: { usedPercent, windowMinutes: 300, resetsAt: undefined },
328
+ secondary: undefined,
329
+ },
330
+ ],
331
+ credits: undefined,
332
+ fetchedAt: 1_893_456_000_000,
333
+ },
334
+ {},
335
+ 1_893_456_000_000,
336
+ 70,
337
+ );
338
+ assert.ok(
339
+ lines
340
+ .map(stripLabelSgr)
341
+ .includes(
342
+ `Codex Session ${"█".repeat(filled)}${"░".repeat(28 - filled)} ${100 - usedPercent}% left · ${usedPercent}% used`,
343
+ ),
344
+ );
345
+ }
346
+ });
347
+
348
+ void test("inserts themed dividers after every detail title, bucket heading, and quota heading", () => {
349
+ const theme = {
350
+ fg: (name: string, text: string): string =>
351
+ `\u001B[${name === "border" ? 34 : 36}m${text}\u001B[0m`,
352
+ };
353
+ const snapshot = {
354
+ planType: "plus",
355
+ ordinaryUsageAllowed: true,
356
+ buckets: [
357
+ {
358
+ id: "codex",
359
+ label: undefined,
360
+ primary: { usedPercent: 37, windowMinutes: 300, resetsAt: undefined },
361
+ secondary: { usedPercent: 71, windowMinutes: 10_080, resetsAt: undefined },
362
+ },
363
+ ],
364
+ credits: undefined,
365
+ fetchedAt: 1_893_456_000_000,
366
+ };
367
+ for (const width of [46, 60, 100]) {
368
+ const lines = renderCodexUsageDashboardLines(
369
+ theme,
370
+ snapshot,
371
+ {},
372
+ 1_893_456_000_000,
373
+ width,
374
+ );
375
+ const primaryTitle = lines.findIndex((line) =>
376
+ stripLabelSgr(line).includes("Session · 5h"),
377
+ );
378
+ const secondaryTitle = lines.findIndex((line) =>
379
+ stripLabelSgr(line).includes("Weekly · 7d"),
380
+ );
381
+ const bucketHeading = lines.findIndex((line) =>
382
+ line.includes("Codex [codex]"),
383
+ );
384
+ const quotaHeading = lines.findIndex((line) =>
385
+ line.includes("Quotas + account"),
386
+ );
387
+ assert.ok(primaryTitle >= 0 && secondaryTitle >= primaryTitle);
388
+ assert.match(lines[primaryTitle + 1] ?? "", /─/);
389
+ assert.match(lines[secondaryTitle + 1] ?? "", /─/);
390
+ assert.match(lines[bucketHeading + 1] ?? "", /─/);
391
+ assert.match(lines[quotaHeading + 1] ?? "", /─/);
392
+ assert.ok(
393
+ [
394
+ primaryTitle + 1,
395
+ secondaryTitle + 1,
396
+ bucketHeading + 1,
397
+ quotaHeading + 1,
398
+ ].every((index) => visibleWidth(lines[index] ?? "") <= width),
399
+ );
400
+ }
401
+ });
402
+
403
+ void test("sanitizes hostile provider snapshot strings before rendering and bounds their widths", () => {
404
+ const theme = { fg: (_name: string, text: string): string => text };
405
+ const hostile =
406
+ "\u001B[31m\u001B]8;;https://evil.example\u0007bad\u001B]8;;\u0007\n\t\u0000";
407
+ const snapshot = {
408
+ planType: hostile,
409
+ ordinaryUsageAllowed: true,
410
+ buckets: [
411
+ {
412
+ id: hostile,
413
+ label: hostile,
414
+ primary: { usedPercent: 37, windowMinutes: 300, resetsAt: undefined },
415
+ secondary: undefined,
416
+ },
417
+ ],
418
+ credits: {
419
+ hasCredits: true,
420
+ unlimited: false,
421
+ balance: hostile,
422
+ resetCreditCount: 0,
423
+ },
424
+ fetchedAt: 1_893_456_000_000,
425
+ };
426
+ for (const width of [46, 60, 100]) {
427
+ const lines = renderCodexUsageDashboardLines(
428
+ theme,
429
+ snapshot,
430
+ {},
431
+ 1_893_456_000_000,
432
+ width,
433
+ );
434
+ assert.ok(lines.some((line) => line.includes("Plan: bad")));
435
+ assert.ok(lines.some((line) => line.includes("Credits: bad")));
436
+ assert.ok(lines.some((line) => line.includes("bad [bad]")));
437
+ assert.ok(
438
+ lines.every((line) =>
439
+ Array.from(stripLabelSgr(line)).every((character) => {
440
+ const code = character.charCodeAt(0);
441
+ return code >= 32 && (code < 127 || code > 159);
442
+ }),
443
+ ),
444
+ );
445
+ assert.ok(lines.every((line) => visibleWidth(line) <= width));
446
+ }
447
+ });
448
+
449
+ void test("separates modal quota footer bars and account metadata with blank lines", () => {
450
+ const theme = { fg: (_name: string, text: string): string => text };
451
+ const lines = renderCodexUsageDashboardLines(
452
+ theme,
453
+ {
454
+ planType: "plus",
455
+ ordinaryUsageAllowed: true,
456
+ buckets: [
457
+ {
458
+ id: "codex",
459
+ label: undefined,
460
+ primary: { usedPercent: 37, windowMinutes: 300, resetsAt: undefined },
461
+ secondary: { usedPercent: 71, windowMinutes: 10_080, resetsAt: undefined },
462
+ },
463
+ ],
464
+ credits: undefined,
465
+ fetchedAt: 1_893_456_000_000,
466
+ },
467
+ { profile: "work", provider: "openai-codex", model: "gpt-5.6" },
468
+ 1_893_456_000_000,
469
+ 70,
470
+ );
471
+
472
+ const footerStart = lines.indexOf("Quotas + account");
473
+ assert.deepEqual(
474
+ lines.slice(footerStart, footerStart + 9).map(stripLabelSgr),
475
+ [
476
+ "Quotas + account",
477
+ "─".repeat(70),
478
+ "Codex Session ██████████████████░░░░░░░░░░ 63% left · 37% used",
479
+ "",
480
+ "Codex Weekly ████████░░░░░░░░░░░░░░░░░░░░ 29% left · 71% used",
481
+ "",
482
+ "Profile: work",
483
+ "Provider: openai-codex",
484
+ "Model: gpt-5.6",
485
+ ],
486
+ );
487
+ });
488
+
489
+ void test("adds only the account section gap for one modal quota footer bar", () => {
490
+ const theme = { fg: (_name: string, text: string): string => text };
491
+ const lines = renderCodexUsageDashboardLines(theme, {
492
+ planType: "plus",
493
+ ordinaryUsageAllowed: true,
494
+ buckets: [
495
+ {
496
+ id: "codex",
497
+ label: undefined,
498
+ primary: { usedPercent: 37, windowMinutes: 300, resetsAt: undefined },
499
+ secondary: undefined,
500
+ },
501
+ ],
502
+ credits: undefined,
503
+ fetchedAt: 1_893_456_000_000,
504
+ });
505
+ const footerStart = lines.indexOf("Quotas + account");
506
+ assert.deepEqual(
507
+ lines.slice(footerStart, footerStart + 5).map(stripLabelSgr),
508
+ [
509
+ "Quotas + account",
510
+ "─".repeat(94),
511
+ "Codex Session ██████████████████░░░░░░░░░░ 63% left · 37% used",
512
+ "",
513
+ "Profile: none · Provider: unknown · Model: unknown",
514
+ ],
515
+ );
516
+ });
517
+
518
+ void test("does not add a quota gap when the modal footer has no quota bars", () => {
519
+ const theme = { fg: (_name: string, text: string): string => text };
520
+ const lines = renderCodexUsageDashboardLines(theme, {
521
+ planType: "plus",
522
+ ordinaryUsageAllowed: true,
523
+ buckets: [],
524
+ credits: undefined,
525
+ fetchedAt: 1_893_456_000_000,
526
+ });
527
+ const footerStart = lines.indexOf("Quotas + account");
528
+ assert.deepEqual(lines.slice(footerStart, footerStart + 3), [
529
+ "Quotas + account",
530
+ "─".repeat(94),
531
+ "Profile: none · Provider: unknown · Model: unknown",
532
+ ]);
533
+ });
534
+
535
+ void test("renders compact quota footer bars and account fields without detail-card duplication", () => {
536
+ const theme = { fg: (_name: string, text: string): string => text };
537
+ const snapshot = {
538
+ planType: "plus",
539
+ ordinaryUsageAllowed: true,
540
+ buckets: [
541
+ {
542
+ id: "codex",
543
+ label: undefined,
544
+ primary: { usedPercent: 37, windowMinutes: 300, resetsAt: 1_893_463_200 },
545
+ secondary: undefined,
546
+ },
547
+ ],
548
+ credits: {
549
+ hasCredits: true,
550
+ unlimited: false,
551
+ balance: "12.50",
552
+ resetCreditCount: 2,
553
+ },
554
+ fetchedAt: 1_893_456_000_000,
555
+ };
556
+ const lines = renderCodexUsageDashboardLines(
557
+ theme,
558
+ snapshot,
559
+ { profile: "work", provider: "openai-codex", model: "gpt-5.6" },
560
+ 1_893_456_000_000,
561
+ 70,
562
+ );
563
+ assert.ok(lines.includes("Quotas + account"));
564
+ assert.ok(
565
+ lines.some(
566
+ (line) =>
567
+ stripLabelSgr(line).includes("Codex Session") &&
568
+ line.includes("█") &&
569
+ line.includes("63% left") &&
570
+ line.includes("37% used"),
571
+ ),
572
+ );
573
+ assert.ok(lines.includes("Profile: work"));
574
+ assert.ok(lines.includes("Provider: openai-codex"));
575
+ assert.ok(lines.includes("Model: gpt-5.6"));
576
+ const detailLines = lines.slice(0, lines.indexOf("Quotas + account"));
577
+ assert.ok(detailLines.some((line) => line.includes("Window: 5h")));
578
+ assert.ok(
579
+ detailLines.some((line) => line.includes("Local:")) &&
580
+ detailLines.some((line) => line.includes("UTC:")),
581
+ );
582
+ assert.ok(
583
+ !detailLines.some((line) => line.includes("% used") || line.includes("█")),
584
+ );
585
+ });
586
+
587
+ void test("puts one final control line in ready and error output while remaining ANSI-width safe", () => {
588
+ const theme = {
589
+ fg: (name: string, text: string): string =>
590
+ `\u001B[${name === "warning" ? 33 : 36}m${text}\u001B[0m`,
591
+ };
592
+ const snapshot = {
593
+ planType: undefined,
594
+ ordinaryUsageAllowed: undefined,
595
+ buckets: [
596
+ {
597
+ id: "codex",
598
+ label: undefined,
599
+ primary: { usedPercent: 37, windowMinutes: 300, resetsAt: 1_893_463_200 },
600
+ secondary: undefined,
601
+ },
602
+ ],
603
+ credits: undefined,
604
+ fetchedAt: 1_893_456_000_000,
605
+ };
606
+ for (const state of [
607
+ { kind: "ready" as const, snapshot },
608
+ { kind: "error" as const, message: "Unavailable", snapshot },
609
+ ]) {
610
+ const lines = renderCodexUsagePanelLines(
611
+ theme,
612
+ state,
613
+ {},
614
+ 1_893_456_000_000,
615
+ 48,
616
+ );
617
+ assert.equal(
618
+ lines.filter(
619
+ (line) => line.includes("r refresh") || line.includes("esc/q close"),
620
+ ).length,
621
+ 1,
622
+ );
623
+ assert.match(lines.at(-2) ?? "", /r refresh · esc\/q close/);
624
+ assert.ok(lines.some((line) => line.includes("Session")));
625
+ assert.ok(
626
+ !lines.some(
627
+ (line) => line.includes("Primary") || line.includes("Secondary"),
628
+ ),
629
+ );
630
+ assert.ok(lines.every((line) => visibleWidth(line) <= 48));
631
+ }
632
+ });
633
+
634
+ void test("stacks Session and Weekly window cards in a narrow usage dashboard", () => {
635
+ const theme = { fg: (_name: string, text: string): string => text };
636
+ const snapshot = {
637
+ planType: "plus",
638
+ ordinaryUsageAllowed: true,
639
+ buckets: [
640
+ {
641
+ id: "codex",
642
+ label: undefined,
643
+ primary: { usedPercent: 37, windowMinutes: 300, resetsAt: undefined },
644
+ secondary: { usedPercent: 71, windowMinutes: 10_080, resetsAt: undefined },
645
+ },
646
+ ],
647
+ credits: undefined,
648
+ fetchedAt: 1_893_456_000_000,
649
+ };
650
+ const lines = renderCodexUsageDashboardLines(
651
+ theme,
652
+ snapshot,
653
+ {},
654
+ 1_893_456_000_000,
655
+ 70,
656
+ );
657
+ const primaryIndex = lines.findIndex((line) => line.includes("Session"));
658
+ const secondaryIndex = lines.findIndex((line) => line.includes("Weekly"));
659
+
660
+ assert.ok(primaryIndex >= 0);
661
+ assert.ok(secondaryIndex > primaryIndex);
662
+ assert.ok(
663
+ !lines.some((line) => line.includes("Session") && line.includes("Weekly")),
664
+ );
665
+ });
666
+
667
+ void test("adapts dashboard content at the minimum and intermediate narrow widths without losing account data", () => {
668
+ const theme = {
669
+ fg: (name: string, text: string): string =>
670
+ `\u001B[${name === "accent" ? 36 : name === "mdLink" ? 35 : 90}m${text}\u001B[0m`,
671
+ };
672
+ const snapshot = {
673
+ planType: undefined,
674
+ ordinaryUsageAllowed: false,
675
+ buckets: [
676
+ {
677
+ id: "codex",
678
+ label: undefined,
679
+ primary: { usedPercent: 37, windowMinutes: 300, resetsAt: 1_893_463_200 },
680
+ secondary: {
681
+ usedPercent: 71,
682
+ windowMinutes: 10_080,
683
+ resetsAt: 1_893_463_200,
684
+ },
685
+ },
686
+ ],
687
+ credits: {
688
+ hasCredits: true,
689
+ unlimited: false,
690
+ balance: "12.50",
691
+ resetCreditCount: 0,
692
+ },
693
+ fetchedAt: 1_893_456_000_000,
694
+ };
695
+ for (const width of [46, 60]) {
696
+ const lines = renderCodexUsageDashboardLines(
697
+ theme,
698
+ snapshot,
699
+ {
700
+ profile: "engineering-production-profile",
701
+ provider: "openai-codex-enterprise-provider-with-a-long-name",
702
+ model: "openai-codex/gpt-5.6-super-long-model-variant",
703
+ },
704
+ 1_893_456_000_000,
705
+ width,
706
+ );
707
+ const primaryCard = lines.findIndex((line) =>
708
+ stripLabelSgr(line).includes("Session · 5h"),
709
+ );
710
+ const secondaryCard = lines.findIndex((line) =>
711
+ stripLabelSgr(line).includes("Weekly · 7d"),
712
+ );
713
+ assert.ok(primaryCard >= 0 && secondaryCard > primaryCard);
714
+ assert.ok(
715
+ lines.some(
716
+ (line) => line.includes("Reset:") && line.includes("resets in 2h"),
717
+ ),
718
+ );
719
+ assert.ok(lines.some((line) => line.includes("Local:")));
720
+ assert.ok(lines.some((line) => line.includes("UTC: 2030-01-01 02:00 UTC")));
721
+ const plainOutput = stripLabelSgr(lines.join(""))
722
+ .replaceAll("\u001B[36m", "")
723
+ .replaceAll("\u001B[35m", "")
724
+ .replaceAll("\u001B[90m", "")
725
+ .replaceAll("\u001B[0m", "");
726
+ assert.ok(
727
+ plainOutput.includes("Codex Session") && plainOutput.includes("63% left"),
728
+ );
729
+ assert.ok(
730
+ plainOutput.includes("Codex Weekly") && plainOutput.includes("29% left"),
731
+ );
732
+ assert.ok(lines.some((line) => line.includes("Profile:")));
733
+ assert.ok(lines.some((line) => line.includes("Provider:")));
734
+ assert.ok(lines.some((line) => line.includes("Model:")));
735
+ assert.ok(plainOutput.includes("engineering-production-profile"));
736
+ assert.ok(
737
+ plainOutput.includes("openai-codex-enterprise-provider-with-a-long-name"),
738
+ );
739
+ assert.ok(
740
+ plainOutput.includes("openai-codex/gpt-5.6-super-long-model-variant"),
741
+ );
742
+ assert.ok(!lines.some((line) => line.includes("Plan:")));
743
+ assert.ok(lines.some((line) => line.includes("Availability: not allowed")));
744
+ assert.ok(lines.some((line) => line.includes("Credits: 12.50")));
745
+ assert.ok(lines.some((line) => line.includes("Credit resets: 0")));
746
+ assert.ok(lines.at(-1)?.includes("r refresh · esc/q close"));
747
+ assert.ok(lines.every((line) => visibleWidth(line) <= width));
748
+ }
749
+ });
750
+
751
+ void test("renders each additional bucket below Codex with its own window cards", () => {
752
+ const theme = { fg: (_name: string, text: string): string => text };
753
+ const lines = renderCodexUsageDashboardLines(
754
+ theme,
755
+ {
756
+ planType: "plus",
757
+ ordinaryUsageAllowed: true,
758
+ buckets: [
759
+ {
760
+ id: "codex",
761
+ label: undefined,
762
+ primary: { usedPercent: 37, windowMinutes: 300, resetsAt: undefined },
763
+ secondary: undefined,
764
+ },
765
+ {
766
+ id: "additional",
767
+ label: "Additional limits",
768
+ primary: { usedPercent: 25, windowMinutes: 60, resetsAt: undefined },
769
+ secondary: { usedPercent: 50, windowMinutes: 120, resetsAt: undefined },
770
+ },
771
+ ],
772
+ credits: undefined,
773
+ fetchedAt: 1_893_456_000_000,
774
+ },
775
+ {},
776
+ 1_893_456_000_000,
777
+ 100,
778
+ );
779
+ const codexIndex = lines.findIndex((line) => line === "Codex [codex]");
780
+ const additionalIndex = lines.findIndex(
781
+ (line) => line === "Additional limits [additional]",
782
+ );
783
+
784
+ assert.ok(codexIndex >= 0);
785
+ assert.ok(additionalIndex > codexIndex);
786
+ assert.ok(
787
+ lines
788
+ .slice(additionalIndex + 1)
789
+ .some((line) => line.includes("Session") && line.includes("Weekly")),
790
+ );
791
+ });
792
+
793
+ void test("uses the requested near-full-screen overlay dimensions", () => {
794
+ assert.deepEqual(CODEX_USAGE_OVERLAY_OPTIONS, {
795
+ anchor: "center",
796
+ width: 96,
797
+ minWidth: 48,
798
+ maxHeight: "92%",
799
+ margin: 1,
800
+ });
801
+ });
802
+
803
+ void test("renders compact themed remaining-capacity bars for full, partial, and empty quotas", () => {
804
+ const theme = { fg: (_name: string, text: string): string => text };
805
+ for (const { usedPercent, bar } of [
806
+ { usedPercent: 0, bar: "████████████" },
807
+ { usedPercent: 50, bar: "██████░░░░░░" },
808
+ { usedPercent: 100, bar: "░░░░░░░░░░░░" },
809
+ ]) {
810
+ const lines = renderCompactCodexQuotaBars(
811
+ theme,
812
+ {
813
+ planType: "plus",
814
+ ordinaryUsageAllowed: true,
815
+ buckets: [
816
+ {
817
+ id: "codex",
818
+ label: undefined,
819
+ primary: { usedPercent, windowMinutes: 300, resetsAt: undefined },
820
+ secondary: undefined,
821
+ },
822
+ ],
823
+ credits: undefined,
824
+ fetchedAt: 0,
825
+ },
826
+ 80,
827
+ );
828
+ assert.deepEqual(lines.map(stripLabelSgr), [
829
+ `Session 5h ${100 - usedPercent}% left ${bar}`,
830
+ ]);
831
+ }
832
+ });
833
+
834
+ void test("places compact Codex quota bars on one wide line and stacks them when narrow", () => {
835
+ const theme = { fg: (_name: string, text: string): string => text };
836
+ const snapshot = {
837
+ planType: "plus",
838
+ ordinaryUsageAllowed: true,
839
+ buckets: [
840
+ {
841
+ id: "codex",
842
+ label: undefined,
843
+ primary: { usedPercent: 37, windowMinutes: 300, resetsAt: undefined },
844
+ secondary: { usedPercent: 71, windowMinutes: 10_080, resetsAt: undefined },
845
+ },
846
+ ],
847
+ credits: undefined,
848
+ fetchedAt: 0,
849
+ };
850
+ const wide = renderCompactCodexQuotaBars(theme, snapshot, 80);
851
+ const narrow = renderCompactCodexQuotaBars(theme, snapshot, 40);
852
+ assert.equal(wide.length, 1);
853
+ assert.match(
854
+ stripLabelSgr(wide[0] ?? ""),
855
+ /Session 5h 63% left.*Weekly 7d 29% left/,
856
+ );
857
+ assert.equal(narrow.length, 2);
858
+ assert.match(stripLabelSgr(narrow[0] ?? ""), /Session 5h 63% left/);
859
+ assert.match(stripLabelSgr(narrow[1] ?? ""), /Weekly 7d 29% left/);
860
+ assert.ok([...wide, ...narrow].every((line) => !line.includes("% used")));
861
+ });
862
+
863
+ void test("fits ANSI-colored compact quota bars at very narrow widths without losing windows", () => {
864
+ const theme = {
865
+ fg: (name: string, text: string): string =>
866
+ `\u001B[${name === "accent" ? 36 : 90}m${text}\u001B[0m`,
867
+ };
868
+ const snapshot = {
869
+ planType: "plus",
870
+ ordinaryUsageAllowed: true,
871
+ buckets: [
872
+ {
873
+ id: "codex",
874
+ label: undefined,
875
+ primary: { usedPercent: 37, windowMinutes: 300, resetsAt: undefined },
876
+ secondary: { usedPercent: 71, windowMinutes: 10_080, resetsAt: undefined },
877
+ },
878
+ ],
879
+ credits: undefined,
880
+ fetchedAt: 0,
881
+ };
882
+ for (const width of [1, 2, 3, 10, 12, 20]) {
883
+ const lines = renderCompactCodexQuotaBars(theme, snapshot, width);
884
+ assert.equal(lines.length, 2);
885
+ assert.ok(lines.every((line) => visibleWidth(line) <= Math.max(1, width)));
886
+ assert.ok(lines.every((line) => /[█░]/.test(line)));
887
+ }
888
+ const lines = renderCompactCodexQuotaBars(theme, snapshot, 20);
889
+ assert.ok(stripSgr(lines[0] ?? "").includes("5h 63% left"));
890
+ assert.ok(stripSgr(lines[1] ?? "").includes("7d 29% left"));
891
+ });
892
+
893
+ void test("colors quota bar fill boundaries while keeping percentages muted across compact, ready, and modal lines", () => {
894
+ const boundaries = [
895
+ { usedPercent: 59, remaining: 41, role: "accent" },
896
+ { usedPercent: 60, remaining: 40, role: "warning" },
897
+ { usedPercent: 84, remaining: 16, role: "warning" },
898
+ { usedPercent: 85, remaining: 15, role: "error" },
899
+ ] as const;
900
+ const theme = {
901
+ fg: (name: string, text: string): string => `[${name}:${text}]`,
902
+ };
903
+ for (const { usedPercent, remaining, role } of boundaries) {
904
+ const snapshot = {
905
+ planType: "plus",
906
+ ordinaryUsageAllowed: true,
907
+ buckets: [
908
+ {
909
+ id: "codex",
910
+ label: undefined,
911
+ primary: { usedPercent, windowMinutes: 300, resetsAt: undefined },
912
+ secondary: undefined,
913
+ },
914
+ ],
915
+ credits: undefined,
916
+ fetchedAt: 0,
917
+ };
918
+ const outputs = [
919
+ renderCompactCodexQuotaBars(theme, snapshot, 80).join("\n"),
920
+ renderCodexUsageReadyLines(theme, snapshot, 0).join("\n"),
921
+ renderCodexUsageDashboardLines(theme, snapshot, {}, 0, 100).join("\n"),
922
+ ];
923
+ for (const output of outputs) {
924
+ assert.ok(output.includes(`[muted:${remaining}% left]`));
925
+ assert.ok(output.includes(`[${role}:█`));
926
+ }
927
+ }
928
+ });
929
+
930
+ void test("uses theme bar colors at normal quota levels in modal and compact output", () => {
931
+ const calls: Array<{ name: string; text: string }> = [];
932
+ const theme = {
933
+ fg: (name: string, text: string): string => {
934
+ calls.push({ name, text });
935
+ return `[${name}:${text}]`;
936
+ },
937
+ };
938
+ const snapshot = {
939
+ planType: "plus",
940
+ ordinaryUsageAllowed: true,
941
+ buckets: [
942
+ {
943
+ id: "codex",
944
+ label: undefined,
945
+ primary: { usedPercent: 50, windowMinutes: 300, resetsAt: undefined },
946
+ secondary: { usedPercent: 50, windowMinutes: 10_080, resetsAt: undefined },
947
+ },
948
+ {
949
+ id: "additional",
950
+ label: "Additional",
951
+ primary: { usedPercent: 50, windowMinutes: 60, resetsAt: undefined },
952
+ secondary: { usedPercent: 50, windowMinutes: 120, resetsAt: undefined },
953
+ },
954
+ ],
955
+ credits: undefined,
956
+ fetchedAt: 0,
957
+ };
958
+ const modal = renderCodexUsageDashboardLines(theme, snapshot, {}, 0, 100).join(
959
+ "\n",
960
+ );
961
+ const compact = renderCompactCodexQuotaBars(theme, snapshot, 80).join("\n");
962
+
963
+ assert.ok(modal.includes("[accent: \u001B[1mSession\u001B[22m · 5h"));
964
+ assert.ok(modal.includes("[accent: \u001B[1mWeekly\u001B[22m · 7d"));
965
+ assert.ok(modal.includes("[accent:\u001B[1mSession\u001B[22m ]"));
966
+ assert.ok(modal.includes("[accent:\u001B[1mWeekly\u001B[22m ]"));
967
+ assert.ok(modal.includes("[accent:████") && modal.includes("[mdLink:████"));
968
+ assert.ok(
969
+ compact.includes(
970
+ "[accent:\u001B[1mSession\u001B[22m ][muted:5h ][muted:50% left][muted: ][accent:████",
971
+ ),
972
+ );
973
+ assert.ok(
974
+ compact.includes(
975
+ "[accent:\u001B[1mWeekly\u001B[22m ][muted:7d ][muted:50% left][muted: ][mdLink:████",
976
+ ),
977
+ );
978
+ assert.ok(
979
+ calls.some(
980
+ ({ name, text }) =>
981
+ name === "accent" && text.includes("\u001B[1mSession\u001B[22m"),
982
+ ),
983
+ );
984
+ assert.ok(
985
+ calls.some(
986
+ ({ name, text }) =>
987
+ name === "accent" && text.includes("\u001B[1mWeekly\u001B[22m"),
988
+ ),
989
+ );
990
+ assert.ok(
991
+ calls
992
+ .filter(({ name }) => name === "muted")
993
+ .some(({ text }) => text.includes("░")),
994
+ );
995
+ });
996
+
997
+ void test("renders Session and Weekly labels bold accent while preserving normal theme bar colors", () => {
998
+ const theme = {
999
+ fg: (name: string, text: string): string =>
1000
+ `\u001B[${name === "accent" ? 36 : name === "mdLink" ? 35 : 90}m${text}\u001B[0m`,
1001
+ };
1002
+ const snapshot = {
1003
+ planType: "plus",
1004
+ ordinaryUsageAllowed: true,
1005
+ buckets: [
1006
+ {
1007
+ id: "codex",
1008
+ label: undefined,
1009
+ primary: { usedPercent: 50, windowMinutes: 300, resetsAt: undefined },
1010
+ secondary: { usedPercent: 50, windowMinutes: 10_080, resetsAt: undefined },
1011
+ },
1012
+ ],
1013
+ credits: undefined,
1014
+ fetchedAt: 0,
1015
+ };
1016
+ const modal = renderCodexUsageDashboardLines(theme, snapshot, {}, 0, 100);
1017
+ const compact = renderCompactCodexQuotaBars(theme, snapshot, 80);
1018
+ const ready = renderCodexUsageReadyLines(theme, snapshot, 0);
1019
+ const error = renderCodexUsagePanelLines(
1020
+ theme,
1021
+ { kind: "error", message: "Unavailable", snapshot },
1022
+ {},
1023
+ 0,
1024
+ 100,
1025
+ );
1026
+
1027
+ const modalOutput = modal.join("\n");
1028
+ const compactOutput = compact.join("\n");
1029
+ for (const output of [
1030
+ modalOutput,
1031
+ compactOutput,
1032
+ ready.join("\n"),
1033
+ error.join("\n"),
1034
+ ]) {
1035
+ assert.ok(output.includes("\u001B[36m\u001B[1mSession\u001B[22m"));
1036
+ assert.ok(output.includes("\u001B[36m\u001B[1mWeekly\u001B[22m"));
1037
+ }
1038
+ for (const output of [modalOutput, compactOutput]) {
1039
+ assert.ok(output.includes("\u001B[36m█"));
1040
+ assert.ok(output.includes("\u001B[35m█"));
1041
+ assert.ok(output.includes("\u001B[90m░"));
1042
+ }
1043
+ assert.ok(
1044
+ [...modal, ...compact, ...ready, ...error].every(
1045
+ (line) => visibleWidth(line) <= 100,
1046
+ ),
1047
+ );
1048
+ });
1049
+
1050
+ void test("repaints the modal after refresh synchronously enters loading and when it becomes ready", async () => {
1051
+ const refreshedSnapshot: CodexUsageSnapshot = {
1052
+ planType: "plus",
1053
+ ordinaryUsageAllowed: true,
1054
+ buckets: [
1055
+ {
1056
+ id: "codex",
1057
+ label: undefined,
1058
+ primary: { usedPercent: 37, windowMinutes: 300, resetsAt: undefined },
1059
+ secondary: undefined,
1060
+ },
1061
+ ],
1062
+ credits: undefined,
1063
+ fetchedAt: 1_900_000_000_000,
1064
+ };
1065
+ let component:
1066
+ | { handleInput(data: string): void; render(width: number): string[] }
1067
+ | undefined;
1068
+ const observedStates: string[] = [];
1069
+ const resolvers: Array<() => void> = [];
1070
+ let refreshCalls = 0;
1071
+ let state:
1072
+ | { kind: "loading"; snapshot: undefined }
1073
+ | { kind: "ready"; snapshot: CodexUsageSnapshot } = {
1074
+ kind: "ready",
1075
+ snapshot: refreshedSnapshot,
1076
+ };
1077
+ const refresh = (): Promise<void> => {
1078
+ refreshCalls += 1;
1079
+ state = { kind: "loading", snapshot: undefined };
1080
+ return new Promise<void>((resolve) => {
1081
+ resolvers.push(() => {
1082
+ state = { kind: "ready", snapshot: refreshedSnapshot };
1083
+ resolve();
1084
+ });
1085
+ });
1086
+ };
1087
+
1088
+ void showCodexUsagePanel(
1089
+ {
1090
+ ui: {
1091
+ custom: async <T>(
1092
+ factory: (
1093
+ tui: TUI,
1094
+ theme: SimpleTheme,
1095
+ keybindings: unknown,
1096
+ done: (result: T) => void,
1097
+ ) => Component,
1098
+ ): Promise<T> => {
1099
+ component = factory(
1100
+ {
1101
+ requestRender: () => {
1102
+ observedStates.push(state.kind);
1103
+ },
1104
+ } as TUI,
1105
+ { fg: (_name: string, text: string): string => text },
1106
+ {},
1107
+ () => {},
1108
+ ) as { handleInput(data: string): void; render(width: number): string[] };
1109
+ return await new Promise<T>(() => {});
1110
+ },
1111
+ },
1112
+ },
1113
+ () => state,
1114
+ refresh,
1115
+ );
1116
+ await Promise.resolve();
1117
+
1118
+ assert.equal(refreshCalls, 1);
1119
+ assert.equal(observedStates[0], "loading");
1120
+ resolvers.shift()?.();
1121
+ await Promise.resolve();
1122
+ await Promise.resolve();
1123
+ assert.equal(observedStates.at(-1), "ready");
1124
+ assert.deepEqual(state, { kind: "ready", snapshot: refreshedSnapshot });
1125
+ assert.ok(component?.render(96).some((line) => line.includes("63% left")));
1126
+
1127
+ observedStates.length = 0;
1128
+ component?.handleInput("r");
1129
+ component?.handleInput("r");
1130
+ assert.equal(refreshCalls, 2);
1131
+ assert.equal(observedStates[0], "loading");
1132
+ resolvers.shift()?.();
1133
+ await Promise.resolve();
1134
+ await Promise.resolve();
1135
+ assert.equal(observedStates.at(-1), "ready");
1136
+ assert.deepEqual(state, { kind: "ready", snapshot: refreshedSnapshot });
1137
+ });
1138
+
1139
+ void test("keeps Codex quota out of the editor top border layout", () => {
1140
+ const title = " Osdy-Pi ";
1141
+ const modelAndThinking = "openai-codex/gpt-5.6-sol · think medium";
1142
+ assert.deepEqual(resolveCodexUsageLayout(title, modelAndThinking), {
1143
+ topRight: modelAndThinking,
1144
+ });
1145
+ });