@inferhub/usage 0.1.3 → 0.1.5
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/format.d.ts +3 -4
- package/dist/format.js +30 -55
- package/dist/format.test.js +31 -47
- package/package.json +1 -1
- package/src/format.test.ts +34 -50
- package/src/format.ts +31 -67
package/dist/format.d.ts
CHANGED
|
@@ -3,16 +3,15 @@ export declare function money(usdc: string | number | null | undefined, digits?:
|
|
|
3
3
|
export declare function tokens(n: number | null | undefined): string;
|
|
4
4
|
export declare function shortModel(model: string | null | undefined): string;
|
|
5
5
|
/**
|
|
6
|
-
*
|
|
6
|
+
* One-line Claude statusline — keep short (Claude only shows one row).
|
|
7
7
|
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
8
|
+
* Example:
|
|
9
|
+
* InferHub · sess 19r · day 129r · all $0.41 · bal $1.31 · top gpt-5.5
|
|
10
10
|
*/
|
|
11
11
|
export declare function formatStatusLine(usage: AccountUsage, extras?: {
|
|
12
12
|
sessionCostUsd?: number | null;
|
|
13
13
|
contextPct?: number | null;
|
|
14
14
|
model?: string | null;
|
|
15
|
-
/** When true, include Claude local list-price estimate. Default false. */
|
|
16
15
|
showEstimate?: boolean;
|
|
17
16
|
}): string;
|
|
18
17
|
/** Multi-line human report for /usage skills. */
|
package/dist/format.js
CHANGED
|
@@ -1,10 +1,14 @@
|
|
|
1
1
|
export function money(usdc, digits = 2) {
|
|
2
2
|
const n = Number(usdc ?? 0);
|
|
3
3
|
if (!Number.isFinite(n))
|
|
4
|
-
return "$0
|
|
5
|
-
if (
|
|
4
|
+
return "$0";
|
|
5
|
+
if (n === 0)
|
|
6
|
+
return "$0";
|
|
7
|
+
if (Math.abs(n) < 0.01)
|
|
6
8
|
return `$${n.toFixed(4)}`;
|
|
7
|
-
|
|
9
|
+
if (Math.abs(n) < 1)
|
|
10
|
+
return `$${n.toFixed(2)}`;
|
|
11
|
+
return `$${n.toFixed(2)}`;
|
|
8
12
|
}
|
|
9
13
|
export function tokens(n) {
|
|
10
14
|
const v = Number(n ?? 0);
|
|
@@ -20,69 +24,40 @@ export function shortModel(model) {
|
|
|
20
24
|
const parts = model.split("/");
|
|
21
25
|
return parts[parts.length - 1] || model;
|
|
22
26
|
}
|
|
23
|
-
/**
|
|
24
|
-
function
|
|
25
|
-
const
|
|
26
|
-
const
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
bits.push(`${req.toLocaleString()} req`);
|
|
31
|
-
bits.push(`${tokens(tok)} tok`);
|
|
27
|
+
/** Compact metric: "$0.12" if billed, else "19r" (optionally with tokens if tiny). */
|
|
28
|
+
function compact(spendUsdc, requests, totalTokens) {
|
|
29
|
+
const spend = Number(spendUsdc ?? 0);
|
|
30
|
+
const req = Number(requests ?? 0);
|
|
31
|
+
if (spend > 0) {
|
|
32
|
+
// billed: show money + req if space-ish useful
|
|
33
|
+
return req > 0 ? `${money(spend)}/${req}r` : money(spend);
|
|
32
34
|
}
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
bits.push(money(spend));
|
|
38
|
-
else
|
|
39
|
-
bits.push("$0");
|
|
40
|
-
return `${label} ${bits.join(" / ")}`;
|
|
35
|
+
// free / zero spend: show traffic only
|
|
36
|
+
if (req <= 0 && Number(totalTokens ?? 0) <= 0)
|
|
37
|
+
return "—";
|
|
38
|
+
return `${req}r`;
|
|
41
39
|
}
|
|
42
40
|
/**
|
|
43
|
-
*
|
|
41
|
+
* One-line Claude statusline — keep short (Claude only shows one row).
|
|
44
42
|
*
|
|
45
|
-
*
|
|
46
|
-
*
|
|
43
|
+
* Example:
|
|
44
|
+
* InferHub · sess 19r · day 129r · all $0.41 · bal $1.31 · top gpt-5.5
|
|
47
45
|
*/
|
|
48
46
|
export function formatStatusLine(usage, extras) {
|
|
49
|
-
const model = extras?.model ? shortModel(extras.model) : null;
|
|
50
|
-
const bal = money(usage.balance.amount_usdc);
|
|
51
|
-
const top = shortModel(usage.top_model?.model);
|
|
52
|
-
const ctx = extras?.contextPct != null && Number.isFinite(extras.contextPct)
|
|
53
|
-
? `${Math.round(extras.contextPct)}% context`
|
|
54
|
-
: null;
|
|
55
47
|
const parts = ["InferHub"];
|
|
56
|
-
|
|
57
|
-
parts.push(model);
|
|
58
|
-
// Latest conversation on InferHub (server-derived session), if present and useful
|
|
48
|
+
// Session (latest IH conversation) — omit if empty
|
|
59
49
|
if (usage.session && (usage.session.requests > 0 || Number(usage.session.spend_usdc) > 0)) {
|
|
60
|
-
parts.push(
|
|
61
|
-
spendUsdc: usage.session.spend_usdc,
|
|
62
|
-
requests: usage.session.requests,
|
|
63
|
-
totalTokens: usage.session.total_tokens,
|
|
64
|
-
}));
|
|
50
|
+
parts.push(`sess ${compact(usage.session.spend_usdc, usage.session.requests, usage.session.total_tokens)}`);
|
|
65
51
|
}
|
|
66
|
-
parts.push(
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
}));
|
|
71
|
-
parts.push(activity("all-time", {
|
|
72
|
-
spendUsdc: usage.all_time.spend_usdc,
|
|
73
|
-
requests: usage.all_time.requests,
|
|
74
|
-
totalTokens: usage.all_time.total_tokens,
|
|
75
|
-
}));
|
|
76
|
-
parts.push(`balance ${bal}`);
|
|
52
|
+
parts.push(`day ${compact(usage.window.spend_usdc, usage.window.requests, usage.window.total_tokens)}`);
|
|
53
|
+
parts.push(`all ${compact(usage.all_time.spend_usdc, usage.all_time.requests)}`);
|
|
54
|
+
parts.push(`bal ${money(usage.balance.amount_usdc)}`);
|
|
55
|
+
const top = shortModel(usage.top_model?.model);
|
|
77
56
|
if (top && top !== "—")
|
|
78
57
|
parts.push(`top ${top}`);
|
|
79
|
-
if
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
extras.sessionCostUsd != null &&
|
|
83
|
-
Number.isFinite(extras.sessionCostUsd) &&
|
|
84
|
-
extras.sessionCostUsd > 0) {
|
|
85
|
-
parts.push(`claude-est ${money(extras.sessionCostUsd)}`);
|
|
58
|
+
// context % is useful but optional — only if provided and non-zero space
|
|
59
|
+
if (extras?.contextPct != null && Number.isFinite(extras.contextPct)) {
|
|
60
|
+
parts.push(`${Math.round(extras.contextPct)}%`);
|
|
86
61
|
}
|
|
87
62
|
return parts.join(" · ");
|
|
88
63
|
}
|
package/dist/format.test.js
CHANGED
|
@@ -3,41 +3,39 @@ import test from "node:test";
|
|
|
3
3
|
import { formatStatusLine, money, normalizeBaseUrl, usageUrl } from "./index.js";
|
|
4
4
|
test("normalizeBaseUrl adds /v1", () => {
|
|
5
5
|
assert.equal(normalizeBaseUrl("https://api.inferhub.dev"), "https://api.inferhub.dev/v1");
|
|
6
|
-
assert.equal(normalizeBaseUrl("https://api.inferhub.dev/v1/"), "https://api.inferhub.dev/v1");
|
|
7
6
|
});
|
|
8
7
|
test("usageUrl", () => {
|
|
9
|
-
assert.equal(usageUrl("https://api.inferhub.dev", "day", "UTC"), "https://api.inferhub.dev/v1/me/usage?window=day&tz=UTC");
|
|
10
8
|
assert.equal(usageUrl("https://api.inferhub.dev", "day", "UTC", "abc"), "https://api.inferhub.dev/v1/me/usage?window=day&tz=UTC&session_id=abc");
|
|
11
9
|
});
|
|
12
|
-
test("formatStatusLine is
|
|
10
|
+
test("formatStatusLine is compact one-liner", () => {
|
|
13
11
|
const usage = {
|
|
14
12
|
object: "account.usage",
|
|
15
13
|
currency: "USDC",
|
|
16
|
-
balance: { amount_usdc: "1.
|
|
14
|
+
balance: { amount_usdc: "1.312816", updated_at: null },
|
|
17
15
|
window: {
|
|
18
16
|
kind: "day",
|
|
19
17
|
tz: "UTC",
|
|
20
18
|
since: "",
|
|
21
19
|
until: "",
|
|
22
|
-
requests:
|
|
23
|
-
prompt_tokens:
|
|
24
|
-
completion_tokens:
|
|
25
|
-
total_tokens:
|
|
20
|
+
requests: 129,
|
|
21
|
+
prompt_tokens: 0,
|
|
22
|
+
completion_tokens: 0,
|
|
23
|
+
total_tokens: 26_400_000,
|
|
26
24
|
spend_usdc: "0",
|
|
27
25
|
},
|
|
28
26
|
all_time: {
|
|
29
|
-
requests:
|
|
30
|
-
prompt_tokens:
|
|
31
|
-
completion_tokens:
|
|
32
|
-
total_tokens:
|
|
33
|
-
spend_usdc: "0.
|
|
27
|
+
requests: 3933,
|
|
28
|
+
prompt_tokens: 0,
|
|
29
|
+
completion_tokens: 0,
|
|
30
|
+
total_tokens: 354_200_000,
|
|
31
|
+
spend_usdc: "0.41",
|
|
34
32
|
},
|
|
35
33
|
session: {
|
|
36
|
-
id: "
|
|
37
|
-
requests:
|
|
38
|
-
prompt_tokens:
|
|
39
|
-
completion_tokens:
|
|
40
|
-
total_tokens:
|
|
34
|
+
id: "s",
|
|
35
|
+
requests: 19,
|
|
36
|
+
prompt_tokens: 0,
|
|
37
|
+
completion_tokens: 0,
|
|
38
|
+
total_tokens: 6_000_000,
|
|
41
39
|
spend_usdc: "0",
|
|
42
40
|
since: null,
|
|
43
41
|
until: null,
|
|
@@ -45,41 +43,27 @@ test("formatStatusLine is plain language", () => {
|
|
|
45
43
|
top_model: {
|
|
46
44
|
model: "cx/gpt-5.5",
|
|
47
45
|
requests: 212,
|
|
48
|
-
tokens:
|
|
49
|
-
spend_usdc: "0.
|
|
46
|
+
tokens: 1,
|
|
47
|
+
spend_usdc: "0.14",
|
|
50
48
|
},
|
|
51
49
|
cache: { cached: false, ttl_seconds: 30 },
|
|
52
50
|
};
|
|
53
51
|
const line = formatStatusLine(usage, {
|
|
54
|
-
model: "
|
|
52
|
+
model: "grok-4.5",
|
|
55
53
|
contextPct: 8,
|
|
56
|
-
sessionCostUsd: 2.69,
|
|
57
54
|
});
|
|
58
|
-
|
|
59
|
-
assert.
|
|
60
|
-
assert.
|
|
61
|
-
assert.
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
assert.match(line, /8% context/);
|
|
65
|
-
assert.doesNotMatch(line, /\bIH\b/);
|
|
66
|
-
assert.doesNotMatch(line, /0r\/0/);
|
|
67
|
-
assert.doesNotMatch(line, /claude-est/); // estimate off by default
|
|
68
|
-
// empty/zero session should be omitted (not "sess 0r/0")
|
|
69
|
-
const noSess = {
|
|
55
|
+
// Must be short enough for one Claude status row
|
|
56
|
+
assert.ok(line.length < 100, `too long: ${line.length} ${line}`);
|
|
57
|
+
assert.equal(line, "InferHub · sess 19r · day 129r · all $0.41 · bal $1.31 · top gpt-5.5 · 8%");
|
|
58
|
+
assert.doesNotMatch(line, /req \/|tokens|context|today|all-time|balance /);
|
|
59
|
+
// paid day shows money
|
|
60
|
+
const paid = {
|
|
70
61
|
...usage,
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
requests: 0,
|
|
74
|
-
prompt_tokens: 0,
|
|
75
|
-
completion_tokens: 0,
|
|
76
|
-
total_tokens: 0,
|
|
77
|
-
spend_usdc: "0",
|
|
78
|
-
since: null,
|
|
79
|
-
until: null,
|
|
80
|
-
},
|
|
62
|
+
window: { ...usage.window, spend_usdc: "0.12", requests: 5 },
|
|
63
|
+
session: null,
|
|
81
64
|
};
|
|
82
|
-
const
|
|
83
|
-
assert.
|
|
84
|
-
assert.
|
|
65
|
+
const paidLine = formatStatusLine(paid);
|
|
66
|
+
assert.match(paidLine, /day \$0\.12\/5r/);
|
|
67
|
+
assert.doesNotMatch(paidLine, /sess /);
|
|
68
|
+
assert.equal(money("0"), "$0");
|
|
85
69
|
});
|
package/package.json
CHANGED
package/src/format.test.ts
CHANGED
|
@@ -5,49 +5,44 @@ import type { AccountUsage } from "./types.js";
|
|
|
5
5
|
|
|
6
6
|
test("normalizeBaseUrl adds /v1", () => {
|
|
7
7
|
assert.equal(normalizeBaseUrl("https://api.inferhub.dev"), "https://api.inferhub.dev/v1");
|
|
8
|
-
assert.equal(normalizeBaseUrl("https://api.inferhub.dev/v1/"), "https://api.inferhub.dev/v1");
|
|
9
8
|
});
|
|
10
9
|
|
|
11
10
|
test("usageUrl", () => {
|
|
12
|
-
assert.equal(
|
|
13
|
-
usageUrl("https://api.inferhub.dev", "day", "UTC"),
|
|
14
|
-
"https://api.inferhub.dev/v1/me/usage?window=day&tz=UTC",
|
|
15
|
-
);
|
|
16
11
|
assert.equal(
|
|
17
12
|
usageUrl("https://api.inferhub.dev", "day", "UTC", "abc"),
|
|
18
13
|
"https://api.inferhub.dev/v1/me/usage?window=day&tz=UTC&session_id=abc",
|
|
19
14
|
);
|
|
20
15
|
});
|
|
21
16
|
|
|
22
|
-
test("formatStatusLine is
|
|
17
|
+
test("formatStatusLine is compact one-liner", () => {
|
|
23
18
|
const usage: AccountUsage = {
|
|
24
19
|
object: "account.usage",
|
|
25
20
|
currency: "USDC",
|
|
26
|
-
balance: { amount_usdc: "1.
|
|
21
|
+
balance: { amount_usdc: "1.312816", updated_at: null },
|
|
27
22
|
window: {
|
|
28
23
|
kind: "day",
|
|
29
24
|
tz: "UTC",
|
|
30
25
|
since: "",
|
|
31
26
|
until: "",
|
|
32
|
-
requests:
|
|
33
|
-
prompt_tokens:
|
|
34
|
-
completion_tokens:
|
|
35
|
-
total_tokens:
|
|
27
|
+
requests: 129,
|
|
28
|
+
prompt_tokens: 0,
|
|
29
|
+
completion_tokens: 0,
|
|
30
|
+
total_tokens: 26_400_000,
|
|
36
31
|
spend_usdc: "0",
|
|
37
32
|
},
|
|
38
33
|
all_time: {
|
|
39
|
-
requests:
|
|
40
|
-
prompt_tokens:
|
|
41
|
-
completion_tokens:
|
|
42
|
-
total_tokens:
|
|
43
|
-
spend_usdc: "0.
|
|
34
|
+
requests: 3933,
|
|
35
|
+
prompt_tokens: 0,
|
|
36
|
+
completion_tokens: 0,
|
|
37
|
+
total_tokens: 354_200_000,
|
|
38
|
+
spend_usdc: "0.41",
|
|
44
39
|
},
|
|
45
40
|
session: {
|
|
46
|
-
id: "
|
|
47
|
-
requests:
|
|
48
|
-
prompt_tokens:
|
|
49
|
-
completion_tokens:
|
|
50
|
-
total_tokens:
|
|
41
|
+
id: "s",
|
|
42
|
+
requests: 19,
|
|
43
|
+
prompt_tokens: 0,
|
|
44
|
+
completion_tokens: 0,
|
|
45
|
+
total_tokens: 6_000_000,
|
|
51
46
|
spend_usdc: "0",
|
|
52
47
|
since: null,
|
|
53
48
|
until: null,
|
|
@@ -55,45 +50,34 @@ test("formatStatusLine is plain language", () => {
|
|
|
55
50
|
top_model: {
|
|
56
51
|
model: "cx/gpt-5.5",
|
|
57
52
|
requests: 212,
|
|
58
|
-
tokens:
|
|
59
|
-
spend_usdc: "0.
|
|
53
|
+
tokens: 1,
|
|
54
|
+
spend_usdc: "0.14",
|
|
60
55
|
},
|
|
61
56
|
cache: { cached: false, ttl_seconds: 30 },
|
|
62
57
|
};
|
|
63
58
|
|
|
64
59
|
const line = formatStatusLine(usage, {
|
|
65
|
-
model: "
|
|
60
|
+
model: "grok-4.5",
|
|
66
61
|
contextPct: 8,
|
|
67
|
-
sessionCostUsd: 2.69,
|
|
68
62
|
});
|
|
69
63
|
|
|
70
|
-
|
|
71
|
-
assert.
|
|
72
|
-
assert.
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
assert.
|
|
77
|
-
assert.doesNotMatch(line, /\bIH\b/);
|
|
78
|
-
assert.doesNotMatch(line, /0r\/0/);
|
|
79
|
-
assert.doesNotMatch(line, /claude-est/); // estimate off by default
|
|
64
|
+
// Must be short enough for one Claude status row
|
|
65
|
+
assert.ok(line.length < 100, `too long: ${line.length} ${line}`);
|
|
66
|
+
assert.equal(
|
|
67
|
+
line,
|
|
68
|
+
"InferHub · sess 19r · day 129r · all $0.41 · bal $1.31 · top gpt-5.5 · 8%",
|
|
69
|
+
);
|
|
70
|
+
assert.doesNotMatch(line, /req \/|tokens|context|today|all-time|balance /);
|
|
80
71
|
|
|
81
|
-
//
|
|
82
|
-
const
|
|
72
|
+
// paid day shows money
|
|
73
|
+
const paid: AccountUsage = {
|
|
83
74
|
...usage,
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
requests: 0,
|
|
87
|
-
prompt_tokens: 0,
|
|
88
|
-
completion_tokens: 0,
|
|
89
|
-
total_tokens: 0,
|
|
90
|
-
spend_usdc: "0",
|
|
91
|
-
since: null,
|
|
92
|
-
until: null,
|
|
93
|
-
},
|
|
75
|
+
window: { ...usage.window, spend_usdc: "0.12", requests: 5 },
|
|
76
|
+
session: null,
|
|
94
77
|
};
|
|
95
|
-
const
|
|
96
|
-
assert.
|
|
78
|
+
const paidLine = formatStatusLine(paid);
|
|
79
|
+
assert.match(paidLine, /day \$0\.12\/5r/);
|
|
80
|
+
assert.doesNotMatch(paidLine, /sess /);
|
|
97
81
|
|
|
98
|
-
assert.equal(money("0
|
|
82
|
+
assert.equal(money("0"), "$0");
|
|
99
83
|
});
|
package/src/format.ts
CHANGED
|
@@ -2,9 +2,11 @@ import type { AccountUsage } from "./types.js";
|
|
|
2
2
|
|
|
3
3
|
export function money(usdc: string | number | null | undefined, digits = 2): string {
|
|
4
4
|
const n = Number(usdc ?? 0);
|
|
5
|
-
if (!Number.isFinite(n)) return "$0
|
|
6
|
-
if (
|
|
7
|
-
return `$${n.toFixed(
|
|
5
|
+
if (!Number.isFinite(n)) return "$0";
|
|
6
|
+
if (n === 0) return "$0";
|
|
7
|
+
if (Math.abs(n) < 0.01) return `$${n.toFixed(4)}`;
|
|
8
|
+
if (Math.abs(n) < 1) return `$${n.toFixed(2)}`;
|
|
9
|
+
return `$${n.toFixed(2)}`;
|
|
8
10
|
}
|
|
9
11
|
|
|
10
12
|
export function tokens(n: number | null | undefined): string {
|
|
@@ -20,35 +22,28 @@ export function shortModel(model: string | null | undefined): string {
|
|
|
20
22
|
return parts[parts.length - 1] || model;
|
|
21
23
|
}
|
|
22
24
|
|
|
23
|
-
/**
|
|
24
|
-
function
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
requests?: number | null;
|
|
29
|
-
totalTokens?: number | null;
|
|
30
|
-
},
|
|
25
|
+
/** Compact metric: "$0.12" if billed, else "19r" (optionally with tokens if tiny). */
|
|
26
|
+
function compact(
|
|
27
|
+
spendUsdc: string | number | null | undefined,
|
|
28
|
+
requests: number | null | undefined,
|
|
29
|
+
totalTokens?: number | null,
|
|
31
30
|
): string {
|
|
32
|
-
const
|
|
33
|
-
const
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
bits.push(`${req.toLocaleString()} req`);
|
|
38
|
-
bits.push(`${tokens(tok)} tok`);
|
|
39
|
-
} else {
|
|
40
|
-
bits.push("no traffic");
|
|
31
|
+
const spend = Number(spendUsdc ?? 0);
|
|
32
|
+
const req = Number(requests ?? 0);
|
|
33
|
+
if (spend > 0) {
|
|
34
|
+
// billed: show money + req if space-ish useful
|
|
35
|
+
return req > 0 ? `${money(spend)}/${req}r` : money(spend);
|
|
41
36
|
}
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
return `${
|
|
37
|
+
// free / zero spend: show traffic only
|
|
38
|
+
if (req <= 0 && Number(totalTokens ?? 0) <= 0) return "—";
|
|
39
|
+
return `${req}r`;
|
|
45
40
|
}
|
|
46
41
|
|
|
47
42
|
/**
|
|
48
|
-
*
|
|
43
|
+
* One-line Claude statusline — keep short (Claude only shows one row).
|
|
49
44
|
*
|
|
50
|
-
*
|
|
51
|
-
*
|
|
45
|
+
* Example:
|
|
46
|
+
* InferHub · sess 19r · day 129r · all $0.41 · bal $1.31 · top gpt-5.5
|
|
52
47
|
*/
|
|
53
48
|
export function formatStatusLine(
|
|
54
49
|
usage: AccountUsage,
|
|
@@ -56,57 +51,26 @@ export function formatStatusLine(
|
|
|
56
51
|
sessionCostUsd?: number | null;
|
|
57
52
|
contextPct?: number | null;
|
|
58
53
|
model?: string | null;
|
|
59
|
-
/** When true, include Claude local list-price estimate. Default false. */
|
|
60
54
|
showEstimate?: boolean;
|
|
61
55
|
},
|
|
62
56
|
): string {
|
|
63
|
-
const model = extras?.model ? shortModel(extras.model) : null;
|
|
64
|
-
const bal = money(usage.balance.amount_usdc);
|
|
65
|
-
const top = shortModel(usage.top_model?.model);
|
|
66
|
-
const ctx =
|
|
67
|
-
extras?.contextPct != null && Number.isFinite(extras.contextPct)
|
|
68
|
-
? `${Math.round(extras.contextPct)}% context`
|
|
69
|
-
: null;
|
|
70
|
-
|
|
71
57
|
const parts: string[] = ["InferHub"];
|
|
72
|
-
if (model) parts.push(model);
|
|
73
58
|
|
|
74
|
-
//
|
|
59
|
+
// Session (latest IH conversation) — omit if empty
|
|
75
60
|
if (usage.session && (usage.session.requests > 0 || Number(usage.session.spend_usdc) > 0)) {
|
|
76
|
-
parts.push(
|
|
77
|
-
activity("session", {
|
|
78
|
-
spendUsdc: usage.session.spend_usdc,
|
|
79
|
-
requests: usage.session.requests,
|
|
80
|
-
totalTokens: usage.session.total_tokens,
|
|
81
|
-
}),
|
|
82
|
-
);
|
|
61
|
+
parts.push(`sess ${compact(usage.session.spend_usdc, usage.session.requests, usage.session.total_tokens)}`);
|
|
83
62
|
}
|
|
84
63
|
|
|
85
|
-
parts.push(
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
}),
|
|
91
|
-
);
|
|
92
|
-
parts.push(
|
|
93
|
-
activity("all-time", {
|
|
94
|
-
spendUsdc: usage.all_time.spend_usdc,
|
|
95
|
-
requests: usage.all_time.requests,
|
|
96
|
-
totalTokens: usage.all_time.total_tokens,
|
|
97
|
-
}),
|
|
98
|
-
);
|
|
99
|
-
parts.push(`balance ${bal}`);
|
|
64
|
+
parts.push(`day ${compact(usage.window.spend_usdc, usage.window.requests, usage.window.total_tokens)}`);
|
|
65
|
+
parts.push(`all ${compact(usage.all_time.spend_usdc, usage.all_time.requests)}`);
|
|
66
|
+
parts.push(`bal ${money(usage.balance.amount_usdc)}`);
|
|
67
|
+
|
|
68
|
+
const top = shortModel(usage.top_model?.model);
|
|
100
69
|
if (top && top !== "—") parts.push(`top ${top}`);
|
|
101
|
-
if (ctx) parts.push(ctx);
|
|
102
70
|
|
|
103
|
-
if
|
|
104
|
-
|
|
105
|
-
extras.
|
|
106
|
-
Number.isFinite(extras.sessionCostUsd) &&
|
|
107
|
-
extras.sessionCostUsd > 0
|
|
108
|
-
) {
|
|
109
|
-
parts.push(`claude-est ${money(extras.sessionCostUsd)}`);
|
|
71
|
+
// context % is useful but optional — only if provided and non-zero space
|
|
72
|
+
if (extras?.contextPct != null && Number.isFinite(extras.contextPct)) {
|
|
73
|
+
parts.push(`${Math.round(extras.contextPct)}%`);
|
|
110
74
|
}
|
|
111
75
|
|
|
112
76
|
return parts.join(" · ");
|